@happyvertical/smrt-cli 0.51.39 → 0.53.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.
- package/AGENTS.md +7 -2
- package/README.md +22 -0
- package/agents/type-drift.md +16 -0
- package/dist/{ApiKey-BZmbOTnL-DEwZtcGA.js → ApiKey-BZmbOTnL-d61__hH4.js} +2 -2
- package/dist/ApiKeyCollection-Bfb_nw81-BVJ-i1Aw.js +2 -0
- package/dist/AuditLogCollection-B1YonCAP-bpq7rM2b.js +2 -0
- package/dist/{NostrIdentity-n70E0vck-DiBJPv76.js → NostrIdentity-n70E0vck-CmFPKTaE.js} +3 -3
- package/dist/NostrIdentityCollection-Ca74dkaL-C0rNgSy-.js +2 -0
- package/dist/{OidcIdentity-K8V4u0CR-B_ek3cPN.js → OidcIdentity-Cb1bxreM-L5LCgsel.js} +3 -3
- package/dist/OidcIdentityCollection-TV8VdK69-CUmZ-j4r.js +2 -0
- package/dist/ProfileAssetCollection-B9hacUJa-C53RAi1e.js +2 -0
- package/dist/{ProfileCollection-DTT4KNpQ-D1RNYfjm.js → ProfileCollection-DuJT7Mum-zuWR2h3v.js} +69 -31
- package/dist/ProfileLinkCollection-4uNURz32-Fmbnrmyr.js +2 -0
- package/dist/ProfileMetadataCollection-DQhbfEfa-D30yWyzB.js +2 -0
- package/dist/{ProfileMetafieldCollection-CMKhVi2I-mh3UgeZA.js → ProfileMetafieldCollection-CoBuM_5G-TNxSMsBJ.js} +1 -1
- package/dist/{ProfileRelationshipCollection-DUVgaIqf-CXHrAni4.js → ProfileRelationshipCollection-DUVgaIqf-CKcxS2xW.js} +1 -1
- package/dist/{ProfileRelationshipTermCollection-DtA9OM23-Cj4bLTpU.js → ProfileRelationshipTermCollection-DtA9OM23-h-4GhOFl.js} +1 -1
- package/dist/{ProfileRelationshipType-BRiRka6t-ICv2cawn.js → ProfileRelationshipType-BRiRka6t-BFgCVe6p.js} +1 -1
- package/dist/{ProfileRelationshipTypeCollection-BdXwd7Kf-CaYLxJmh.js → ProfileRelationshipTypeCollection-BdXwd7Kf-Djb3_k5Z.js} +1 -1
- package/dist/cli-generator.d.ts.map +1 -1
- package/dist/commands/db-diff.d.ts.map +1 -1
- package/dist/commands/db-history.d.ts.map +1 -1
- package/dist/commands/db-migrate-actions.d.ts +7 -0
- package/dist/commands/db-migrate-actions.d.ts.map +1 -1
- package/dist/commands/db-parity.d.ts +7 -0
- package/dist/commands/db-parity.d.ts.map +1 -1
- package/dist/commands/db-qualified-names.d.ts +39 -0
- package/dist/commands/db-qualified-names.d.ts.map +1 -0
- package/dist/commands/db-status.d.ts.map +1 -1
- package/dist/commands/gnode.d.ts.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/mcp-apps-packaging.d.ts +24 -0
- package/dist/commands/mcp-apps-packaging.d.ts.map +1 -0
- package/dist/commands/tenant-natural-keys.d.ts +58 -0
- package/dist/commands/tenant-natural-keys.d.ts.map +1 -0
- package/dist/commands/utilities.d.ts.map +1 -1
- package/dist/{commands-C2PjCUio.js → commands-e1tsvozP.js} +650 -22
- package/dist/{dist-B3npUhW6.js → dist-8C4XjDhz.js} +151 -6
- package/dist/{dist-C8sNOzr2.js → dist-CLA60jwS.js} +4 -4
- package/dist/dist-CksLvqnZ.js +1705 -0
- package/dist/dist-DtTkpUee.js +3937 -0
- package/dist/index.js +17 -11
- package/dist/{json-validator-oEN7eUI3.js → json-validator-BiAdsE1O.js} +4 -4
- package/dist/{oidcProvisioningPrimitives-0-3n3D6f-yUBRl2DC.js → oidcProvisioningPrimitives-D9OYu5-F-CJ6bTipi.js} +7 -7
- package/dist/resolveIdentity-B-PK6RwU-DxJFF8ad.js +2 -0
- package/package.json +16 -15
- package/dist/ApiKeyCollection-Bfb_nw81-D4pLjDGS.js +0 -2
- package/dist/AuditLogCollection-B1YonCAP-w1iOHW4A.js +0 -2
- package/dist/NostrIdentityCollection-Ca74dkaL-Ce-O_zQz.js +0 -2
- package/dist/OidcIdentityCollection-gnrLoF08-DJI-69Ow.js +0 -2
- package/dist/ProfileAssetCollection-CmbeSgDi-BpJ7XXsP.js +0 -2
- package/dist/ProfileMetadataCollection-DxX_BJKV-orYFlYii.js +0 -2
- package/dist/dist-DsMohSo_.js +0 -1487
- package/dist/dist-iMaSv6C_.js +0 -3712
- package/dist/resolveIdentity-BrJDCjYi-kdAssLr0.js +0 -2
package/dist/dist-iMaSv6C_.js
DELETED
|
@@ -1,3712 +0,0 @@
|
|
|
1
|
-
import { c as withSystemContext, i as tenantId, r as TenantScoped } from "./dist-B3npUhW6.js";
|
|
2
|
-
import { a as verifyAuthEvent, i as generateNostrKeypair, n as __exportAll$1, r as encryptPrivkey, t as NostrIdentity } from "./NostrIdentity-n70E0vck-DiBJPv76.js";
|
|
3
|
-
import { t as ApiKey } from "./ApiKey-BZmbOTnL-DEwZtcGA.js";
|
|
4
|
-
import { t as OidcIdentity } from "./OidcIdentity-K8V4u0CR-B_ek3cPN.js";
|
|
5
|
-
import { a as removeOwnedAssetFromCollection, i as getOwnedAssetsFromCollection, t as addOwnedAssetFromCollection } from "./dist-DsMohSo_.js";
|
|
6
|
-
import { a as coordinateOidcProvisioning, o as isOidcProvisioningRaceConflict, s as normalizeIdentityEmail } from "./ProfileCollection-DTT4KNpQ-D1RNYfjm.js";
|
|
7
|
-
import { t as ProfileRelationshipType } from "./ProfileRelationshipType-BRiRka6t-ICv2cawn.js";
|
|
8
|
-
import { n as insertOidcProvisioningIdentity, t as createOidcProvisioningPerson } from "./oidcProvisioningPrimitives-0-3n3D6f-yUBRl2DC.js";
|
|
9
|
-
import { ObjectRegistry, SmrtCollection, SmrtJunction, SmrtObject, bumpChangeFeed, crossPackageRef, field, foreignKey, oneToMany, registerRetentionTask, resolveDatabase, smrt } from "@happyvertical/smrt-core";
|
|
10
|
-
import { createLogger } from "@happyvertical/logger";
|
|
11
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
12
|
-
import "@happyvertical/smrt-config";
|
|
13
|
-
import "@happyvertical/smrt-core/migrations";
|
|
14
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15
|
-
import { AccessRequestStatus, MembershipStatus, OverrideEffect, SessionStatus, TenantPermissionEffect, TenantStatus, UserStatus } from "@happyvertical/smrt-types";
|
|
16
|
-
//#region ../profiles/dist/chunks/ApiKeyCollection-Bfb_nw81.js
|
|
17
|
-
var ApiKeyCollection_exports = /* @__PURE__ */ __exportAll$1({ ApiKeyCollection: () => ApiKeyCollection });
|
|
18
|
-
var ApiKeyCollection = class extends SmrtCollection {
|
|
19
|
-
static _itemClass = ApiKey;
|
|
20
|
-
/**
|
|
21
|
-
* Find all keys for a profile
|
|
22
|
-
*/
|
|
23
|
-
async findByProfile(profileId) {
|
|
24
|
-
return await this.list({ where: { profileId } });
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Find active (non-revoked, non-expired) keys for a profile
|
|
28
|
-
*/
|
|
29
|
-
async findActiveByProfile(profileId) {
|
|
30
|
-
return (await this.findByProfile(profileId)).filter((key) => key.isValid());
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Find key by hash
|
|
34
|
-
*/
|
|
35
|
-
async findByHash(keyHash) {
|
|
36
|
-
return await this.findOne({ where: { keyHash } });
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Verify an API key string and return the record if valid
|
|
40
|
-
*/
|
|
41
|
-
async verify(key) {
|
|
42
|
-
const keyHash = ApiKey.hashKey(key);
|
|
43
|
-
const apiKey = await this.findByHash(keyHash);
|
|
44
|
-
if (!apiKey) return null;
|
|
45
|
-
if (!apiKey.isValid()) return null;
|
|
46
|
-
await apiKey.recordUsage();
|
|
47
|
-
if (!apiKey.isValid()) return null;
|
|
48
|
-
return apiKey;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Generate a new key for a profile
|
|
52
|
-
*/
|
|
53
|
-
async generateForProfile(profile, options) {
|
|
54
|
-
return await ApiKey.generate(profile, {
|
|
55
|
-
...options,
|
|
56
|
-
db: this.options.db
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Revoke all keys for a profile
|
|
61
|
-
*/
|
|
62
|
-
async revokeAllForProfile(profileId) {
|
|
63
|
-
const keys = await this.findActiveByProfile(profileId);
|
|
64
|
-
for (const key of keys) await key.revoke();
|
|
65
|
-
return keys.length;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Revoke a specific key by prefix
|
|
69
|
-
*/
|
|
70
|
-
async revokeByPrefix(keyPrefix) {
|
|
71
|
-
const key = await this.findOne({ where: { keyPrefix } });
|
|
72
|
-
if (key?.isValid()) {
|
|
73
|
-
await key.revoke();
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Clean up expired keys (soft delete by setting revokedAt)
|
|
80
|
-
*/
|
|
81
|
-
async cleanupExpired() {
|
|
82
|
-
const now = /* @__PURE__ */ new Date();
|
|
83
|
-
const allKeys = await this.list({});
|
|
84
|
-
let cleaned = 0;
|
|
85
|
-
for (const key of allKeys) if (key.expiresAt && key.expiresAt < now && !key.revokedAt) {
|
|
86
|
-
key.revokedAt = now;
|
|
87
|
-
await key.save();
|
|
88
|
-
cleaned++;
|
|
89
|
-
}
|
|
90
|
-
return cleaned;
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
//#endregion
|
|
94
|
-
//#region ../profiles/dist/chunks/AuditLogCollection-B1YonCAP.js
|
|
95
|
-
var __defProp$22 = Object.defineProperty;
|
|
96
|
-
var __getOwnPropDesc$21 = Object.getOwnPropertyDescriptor;
|
|
97
|
-
var __decorateClass$21 = (decorators, target, key, kind) => {
|
|
98
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$21(target, key) : target;
|
|
99
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
100
|
-
if (kind && result) __defProp$22(target, key, result);
|
|
101
|
-
return result;
|
|
102
|
-
};
|
|
103
|
-
var AuditLog = class extends SmrtObject {
|
|
104
|
-
tenantId = null;
|
|
105
|
-
profileId;
|
|
106
|
-
/**
|
|
107
|
-
* Action performed (e.g., 'issue.update', 'feedback.incorporate')
|
|
108
|
-
*/
|
|
109
|
-
action = "";
|
|
110
|
-
/**
|
|
111
|
-
* Type of resource affected (e.g., 'Issue', 'Repository')
|
|
112
|
-
*/
|
|
113
|
-
resourceType = "";
|
|
114
|
-
/**
|
|
115
|
-
* ID of the affected resource
|
|
116
|
-
*/
|
|
117
|
-
resourceId = "";
|
|
118
|
-
/**
|
|
119
|
-
* Source of the action
|
|
120
|
-
*/
|
|
121
|
-
source = "web";
|
|
122
|
-
/**
|
|
123
|
-
* Additional context (CI run ID, request ID, etc.)
|
|
124
|
-
*/
|
|
125
|
-
metadata = {};
|
|
126
|
-
onBehalfOfId;
|
|
127
|
-
constructor(options = {}) {
|
|
128
|
-
super(options);
|
|
129
|
-
if (options.profileId) this.profileId = options.profileId;
|
|
130
|
-
if (options.action) this.action = options.action;
|
|
131
|
-
if (options.resourceType) this.resourceType = options.resourceType;
|
|
132
|
-
if (options.resourceId) this.resourceId = options.resourceId;
|
|
133
|
-
if (options.source) this.source = options.source;
|
|
134
|
-
if (options.metadata) this.metadata = options.metadata;
|
|
135
|
-
if (options.onBehalfOfId !== void 0) this.onBehalfOfId = options.onBehalfOfId;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Get the profile who performed the action
|
|
139
|
-
*/
|
|
140
|
-
async getProfile() {
|
|
141
|
-
return await this.getRelated("profileId");
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Get the profile on whose behalf the action was performed (if any)
|
|
145
|
-
*/
|
|
146
|
-
async getOnBehalfOf() {
|
|
147
|
-
if (!this.onBehalfOfId) return null;
|
|
148
|
-
return await this.getRelated("onBehalfOfId");
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Get the effective actor (onBehalfOf if set, otherwise profile)
|
|
152
|
-
*/
|
|
153
|
-
async getEffectiveActor() {
|
|
154
|
-
const onBehalfOf = await this.getOnBehalfOf();
|
|
155
|
-
if (onBehalfOf) return onBehalfOf;
|
|
156
|
-
return await this.getProfile();
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Create an audit log entry
|
|
160
|
-
*/
|
|
161
|
-
static async record(options) {
|
|
162
|
-
const log = new AuditLog({
|
|
163
|
-
...options,
|
|
164
|
-
profileId: options.profile.id,
|
|
165
|
-
onBehalfOfId: options.onBehalfOf?.id
|
|
166
|
-
});
|
|
167
|
-
await log.initialize();
|
|
168
|
-
await log.save();
|
|
169
|
-
return log;
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
__decorateClass$21([tenantId({ nullable: true })], AuditLog.prototype, "tenantId", 2);
|
|
173
|
-
__decorateClass$21([foreignKey("Profile", { required: true })], AuditLog.prototype, "profileId", 2);
|
|
174
|
-
__decorateClass$21([foreignKey("Profile", { nullable: true })], AuditLog.prototype, "onBehalfOfId", 2);
|
|
175
|
-
AuditLog = __decorateClass$21([TenantScoped({
|
|
176
|
-
mode: "optional",
|
|
177
|
-
allowSuperAdminBypass: true
|
|
178
|
-
}), smrt({
|
|
179
|
-
tableName: "audit_logs",
|
|
180
|
-
api: { include: ["list", "get"] },
|
|
181
|
-
mcp: { include: ["list", "get"] },
|
|
182
|
-
cli: { include: ["list"] }
|
|
183
|
-
})], AuditLog);
|
|
184
|
-
var AuditLogCollection_exports = /* @__PURE__ */ __exportAll$1({ AuditLogCollection: () => AuditLogCollection });
|
|
185
|
-
var AuditLogCollection = class extends SmrtCollection {
|
|
186
|
-
static _itemClass = AuditLog;
|
|
187
|
-
/**
|
|
188
|
-
* Find logs for a profile (actions they performed)
|
|
189
|
-
*/
|
|
190
|
-
async findByProfile(profileId) {
|
|
191
|
-
return await this.list({
|
|
192
|
-
where: { profileId },
|
|
193
|
-
orderBy: "createdAt DESC"
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Find logs for a resource
|
|
198
|
-
*/
|
|
199
|
-
async findByResource(resourceType, resourceId) {
|
|
200
|
-
return await this.list({
|
|
201
|
-
where: {
|
|
202
|
-
resourceType,
|
|
203
|
-
resourceId
|
|
204
|
-
},
|
|
205
|
-
orderBy: "createdAt DESC"
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Find logs by action type
|
|
210
|
-
*/
|
|
211
|
-
async findByAction(action) {
|
|
212
|
-
return await this.list({
|
|
213
|
-
where: { action },
|
|
214
|
-
orderBy: "createdAt DESC"
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Find logs by source
|
|
219
|
-
*/
|
|
220
|
-
async findBySource(source) {
|
|
221
|
-
return await this.list({
|
|
222
|
-
where: { source },
|
|
223
|
-
orderBy: "createdAt DESC"
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Find logs where actions were performed on behalf of someone
|
|
228
|
-
*/
|
|
229
|
-
async findOnBehalfOf(profileId) {
|
|
230
|
-
return await this.list({
|
|
231
|
-
where: { onBehalfOfId: profileId },
|
|
232
|
-
orderBy: "createdAt DESC"
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Record a new audit log entry
|
|
237
|
-
*/
|
|
238
|
-
async record(options) {
|
|
239
|
-
const log = new AuditLog({
|
|
240
|
-
...this.options,
|
|
241
|
-
profileId: options.profile.id,
|
|
242
|
-
action: options.action,
|
|
243
|
-
resourceType: options.resourceType,
|
|
244
|
-
resourceId: options.resourceId,
|
|
245
|
-
source: options.source || "web",
|
|
246
|
-
metadata: options.metadata || {},
|
|
247
|
-
onBehalfOfId: options.onBehalfOf?.id
|
|
248
|
-
});
|
|
249
|
-
await log.initialize();
|
|
250
|
-
await log.save();
|
|
251
|
-
return log;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Get recent activity for a profile
|
|
255
|
-
*/
|
|
256
|
-
async getRecentActivity(profileId, limit = 50) {
|
|
257
|
-
return await this.list({
|
|
258
|
-
where: { profileId },
|
|
259
|
-
orderBy: "createdAt DESC",
|
|
260
|
-
limit
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Get activity timeline for a resource
|
|
265
|
-
*/
|
|
266
|
-
async getResourceTimeline(resourceType, resourceId) {
|
|
267
|
-
return await this.list({
|
|
268
|
-
where: {
|
|
269
|
-
resourceType,
|
|
270
|
-
resourceId
|
|
271
|
-
},
|
|
272
|
-
orderBy: "createdAt ASC"
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
//#endregion
|
|
277
|
-
//#region ../profiles/dist/chunks/NostrIdentityCollection-Ca74dkaL.js
|
|
278
|
-
var NostrIdentityCollection_exports = /* @__PURE__ */ __exportAll$1({ NostrIdentityCollection: () => NostrIdentityCollection });
|
|
279
|
-
var NostrIdentityCollection = class extends SmrtCollection {
|
|
280
|
-
static _itemClass = NostrIdentity;
|
|
281
|
-
/**
|
|
282
|
-
* Find identities for a profile
|
|
283
|
-
*/
|
|
284
|
-
async findByProfile(profileId) {
|
|
285
|
-
return await this.list({ where: { profileId } });
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Find identity by public key
|
|
289
|
-
*/
|
|
290
|
-
async findByPubkey(pubkey) {
|
|
291
|
-
return await this.findOne({ where: { pubkey } });
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Find identity by email
|
|
295
|
-
*/
|
|
296
|
-
async findByEmail(email) {
|
|
297
|
-
return await this.findOne({ where: { email: email.toLowerCase() } });
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Find identity by NIP-05 username
|
|
301
|
-
*/
|
|
302
|
-
async findByNip05(username) {
|
|
303
|
-
return await this.findOne({ where: { nip05Username: username.toLowerCase() } });
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Link a new Nostr identity to a profile with a new keypair
|
|
307
|
-
* @param profile - The profile to link to
|
|
308
|
-
* @param email - Email address for this identity
|
|
309
|
-
* @param masterSecret - Server master secret for encryption
|
|
310
|
-
* @param nip05Username - Optional NIP-05 username (defaults to email local part)
|
|
311
|
-
*/
|
|
312
|
-
async createForProfile(profile, email, masterSecret, nip05Username) {
|
|
313
|
-
const normalizedEmail = email.toLowerCase();
|
|
314
|
-
if (await this.findByEmail(normalizedEmail)) throw new Error(`Nostr identity already exists for email: ${email}`);
|
|
315
|
-
const keypair = generateNostrKeypair();
|
|
316
|
-
const encrypted = encryptPrivkey(keypair.privkey, masterSecret);
|
|
317
|
-
const username = nip05Username?.toLowerCase() || normalizedEmail.split("@")[0];
|
|
318
|
-
const identity = new NostrIdentity({
|
|
319
|
-
...this.options,
|
|
320
|
-
profileId: profile.id,
|
|
321
|
-
pubkey: keypair.pubkey,
|
|
322
|
-
encryptedPrivkey: encrypted.ciphertext,
|
|
323
|
-
encryptionIv: encrypted.iv,
|
|
324
|
-
encryptionTag: encrypted.tag,
|
|
325
|
-
email: normalizedEmail,
|
|
326
|
-
nip05Username: username
|
|
327
|
-
});
|
|
328
|
-
await identity.initialize();
|
|
329
|
-
await identity.save();
|
|
330
|
-
return identity;
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Link an existing Nostr identity (with encrypted keypair) to a profile
|
|
334
|
-
*/
|
|
335
|
-
async linkToProfile(profile, nostrData) {
|
|
336
|
-
if (await this.findByPubkey(nostrData.pubkey)) throw new Error("Nostr identity with this public key already exists");
|
|
337
|
-
if (await this.findByEmail(nostrData.email)) throw new Error("Nostr identity with this email already exists");
|
|
338
|
-
const identity = new NostrIdentity({
|
|
339
|
-
...this.options,
|
|
340
|
-
profileId: profile.id,
|
|
341
|
-
pubkey: nostrData.pubkey,
|
|
342
|
-
encryptedPrivkey: nostrData.encryptedPrivkey,
|
|
343
|
-
encryptionIv: nostrData.encryptionIv,
|
|
344
|
-
encryptionTag: nostrData.encryptionTag,
|
|
345
|
-
email: nostrData.email.toLowerCase(),
|
|
346
|
-
nip05Username: nostrData.nip05Username?.toLowerCase() || nostrData.email.toLowerCase().split("@")[0]
|
|
347
|
-
});
|
|
348
|
-
await identity.initialize();
|
|
349
|
-
await identity.save();
|
|
350
|
-
return identity;
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Unlink a Nostr identity from a profile
|
|
354
|
-
*/
|
|
355
|
-
async unlinkFromProfile(profileId, pubkey) {
|
|
356
|
-
const identity = await this.findOne({ where: {
|
|
357
|
-
profileId,
|
|
358
|
-
pubkey
|
|
359
|
-
} });
|
|
360
|
-
if (identity) {
|
|
361
|
-
await identity.delete();
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Get NIP-05 response data for the /.well-known/nostr.json endpoint
|
|
368
|
-
* @param username - Optional username filter, returns all if not provided
|
|
369
|
-
*/
|
|
370
|
-
async getNip05Response(username) {
|
|
371
|
-
const where = username ? { nip05Username: username.toLowerCase() } : {};
|
|
372
|
-
const identities = await this.list({ where });
|
|
373
|
-
const names = {};
|
|
374
|
-
for (const identity of identities) if (identity.nip05Username && identity.pubkey) names[identity.nip05Username] = identity.pubkey;
|
|
375
|
-
return { names };
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Check if a NIP-05 username is available
|
|
379
|
-
*/
|
|
380
|
-
async isNip05Available(username) {
|
|
381
|
-
return await this.findByNip05(username) === null;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Update NIP-05 username for an identity
|
|
385
|
-
*/
|
|
386
|
-
async updateNip05Username(identity, newUsername) {
|
|
387
|
-
const normalizedUsername = newUsername.toLowerCase();
|
|
388
|
-
const existing = await this.findByNip05(normalizedUsername);
|
|
389
|
-
if (existing && existing.id !== identity.id) throw new Error(`NIP-05 username "${newUsername}" is already taken`);
|
|
390
|
-
identity.nip05Username = normalizedUsername;
|
|
391
|
-
await identity.save();
|
|
392
|
-
return identity;
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
//#endregion
|
|
396
|
-
//#region ../profiles/dist/chunks/OidcIdentityCollection-gnrLoF08.js
|
|
397
|
-
var OidcIdentityCollection_exports = /* @__PURE__ */ __exportAll$1({
|
|
398
|
-
AmbiguousOidcIdentityError: () => AmbiguousOidcIdentityError,
|
|
399
|
-
OidcIdentityCollection: () => OidcIdentityCollection
|
|
400
|
-
});
|
|
401
|
-
var AmbiguousOidcIdentityError = class extends Error {
|
|
402
|
-
constructor(issuer, subject) {
|
|
403
|
-
super("Multiple OIDC identities match the same issuer and subject.");
|
|
404
|
-
this.issuer = issuer;
|
|
405
|
-
this.subject = subject;
|
|
406
|
-
this.name = "AmbiguousOidcIdentityError";
|
|
407
|
-
}
|
|
408
|
-
issuer;
|
|
409
|
-
subject;
|
|
410
|
-
};
|
|
411
|
-
var OidcIdentityCollection = class extends SmrtCollection {
|
|
412
|
-
static _itemClass = OidcIdentity;
|
|
413
|
-
/**
|
|
414
|
-
* Find identities for a profile
|
|
415
|
-
*/
|
|
416
|
-
async findByProfile(profileId) {
|
|
417
|
-
return await this.list({ where: { profileId } });
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Find identity by issuer and subject
|
|
421
|
-
*/
|
|
422
|
-
async findBySubject(issuer, subject) {
|
|
423
|
-
const result = await this.db.query(`SELECT CAST(id AS VARCHAR) AS id,
|
|
424
|
-
CAST(profile_id AS VARCHAR) AS profile_id
|
|
425
|
-
FROM oidc_identities
|
|
426
|
-
WHERE issuer = ? AND subject = ?
|
|
427
|
-
LIMIT 2`, issuer, subject);
|
|
428
|
-
if (result.rows.length > 1) throw new AmbiguousOidcIdentityError(issuer, subject);
|
|
429
|
-
const row = result.rows[0];
|
|
430
|
-
const id = row?.id;
|
|
431
|
-
const profileId = row?.profile_id;
|
|
432
|
-
if (typeof id !== "string" || typeof profileId !== "string") return null;
|
|
433
|
-
const identity = await this.get({ id });
|
|
434
|
-
if (!identity) return null;
|
|
435
|
-
identity.id = id;
|
|
436
|
-
identity.profileId = profileId;
|
|
437
|
-
return identity;
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Find identities by provider
|
|
441
|
-
*/
|
|
442
|
-
async findByProvider(provider) {
|
|
443
|
-
return await this.list({ where: { provider } });
|
|
444
|
-
}
|
|
445
|
-
/**
|
|
446
|
-
* Reuse an existing exact OIDC identity for its unchanged Profile.
|
|
447
|
-
*
|
|
448
|
-
* @deprecated New authentication links require the owner-aware,
|
|
449
|
-
* transactional provisioning APIs. This compatibility helper may refresh a
|
|
450
|
-
* legacy Profile type, but refuses to create or rebind authority.
|
|
451
|
-
*/
|
|
452
|
-
async linkToProfile(profile, oidcData) {
|
|
453
|
-
return OidcIdentity.findOrCreate(profile, oidcData, this.options);
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Unlink an OIDC identity from a profile
|
|
457
|
-
*/
|
|
458
|
-
async unlinkFromProfile(profileId, issuer, subject) {
|
|
459
|
-
const identity = await this.findOne({ where: {
|
|
460
|
-
profileId,
|
|
461
|
-
issuer,
|
|
462
|
-
subject
|
|
463
|
-
} });
|
|
464
|
-
if (identity) {
|
|
465
|
-
await identity.delete();
|
|
466
|
-
return true;
|
|
467
|
-
}
|
|
468
|
-
return false;
|
|
469
|
-
}
|
|
470
|
-
};
|
|
471
|
-
//#endregion
|
|
472
|
-
//#region ../profiles/dist/chunks/ProfileAssetCollection-CmbeSgDi.js
|
|
473
|
-
var __defProp$1$19 = Object.defineProperty;
|
|
474
|
-
var __getOwnPropDesc$1$18 = Object.getOwnPropertyDescriptor;
|
|
475
|
-
var __decorateClass$1$18 = (decorators, target, key, kind) => {
|
|
476
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1$18(target, key) : target;
|
|
477
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
478
|
-
if (kind && result) __defProp$1$19(target, key, result);
|
|
479
|
-
return result;
|
|
480
|
-
};
|
|
481
|
-
var ProfileAsset = class extends SmrtObject {
|
|
482
|
-
tenantId = null;
|
|
483
|
-
profileId = "";
|
|
484
|
-
assetId = "";
|
|
485
|
-
relationship = "attachment";
|
|
486
|
-
sortOrder = 0;
|
|
487
|
-
constructor(options = {}) {
|
|
488
|
-
super(options);
|
|
489
|
-
if (options.profileId) this.profileId = options.profileId;
|
|
490
|
-
if (options.assetId) this.assetId = options.assetId;
|
|
491
|
-
if (options.relationship) this.relationship = options.relationship;
|
|
492
|
-
if (options.sortOrder !== void 0) this.sortOrder = options.sortOrder;
|
|
493
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
494
|
-
}
|
|
495
|
-
};
|
|
496
|
-
__decorateClass$1$18([tenantId({ nullable: true })], ProfileAsset.prototype, "tenantId", 2);
|
|
497
|
-
__decorateClass$1$18([foreignKey("Profile", { required: true })], ProfileAsset.prototype, "profileId", 2);
|
|
498
|
-
__decorateClass$1$18([crossPackageRef("@happyvertical/smrt-assets:Asset", { required: true })], ProfileAsset.prototype, "assetId", 2);
|
|
499
|
-
__decorateClass$1$18([field({ required: true })], ProfileAsset.prototype, "relationship", 2);
|
|
500
|
-
__decorateClass$1$18([field()], ProfileAsset.prototype, "sortOrder", 2);
|
|
501
|
-
ProfileAsset = __decorateClass$1$18([TenantScoped({ mode: "optional" }), smrt({
|
|
502
|
-
tableName: "profile_assets",
|
|
503
|
-
conflictColumns: [
|
|
504
|
-
"profile_id",
|
|
505
|
-
"asset_id",
|
|
506
|
-
"relationship"
|
|
507
|
-
],
|
|
508
|
-
api: false,
|
|
509
|
-
mcp: false,
|
|
510
|
-
cli: false
|
|
511
|
-
})], ProfileAsset);
|
|
512
|
-
var ProfileAssetCollection_exports = /* @__PURE__ */ __exportAll$1({ ProfileAssetCollection: () => ProfileAssetCollection });
|
|
513
|
-
var __defProp$21 = Object.defineProperty;
|
|
514
|
-
var __getOwnPropDesc$20 = Object.getOwnPropertyDescriptor;
|
|
515
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp$21(obj, key, {
|
|
516
|
-
enumerable: true,
|
|
517
|
-
configurable: true,
|
|
518
|
-
writable: true,
|
|
519
|
-
value
|
|
520
|
-
}) : obj[key] = value;
|
|
521
|
-
var __decorateClass$20 = (decorators, target, key, kind) => {
|
|
522
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$20(target, key) : target;
|
|
523
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
524
|
-
if (kind && result) __defProp$21(target, key, result);
|
|
525
|
-
return result;
|
|
526
|
-
};
|
|
527
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
528
|
-
var ProfileAssetCollection = class extends SmrtJunction {
|
|
529
|
-
leftField = "profileId";
|
|
530
|
-
rightField = "assetId";
|
|
531
|
-
profileCollectionPromise = null;
|
|
532
|
-
async getProfileCollection() {
|
|
533
|
-
if (!this.profileCollectionPromise) {
|
|
534
|
-
const { ProfileCollection } = await import("./ProfileCollection-DTT4KNpQ-D1RNYfjm.js").then((n) => n.r).then((n) => n.r);
|
|
535
|
-
this.profileCollectionPromise = ProfileCollection.create({ db: this.db });
|
|
536
|
-
}
|
|
537
|
-
return this.profileCollectionPromise;
|
|
538
|
-
}
|
|
539
|
-
async getAssets(profileId, relationship) {
|
|
540
|
-
return getOwnedAssetsFromCollection(await this.getProfileCollection(), profileId, relationship);
|
|
541
|
-
}
|
|
542
|
-
async addAsset(profileId, asset, relationship = "attachment", sortOrder = 0) {
|
|
543
|
-
await addOwnedAssetFromCollection(await this.getProfileCollection(), "Profile", profileId, asset, relationship, sortOrder);
|
|
544
|
-
}
|
|
545
|
-
async removeAsset(profileId, assetId, relationship) {
|
|
546
|
-
await removeOwnedAssetFromCollection(await this.getProfileCollection(), "Profile", profileId, assetId, relationship);
|
|
547
|
-
}
|
|
548
|
-
};
|
|
549
|
-
__publicField(ProfileAssetCollection, "_itemClass", ProfileAsset);
|
|
550
|
-
ProfileAssetCollection = __decorateClass$20([smrt({
|
|
551
|
-
api: false,
|
|
552
|
-
mcp: false,
|
|
553
|
-
cli: false
|
|
554
|
-
})], ProfileAssetCollection);
|
|
555
|
-
//#endregion
|
|
556
|
-
//#region ../profiles/dist/chunks/ProfileMetadataCollection-DxX_BJKV.js
|
|
557
|
-
var __defProp$20 = Object.defineProperty;
|
|
558
|
-
var __getOwnPropDesc$19 = Object.getOwnPropertyDescriptor;
|
|
559
|
-
var __decorateClass$19 = (decorators, target, key, kind) => {
|
|
560
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$19(target, key) : target;
|
|
561
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
562
|
-
if (kind && result) __defProp$20(target, key, result);
|
|
563
|
-
return result;
|
|
564
|
-
};
|
|
565
|
-
var ProfileMetadata = class extends SmrtObject {
|
|
566
|
-
tenantId = null;
|
|
567
|
-
profileId;
|
|
568
|
-
metafieldId;
|
|
569
|
-
value = "";
|
|
570
|
-
constructor(options = {}) {
|
|
571
|
-
super(options);
|
|
572
|
-
if (options.profileId !== void 0) this.profileId = options.profileId;
|
|
573
|
-
if (options.metafieldId !== void 0) this.metafieldId = options.metafieldId;
|
|
574
|
-
if (options.value) this.value = options.value;
|
|
575
|
-
}
|
|
576
|
-
/**
|
|
577
|
-
* Validate this metadata value against the metafield's validation schema
|
|
578
|
-
*
|
|
579
|
-
* @returns True if valid, throws error if invalid
|
|
580
|
-
*/
|
|
581
|
-
async validate() {
|
|
582
|
-
const metafield = await this.loadRelated("metafieldId");
|
|
583
|
-
if (!metafield) throw new Error("Metafield not found");
|
|
584
|
-
return await metafield.validateValue(this.value);
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Get the metafield slug for this metadata
|
|
588
|
-
*
|
|
589
|
-
* @returns The slug of the metafield
|
|
590
|
-
*/
|
|
591
|
-
async getMetafieldSlug() {
|
|
592
|
-
return (await this.loadRelated("metafieldId"))?.slug || "";
|
|
593
|
-
}
|
|
594
|
-
};
|
|
595
|
-
__decorateClass$19([tenantId({ nullable: true })], ProfileMetadata.prototype, "tenantId", 2);
|
|
596
|
-
__decorateClass$19([foreignKey("Profile", { required: true })], ProfileMetadata.prototype, "profileId", 2);
|
|
597
|
-
__decorateClass$19([foreignKey("ProfileMetafield", { required: true })], ProfileMetadata.prototype, "metafieldId", 2);
|
|
598
|
-
__decorateClass$19([field({ required: true })], ProfileMetadata.prototype, "value", 2);
|
|
599
|
-
ProfileMetadata = __decorateClass$19([TenantScoped({ mode: "optional" }), smrt({
|
|
600
|
-
tableStrategy: "sti",
|
|
601
|
-
api: { include: [
|
|
602
|
-
"list",
|
|
603
|
-
"get",
|
|
604
|
-
"create",
|
|
605
|
-
"update",
|
|
606
|
-
"delete"
|
|
607
|
-
] },
|
|
608
|
-
mcp: { include: ["list", "get"] },
|
|
609
|
-
cli: { skipApiCheck: true }
|
|
610
|
-
})], ProfileMetadata);
|
|
611
|
-
var ProfileMetadataCollection_exports = /* @__PURE__ */ __exportAll$1({ ProfileMetadataCollection: () => ProfileMetadataCollection });
|
|
612
|
-
var ProfileMetadataCollection = class extends SmrtCollection {
|
|
613
|
-
static _itemClass = ProfileMetadata;
|
|
614
|
-
/**
|
|
615
|
-
* Get all metadata for a profile
|
|
616
|
-
*
|
|
617
|
-
* @param profileId - The profile UUID
|
|
618
|
-
* @returns Array of ProfileMetadata instances
|
|
619
|
-
*/
|
|
620
|
-
async getByProfile(profileId) {
|
|
621
|
-
return await this.list({ where: { profileId } });
|
|
622
|
-
}
|
|
623
|
-
/**
|
|
624
|
-
* Get metadata as key-value object for a profile
|
|
625
|
-
*
|
|
626
|
-
* @param profileId - The profile UUID
|
|
627
|
-
* @returns Object with metafield slugs as keys
|
|
628
|
-
*/
|
|
629
|
-
async getMetadataObject(profileId) {
|
|
630
|
-
const metadata = await this.getByProfile(profileId);
|
|
631
|
-
const result = {};
|
|
632
|
-
for (const item of metadata) {
|
|
633
|
-
const slug = await item.getMetafieldSlug();
|
|
634
|
-
if (slug) result[slug] = item.value;
|
|
635
|
-
}
|
|
636
|
-
return result;
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* Find all profiles with a specific metadata key-value pair
|
|
640
|
-
*
|
|
641
|
-
* @param metafieldId - The metafield UUID
|
|
642
|
-
* @param value - The value to match
|
|
643
|
-
* @returns Array of profile UUIDs
|
|
644
|
-
*/
|
|
645
|
-
async findProfilesByMetadata(metafieldId, value) {
|
|
646
|
-
return (await this.list({ where: {
|
|
647
|
-
metafieldId,
|
|
648
|
-
value: String(value)
|
|
649
|
-
} })).map((m) => m.profileId).filter((id) => typeof id === "string");
|
|
650
|
-
}
|
|
651
|
-
};
|
|
652
|
-
//#endregion
|
|
653
|
-
//#region ../profiles/dist/chunks/ProfileMetafieldCollection-CMKhVi2I.js
|
|
654
|
-
var __defProp$19 = Object.defineProperty;
|
|
655
|
-
var __getOwnPropDesc$18 = Object.getOwnPropertyDescriptor;
|
|
656
|
-
var __decorateClass$18 = (decorators, target, key, kind) => {
|
|
657
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$18(target, key) : target;
|
|
658
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
659
|
-
if (kind && result) __defProp$19(target, key, result);
|
|
660
|
-
return result;
|
|
661
|
-
};
|
|
662
|
-
function getCustomValidators() {
|
|
663
|
-
if (!globalThis.__smrtProfileMetafieldValidators) globalThis.__smrtProfileMetafieldValidators = /* @__PURE__ */ new Map();
|
|
664
|
-
return globalThis.__smrtProfileMetafieldValidators;
|
|
665
|
-
}
|
|
666
|
-
var ProfileMetafield = class extends SmrtObject {
|
|
667
|
-
tenantId = null;
|
|
668
|
-
name = "";
|
|
669
|
-
description;
|
|
670
|
-
validation;
|
|
671
|
-
constructor(options = {}) {
|
|
672
|
-
super(options);
|
|
673
|
-
if (options.name) this.name = options.name;
|
|
674
|
-
if (options.description !== void 0) this.description = options.description;
|
|
675
|
-
if (options.validation !== void 0) this.validation = options.validation;
|
|
676
|
-
}
|
|
677
|
-
/**
|
|
678
|
-
* Convenience method for slug-based lookup
|
|
679
|
-
*
|
|
680
|
-
* @param slug - The slug to search for
|
|
681
|
-
* @returns ProfileMetafield instance or null if not found
|
|
682
|
-
*/
|
|
683
|
-
static async getBySlug(_slug) {
|
|
684
|
-
return null;
|
|
685
|
-
}
|
|
686
|
-
/**
|
|
687
|
-
* Register a custom validator function
|
|
688
|
-
*
|
|
689
|
-
* @param name - Name of the validator (used in validation.custom field)
|
|
690
|
-
* @param validator - The validator function
|
|
691
|
-
*/
|
|
692
|
-
static registerValidator(name, validator) {
|
|
693
|
-
getCustomValidators().set(name, validator);
|
|
694
|
-
}
|
|
695
|
-
/**
|
|
696
|
-
* Get a registered custom validator
|
|
697
|
-
*
|
|
698
|
-
* @param name - Name of the validator
|
|
699
|
-
* @returns The validator function or undefined
|
|
700
|
-
*/
|
|
701
|
-
static getValidator(name) {
|
|
702
|
-
return getCustomValidators().get(name);
|
|
703
|
-
}
|
|
704
|
-
/**
|
|
705
|
-
* Validate a value against this metafield's validation schema
|
|
706
|
-
*
|
|
707
|
-
* @param value - The value to validate
|
|
708
|
-
* @returns True if valid, throws ValidationError if invalid
|
|
709
|
-
*/
|
|
710
|
-
async validateValue(value) {
|
|
711
|
-
if (!this.validation) return true;
|
|
712
|
-
const schema = this.validation;
|
|
713
|
-
if (schema.type) {
|
|
714
|
-
const actualType = typeof value;
|
|
715
|
-
const expectedType = schema.type;
|
|
716
|
-
if (expectedType === "number" && actualType !== "number") throw new Error(schema.message || `Expected ${expectedType}, got ${actualType}`);
|
|
717
|
-
if (expectedType === "string" && actualType !== "string") throw new Error(schema.message || `Expected ${expectedType}, got ${actualType}`);
|
|
718
|
-
if (expectedType === "boolean" && actualType !== "boolean") throw new Error(schema.message || `Expected ${expectedType}, got ${actualType}`);
|
|
719
|
-
}
|
|
720
|
-
if (schema.pattern && typeof value === "string") {
|
|
721
|
-
if (!new RegExp(schema.pattern).test(value)) throw new Error(schema.message || "Pattern validation failed");
|
|
722
|
-
}
|
|
723
|
-
if (schema.minLength && typeof value === "string") {
|
|
724
|
-
if (value.length < schema.minLength) throw new Error(schema.message || `Minimum length is ${schema.minLength}, got ${value.length}`);
|
|
725
|
-
}
|
|
726
|
-
if (schema.maxLength && typeof value === "string") {
|
|
727
|
-
if (value.length > schema.maxLength) throw new Error(schema.message || `Maximum length is ${schema.maxLength}, got ${value.length}`);
|
|
728
|
-
}
|
|
729
|
-
if (schema.min !== void 0 && typeof value === "number") {
|
|
730
|
-
if (value < schema.min) throw new Error(schema.message || `Value must be at least ${schema.min}`);
|
|
731
|
-
}
|
|
732
|
-
if (schema.max !== void 0 && typeof value === "number") {
|
|
733
|
-
if (value > schema.max) throw new Error(schema.message || `Value must be at most ${schema.max}`);
|
|
734
|
-
}
|
|
735
|
-
if (schema.custom) {
|
|
736
|
-
const validator = ProfileMetafield.getValidator(schema.custom);
|
|
737
|
-
if (!validator) throw new Error(`Custom validator '${schema.custom}' not registered`);
|
|
738
|
-
if (!await validator(value)) throw new Error(schema.message || "Custom validation failed");
|
|
739
|
-
}
|
|
740
|
-
return true;
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
__decorateClass$18([tenantId({ nullable: true })], ProfileMetafield.prototype, "tenantId", 2);
|
|
744
|
-
__decorateClass$18([field({ required: true })], ProfileMetafield.prototype, "name", 2);
|
|
745
|
-
ProfileMetafield = __decorateClass$18([TenantScoped({ mode: "optional" }), smrt({
|
|
746
|
-
tableStrategy: "sti",
|
|
747
|
-
api: { include: [
|
|
748
|
-
"list",
|
|
749
|
-
"get",
|
|
750
|
-
"create",
|
|
751
|
-
"update"
|
|
752
|
-
] },
|
|
753
|
-
mcp: { include: ["list", "get"] },
|
|
754
|
-
cli: { skipApiCheck: true }
|
|
755
|
-
})], ProfileMetafield);
|
|
756
|
-
var ProfileMetafieldCollection_exports = /* @__PURE__ */ __exportAll$1({ ProfileMetafieldCollection: () => ProfileMetafieldCollection });
|
|
757
|
-
var ProfileMetafieldCollection = class extends SmrtCollection {
|
|
758
|
-
static _itemClass = ProfileMetafield;
|
|
759
|
-
/**
|
|
760
|
-
* Get metafield by slug
|
|
761
|
-
*
|
|
762
|
-
* @param slug - The slug to search for
|
|
763
|
-
* @returns ProfileMetafield instance or null
|
|
764
|
-
*/
|
|
765
|
-
async getBySlug(slug) {
|
|
766
|
-
return await this.get({ slug });
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Get or create a metafield by slug
|
|
770
|
-
*
|
|
771
|
-
* @param slug - The slug to search for
|
|
772
|
-
* @param defaults - Default values if creating
|
|
773
|
-
* @returns ProfileMetafield instance
|
|
774
|
-
*/
|
|
775
|
-
async getOrCreateBySlug(slug, defaults) {
|
|
776
|
-
const existing = await this.getBySlug(slug);
|
|
777
|
-
if (existing) return existing;
|
|
778
|
-
const metafield = await this.create({
|
|
779
|
-
slug,
|
|
780
|
-
...defaults
|
|
781
|
-
});
|
|
782
|
-
await metafield.save();
|
|
783
|
-
return metafield;
|
|
784
|
-
}
|
|
785
|
-
};
|
|
786
|
-
//#endregion
|
|
787
|
-
//#region ../profiles/dist/chunks/ProfileRelationshipCollection-DUVgaIqf.js
|
|
788
|
-
var __defProp$18 = Object.defineProperty;
|
|
789
|
-
var __getOwnPropDesc$17 = Object.getOwnPropertyDescriptor;
|
|
790
|
-
var __decorateClass$17 = (decorators, target, key, kind) => {
|
|
791
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$17(target, key) : target;
|
|
792
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
793
|
-
if (kind && result) __defProp$18(target, key, result);
|
|
794
|
-
return result;
|
|
795
|
-
};
|
|
796
|
-
var ProfileRelationship = class extends SmrtObject {
|
|
797
|
-
tenantId = null;
|
|
798
|
-
fromProfileId;
|
|
799
|
-
toProfileId;
|
|
800
|
-
typeId;
|
|
801
|
-
contextProfileId;
|
|
802
|
-
terms = [];
|
|
803
|
-
constructor(options = {}) {
|
|
804
|
-
super(options);
|
|
805
|
-
if (options.fromProfileId !== void 0) this.fromProfileId = options.fromProfileId;
|
|
806
|
-
if (options.toProfileId !== void 0) this.toProfileId = options.toProfileId;
|
|
807
|
-
if (options.typeId !== void 0) this.typeId = options.typeId;
|
|
808
|
-
if (options.contextProfileId !== void 0) this.contextProfileId = options.contextProfileId;
|
|
809
|
-
}
|
|
810
|
-
/**
|
|
811
|
-
* Get the relationship type slug
|
|
812
|
-
*
|
|
813
|
-
* @returns The slug of the relationship type
|
|
814
|
-
*/
|
|
815
|
-
async getTypeSlug() {
|
|
816
|
-
return (await this.loadRelated("typeId"))?.slug || "";
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* Add a term (time period) to this relationship
|
|
820
|
-
*
|
|
821
|
-
* @param startedAt - Start date of the term
|
|
822
|
-
* @param endedAt - Optional end date of the term
|
|
823
|
-
*/
|
|
824
|
-
async addTerm(startedAt, endedAt) {
|
|
825
|
-
if (!this.id) throw new Error("ProfileRelationship.addTerm requires a persisted relationship (missing id)");
|
|
826
|
-
const relationshipId = this.id;
|
|
827
|
-
const { ProfileRelationshipTermCollection } = await import("./ProfileRelationshipTermCollection-DtA9OM23-Cj4bLTpU.js").then((n) => n.n);
|
|
828
|
-
await (await (await ProfileRelationshipTermCollection.create(this.options)).create({
|
|
829
|
-
relationshipId,
|
|
830
|
-
startedAt,
|
|
831
|
-
endedAt
|
|
832
|
-
})).save();
|
|
833
|
-
}
|
|
834
|
-
/**
|
|
835
|
-
* End the current active term
|
|
836
|
-
*
|
|
837
|
-
* @param endedAt - End date for the term
|
|
838
|
-
*/
|
|
839
|
-
async endCurrentTerm(endedAt) {
|
|
840
|
-
const activeTerm = await this.getActiveTerm();
|
|
841
|
-
if (activeTerm) await activeTerm.end(endedAt);
|
|
842
|
-
}
|
|
843
|
-
/**
|
|
844
|
-
* Get all terms for this relationship
|
|
845
|
-
*
|
|
846
|
-
* @returns Array of ProfileRelationshipTerm instances
|
|
847
|
-
*/
|
|
848
|
-
async getTerms() {
|
|
849
|
-
const { ProfileRelationshipTermCollection } = await import("./ProfileRelationshipTermCollection-DtA9OM23-Cj4bLTpU.js").then((n) => n.n);
|
|
850
|
-
return await (await ProfileRelationshipTermCollection.create(this.options)).getByRelationship(this.id);
|
|
851
|
-
}
|
|
852
|
-
/**
|
|
853
|
-
* Get the active term (no end date)
|
|
854
|
-
*
|
|
855
|
-
* @returns Current term or null if none active
|
|
856
|
-
*/
|
|
857
|
-
async getActiveTerm() {
|
|
858
|
-
const { ProfileRelationshipTermCollection } = await import("./ProfileRelationshipTermCollection-DtA9OM23-Cj4bLTpU.js").then((n) => n.n);
|
|
859
|
-
return await (await ProfileRelationshipTermCollection.create(this.options)).getActiveTerm(this.id);
|
|
860
|
-
}
|
|
861
|
-
};
|
|
862
|
-
__decorateClass$17([tenantId({ nullable: true })], ProfileRelationship.prototype, "tenantId", 2);
|
|
863
|
-
__decorateClass$17([foreignKey("Profile", { required: true })], ProfileRelationship.prototype, "fromProfileId", 2);
|
|
864
|
-
__decorateClass$17([foreignKey("Profile", { required: true })], ProfileRelationship.prototype, "toProfileId", 2);
|
|
865
|
-
__decorateClass$17([foreignKey("ProfileRelationshipType", { required: true })], ProfileRelationship.prototype, "typeId", 2);
|
|
866
|
-
__decorateClass$17([foreignKey("Profile")], ProfileRelationship.prototype, "contextProfileId", 2);
|
|
867
|
-
__decorateClass$17([oneToMany("ProfileRelationshipTerm")], ProfileRelationship.prototype, "terms", 2);
|
|
868
|
-
ProfileRelationship = __decorateClass$17([TenantScoped({ mode: "optional" }), smrt({
|
|
869
|
-
tableStrategy: "sti",
|
|
870
|
-
api: { include: [
|
|
871
|
-
"list",
|
|
872
|
-
"get",
|
|
873
|
-
"create",
|
|
874
|
-
"delete"
|
|
875
|
-
] },
|
|
876
|
-
mcp: { include: ["list", "get"] },
|
|
877
|
-
cli: { skipApiCheck: true }
|
|
878
|
-
})], ProfileRelationship);
|
|
879
|
-
var ProfileRelationshipCollection_exports = /* @__PURE__ */ __exportAll$1({ ProfileRelationshipCollection: () => ProfileRelationshipCollection });
|
|
880
|
-
var ProfileRelationshipCollection = class extends SmrtCollection {
|
|
881
|
-
static _itemClass = ProfileRelationship;
|
|
882
|
-
/**
|
|
883
|
-
* Get all relationships from a profile
|
|
884
|
-
*
|
|
885
|
-
* @param fromProfileId - The origin profile UUID
|
|
886
|
-
* @param typeId - Optional filter by relationship type UUID
|
|
887
|
-
* @returns Array of ProfileRelationship instances
|
|
888
|
-
*/
|
|
889
|
-
async getFromProfile(fromProfileId, typeId) {
|
|
890
|
-
const where = { fromProfileId };
|
|
891
|
-
if (typeId) where.typeId = typeId;
|
|
892
|
-
return await this.list({ where });
|
|
893
|
-
}
|
|
894
|
-
/**
|
|
895
|
-
* Get all relationships to a profile
|
|
896
|
-
*
|
|
897
|
-
* @param toProfileId - The target profile UUID
|
|
898
|
-
* @param typeId - Optional filter by relationship type UUID
|
|
899
|
-
* @returns Array of ProfileRelationship instances
|
|
900
|
-
*/
|
|
901
|
-
async getToProfile(toProfileId, typeId) {
|
|
902
|
-
const where = { toProfileId };
|
|
903
|
-
if (typeId) where.typeId = typeId;
|
|
904
|
-
return await this.list({ where });
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* Get all relationships for a profile (both directions)
|
|
908
|
-
*
|
|
909
|
-
* @param profileId - The profile UUID
|
|
910
|
-
* @param typeId - Optional filter by relationship type UUID
|
|
911
|
-
* @returns Array of ProfileRelationship instances
|
|
912
|
-
*/
|
|
913
|
-
async getForProfile(profileId, typeId) {
|
|
914
|
-
const fromRelationships = await this.getFromProfile(profileId, typeId);
|
|
915
|
-
const toRelationships = await this.getToProfile(profileId, typeId);
|
|
916
|
-
return [...fromRelationships, ...toRelationships];
|
|
917
|
-
}
|
|
918
|
-
/**
|
|
919
|
-
* Check if a relationship exists between two profiles
|
|
920
|
-
*
|
|
921
|
-
* @param fromProfileId - The origin profile UUID
|
|
922
|
-
* @param toProfileId - The target profile UUID
|
|
923
|
-
* @param typeId - The relationship type UUID
|
|
924
|
-
* @returns True if relationship exists
|
|
925
|
-
*/
|
|
926
|
-
async exists(fromProfileId, toProfileId, typeId) {
|
|
927
|
-
return (await this.list({
|
|
928
|
-
where: {
|
|
929
|
-
fromProfileId,
|
|
930
|
-
toProfileId,
|
|
931
|
-
typeId
|
|
932
|
-
},
|
|
933
|
-
limit: 1
|
|
934
|
-
})).length > 0;
|
|
935
|
-
}
|
|
936
|
-
};
|
|
937
|
-
//#endregion
|
|
938
|
-
//#region ../profiles/dist/chunks/ProfileRelationshipTermCollection-DtA9OM23.js
|
|
939
|
-
var __defProp$17 = Object.defineProperty;
|
|
940
|
-
var __getOwnPropDesc$16 = Object.getOwnPropertyDescriptor;
|
|
941
|
-
var __decorateClass$16 = (decorators, target, key, kind) => {
|
|
942
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$16(target, key) : target;
|
|
943
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
944
|
-
if (kind && result) __defProp$17(target, key, result);
|
|
945
|
-
return result;
|
|
946
|
-
};
|
|
947
|
-
var ProfileRelationshipTerm = class extends SmrtObject {
|
|
948
|
-
relationshipId;
|
|
949
|
-
startedAt = /* @__PURE__ */ new Date();
|
|
950
|
-
endedAt;
|
|
951
|
-
constructor(options = {}) {
|
|
952
|
-
super(options);
|
|
953
|
-
if (options.relationshipId !== void 0) this.relationshipId = options.relationshipId;
|
|
954
|
-
if (options.startedAt) this.startedAt = options.startedAt;
|
|
955
|
-
if (options.endedAt !== void 0) this.endedAt = options.endedAt;
|
|
956
|
-
}
|
|
957
|
-
/**
|
|
958
|
-
* Check if this term is currently active
|
|
959
|
-
*
|
|
960
|
-
* @returns True if active (no end date or end date in future)
|
|
961
|
-
*/
|
|
962
|
-
isActive() {
|
|
963
|
-
if (!this.endedAt) return true;
|
|
964
|
-
return this.endedAt > /* @__PURE__ */ new Date();
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* End this term
|
|
968
|
-
*
|
|
969
|
-
* @param endedAt - End date for the term (defaults to now)
|
|
970
|
-
*/
|
|
971
|
-
async end(endedAt = /* @__PURE__ */ new Date()) {
|
|
972
|
-
this.endedAt = endedAt;
|
|
973
|
-
await this.save();
|
|
974
|
-
}
|
|
975
|
-
/**
|
|
976
|
-
* Get the duration of this term in days
|
|
977
|
-
*
|
|
978
|
-
* @returns Duration in days
|
|
979
|
-
*/
|
|
980
|
-
getDurationDays() {
|
|
981
|
-
const diffMs = (this.endedAt || /* @__PURE__ */ new Date()).getTime() - this.startedAt.getTime();
|
|
982
|
-
return Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
983
|
-
}
|
|
984
|
-
};
|
|
985
|
-
__decorateClass$16([foreignKey("ProfileRelationship", { required: true })], ProfileRelationshipTerm.prototype, "relationshipId", 2);
|
|
986
|
-
__decorateClass$16([field({ required: true })], ProfileRelationshipTerm.prototype, "startedAt", 2);
|
|
987
|
-
ProfileRelationshipTerm = __decorateClass$16([smrt({
|
|
988
|
-
tableStrategy: "sti",
|
|
989
|
-
api: { include: [
|
|
990
|
-
"list",
|
|
991
|
-
"get",
|
|
992
|
-
"create",
|
|
993
|
-
"update",
|
|
994
|
-
"delete"
|
|
995
|
-
] },
|
|
996
|
-
mcp: { include: ["list", "get"] },
|
|
997
|
-
cli: { skipApiCheck: true }
|
|
998
|
-
})], ProfileRelationshipTerm);
|
|
999
|
-
var ProfileRelationshipTermCollection_exports = /* @__PURE__ */ __exportAll$1({ ProfileRelationshipTermCollection: () => ProfileRelationshipTermCollection });
|
|
1000
|
-
var ProfileRelationshipTermCollection = class extends SmrtCollection {
|
|
1001
|
-
static _itemClass = ProfileRelationshipTerm;
|
|
1002
|
-
/**
|
|
1003
|
-
* Get all terms for a relationship
|
|
1004
|
-
*
|
|
1005
|
-
* @param relationshipId - The relationship UUID
|
|
1006
|
-
* @returns Array of ProfileRelationshipTerm instances
|
|
1007
|
-
*/
|
|
1008
|
-
async getByRelationship(relationshipId) {
|
|
1009
|
-
return await this.list({
|
|
1010
|
-
where: { relationshipId },
|
|
1011
|
-
orderBy: ["startedAt DESC"]
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
/**
|
|
1015
|
-
* Get the active term for a relationship (no end date or future end date)
|
|
1016
|
-
*
|
|
1017
|
-
* @param relationshipId - The relationship UUID
|
|
1018
|
-
* @returns Active term or null
|
|
1019
|
-
*/
|
|
1020
|
-
async getActiveTerm(relationshipId) {
|
|
1021
|
-
const terms = await this.getByRelationship(relationshipId);
|
|
1022
|
-
for (const term of terms) if (term.isActive()) return term;
|
|
1023
|
-
return null;
|
|
1024
|
-
}
|
|
1025
|
-
/**
|
|
1026
|
-
* Get all historical (ended) terms for a relationship
|
|
1027
|
-
*
|
|
1028
|
-
* @param relationshipId - The relationship UUID
|
|
1029
|
-
* @returns Array of ended ProfileRelationshipTerm instances
|
|
1030
|
-
*/
|
|
1031
|
-
async getHistoricalTerms(relationshipId) {
|
|
1032
|
-
return (await this.getByRelationship(relationshipId)).filter((term) => !term.isActive());
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
//#endregion
|
|
1036
|
-
//#region ../profiles/dist/chunks/ProfileRelationshipTypeCollection-BdXwd7Kf.js
|
|
1037
|
-
var ProfileRelationshipTypeCollection_exports = /* @__PURE__ */ __exportAll$1({ ProfileRelationshipTypeCollection: () => ProfileRelationshipTypeCollection });
|
|
1038
|
-
var ProfileRelationshipTypeCollection = class extends SmrtCollection {
|
|
1039
|
-
static _itemClass = ProfileRelationshipType;
|
|
1040
|
-
/**
|
|
1041
|
-
* Get relationship type by slug
|
|
1042
|
-
*
|
|
1043
|
-
* @param slug - The slug to search for
|
|
1044
|
-
* @returns ProfileRelationshipType instance or null
|
|
1045
|
-
*/
|
|
1046
|
-
async getBySlug(slug) {
|
|
1047
|
-
return await this.get({ slug });
|
|
1048
|
-
}
|
|
1049
|
-
/**
|
|
1050
|
-
* Get or create a relationship type by slug
|
|
1051
|
-
*
|
|
1052
|
-
* @param slug - The slug to search for
|
|
1053
|
-
* @param defaults - Default values if creating
|
|
1054
|
-
* @returns ProfileRelationshipType instance
|
|
1055
|
-
*/
|
|
1056
|
-
async getOrCreateBySlug(slug, defaults) {
|
|
1057
|
-
const existing = await this.getBySlug(slug);
|
|
1058
|
-
if (existing) return existing;
|
|
1059
|
-
const relationshipType = await this.create({
|
|
1060
|
-
slug,
|
|
1061
|
-
...defaults
|
|
1062
|
-
});
|
|
1063
|
-
await relationshipType.save();
|
|
1064
|
-
return relationshipType;
|
|
1065
|
-
}
|
|
1066
|
-
/**
|
|
1067
|
-
* Get all reciprocal relationship types
|
|
1068
|
-
*
|
|
1069
|
-
* @returns Array of reciprocal ProfileRelationshipType instances
|
|
1070
|
-
*/
|
|
1071
|
-
async getReciprocal() {
|
|
1072
|
-
return await this.list({ where: { reciprocal: true } });
|
|
1073
|
-
}
|
|
1074
|
-
/**
|
|
1075
|
-
* Get all directional (non-reciprocal) relationship types
|
|
1076
|
-
*
|
|
1077
|
-
* @returns Array of directional ProfileRelationshipType instances
|
|
1078
|
-
*/
|
|
1079
|
-
async getDirectional() {
|
|
1080
|
-
return await this.list({ where: { reciprocal: false } });
|
|
1081
|
-
}
|
|
1082
|
-
};
|
|
1083
|
-
//#endregion
|
|
1084
|
-
//#region ../profiles/dist/chunks/resolveIdentity-BrJDCjYi.js
|
|
1085
|
-
var resolveIdentity_exports = /* @__PURE__ */ __exportAll$1({
|
|
1086
|
-
createProfileFromNostr: () => createProfileFromNostr,
|
|
1087
|
-
createProfileFromOidc: () => createProfileFromOidc,
|
|
1088
|
-
resolveIdentity: () => resolveIdentity,
|
|
1089
|
-
reuseExistingOidcIdentityForProfile: () => reuseExistingOidcIdentityForProfile
|
|
1090
|
-
});
|
|
1091
|
-
async function resolveIdentity(context) {
|
|
1092
|
-
const options = { db: context.db };
|
|
1093
|
-
if (context.apiKey) {
|
|
1094
|
-
const apiKey = await ApiKey.verify(context.apiKey, options);
|
|
1095
|
-
if (apiKey) {
|
|
1096
|
-
const profile = await apiKey.getProfile();
|
|
1097
|
-
if (profile) return {
|
|
1098
|
-
profile,
|
|
1099
|
-
source: "api_key",
|
|
1100
|
-
apiKey
|
|
1101
|
-
};
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
if (context.oidcSession?.sub && context.oidcSession?.iss) {
|
|
1105
|
-
const oidcIdentity = await OidcIdentity.findBySubject(context.oidcSession.iss, context.oidcSession.sub, options);
|
|
1106
|
-
if (oidcIdentity) {
|
|
1107
|
-
await oidcIdentity.recordUsage();
|
|
1108
|
-
const profile = await oidcIdentity.getProfile();
|
|
1109
|
-
if (profile) return {
|
|
1110
|
-
profile,
|
|
1111
|
-
source: "oidc",
|
|
1112
|
-
oidcIdentity
|
|
1113
|
-
};
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
if (context.nostrAuth?.event && context.nostrAuth?.challenge) {
|
|
1117
|
-
const { event, challenge } = context.nostrAuth;
|
|
1118
|
-
if (verifyAuthEvent(event, challenge).valid) {
|
|
1119
|
-
const nostrIdentity = await NostrIdentity.findByPubkey(event.pubkey, options);
|
|
1120
|
-
if (nostrIdentity) {
|
|
1121
|
-
await nostrIdentity.recordUsage();
|
|
1122
|
-
const profile = await nostrIdentity.getProfile();
|
|
1123
|
-
if (profile) return {
|
|
1124
|
-
profile,
|
|
1125
|
-
source: "nostr",
|
|
1126
|
-
nostrIdentity
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
if (context.actor) {
|
|
1132
|
-
const profile = await findProfileByExternalId("github", context.actor, options);
|
|
1133
|
-
if (profile) return {
|
|
1134
|
-
profile,
|
|
1135
|
-
source: "actor"
|
|
1136
|
-
};
|
|
1137
|
-
}
|
|
1138
|
-
return {
|
|
1139
|
-
profile: null,
|
|
1140
|
-
source: "none"
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
async function findProfileByExternalId(provider, externalId, options) {
|
|
1144
|
-
const { OidcIdentityCollection } = await import("./OidcIdentityCollection-gnrLoF08-DJI-69Ow.js").then((n) => n.r);
|
|
1145
|
-
const identities = await (await OidcIdentityCollection.create(options)).findByProvider(provider);
|
|
1146
|
-
for (const identity of identities) if (identity.subject === externalId || identity.email?.includes(externalId)) {
|
|
1147
|
-
const profile = await identity.getProfile();
|
|
1148
|
-
if (profile) return profile;
|
|
1149
|
-
}
|
|
1150
|
-
const { ProfileCollection } = await import("./ProfileCollection-DTT4KNpQ-D1RNYfjm.js").then((n) => n.r).then((n) => n.r);
|
|
1151
|
-
const profiles = await (await ProfileCollection.create(options)).list({
|
|
1152
|
-
where: { email: `${externalId}@users.noreply.github.com` },
|
|
1153
|
-
limit: 1
|
|
1154
|
-
});
|
|
1155
|
-
if (profiles.length > 0) return profiles[0];
|
|
1156
|
-
return null;
|
|
1157
|
-
}
|
|
1158
|
-
async function createProfileFromOidc(claims, provider, options) {
|
|
1159
|
-
return coordinateProfileOidcProvisioning(claims, provider, options);
|
|
1160
|
-
}
|
|
1161
|
-
async function reuseExistingOidcIdentityForProfile(profileId, claims, provider, options) {
|
|
1162
|
-
const normalizedClaims = normalizeOidcProfileClaims(claims);
|
|
1163
|
-
return coordinateOidcProvisioning({
|
|
1164
|
-
db: await resolveOidcProfileDatabase(options.db),
|
|
1165
|
-
lockKeys: [`identity:${OidcIdentity.buildIdentityKey(normalizedClaims.iss, normalizedClaims.sub)}`],
|
|
1166
|
-
isRaceConflict: isOidcProvisioningRaceConflict,
|
|
1167
|
-
createTransactionError: (message, cause) => new Error(message, cause === void 0 ? void 0 : { cause }),
|
|
1168
|
-
createConcurrencyError: (cause) => new Error("Concurrent exact OIDC identity reuse did not converge.", cause === void 0 ? void 0 : { cause }),
|
|
1169
|
-
rebindRootResult: rebindOidcProfileResult,
|
|
1170
|
-
provision: (tx) => withSystemContext(async () => {
|
|
1171
|
-
const { OidcIdentityCollection } = await import("./OidcIdentityCollection-gnrLoF08-DJI-69Ow.js").then((n) => n.r);
|
|
1172
|
-
const identity = await (await OidcIdentityCollection.create({ db: tx })).findBySubject(normalizedClaims.iss, normalizedClaims.sub);
|
|
1173
|
-
if (!identity) throw new Error("OidcIdentity.findOrCreate() no longer creates authentication links; use UserCollection.getOrCreateFromOidc() or createProfileFromOidc().");
|
|
1174
|
-
if (identity.profileId !== profileId) throw new Error(`OIDC identity ${normalizedClaims.iss} subject ${normalizedClaims.sub} belongs to a different Profile.`);
|
|
1175
|
-
const profile = await identity.getProfile();
|
|
1176
|
-
if (!profile) throw new Error("The exact OIDC identity has no linked Profile.");
|
|
1177
|
-
identity.provider = provider;
|
|
1178
|
-
if (normalizedClaims.email) identity.email = normalizedClaims.email;
|
|
1179
|
-
identity.lastUsedAt = /* @__PURE__ */ new Date();
|
|
1180
|
-
await identity.save();
|
|
1181
|
-
return {
|
|
1182
|
-
profile,
|
|
1183
|
-
oidcIdentity: identity,
|
|
1184
|
-
created: false
|
|
1185
|
-
};
|
|
1186
|
-
})
|
|
1187
|
-
});
|
|
1188
|
-
}
|
|
1189
|
-
async function coordinateProfileOidcProvisioning(claims, provider, options) {
|
|
1190
|
-
const normalizedClaims = normalizeOidcProfileClaims(claims);
|
|
1191
|
-
return coordinateOidcProvisioning({
|
|
1192
|
-
db: await resolveOidcProfileDatabase(options.db),
|
|
1193
|
-
lockKeys: [`identity:${OidcIdentity.buildIdentityKey(normalizedClaims.iss, normalizedClaims.sub)}`, ...normalizedClaims.email ? [`email:${normalizedClaims.email}`] : []],
|
|
1194
|
-
isRaceConflict: isOidcProvisioningRaceConflict,
|
|
1195
|
-
createTransactionError: (message, cause) => new Error(message, cause === void 0 ? void 0 : { cause }),
|
|
1196
|
-
createConcurrencyError: (cause) => new Error("Concurrent OIDC Profile provisioning did not converge.", cause === void 0 ? void 0 : { cause }),
|
|
1197
|
-
rebindRootResult: rebindOidcProfileResult,
|
|
1198
|
-
provision: (tx) => withSystemContext(() => provisionOidcProfile(normalizedClaims, provider, {
|
|
1199
|
-
...options,
|
|
1200
|
-
db: tx
|
|
1201
|
-
}))
|
|
1202
|
-
});
|
|
1203
|
-
}
|
|
1204
|
-
async function provisionOidcProfile(claims, provider, options) {
|
|
1205
|
-
const { OidcIdentityCollection } = await import("./OidcIdentityCollection-gnrLoF08-DJI-69Ow.js").then((n) => n.r);
|
|
1206
|
-
const existingIdentity = await (await OidcIdentityCollection.create(options)).findBySubject(claims.iss, claims.sub);
|
|
1207
|
-
if (existingIdentity) {
|
|
1208
|
-
const profile2 = await existingIdentity.getProfile();
|
|
1209
|
-
if (!profile2) throw new Error("The exact OIDC identity has no linked Profile.");
|
|
1210
|
-
profile2.id = requireOidcProfileId(existingIdentity.profileId);
|
|
1211
|
-
if (claims.email) existingIdentity.email = claims.email;
|
|
1212
|
-
existingIdentity.lastUsedAt = /* @__PURE__ */ new Date();
|
|
1213
|
-
await existingIdentity.save();
|
|
1214
|
-
return {
|
|
1215
|
-
profile: profile2,
|
|
1216
|
-
oidcIdentity: existingIdentity,
|
|
1217
|
-
created: false
|
|
1218
|
-
};
|
|
1219
|
-
}
|
|
1220
|
-
const { ProfileCollection } = await import("./ProfileCollection-DTT4KNpQ-D1RNYfjm.js").then((n) => n.r).then((n) => n.r);
|
|
1221
|
-
const profileCollection = await ProfileCollection.create(options);
|
|
1222
|
-
if (claims.email) {
|
|
1223
|
-
if (await profileCollection.findUniqueGlobalPersonByEmail(claims.email)) {
|
|
1224
|
-
if (claims.email_verified !== true) throw new Error(`OIDC email ${claims.email} is not verified and already belongs to a Profile.`);
|
|
1225
|
-
throw new Error(`OIDC email ${claims.email} already belongs to a Profile; createProfileFromOidc() cannot prove that Profile is unowned. Use UserCollection.getOrCreateFromOidc() for owner-aware linking.`);
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
const profile = await createOidcProvisioningPerson(options.db, {
|
|
1229
|
-
email: claims.email ?? "",
|
|
1230
|
-
name: claims.name,
|
|
1231
|
-
preferredUsername: claims.preferred_username,
|
|
1232
|
-
subject: claims.sub
|
|
1233
|
-
});
|
|
1234
|
-
return {
|
|
1235
|
-
profile,
|
|
1236
|
-
oidcIdentity: await insertOidcProvisioningIdentity(options.db, {
|
|
1237
|
-
email: claims.email,
|
|
1238
|
-
issuer: claims.iss,
|
|
1239
|
-
profileId: requireOidcProfileId(profile.id),
|
|
1240
|
-
provider,
|
|
1241
|
-
subject: claims.sub
|
|
1242
|
-
}),
|
|
1243
|
-
created: true
|
|
1244
|
-
};
|
|
1245
|
-
}
|
|
1246
|
-
async function rebindOidcProfileResult(result, rootDb) {
|
|
1247
|
-
const { OidcIdentityCollection } = await import("./OidcIdentityCollection-gnrLoF08-DJI-69Ow.js").then((n) => n.r);
|
|
1248
|
-
const { ProfileCollection } = await import("./ProfileCollection-DTT4KNpQ-D1RNYfjm.js").then((n) => n.r).then((n) => n.r);
|
|
1249
|
-
const profileId = requireOidcProfileId(result.profile.id);
|
|
1250
|
-
const identityId = requireOidcProfileId(result.oidcIdentity.id);
|
|
1251
|
-
const [profile, oidcIdentity] = await withSystemContext(async () => {
|
|
1252
|
-
const profiles = await ProfileCollection.create({ db: rootDb });
|
|
1253
|
-
const identities = await OidcIdentityCollection.create({ db: rootDb });
|
|
1254
|
-
return [await profiles.get({ id: profileId }), await identities.get({ id: identityId })];
|
|
1255
|
-
});
|
|
1256
|
-
if (!profile || !oidcIdentity) throw new Error("Committed OIDC Profile provisioning result was not found.");
|
|
1257
|
-
profile.id = profileId;
|
|
1258
|
-
oidcIdentity.id = identityId;
|
|
1259
|
-
oidcIdentity.profileId = profileId;
|
|
1260
|
-
return {
|
|
1261
|
-
...result,
|
|
1262
|
-
profile,
|
|
1263
|
-
oidcIdentity
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
function normalizeOidcProfileClaims(claims) {
|
|
1267
|
-
const sub = claims?.sub;
|
|
1268
|
-
const iss = claims?.iss;
|
|
1269
|
-
if (typeof sub !== "string" || sub.trim().length === 0 || typeof iss !== "string" || iss.trim().length === 0) throw new Error("Invalid OIDC claims: both \"sub\" and \"iss\" must be non-empty strings.");
|
|
1270
|
-
const suppliedEmail = claims.email;
|
|
1271
|
-
return {
|
|
1272
|
-
...claims,
|
|
1273
|
-
sub,
|
|
1274
|
-
iss,
|
|
1275
|
-
email: typeof suppliedEmail === "string" && suppliedEmail.trim() ? normalizeIdentityEmail(suppliedEmail) : void 0
|
|
1276
|
-
};
|
|
1277
|
-
}
|
|
1278
|
-
function requireOidcProfileId(value) {
|
|
1279
|
-
if (typeof value !== "string" || !value) throw new Error("OIDC Profile provisioning did not produce an id.");
|
|
1280
|
-
return value;
|
|
1281
|
-
}
|
|
1282
|
-
async function resolveOidcProfileDatabase(db) {
|
|
1283
|
-
if (!db) throw new Error("OIDC Profile provisioning requires an initialized database.");
|
|
1284
|
-
return resolveDatabase(db);
|
|
1285
|
-
}
|
|
1286
|
-
async function createProfileFromNostr(email, nostrData, options) {
|
|
1287
|
-
const normalizedEmail = normalizeIdentityEmail(email);
|
|
1288
|
-
const existingIdentity = await NostrIdentity.findByEmail(normalizedEmail, options);
|
|
1289
|
-
if (existingIdentity) {
|
|
1290
|
-
const profile2 = await existingIdentity.getProfile();
|
|
1291
|
-
if (profile2) return {
|
|
1292
|
-
profile: profile2,
|
|
1293
|
-
nostrIdentity: existingIdentity,
|
|
1294
|
-
created: false
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
const { Person } = await import("./oidcProvisioningPrimitives-0-3n3D6f-yUBRl2DC.js").then((n) => n.r).then((n) => n.o);
|
|
1298
|
-
const { ProfileTypeCollection } = await import("./oidcProvisioningPrimitives-0-3n3D6f-yUBRl2DC.js").then((n) => n.r).then((n) => n.c);
|
|
1299
|
-
let personType = await (await ProfileTypeCollection.create(options)).getBySlug("person");
|
|
1300
|
-
if (!personType) {
|
|
1301
|
-
const { ProfileType } = await import("./ProfileCollection-DTT4KNpQ-D1RNYfjm.js").then((n) => n.r).then((n) => n.h);
|
|
1302
|
-
personType = new ProfileType({
|
|
1303
|
-
...options,
|
|
1304
|
-
slug: "person",
|
|
1305
|
-
name: "Person",
|
|
1306
|
-
description: "Individual person profile"
|
|
1307
|
-
});
|
|
1308
|
-
await personType.initialize();
|
|
1309
|
-
await personType.save();
|
|
1310
|
-
}
|
|
1311
|
-
const profile = new Person({
|
|
1312
|
-
...options,
|
|
1313
|
-
typeId: personType.id,
|
|
1314
|
-
email: normalizedEmail,
|
|
1315
|
-
name: normalizedEmail.split("@")[0]
|
|
1316
|
-
});
|
|
1317
|
-
await profile.initialize();
|
|
1318
|
-
await profile.save();
|
|
1319
|
-
const nostrIdentity = new NostrIdentity({
|
|
1320
|
-
...options,
|
|
1321
|
-
profileId: profile.id,
|
|
1322
|
-
pubkey: nostrData.pubkey,
|
|
1323
|
-
encryptedPrivkey: nostrData.encryptedPrivkey,
|
|
1324
|
-
encryptionIv: nostrData.encryptionIv,
|
|
1325
|
-
encryptionTag: nostrData.encryptionTag,
|
|
1326
|
-
email: normalizedEmail,
|
|
1327
|
-
nip05Username: nostrData.nip05Username?.toLowerCase() || normalizedEmail.split("@")[0]
|
|
1328
|
-
});
|
|
1329
|
-
await nostrIdentity.initialize();
|
|
1330
|
-
await nostrIdentity.save();
|
|
1331
|
-
return {
|
|
1332
|
-
profile,
|
|
1333
|
-
nostrIdentity,
|
|
1334
|
-
created: true
|
|
1335
|
-
};
|
|
1336
|
-
}
|
|
1337
|
-
//#endregion
|
|
1338
|
-
//#region ../profiles/dist/index.js
|
|
1339
|
-
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-profiles\",\"packageVersion\":\"0.51.39\",\"objects\":{\"@happyvertical/smrt-profiles:ApiKeyCollection\":{\"name\":\"apikeycollection\",\"className\":\"ApiKeyCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ApiKeyCollection\",\"collection\":\"apikeys\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ApiKeyCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"findByProfile\":{\"name\":\"findByProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"findActiveByProfile\":{\"name\":\"findActiveByProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"findByHash\":{\"name\":\"findByHash\",\"async\":true,\"parameters\":[{\"name\":\"keyHash\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ApiKey | null>\",\"isStatic\":false,\"isPublic\":true},\"verify\":{\"name\":\"verify\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ApiKey | null>\",\"isStatic\":false,\"isPublic\":true},\"generateForProfile\":{\"name\":\"generateForProfile\",\"async\":true,\"parameters\":[{\"name\":\"profile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string[]\",\"Date | null\"]}],\"returnType\":\"Promise<GenerateKeyResult>\",\"isStatic\":false,\"isPublic\":true},\"revokeAllForProfile\":{\"name\":\"revokeAllForProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"revokeByPrefix\":{\"name\":\"revokeByPrefix\",\"async\":true,\"parameters\":[{\"name\":\"keyPrefix\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"cleanupExpired\":{\"name\":\"cleanupExpired\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"api_keys\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ApiKey\",\"exportName\":\"ApiKeyCollection\",\"collectionExportName\":\"ApiKeyCollectionCollection\",\"schema\":{\"tableName\":\"api_keys\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"api_keys\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"key_hash\\\" TEXT DEFAULT '',\\n \\\"key_prefix\\\" TEXT DEFAULT '',\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"scopes\\\" JSON DEFAULT '[]',\\n \\\"last_used_at\\\" TIMESTAMP,\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"revoked_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"key_hash\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"key_prefix\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"scopes\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":[]},\"last_used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"revoked_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"api_keys_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"api_keys_key_hash_idx\",\"columns\":[\"key_hash\"]},{\"name\":\"api_keys_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"api_keys_profile_id_idx\",\"columns\":[\"profile_id\"]}],\"version\":\"9b0d49e8\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:AuditLogCollection\":{\"name\":\"auditlogcollection\",\"className\":\"AuditLogCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:AuditLogCollection\",\"collection\":\"auditlogs\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/AuditLogCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"findByProfile\":{\"name\":\"findByProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"findByResource\":{\"name\":\"findByResource\",\"async\":true,\"parameters\":[{\"name\":\"resourceType\",\"type\":\"string\",\"optional\":false},{\"name\":\"resourceId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"findByAction\":{\"name\":\"findByAction\",\"async\":true,\"parameters\":[{\"name\":\"action\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"findBySource\":{\"name\":\"findBySource\",\"async\":true,\"parameters\":[{\"name\":\"source\",\"type\":\"AuditSource\",\"optional\":false}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"findOnBehalfOf\":{\"name\":\"findOnBehalfOf\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"record\":{\"name\":\"record\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"Profile\",\"string\",\"AuditSource\",\"Record<string, unknown>\",\"Profile | null\"]}],\"returnType\":\"Promise<AuditLog>\",\"isStatic\":false,\"isPublic\":true},\"getRecentActivity\":{\"name\":\"getRecentActivity\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"limit\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"getResourceTimeline\":{\"name\":\"getResourceTimeline\",\"async\":true,\"parameters\":[{\"name\":\"resourceType\",\"type\":\"string\",\"optional\":false},{\"name\":\"resourceId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"audit_logs\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AuditLog\",\"exportName\":\"AuditLogCollection\",\"collectionExportName\":\"AuditLogCollectionCollection\",\"schema\":{\"tableName\":\"audit_logs\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"audit_logs\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"action\\\" TEXT DEFAULT '',\\n \\\"resource_type\\\" TEXT DEFAULT '',\\n \\\"resource_id\\\" TEXT DEFAULT '',\\n \\\"source\\\" TEXT DEFAULT 'web',\\n \\\"metadata\\\" JSON DEFAULT '{}',\\n \\\"on_behalf_of_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"action\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"resource_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"resource_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"web\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}},\"on_behalf_of_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"audit_logs_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"audit_logs_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"audit_logs_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"audit_logs_on_behalf_of_id_idx\",\"columns\":[\"on_behalf_of_id\"]}],\"version\":\"d2b35971\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:MagicLinkTokenCollection\":{\"name\":\"magiclinktokencollection\",\"className\":\"MagicLinkTokenCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:MagicLinkTokenCollection\",\"collection\":\"magiclinktokens\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/MagicLinkTokenCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"findByTokenHash\":{\"name\":\"findByTokenHash\",\"async\":true,\"parameters\":[{\"name\":\"tokenHash\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MagicLinkToken | null>\",\"isStatic\":false,\"isPublic\":true},\"findActiveForEmail\":{\"name\":\"findActiveForEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MagicLinkToken[]>\",\"isStatic\":false,\"isPublic\":true},\"findByIdentity\":{\"name\":\"findByIdentity\",\"async\":true,\"parameters\":[{\"name\":\"nostrIdentityId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MagicLinkToken[]>\",\"isStatic\":false,\"isPublic\":true},\"countRecentByEmail\":{\"name\":\"countRecentByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false},{\"name\":\"withinMinutes\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"countRecentByIp\":{\"name\":\"countRecentByIp\",\"async\":true,\"parameters\":[{\"name\":\"ip\",\"type\":\"string\",\"optional\":false},{\"name\":\"withinMinutes\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"verify\":{\"name\":\"verify\",\"async\":true,\"parameters\":[{\"name\":\"token\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MagicLinkToken | null>\",\"isStatic\":false,\"isPublic\":true},\"cleanupExpired\":{\"name\":\"cleanupExpired\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"revokeForIdentity\":{\"name\":\"revokeForIdentity\",\"async\":true,\"parameters\":[{\"name\":\"nostrIdentityId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"isRateLimitedByEmail\":{\"name\":\"isRateLimitedByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false},{\"name\":\"maxPerHour\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"isRateLimitedByIp\":{\"name\":\"isRateLimitedByIp\",\"async\":true,\"parameters\":[{\"name\":\"ip\",\"type\":\"string\",\"optional\":false},{\"name\":\"maxPerHour\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"magic_link_tokens\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"MagicLinkToken\",\"exportName\":\"MagicLinkTokenCollection\",\"collectionExportName\":\"MagicLinkTokenCollectionCollection\",\"schema\":{\"tableName\":\"magic_link_tokens\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"magic_link_tokens\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"nostr_identity_id\\\" UUID NOT NULL,\\n \\\"token_hash\\\" TEXT DEFAULT '',\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"used_at\\\" TIMESTAMP,\\n \\\"requested_from_ip\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"nostr_identity_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"nostr_identities\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"token_hash\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"requested_from_ip\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"magic_link_tokens_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"magic_link_tokens_token_hash_idx\",\"columns\":[\"token_hash\"]},{\"name\":\"magic_link_tokens_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"magic_link_tokens_nostr_identity_id_idx\",\"columns\":[\"nostr_identity_id\"]}],\"version\":\"d60748fe\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:NostrIdentityCollection\":{\"name\":\"nostridentitycollection\",\"className\":\"NostrIdentityCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:NostrIdentityCollection\",\"collection\":\"nostridentities\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/NostrIdentityCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"findByProfile\":{\"name\":\"findByProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<NostrIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"findByPubkey\":{\"name\":\"findByPubkey\",\"async\":true,\"parameters\":[{\"name\":\"pubkey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<NostrIdentity | null>\",\"isStatic\":false,\"isPublic\":true},\"findByEmail\":{\"name\":\"findByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<NostrIdentity | null>\",\"isStatic\":false,\"isPublic\":true},\"findByNip05\":{\"name\":\"findByNip05\",\"async\":true,\"parameters\":[{\"name\":\"username\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<NostrIdentity | null>\",\"isStatic\":false,\"isPublic\":true},\"createForProfile\":{\"name\":\"createForProfile\",\"async\":true,\"parameters\":[{\"name\":\"profile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"email\",\"type\":\"string\",\"optional\":false},{\"name\":\"masterSecret\",\"type\":\"string\",\"optional\":false},{\"name\":\"nip05Username\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<NostrIdentity>\",\"isStatic\":false,\"isPublic\":true},\"linkToProfile\":{\"name\":\"linkToProfile\",\"async\":true,\"parameters\":[{\"name\":\"profile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"nostrData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<NostrIdentity>\",\"isStatic\":false,\"isPublic\":true},\"unlinkFromProfile\":{\"name\":\"unlinkFromProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"pubkey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getNip05Response\":{\"name\":\"getNip05Response\",\"async\":true,\"parameters\":[{\"name\":\"username\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Nip05Response>\",\"isStatic\":false,\"isPublic\":true},\"isNip05Available\":{\"name\":\"isNip05Available\",\"async\":true,\"parameters\":[{\"name\":\"username\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"updateNip05Username\":{\"name\":\"updateNip05Username\",\"async\":true,\"parameters\":[{\"name\":\"identity\",\"type\":\"NostrIdentity\",\"optional\":false},{\"name\":\"newUsername\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<NostrIdentity>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"nostr_identities\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"NostrIdentity\",\"exportName\":\"NostrIdentityCollection\",\"collectionExportName\":\"NostrIdentityCollectionCollection\",\"schema\":{\"tableName\":\"nostr_identities\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"nostr_identities\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"pubkey\\\" TEXT DEFAULT '',\\n \\\"encrypted_privkey\\\" TEXT DEFAULT '',\\n \\\"encryption_iv\\\" TEXT DEFAULT '',\\n \\\"encryption_tag\\\" TEXT DEFAULT '',\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"nip05_username\\\" TEXT DEFAULT '',\\n \\\"last_used_at\\\" TIMESTAMP,\\n \\\"verified_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"pubkey\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"encrypted_privkey\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"encryption_iv\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"encryption_tag\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"nip05_username\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"last_used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"verified_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"nostr_identities_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"nostr_identities_pubkey_idx\",\"columns\":[\"pubkey\"]},{\"name\":\"nostr_identities_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"nostr_identities_profile_id_idx\",\"columns\":[\"profile_id\"]}],\"version\":\"92eda375\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:OidcIdentityCollection\":{\"name\":\"oidcidentitycollection\",\"className\":\"OidcIdentityCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:OidcIdentityCollection\",\"collection\":\"oidcidentities\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/OidcIdentityCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"findByProfile\":{\"name\":\"findByProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<OidcIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"findBySubject\":{\"name\":\"findBySubject\",\"async\":true,\"parameters\":[{\"name\":\"issuer\",\"type\":\"string\",\"optional\":false},{\"name\":\"subject\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<OidcIdentity | null>\",\"isStatic\":false,\"isPublic\":true},\"findByProvider\":{\"name\":\"findByProvider\",\"async\":true,\"parameters\":[{\"name\":\"provider\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<OidcIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkToProfile\":{\"name\":\"linkToProfile\",\"async\":true,\"parameters\":[{\"name\":\"profile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"oidcData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<OidcIdentity>\",\"isStatic\":false,\"isPublic\":true},\"unlinkFromProfile\":{\"name\":\"unlinkFromProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"issuer\",\"type\":\"string\",\"optional\":false},{\"name\":\"subject\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"oidc_identities\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"OidcIdentity\",\"exportName\":\"OidcIdentityCollection\",\"collectionExportName\":\"OidcIdentityCollectionCollection\",\"schema\":{\"tableName\":\"oidc_identities\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"oidc_identities\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"provider\\\" TEXT,\\n \\\"issuer\\\" TEXT,\\n \\\"subject\\\" TEXT,\\n \\\"identity_key\\\" TEXT UNIQUE,\\n \\\"email\\\" TEXT,\\n \\\"last_used_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"provider\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"issuer\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"subject\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"identity_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":true},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"oidc_identities_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"oidc_identities_issuer_idx\",\"columns\":[\"issuer\"]},{\"name\":\"oidc_identities_subject_idx\",\"columns\":[\"subject\"]},{\"name\":\"oidc_identities_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"oidc_identities_profile_id_idx\",\"columns\":[\"profile_id\"]}],\"version\":\"925387ea\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:OidcProfileEmailReservationCollection\":{\"name\":\"oidcprofileemailreservationcollection\",\"className\":\"OidcProfileEmailReservationCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:OidcProfileEmailReservationCollection\",\"collection\":\"oidcprofileemailreservations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/OidcProfileEmailReservationCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"oidc_profile_email_reservations\",\"api\":false,\"mcp\":false,\"cli\":false},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"OidcProfileEmailReservation\",\"exportName\":\"OidcProfileEmailReservationCollection\",\"collectionExportName\":\"OidcProfileEmailReservationCollectionCollection\",\"schema\":{\"tableName\":\"oidc_profile_email_reservations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"oidc_profile_email_reservations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL UNIQUE,\\n \\\"email_key\\\" TEXT NOT NULL UNIQUE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":true,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"email_key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true}},\"indexes\":[{\"name\":\"oidc_profile_email_reservations_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"oidc_profile_email_reservations_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"01586e67\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileAssetCollection\":{\"name\":\"profileassetcollection\",\"className\":\"ProfileAssetCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileAssetCollection\",\"collection\":\"profileassets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileAssetCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"byLeft\":{\"name\":\"byLeft\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem[]>\",\"isStatic\":false,\"isPublic\":true},\"byRight\":{\"name\":\"byRight\",\"async\":true,\"parameters\":[{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem[]>\",\"isStatic\":false,\"isPublic\":true},\"attach\":{\"name\":\"attach\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionAttachOptions\",\"optional\":true}],\"returnType\":\"Promise<TItem>\",\"isStatic\":false,\"isPublic\":true},\"detach\":{\"name\":\"detach\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightId\",\"type\":\"string\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionFilterOptions\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"setLinks\":{\"name\":\"setLinks\",\"async\":true,\"parameters\":[{\"name\":\"leftId\",\"type\":\"string\",\"optional\":false},{\"name\":\"rightIds\",\"type\":\"string[]\",\"optional\":false},{\"name\":\"opts\",\"type\":\"JunctionAttachOptions\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":false,\"mcp\":false,\"cli\":false,\"tableName\":\"profile_assets\"},\"extends\":\"SmrtJunction\",\"extendsTypeArg\":\"ProfileAsset\",\"exportName\":\"ProfileAssetCollection\",\"collectionExportName\":\"ProfileAssetCollectionCollection\",\"schema\":{\"tableName\":\"profile_assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"asset_id\\\" UUID NOT NULL,\\n \\\"relationship\\\" TEXT NOT NULL,\\n \\\"sort_order\\\" INTEGER NOT NULL DEFAULT 0\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"relationship\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"sort_order\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0}},\"indexes\":[{\"name\":\"profile_assets_profile_id_asset_id_idx\",\"columns\":[\"profile_id\",\"asset_id\",\"relationship\"],\"unique\":true},{\"name\":\"profile_assets_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"profile_assets_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profile_assets_asset_id_idx\",\"columns\":[\"asset_id\"]}],\"version\":\"d0d7c2a2\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileCollection\":{\"name\":\"profilecollection\",\"className\":\"ProfileCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileCollection\",\"collection\":\"profiles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"findByEmail\":{\"name\":\"findByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"findUniqueGlobalPersonByEmail\":{\"name\":\"findUniqueGlobalPersonByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"requireCanonicalGlobalPerson\":{\"name\":\"requireCanonicalGlobalPerson\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"email\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile>\",\"isStatic\":false,\"isPublic\":true},\"reserveCanonicalIdentityEmail\":{\"name\":\"reserveCanonicalIdentityEmail\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"email\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile>\",\"isStatic\":false,\"isPublic\":true},\"findByType\":{\"name\":\"findByType\",\"async\":true,\"parameters\":[{\"name\":\"typeSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"batchGetMetadata\":{\"name\":\"batchGetMetadata\",\"async\":true,\"parameters\":[{\"name\":\"profileIds\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"Promise<Map<string, Record<string, string>>>\",\"isStatic\":false,\"isPublic\":true},\"batchUpdateMetadata\":{\"name\":\"batchUpdateMetadata\",\"async\":true,\"parameters\":[{\"name\":\"updates\",\"type\":\"Array<object>\",\"optional\":false,\"memberTypes\":[\"string\",\"Record<string, unknown>\"]}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"findRelated\":{\"name\":\"findRelated\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getRelationshipNetwork\":{\"name\":\"getRelationshipNetwork\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"number\"]}],\"returnType\":\"Promise<Map<string, number>>\",\"isStatic\":false,\"isPublic\":true},\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"findGlobal\":{\"name\":\"findGlobal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"findWithGlobals\":{\"name\":\"findWithGlobals\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Profile\",\"exportName\":\"ProfileCollection\",\"collectionExportName\":\"ProfileCollectionCollection\",\"schema\":{\"tableName\":\"profiles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profiles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type_id\\\" UUID,\\n \\\"email\\\" TEXT,\\n \\\"email_key\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_types\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"email\":{\"type\":\"TEXT\",\"notNull\":false},\"email_key\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"profiles_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profiles_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profiles_email_key_idx\",\"columns\":[\"email_key\"]},{\"name\":\"profiles_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profiles_type_id_idx\",\"columns\":[\"type_id\"]}],\"version\":\"fd4497fb\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileMetadataCollection\":{\"name\":\"profilemetadatacollection\",\"className\":\"ProfileMetadataCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileMetadataCollection\",\"collection\":\"profilemetadatas\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileMetadataCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"getByProfile\":{\"name\":\"getByProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileMetadata[]>\",\"isStatic\":false,\"isPublic\":true},\"getMetadataObject\":{\"name\":\"getMetadataObject\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Record<string, string>>\",\"isStatic\":false,\"isPublic\":true},\"findProfilesByMetadata\":{\"name\":\"findProfilesByMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldId\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProfileMetadata\",\"exportName\":\"ProfileMetadataCollection\",\"collectionExportName\":\"ProfileMetadataCollectionCollection\",\"schema\":{\"tableName\":\"profile_metadata\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_metadata\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"profile_id\\\" UUID,\\n \\\"metafield_id\\\" UUID,\\n \\\"value\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"metafield_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_metafields\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"value\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"profile_metadata_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_metadata_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_metadata_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profile_metadata_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"profile_metadata_metafield_id_idx\",\"columns\":[\"metafield_id\"]}],\"version\":\"d3ab1b70\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileMetafieldCollection\":{\"name\":\"profilemetafieldcollection\",\"className\":\"ProfileMetafieldCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileMetafieldCollection\",\"collection\":\"profilemetafields\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileMetafieldCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileMetafield | null>\",\"isStatic\":false,\"isPublic\":true},\"getOrCreateBySlug\":{\"name\":\"getOrCreateBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"defaults\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"ValidationSchema\"]}],\"returnType\":\"Promise<ProfileMetafield>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProfileMetafield\",\"exportName\":\"ProfileMetafieldCollection\",\"collectionExportName\":\"ProfileMetafieldCollectionCollection\",\"schema\":{\"tableName\":\"profile_metafields\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_metafields\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT,\\n \\\"validation\\\" JSON\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"validation\":{\"type\":\"JSON\",\"notNull\":false}},\"indexes\":[{\"name\":\"profile_metafields_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_metafields_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_metafields_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"afe420df\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileRelationshipCollection\":{\"name\":\"profilerelationshipcollection\",\"className\":\"ProfileRelationshipCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileRelationshipCollection\",\"collection\":\"profilerelationships\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileRelationshipCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"getFromProfile\":{\"name\":\"getFromProfile\",\"async\":true,\"parameters\":[{\"name\":\"fromProfileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"typeId\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<ProfileRelationship[]>\",\"isStatic\":false,\"isPublic\":true},\"getToProfile\":{\"name\":\"getToProfile\",\"async\":true,\"parameters\":[{\"name\":\"toProfileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"typeId\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<ProfileRelationship[]>\",\"isStatic\":false,\"isPublic\":true},\"getForProfile\":{\"name\":\"getForProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"typeId\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<ProfileRelationship[]>\",\"isStatic\":false,\"isPublic\":true},\"exists\":{\"name\":\"exists\",\"async\":true,\"parameters\":[{\"name\":\"fromProfileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"toProfileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"typeId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProfileRelationship\",\"exportName\":\"ProfileRelationshipCollection\",\"collectionExportName\":\"ProfileRelationshipCollectionCollection\",\"schema\":{\"tableName\":\"profile_relationships\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_relationships\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"from_profile_id\\\" UUID,\\n \\\"to_profile_id\\\" UUID,\\n \\\"type_id\\\" UUID,\\n \\\"context_profile_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"from_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"to_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"type_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_relationship_types\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"context_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"profile_relationships_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_relationships_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_relationships_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profile_relationships_from_profile_id_idx\",\"columns\":[\"from_profile_id\"]},{\"name\":\"profile_relationships_to_profile_id_idx\",\"columns\":[\"to_profile_id\"]},{\"name\":\"profile_relationships_type_id_idx\",\"columns\":[\"type_id\"]},{\"name\":\"profile_relationships_context_profile_id_idx\",\"columns\":[\"context_profile_id\"]}],\"version\":\"48878dba\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileRelationshipTermCollection\":{\"name\":\"profilerelationshiptermcollection\",\"className\":\"ProfileRelationshipTermCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileRelationshipTermCollection\",\"collection\":\"profilerelationshipterms\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileRelationshipTermCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"getByRelationship\":{\"name\":\"getByRelationship\",\"async\":true,\"parameters\":[{\"name\":\"relationshipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileRelationshipTerm[]>\",\"isStatic\":false,\"isPublic\":true},\"getActiveTerm\":{\"name\":\"getActiveTerm\",\"async\":true,\"parameters\":[{\"name\":\"relationshipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileRelationshipTerm | null>\",\"isStatic\":false,\"isPublic\":true},\"getHistoricalTerms\":{\"name\":\"getHistoricalTerms\",\"async\":true,\"parameters\":[{\"name\":\"relationshipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileRelationshipTerm[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProfileRelationshipTerm\",\"exportName\":\"ProfileRelationshipTermCollection\",\"collectionExportName\":\"ProfileRelationshipTermCollectionCollection\",\"schema\":{\"tableName\":\"profile_relationship_terms\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_relationship_terms\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"relationship_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"relationship_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_relationships\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false}},\"indexes\":[{\"name\":\"profile_relationship_terms_slug_context_meta_type_idx\",\"columns\":[\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"profile_relationship_terms_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_relationship_terms_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"profile_relationship_terms_relationship_id_idx\",\"columns\":[\"relationship_id\"]}],\"version\":\"ef299102\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileRelationshipTypeCollection\":{\"name\":\"profilerelationshiptypecollection\",\"className\":\"ProfileRelationshipTypeCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileRelationshipTypeCollection\",\"collection\":\"profilerelationshiptypes\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileRelationshipTypeCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileRelationshipType | null>\",\"isStatic\":false,\"isPublic\":true},\"getOrCreateBySlug\":{\"name\":\"getOrCreateBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"defaults\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"boolean\"]}],\"returnType\":\"Promise<ProfileRelationshipType>\",\"isStatic\":false,\"isPublic\":true},\"getReciprocal\":{\"name\":\"getReciprocal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ProfileRelationshipType[]>\",\"isStatic\":false,\"isPublic\":true},\"getDirectional\":{\"name\":\"getDirectional\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ProfileRelationshipType[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProfileRelationshipType\",\"exportName\":\"ProfileRelationshipTypeCollection\",\"collectionExportName\":\"ProfileRelationshipTypeCollectionCollection\",\"schema\":{\"tableName\":\"profile_relationship_types\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_relationship_types\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"reciprocal\\\" BOOLEAN DEFAULT TRUE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"reciprocal\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true}},\"indexes\":[{\"name\":\"profile_relationship_types_slug_context_meta_type_idx\",\"columns\":[\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"profile_relationship_types_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_relationship_types_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"719fe0d9\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileTypeCollection\":{\"name\":\"profiletypecollection\",\"className\":\"ProfileTypeCollection\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileTypeCollection\",\"collection\":\"profiletypes\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/collections/ProfileTypeCollection.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{},\"methods\":{\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileType | null>\",\"isStatic\":false,\"isPublic\":true},\"getOrCreateBySlug\":{\"name\":\"getOrCreateBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"defaults\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<ProfileType>\",\"isStatic\":false,\"isPublic\":true},\"getOrCreateGlobalBySlug\":{\"name\":\"getOrCreateGlobalBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"defaults\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<ProfileType>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProfileType\",\"exportName\":\"ProfileTypeCollection\",\"collectionExportName\":\"ProfileTypeCollectionCollection\",\"schema\":{\"tableName\":\"profile_types\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_types\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"profile_types_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_types_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_types_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"0fb37aeb\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ApiKey\":{\"name\":\"apikey\",\"className\":\"ApiKey\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ApiKey\",\"collection\":\"apikeys\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ApiKey.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"profileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"keyHash\":{\"type\":\"text\",\"required\":false,\"default\":\"\",\"_meta\":{\"indexed\":true}},\"keyPrefix\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"scopes\":{\"type\":\"json\",\"required\":false,\"default\":[]},\"lastUsedAt\":{\"type\":\"datetime\",\"required\":false},\"expiresAt\":{\"type\":\"datetime\",\"required\":false},\"revokedAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"getProfile\":{\"name\":\"getProfile\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"isValid\":{\"name\":\"isValid\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"hasScope\":{\"name\":\"hasScope\",\"async\":false,\"parameters\":[{\"name\":\"scope\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"revoke\":{\"name\":\"revoke\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"recordUsage\":{\"name\":\"recordUsage\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"hashKey\":{\"name\":\"hashKey\",\"async\":false,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"string\",\"isStatic\":true,\"isPublic\":true},\"generate\":{\"name\":\"generate\",\"async\":true,\"parameters\":[{\"name\":\"profile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"typeUnresolved\":true,\"memberTypes\":[\"string\",\"string[]\",\"Date | null\"]}],\"returnType\":\"Promise<GenerateKeyResult>\",\"isStatic\":true,\"isPublic\":true},\"verify\":{\"name\":\"verify\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"SmrtObjectOptions\",\"optional\":true}],\"returnType\":\"Promise<ApiKey | null>\",\"isStatic\":true,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"api_keys\",\"sensitive\":true,\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\",\"create\",\"revoke\"],\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"ApiKey\",\"collectionExportName\":\"ApiKeyCollection\",\"validationRules\":[{\"field\":\"profileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"api_keys\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"api_keys\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"key_hash\\\" TEXT DEFAULT '',\\n \\\"key_prefix\\\" TEXT DEFAULT '',\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"scopes\\\" JSON DEFAULT '[]',\\n \\\"last_used_at\\\" TIMESTAMP,\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"revoked_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"key_hash\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"key_prefix\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"scopes\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":[]},\"last_used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"revoked_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"api_keys_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"api_keys_key_hash_idx\",\"columns\":[\"key_hash\"]},{\"name\":\"api_keys_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"api_keys_profile_id_idx\",\"columns\":[\"profile_id\"]}],\"version\":\"9b0d49e8\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:AuditLog\":{\"name\":\"auditlog\",\"className\":\"AuditLog\",\"qualifiedName\":\"@happyvertical/smrt-profiles:AuditLog\",\"collection\":\"auditlogs\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/AuditLog.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":true}}},\"profileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"action\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"resourceType\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"resourceId\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"source\":{\"type\":\"text\",\"required\":false,\"default\":\"web\"},\"metadata\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"onBehalfOfId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Profile\",\"_meta\":{\"nullable\":true}}},\"methods\":{\"getProfile\":{\"name\":\"getProfile\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"getOnBehalfOf\":{\"name\":\"getOnBehalfOf\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"getEffectiveActor\":{\"name\":\"getEffectiveActor\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"record\":{\"name\":\"record\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"any\",\"optional\":false,\"typeUnresolved\":true}],\"returnType\":\"Promise<AuditLog>\",\"isStatic\":true,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"audit_logs\",\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\"]},\"tenantScoped\":{\"mode\":\"optional\",\"allowSuperAdminBypass\":true},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"AuditLog\",\"collectionExportName\":\"AuditLogCollection\",\"validationRules\":[{\"field\":\"profileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"audit_logs\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"audit_logs\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"action\\\" TEXT DEFAULT '',\\n \\\"resource_type\\\" TEXT DEFAULT '',\\n \\\"resource_id\\\" TEXT DEFAULT '',\\n \\\"source\\\" TEXT DEFAULT 'web',\\n \\\"metadata\\\" JSON DEFAULT '{}',\\n \\\"on_behalf_of_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"action\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"resource_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"resource_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"web\"},\"metadata\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}},\"on_behalf_of_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"audit_logs_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"audit_logs_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"audit_logs_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"audit_logs_on_behalf_of_id_idx\",\"columns\":[\"on_behalf_of_id\"]}],\"version\":\"d2b35971\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:MagicLinkToken\":{\"name\":\"magiclinktoken\",\"className\":\"MagicLinkToken\",\"qualifiedName\":\"@happyvertical/smrt-profiles:MagicLinkToken\",\"collection\":\"magiclinktokens\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/MagicLinkToken.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"nostrIdentityId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"NostrIdentity\",\"_meta\":{\"required\":true}},\"tokenHash\":{\"type\":\"text\",\"required\":false,\"default\":\"\",\"_meta\":{\"indexed\":true}},\"email\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"expiresAt\":{\"type\":\"datetime\",\"required\":false},\"usedAt\":{\"type\":\"datetime\",\"required\":false},\"requestedFromIp\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"createdAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"hashToken\":{\"name\":\"hashToken\",\"async\":false,\"parameters\":[{\"name\":\"token\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"string\",\"isStatic\":true,\"isPublic\":true},\"generate\":{\"name\":\"generate\",\"async\":true,\"parameters\":[{\"name\":\"nostrIdentity\",\"type\":\"NostrIdentity\",\"optional\":false},{\"name\":\"email\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"typeUnresolved\":true,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"Promise<GenerateTokenResult>\",\"isStatic\":true,\"isPublic\":true},\"verify\":{\"name\":\"verify\",\"async\":true,\"parameters\":[{\"name\":\"token\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"SmrtObjectOptions\",\"optional\":true}],\"returnType\":\"Promise<MagicLinkToken | null>\",\"isStatic\":true,\"isPublic\":true},\"isValid\":{\"name\":\"isValid\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isExpired\":{\"name\":\"isExpired\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isUsed\":{\"name\":\"isUsed\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"markUsed\":{\"name\":\"markUsed\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getNostrIdentity\":{\"name\":\"getNostrIdentity\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<NostrIdentity | null>\",\"isStatic\":false,\"isPublic\":true},\"getTimeRemainingSeconds\":{\"name\":\"getTimeRemainingSeconds\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"magic_link_tokens\",\"sensitive\":true,\"api\":{\"exclude\":[\"*\"]},\"mcp\":{\"exclude\":[\"*\"]},\"cli\":{\"include\":[\"list\"]}},\"extends\":\"SmrtObject\",\"exportName\":\"MagicLinkToken\",\"collectionExportName\":\"MagicLinkTokenCollection\",\"validationRules\":[{\"field\":\"nostrIdentityId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"magic_link_tokens\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"magic_link_tokens\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"nostr_identity_id\\\" UUID NOT NULL,\\n \\\"token_hash\\\" TEXT DEFAULT '',\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"used_at\\\" TIMESTAMP,\\n \\\"requested_from_ip\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"nostr_identity_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"nostr_identities\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"token_hash\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"requested_from_ip\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"magic_link_tokens_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"magic_link_tokens_token_hash_idx\",\"columns\":[\"token_hash\"]},{\"name\":\"magic_link_tokens_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"magic_link_tokens_nostr_identity_id_idx\",\"columns\":[\"nostr_identity_id\"]}],\"version\":\"d60748fe\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:NostrIdentity\":{\"name\":\"nostridentity\",\"className\":\"NostrIdentity\",\"qualifiedName\":\"@happyvertical/smrt-profiles:NostrIdentity\",\"collection\":\"nostridentities\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/NostrIdentity.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"profileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"pubkey\":{\"type\":\"text\",\"required\":false,\"default\":\"\",\"_meta\":{\"indexed\":true}},\"encryptedPrivkey\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"encryptionIv\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"encryptionTag\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"email\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"nip05Username\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"lastUsedAt\":{\"type\":\"datetime\",\"required\":false},\"verifiedAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"getProfile\":{\"name\":\"getProfile\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"findByPubkey\":{\"name\":\"findByPubkey\",\"async\":true,\"parameters\":[{\"name\":\"pubkey\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"SmrtObjectOptions\",\"optional\":true}],\"returnType\":\"Promise<NostrIdentity | null>\",\"isStatic\":true,\"isPublic\":true},\"findByEmail\":{\"name\":\"findByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"SmrtObjectOptions\",\"optional\":true}],\"returnType\":\"Promise<NostrIdentity | null>\",\"isStatic\":true,\"isPublic\":true},\"findByNip05\":{\"name\":\"findByNip05\",\"async\":true,\"parameters\":[{\"name\":\"username\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"SmrtObjectOptions\",\"optional\":true}],\"returnType\":\"Promise<NostrIdentity | null>\",\"isStatic\":true,\"isPublic\":true},\"decryptPrivkey\":{\"name\":\"decryptPrivkey\",\"async\":false,\"parameters\":[{\"name\":\"masterSecret\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"string\",\"isStatic\":false,\"isPublic\":true},\"getKeypair\":{\"name\":\"getKeypair\",\"async\":false,\"parameters\":[{\"name\":\"masterSecret\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"object\",\"isStatic\":false,\"isPublic\":true},\"recordUsage\":{\"name\":\"recordUsage\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"markVerified\":{\"name\":\"markVerified\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"isVerified\":{\"name\":\"isVerified\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getNip05Identifier\":{\"name\":\"getNip05Identifier\",\"async\":false,\"parameters\":[{\"name\":\"domain\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"string\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"nostr_identities\",\"sensitive\":true,\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]}},\"extends\":\"SmrtObject\",\"exportName\":\"NostrIdentity\",\"collectionExportName\":\"NostrIdentityCollection\",\"validationRules\":[{\"field\":\"profileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"nostr_identities\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"nostr_identities\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"pubkey\\\" TEXT DEFAULT '',\\n \\\"encrypted_privkey\\\" TEXT DEFAULT '',\\n \\\"encryption_iv\\\" TEXT DEFAULT '',\\n \\\"encryption_tag\\\" TEXT DEFAULT '',\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"nip05_username\\\" TEXT DEFAULT '',\\n \\\"last_used_at\\\" TIMESTAMP,\\n \\\"verified_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"pubkey\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"encrypted_privkey\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"encryption_iv\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"encryption_tag\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"nip05_username\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"last_used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"verified_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"nostr_identities_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"nostr_identities_pubkey_idx\",\"columns\":[\"pubkey\"]},{\"name\":\"nostr_identities_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"nostr_identities_profile_id_idx\",\"columns\":[\"profile_id\"]}],\"version\":\"92eda375\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:OidcIdentity\":{\"name\":\"oidcidentity\",\"className\":\"OidcIdentity\",\"qualifiedName\":\"@happyvertical/smrt-profiles:OidcIdentity\",\"collection\":\"oidcidentities\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/OidcIdentity.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"profileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"provider\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"issuer\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"indexed\":true}},\"subject\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"indexed\":true}},\"identityKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true,\"unique\":true,\"readonly\":true},\"readonly\":true},\"email\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"lastUsedAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{\"getProfile\":{\"name\":\"getProfile\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":false,\"isPublic\":true},\"findBySubject\":{\"name\":\"findBySubject\",\"async\":true,\"parameters\":[{\"name\":\"issuer\",\"type\":\"string\",\"optional\":false},{\"name\":\"subject\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"SmrtObjectOptions\",\"optional\":true}],\"returnType\":\"Promise<OidcIdentity | null>\",\"isStatic\":true,\"isPublic\":true},\"buildIdentityKey\":{\"name\":\"buildIdentityKey\",\"async\":false,\"parameters\":[{\"name\":\"issuer\",\"type\":\"string\",\"optional\":false},{\"name\":\"subject\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"string\",\"isStatic\":true,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"findOrCreate\":{\"name\":\"findOrCreate\",\"async\":true,\"parameters\":[{\"name\":\"profile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"oidcData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]},{\"name\":\"options\",\"type\":\"SmrtObjectOptions\",\"optional\":true}],\"returnType\":\"Promise<OidcIdentity>\",\"isStatic\":true,\"isPublic\":true},\"recordUsage\":{\"name\":\"recordUsage\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"oidc_identities\",\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]}},\"extends\":\"SmrtObject\",\"exportName\":\"OidcIdentity\",\"collectionExportName\":\"OidcIdentityCollection\",\"validationRules\":[{\"field\":\"profileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"oidc_identities\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"oidc_identities\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"provider\\\" TEXT,\\n \\\"issuer\\\" TEXT,\\n \\\"subject\\\" TEXT,\\n \\\"identity_key\\\" TEXT UNIQUE,\\n \\\"email\\\" TEXT,\\n \\\"last_used_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"provider\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"issuer\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"subject\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"identity_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":true},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_used_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"oidc_identities_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"oidc_identities_issuer_idx\",\"columns\":[\"issuer\"]},{\"name\":\"oidc_identities_subject_idx\",\"columns\":[\"subject\"]},{\"name\":\"oidc_identities_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"oidc_identities_profile_id_idx\",\"columns\":[\"profile_id\"]}],\"version\":\"925387ea\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:OidcProfileEmailReservation\":{\"name\":\"oidcprofileemailreservation\",\"className\":\"OidcProfileEmailReservation\",\"qualifiedName\":\"@happyvertical/smrt-profiles:OidcProfileEmailReservation\",\"collection\":\"oidcprofileemailreservations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/OidcProfileEmailReservation.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"profileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true,\"unique\":true}},\"emailKey\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true,\"unique\":true,\"readonly\":true},\"readonly\":true}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"oidc_profile_email_reservations\",\"api\":false,\"mcp\":false,\"cli\":false},\"extends\":\"SmrtObject\",\"exportName\":\"OidcProfileEmailReservation\",\"collectionExportName\":\"OidcProfileEmailReservationCollection\",\"validationRules\":[{\"field\":\"profileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"emailKey\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"oidc_profile_email_reservations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"oidc_profile_email_reservations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID NOT NULL UNIQUE,\\n \\\"email_key\\\" TEXT NOT NULL UNIQUE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":true,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"email_key\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true}},\"indexes\":[{\"name\":\"oidc_profile_email_reservations_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"oidc_profile_email_reservations_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"01586e67\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:Profile\":{\"name\":\"profile\",\"className\":\"Profile\",\"qualifiedName\":\"@happyvertical/smrt-profiles:Profile\",\"collection\":\"profiles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/Profile.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"typeId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProfileType\",\"_meta\":{\"required\":true}},\"email\":{\"type\":\"text\",\"required\":false},\"emailKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true,\"indexed\":true,\"readonly\":true},\"readonly\":true},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"description\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileMetadata\"},\"relationshipsFrom\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"fromProfileId\"}},\"relationshipsTo\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"toProfileId\"}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"getTypeSlug\":{\"name\":\"getTypeSlug\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"setTypeBySlug\":{\"name\":\"setTypeBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addMetadata\":{\"name\":\"addMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Record<string, string>>\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeMetadata\":{\"name\":\"removeMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addRelationship\":{\"name\":\"addRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"contextProfile\",\"type\":\"Profile\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getRelationships\":{\"name\":\"getRelationships\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"'from' | 'to' | 'all'\"]}],\"returnType\":\"Promise<ProfileRelationship[]>\",\"isStatic\":false,\"isPublic\":true},\"getRelatedProfiles\":{\"name\":\"getRelatedProfiles\",\"async\":true,\"parameters\":[{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"removeRelationship\":{\"name\":\"removeRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateBio\":{\"name\":\"generateBio\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"matches\":{\"name\":\"matches\",\"async\":true,\"parameters\":[{\"name\":\"criteria\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"findByMetadata\":{\"name\":\"findByMetadata\",\"async\":true,\"parameters\":[{\"name\":\"_metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"_value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findByType\":{\"name\":\"findByType\",\"async\":true,\"parameters\":[{\"name\":\"_typeSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findRelated\":{\"name\":\"findRelated\",\"async\":true,\"parameters\":[{\"name\":\"_profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"_relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"searchByEmail\":{\"name\":\"searchByEmail\",\"async\":true,\"parameters\":[{\"name\":\"_email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":true,\"isPublic\":true},\"getApiKeys\":{\"name\":\"getApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"getActiveApiKeys\":{\"name\":\"getActiveApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"generateApiKey\":{\"name\":\"generateApiKey\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string[]\",\"Date | null\"]}],\"returnType\":\"Promise<GenerateKeyResult>\",\"isStatic\":false,\"isPublic\":true},\"getOidcIdentities\":{\"name\":\"getOidcIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<OidcIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkOidcIdentity\":{\"name\":\"linkOidcIdentity\",\"async\":true,\"parameters\":[{\"name\":\"oidcData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<OidcIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getNostrIdentities\":{\"name\":\"getNostrIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<NostrIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkNostrIdentity\":{\"name\":\"linkNostrIdentity\",\"async\":true,\"parameters\":[{\"name\":\"nostrData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<NostrIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getAuditLogs\":{\"name\":\"getAuditLogs\",\"async\":true,\"parameters\":[{\"name\":\"limit\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"recordAction\":{\"name\":\"recordAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"'web' | 'cli' | 'ci' | 'webhook' | 'mcp'\",\"Record<string, unknown>\",\"Profile | null\"]}],\"returnType\":\"Promise<AuditLog>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"]},\"extends\":\"SmrtObject\",\"exportName\":\"Profile\",\"collectionExportName\":\"ProfileCollection\",\"validationRules\":[{\"field\":\"typeId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profiles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profiles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type_id\\\" UUID,\\n \\\"email\\\" TEXT,\\n \\\"email_key\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_types\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"email\":{\"type\":\"TEXT\",\"notNull\":false},\"email_key\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"profiles_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profiles_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profiles_email_key_idx\",\"columns\":[\"email_key\"]},{\"name\":\"profiles_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profiles_type_id_idx\",\"columns\":[\"type_id\"]}],\"version\":\"fd4497fb\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileAsset\":{\"name\":\"profileasset\",\"className\":\"ProfileAsset\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileAsset\",\"collection\":\"profileassets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileAsset.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"profileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"assetId\":{\"type\":\"crossPackageRef\",\"required\":true,\"related\":\"@happyvertical/smrt-assets:Asset\"},\"relationship\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"sortOrder\":{\"type\":\"integer\",\"required\":true,\"default\":0}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"profile_assets\",\"conflictColumns\":[\"profile_id\",\"asset_id\",\"relationship\"],\"api\":false,\"mcp\":false,\"cli\":false,\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"ProfileAsset\",\"collectionExportName\":\"ProfileAssetCollection\",\"validationRules\":[{\"field\":\"profileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"assetId\",\"rule\":\"required\",\"fieldType\":\"crossPackageRef\"},{\"field\":\"relationship\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"sortOrder\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"profile_assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"profile_id\\\" UUID NOT NULL,\\n \\\"asset_id\\\" UUID NOT NULL,\\n \\\"relationship\\\" TEXT NOT NULL,\\n \\\"sort_order\\\" INTEGER NOT NULL DEFAULT 0\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"relationship\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"sort_order\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0}},\"indexes\":[{\"name\":\"profile_assets_profile_id_asset_id_idx\",\"columns\":[\"profile_id\",\"asset_id\",\"relationship\"],\"unique\":true},{\"name\":\"profile_assets_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"profile_assets_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profile_assets_asset_id_idx\",\"columns\":[\"asset_id\"]}],\"version\":\"d0d7c2a2\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileMetadata\":{\"name\":\"profilemetadata\",\"className\":\"ProfileMetadata\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileMetadata\",\"collection\":\"profilemetadatas\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileMetadata.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"profileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"metafieldId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProfileMetafield\",\"_meta\":{\"required\":true}},\"value\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}}},\"methods\":{\"validate\":{\"name\":\"validate\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getMetafieldSlug\":{\"name\":\"getMetafieldSlug\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProfileMetadata\",\"collectionExportName\":\"ProfileMetadataCollection\",\"validationRules\":[{\"field\":\"profileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"metafieldId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"value\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profile_metadata\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_metadata\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"profile_id\\\" UUID,\\n \\\"metafield_id\\\" UUID,\\n \\\"value\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"metafield_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_metafields\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"value\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"profile_metadata_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_metadata_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_metadata_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profile_metadata_profile_id_idx\",\"columns\":[\"profile_id\"]},{\"name\":\"profile_metadata_metafield_id_idx\",\"columns\":[\"metafield_id\"]}],\"version\":\"d3ab1b70\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileMetafield\":{\"name\":\"profilemetafield\",\"className\":\"ProfileMetafield\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileMetafield\",\"collection\":\"profilemetafields\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileMetafield.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"description\":{\"type\":\"text\",\"required\":false},\"validation\":{\"type\":\"json\",\"required\":false}},\"methods\":{\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"_slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileMetafield | null>\",\"isStatic\":true,\"isPublic\":true},\"registerValidator\":{\"name\":\"registerValidator\",\"async\":false,\"parameters\":[{\"name\":\"name\",\"type\":\"string\",\"optional\":false},{\"name\":\"validator\",\"type\":\"ValidatorFunction\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":true,\"isPublic\":true},\"getValidator\":{\"name\":\"getValidator\",\"async\":false,\"parameters\":[{\"name\":\"name\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"ValidatorFunction | undefined\",\"isStatic\":true,\"isPublic\":true},\"validateValue\":{\"name\":\"validateValue\",\"async\":true,\"parameters\":[{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProfileMetafield\",\"collectionExportName\":\"ProfileMetafieldCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profile_metafields\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_metafields\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT,\\n \\\"validation\\\" JSON\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"validation\":{\"type\":\"JSON\",\"notNull\":false}},\"indexes\":[{\"name\":\"profile_metafields_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_metafields_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_metafields_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"afe420df\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileRelationship\":{\"name\":\"profilerelationship\",\"className\":\"ProfileRelationship\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileRelationship\",\"collection\":\"profilerelationships\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileRelationship.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"fromProfileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"toProfileId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Profile\",\"_meta\":{\"required\":true}},\"typeId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProfileRelationshipType\",\"_meta\":{\"required\":true}},\"contextProfileId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Profile\"},\"terms\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationshipTerm\"}},\"methods\":{\"getTypeSlug\":{\"name\":\"getTypeSlug\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"addTerm\":{\"name\":\"addTerm\",\"async\":true,\"parameters\":[{\"name\":\"startedAt\",\"type\":\"Date\",\"optional\":false},{\"name\":\"endedAt\",\"type\":\"Date\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"endCurrentTerm\":{\"name\":\"endCurrentTerm\",\"async\":true,\"parameters\":[{\"name\":\"endedAt\",\"type\":\"Date\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getTerms\":{\"name\":\"getTerms\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ProfileRelationshipTerm[]>\",\"isStatic\":false,\"isPublic\":true},\"getActiveTerm\":{\"name\":\"getActiveTerm\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ProfileRelationshipTerm | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProfileRelationship\",\"collectionExportName\":\"ProfileRelationshipCollection\",\"validationRules\":[{\"field\":\"fromProfileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"toProfileId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"typeId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"profile_relationships\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_relationships\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"from_profile_id\\\" UUID,\\n \\\"to_profile_id\\\" UUID,\\n \\\"type_id\\\" UUID,\\n \\\"context_profile_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"from_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"to_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"type_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_relationship_types\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"context_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profiles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"profile_relationships_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_relationships_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_relationships_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profile_relationships_from_profile_id_idx\",\"columns\":[\"from_profile_id\"]},{\"name\":\"profile_relationships_to_profile_id_idx\",\"columns\":[\"to_profile_id\"]},{\"name\":\"profile_relationships_type_id_idx\",\"columns\":[\"type_id\"]},{\"name\":\"profile_relationships_context_profile_id_idx\",\"columns\":[\"context_profile_id\"]}],\"version\":\"48878dba\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileRelationshipTerm\":{\"name\":\"profilerelationshipterm\",\"className\":\"ProfileRelationshipTerm\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileRelationshipTerm\",\"collection\":\"profilerelationshipterms\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileRelationshipTerm.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"relationshipId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProfileRelationship\",\"_meta\":{\"required\":true}},\"startedAt\":{\"type\":\"datetime\",\"required\":true,\"_meta\":{\"required\":true}},\"endedAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"isActive\":{\"name\":\"isActive\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"end\":{\"name\":\"end\",\"async\":true,\"parameters\":[{\"name\":\"endedAt\",\"type\":\"Date\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getDurationDays\":{\"name\":\"getDurationDays\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"ProfileRelationshipTerm\",\"collectionExportName\":\"ProfileRelationshipTermCollection\",\"validationRules\":[{\"field\":\"relationshipId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"startedAt\",\"rule\":\"required\",\"fieldType\":\"datetime\"}],\"schema\":{\"tableName\":\"profile_relationship_terms\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_relationship_terms\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"relationship_id\\\" UUID,\\n \\\"started_at\\\" TIMESTAMP,\\n \\\"ended_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"relationship_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_relationships\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false},\"ended_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false}},\"indexes\":[{\"name\":\"profile_relationship_terms_slug_context_meta_type_idx\",\"columns\":[\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"profile_relationship_terms_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_relationship_terms_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"profile_relationship_terms_relationship_id_idx\",\"columns\":[\"relationship_id\"]}],\"version\":\"ef299102\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileRelationshipType\":{\"name\":\"profilerelationshiptype\",\"className\":\"ProfileRelationshipType\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileRelationshipType\",\"collection\":\"profilerelationshiptypes\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileRelationshipType.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"reciprocal\":{\"type\":\"boolean\",\"required\":false,\"default\":true}},\"methods\":{\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"_slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileRelationshipType | null>\",\"isStatic\":true,\"isPublic\":true},\"registerReciprocalHandler\":{\"name\":\"registerReciprocalHandler\",\"async\":false,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"handler\",\"type\":\"ReciprocalHandler\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":true,\"isPublic\":true},\"getReciprocalHandler\":{\"name\":\"getReciprocalHandler\",\"async\":false,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"ReciprocalHandler | undefined\",\"isStatic\":true,\"isPublic\":true},\"isReciprocal\":{\"name\":\"isReciprocal\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":true,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"ProfileRelationshipType\",\"collectionExportName\":\"ProfileRelationshipTypeCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profile_relationship_types\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_relationship_types\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"reciprocal\\\" BOOLEAN DEFAULT TRUE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"reciprocal\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true}},\"indexes\":[{\"name\":\"profile_relationship_types_slug_context_meta_type_idx\",\"columns\":[\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"profile_relationship_types_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_relationship_types_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"719fe0d9\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:ProfileType\":{\"name\":\"profiletype\",\"className\":\"ProfileType\",\"qualifiedName\":\"@happyvertical/smrt-profiles:ProfileType\",\"collection\":\"profiletypes\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileType.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"description\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"_slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProfileType | null>\",\"isStatic\":true,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProfileType\",\"collectionExportName\":\"ProfileTypeCollection\",\"validationRules\":[{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profile_types\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profile_types\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"profile_types_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profile_types_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profile_types_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"0fb37aeb\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:Person\":{\"name\":\"person\",\"className\":\"Person\",\"qualifiedName\":\"@happyvertical/smrt-profiles:Person\",\"collection\":\"profiles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileTypes.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true}}},\"typeId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProfileType\",\"_meta\":{\"required\":true}},\"email\":{\"type\":\"text\",\"required\":false},\"emailKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true,\"indexed\":true,\"readonly\":true},\"readonly\":true},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"description\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileMetadata\"},\"relationshipsFrom\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"fromProfileId\"}},\"relationshipsTo\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"toProfileId\"}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"getTypeSlug\":{\"name\":\"getTypeSlug\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"setTypeBySlug\":{\"name\":\"setTypeBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addMetadata\":{\"name\":\"addMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Record<string, string>>\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeMetadata\":{\"name\":\"removeMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addRelationship\":{\"name\":\"addRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"contextProfile\",\"type\":\"Profile\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getRelationships\":{\"name\":\"getRelationships\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"'from' | 'to' | 'all'\"]}],\"returnType\":\"Promise<ProfileRelationship[]>\",\"isStatic\":false,\"isPublic\":true},\"getRelatedProfiles\":{\"name\":\"getRelatedProfiles\",\"async\":true,\"parameters\":[{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"removeRelationship\":{\"name\":\"removeRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateBio\":{\"name\":\"generateBio\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"matches\":{\"name\":\"matches\",\"async\":true,\"parameters\":[{\"name\":\"criteria\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"findByMetadata\":{\"name\":\"findByMetadata\",\"async\":true,\"parameters\":[{\"name\":\"_metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"_value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findByType\":{\"name\":\"findByType\",\"async\":true,\"parameters\":[{\"name\":\"_typeSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findRelated\":{\"name\":\"findRelated\",\"async\":true,\"parameters\":[{\"name\":\"_profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"_relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"searchByEmail\":{\"name\":\"searchByEmail\",\"async\":true,\"parameters\":[{\"name\":\"_email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":true,\"isPublic\":true},\"getApiKeys\":{\"name\":\"getApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"getActiveApiKeys\":{\"name\":\"getActiveApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"generateApiKey\":{\"name\":\"generateApiKey\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string[]\",\"Date | null\"]}],\"returnType\":\"Promise<GenerateKeyResult>\",\"isStatic\":false,\"isPublic\":true},\"getOidcIdentities\":{\"name\":\"getOidcIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<OidcIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkOidcIdentity\":{\"name\":\"linkOidcIdentity\",\"async\":true,\"parameters\":[{\"name\":\"oidcData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<OidcIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getNostrIdentities\":{\"name\":\"getNostrIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<NostrIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkNostrIdentity\":{\"name\":\"linkNostrIdentity\",\"async\":true,\"parameters\":[{\"name\":\"nostrData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<NostrIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getAuditLogs\":{\"name\":\"getAuditLogs\",\"async\":true,\"parameters\":[{\"name\":\"limit\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"recordAction\":{\"name\":\"recordAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"'web' | 'cli' | 'ci' | 'webhook' | 'mcp'\",\"Record<string, unknown>\",\"Profile | null\"]}],\"returnType\":\"Promise<AuditLog>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"tableName\":\"profiles\"},\"extends\":\"Profile\",\"exportName\":\"Person\",\"collectionExportName\":\"PersonCollection\",\"validationRules\":[{\"field\":\"typeId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profiles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profiles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type_id\\\" UUID,\\n \\\"email\\\" TEXT,\\n \\\"email_key\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_types\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"email\":{\"type\":\"TEXT\",\"notNull\":false},\"email_key\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"profiles_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profiles_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profiles_email_key_idx\",\"columns\":[\"email_key\"]},{\"name\":\"profiles_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profiles_type_id_idx\",\"columns\":[\"type_id\"]}],\"version\":\"50218e42\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:Organization\":{\"name\":\"organization\",\"className\":\"Organization\",\"qualifiedName\":\"@happyvertical/smrt-profiles:Organization\",\"collection\":\"profiles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileTypes.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true}}},\"typeId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProfileType\",\"_meta\":{\"required\":true}},\"email\":{\"type\":\"text\",\"required\":false},\"emailKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true,\"indexed\":true,\"readonly\":true},\"readonly\":true},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"description\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileMetadata\"},\"relationshipsFrom\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"fromProfileId\"}},\"relationshipsTo\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"toProfileId\"}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"getTypeSlug\":{\"name\":\"getTypeSlug\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"setTypeBySlug\":{\"name\":\"setTypeBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addMetadata\":{\"name\":\"addMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Record<string, string>>\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeMetadata\":{\"name\":\"removeMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addRelationship\":{\"name\":\"addRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"contextProfile\",\"type\":\"Profile\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getRelationships\":{\"name\":\"getRelationships\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"'from' | 'to' | 'all'\"]}],\"returnType\":\"Promise<ProfileRelationship[]>\",\"isStatic\":false,\"isPublic\":true},\"getRelatedProfiles\":{\"name\":\"getRelatedProfiles\",\"async\":true,\"parameters\":[{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"removeRelationship\":{\"name\":\"removeRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateBio\":{\"name\":\"generateBio\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"matches\":{\"name\":\"matches\",\"async\":true,\"parameters\":[{\"name\":\"criteria\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"findByMetadata\":{\"name\":\"findByMetadata\",\"async\":true,\"parameters\":[{\"name\":\"_metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"_value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findByType\":{\"name\":\"findByType\",\"async\":true,\"parameters\":[{\"name\":\"_typeSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findRelated\":{\"name\":\"findRelated\",\"async\":true,\"parameters\":[{\"name\":\"_profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"_relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"searchByEmail\":{\"name\":\"searchByEmail\",\"async\":true,\"parameters\":[{\"name\":\"_email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":true,\"isPublic\":true},\"getApiKeys\":{\"name\":\"getApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"getActiveApiKeys\":{\"name\":\"getActiveApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"generateApiKey\":{\"name\":\"generateApiKey\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string[]\",\"Date | null\"]}],\"returnType\":\"Promise<GenerateKeyResult>\",\"isStatic\":false,\"isPublic\":true},\"getOidcIdentities\":{\"name\":\"getOidcIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<OidcIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkOidcIdentity\":{\"name\":\"linkOidcIdentity\",\"async\":true,\"parameters\":[{\"name\":\"oidcData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<OidcIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getNostrIdentities\":{\"name\":\"getNostrIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<NostrIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkNostrIdentity\":{\"name\":\"linkNostrIdentity\",\"async\":true,\"parameters\":[{\"name\":\"nostrData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<NostrIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getAuditLogs\":{\"name\":\"getAuditLogs\",\"async\":true,\"parameters\":[{\"name\":\"limit\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"recordAction\":{\"name\":\"recordAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"'web' | 'cli' | 'ci' | 'webhook' | 'mcp'\",\"Record<string, unknown>\",\"Profile | null\"]}],\"returnType\":\"Promise<AuditLog>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"tableName\":\"profiles\"},\"extends\":\"Profile\",\"exportName\":\"Organization\",\"collectionExportName\":\"OrganizationCollection\",\"validationRules\":[{\"field\":\"typeId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profiles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profiles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type_id\\\" UUID,\\n \\\"email\\\" TEXT,\\n \\\"email_key\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_types\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"email\":{\"type\":\"TEXT\",\"notNull\":false},\"email_key\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"profiles_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profiles_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profiles_email_key_idx\",\"columns\":[\"email_key\"]},{\"name\":\"profiles_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profiles_type_id_idx\",\"columns\":[\"type_id\"]}],\"version\":\"b6b91ae1\"},\"importPath\":\"@happyvertical/smrt-profiles\"},\"@happyvertical/smrt-profiles:Bot\":{\"name\":\"bot\",\"className\":\"Bot\",\"qualifiedName\":\"@happyvertical/smrt-profiles:Bot\",\"collection\":\"profiles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/profiles/src/models/ProfileTypes.ts\",\"packageName\":\"@happyvertical/smrt-profiles\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true}}},\"typeId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProfileType\",\"_meta\":{\"required\":true}},\"email\":{\"type\":\"text\",\"required\":false},\"emailKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true,\"indexed\":true,\"readonly\":true},\"readonly\":true},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"description\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileMetadata\"},\"relationshipsFrom\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"fromProfileId\"}},\"relationshipsTo\":{\"type\":\"oneToMany\",\"required\":false,\"related\":\"ProfileRelationship\",\"_meta\":{\"foreignKey\":\"toProfileId\"}}},\"methods\":{\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"getTypeSlug\":{\"name\":\"getTypeSlug\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"setTypeBySlug\":{\"name\":\"setTypeBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addMetadata\":{\"name\":\"addMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Record<string, string>>\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeMetadata\":{\"name\":\"removeMetadata\",\"async\":true,\"parameters\":[{\"name\":\"metafieldSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"addRelationship\":{\"name\":\"addRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"contextProfile\",\"type\":\"Profile\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getRelationships\":{\"name\":\"getRelationships\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"string\",\"'from' | 'to' | 'all'\"]}],\"returnType\":\"Promise<ProfileRelationship[]>\",\"isStatic\":false,\"isPublic\":true},\"getRelatedProfiles\":{\"name\":\"getRelatedProfiles\",\"async\":true,\"parameters\":[{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":false,\"isPublic\":true},\"removeRelationship\":{\"name\":\"removeRelationship\",\"async\":true,\"parameters\":[{\"name\":\"toProfile\",\"type\":\"Profile\",\"optional\":false},{\"name\":\"relationshipSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"generateBio\":{\"name\":\"generateBio\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true},\"matches\":{\"name\":\"matches\",\"async\":true,\"parameters\":[{\"name\":\"criteria\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"findByMetadata\":{\"name\":\"findByMetadata\",\"async\":true,\"parameters\":[{\"name\":\"_metafieldSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"_value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findByType\":{\"name\":\"findByType\",\"async\":true,\"parameters\":[{\"name\":\"_typeSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"findRelated\":{\"name\":\"findRelated\",\"async\":true,\"parameters\":[{\"name\":\"_profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"_relationshipSlug\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Profile[]>\",\"isStatic\":true,\"isPublic\":true},\"searchByEmail\":{\"name\":\"searchByEmail\",\"async\":true,\"parameters\":[{\"name\":\"_email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Profile | null>\",\"isStatic\":true,\"isPublic\":true},\"getApiKeys\":{\"name\":\"getApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"getActiveApiKeys\":{\"name\":\"getActiveApiKeys\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<ApiKey[]>\",\"isStatic\":false,\"isPublic\":true},\"generateApiKey\":{\"name\":\"generateApiKey\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"string[]\",\"Date | null\"]}],\"returnType\":\"Promise<GenerateKeyResult>\",\"isStatic\":false,\"isPublic\":true},\"getOidcIdentities\":{\"name\":\"getOidcIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<OidcIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkOidcIdentity\":{\"name\":\"linkOidcIdentity\",\"async\":true,\"parameters\":[{\"name\":\"oidcData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<OidcIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getNostrIdentities\":{\"name\":\"getNostrIdentities\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<NostrIdentity[]>\",\"isStatic\":false,\"isPublic\":true},\"linkNostrIdentity\":{\"name\":\"linkNostrIdentity\",\"async\":true,\"parameters\":[{\"name\":\"nostrData\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<NostrIdentity>\",\"isStatic\":false,\"isPublic\":true},\"getAuditLogs\":{\"name\":\"getAuditLogs\",\"async\":true,\"parameters\":[{\"name\":\"limit\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<AuditLog[]>\",\"isStatic\":false,\"isPublic\":true},\"recordAction\":{\"name\":\"recordAction\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"string\",\"'web' | 'cli' | 'ci' | 'webhook' | 'mcp'\",\"Record<string, unknown>\",\"Profile | null\"]}],\"returnType\":\"Promise<AuditLog>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"tableName\":\"profiles\"},\"extends\":\"Profile\",\"exportName\":\"Bot\",\"collectionExportName\":\"BotCollection\",\"validationRules\":[{\"field\":\"typeId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"profiles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"profiles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"type_id\\\" UUID,\\n \\\"email\\\" TEXT,\\n \\\"email_key\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"type_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"profile_types\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"email\":{\"type\":\"TEXT\",\"notNull\":false},\"email_key\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false}},\"indexes\":[{\"name\":\"profiles_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"profiles_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"profiles_email_key_idx\",\"columns\":[\"email_key\"]},{\"name\":\"profiles_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"profiles_type_id_idx\",\"columns\":[\"type_id\"]}],\"version\":\"39683be5\"},\"importPath\":\"@happyvertical/smrt-profiles\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-assets\",\"@happyvertical/smrt-core\",\"@happyvertical/smrt-prompts\",\"@happyvertical/smrt-tenancy\"]}"));
|
|
1340
|
-
var __defProp$16 = Object.defineProperty;
|
|
1341
|
-
var __getOwnPropDesc$15 = Object.getOwnPropertyDescriptor;
|
|
1342
|
-
var __decorateClass$15 = (decorators, target, key, kind) => {
|
|
1343
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$15(target, key) : target;
|
|
1344
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1345
|
-
if (kind && result) __defProp$16(target, key, result);
|
|
1346
|
-
return result;
|
|
1347
|
-
};
|
|
1348
|
-
var DEFAULT_EXPIRATION_MINUTES = 15;
|
|
1349
|
-
var MagicLinkToken = class extends SmrtObject {
|
|
1350
|
-
nostrIdentityId;
|
|
1351
|
-
tokenHash = "";
|
|
1352
|
-
/**
|
|
1353
|
-
* Email this token was sent to
|
|
1354
|
-
*/
|
|
1355
|
-
email = "";
|
|
1356
|
-
/**
|
|
1357
|
-
* When this token expires
|
|
1358
|
-
*/
|
|
1359
|
-
expiresAt = new Date(Date.now() + DEFAULT_EXPIRATION_MINUTES * 60 * 1e3);
|
|
1360
|
-
/**
|
|
1361
|
-
* When this token was used (null = unused)
|
|
1362
|
-
*/
|
|
1363
|
-
usedAt = null;
|
|
1364
|
-
/**
|
|
1365
|
-
* IP address that requested the token (for rate limiting)
|
|
1366
|
-
*/
|
|
1367
|
-
requestedFromIp = "";
|
|
1368
|
-
/**
|
|
1369
|
-
* When this token was created (for rate limiting)
|
|
1370
|
-
*/
|
|
1371
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
1372
|
-
constructor(options = {}) {
|
|
1373
|
-
super(options);
|
|
1374
|
-
if (options.nostrIdentityId) this.nostrIdentityId = options.nostrIdentityId;
|
|
1375
|
-
if (options.tokenHash) this.tokenHash = options.tokenHash;
|
|
1376
|
-
if (options.email) this.email = options.email;
|
|
1377
|
-
if (options.expiresAt) this.expiresAt = options.expiresAt;
|
|
1378
|
-
if (options.usedAt !== void 0) this.usedAt = options.usedAt;
|
|
1379
|
-
if (options.requestedFromIp) this.requestedFromIp = options.requestedFromIp;
|
|
1380
|
-
if (options.createdAt) this.createdAt = options.createdAt;
|
|
1381
|
-
}
|
|
1382
|
-
/**
|
|
1383
|
-
* Hash a token using SHA-256
|
|
1384
|
-
*/
|
|
1385
|
-
static hashToken(token) {
|
|
1386
|
-
return createHash("sha256").update(token).digest("hex");
|
|
1387
|
-
}
|
|
1388
|
-
/**
|
|
1389
|
-
* Generate a new magic link token
|
|
1390
|
-
* @param nostrIdentity - The identity this token is for
|
|
1391
|
-
* @param email - The email address to send to
|
|
1392
|
-
* @param options - Additional options
|
|
1393
|
-
*/
|
|
1394
|
-
static async generate(nostrIdentity, email, options = {}) {
|
|
1395
|
-
const token = randomBytes(32).toString("base64url");
|
|
1396
|
-
const tokenHash = MagicLinkToken.hashToken(token);
|
|
1397
|
-
const expiresInMinutes = options.expiresInMinutes ?? DEFAULT_EXPIRATION_MINUTES;
|
|
1398
|
-
const expiresAt = new Date(Date.now() + expiresInMinutes * 60 * 1e3);
|
|
1399
|
-
const magicLinkToken = new MagicLinkToken({
|
|
1400
|
-
db: options.db ?? nostrIdentity.options?.db,
|
|
1401
|
-
nostrIdentityId: nostrIdentity.id,
|
|
1402
|
-
tokenHash,
|
|
1403
|
-
email: email.toLowerCase(),
|
|
1404
|
-
expiresAt,
|
|
1405
|
-
requestedFromIp: options.requestedFromIp || ""
|
|
1406
|
-
});
|
|
1407
|
-
await magicLinkToken.initialize();
|
|
1408
|
-
await magicLinkToken.save();
|
|
1409
|
-
return {
|
|
1410
|
-
token,
|
|
1411
|
-
magicLinkToken
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1414
|
-
/**
|
|
1415
|
-
* Verify a token and return the MagicLinkToken if valid
|
|
1416
|
-
* @param token - The plaintext token to verify
|
|
1417
|
-
* @param options - Database options
|
|
1418
|
-
* @returns The MagicLinkToken if valid, null otherwise
|
|
1419
|
-
*/
|
|
1420
|
-
static async verify(token, options = {}) {
|
|
1421
|
-
const tokenHash = MagicLinkToken.hashToken(token);
|
|
1422
|
-
const { MagicLinkTokenCollection } = await Promise.resolve().then(() => MagicLinkTokenCollection_exports);
|
|
1423
|
-
const magicLinkToken = await (await MagicLinkTokenCollection.create(options)).findOne({ where: { tokenHash } });
|
|
1424
|
-
if (!magicLinkToken) return null;
|
|
1425
|
-
if (!magicLinkToken.isValid()) return null;
|
|
1426
|
-
return magicLinkToken;
|
|
1427
|
-
}
|
|
1428
|
-
/**
|
|
1429
|
-
* Check if this token is valid (not expired and not used)
|
|
1430
|
-
*/
|
|
1431
|
-
isValid() {
|
|
1432
|
-
if (this.usedAt !== null) return false;
|
|
1433
|
-
if (/* @__PURE__ */ new Date() > this.expiresAt) return false;
|
|
1434
|
-
return true;
|
|
1435
|
-
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Check if this token has expired
|
|
1438
|
-
*/
|
|
1439
|
-
isExpired() {
|
|
1440
|
-
return /* @__PURE__ */ new Date() > this.expiresAt;
|
|
1441
|
-
}
|
|
1442
|
-
/**
|
|
1443
|
-
* Check if this token has been used
|
|
1444
|
-
*/
|
|
1445
|
-
isUsed() {
|
|
1446
|
-
return this.usedAt !== null;
|
|
1447
|
-
}
|
|
1448
|
-
/**
|
|
1449
|
-
* Mark this token as used
|
|
1450
|
-
*/
|
|
1451
|
-
async markUsed() {
|
|
1452
|
-
this.usedAt = /* @__PURE__ */ new Date();
|
|
1453
|
-
await this.save();
|
|
1454
|
-
}
|
|
1455
|
-
/**
|
|
1456
|
-
* Get the NostrIdentity this token is for
|
|
1457
|
-
*/
|
|
1458
|
-
async getNostrIdentity() {
|
|
1459
|
-
return await this.getRelated("nostrIdentityId");
|
|
1460
|
-
}
|
|
1461
|
-
/**
|
|
1462
|
-
* Get time remaining until expiration in seconds
|
|
1463
|
-
*/
|
|
1464
|
-
getTimeRemainingSeconds() {
|
|
1465
|
-
const now = /* @__PURE__ */ new Date();
|
|
1466
|
-
const diff = this.expiresAt.getTime() - now.getTime();
|
|
1467
|
-
return Math.max(0, Math.floor(diff / 1e3));
|
|
1468
|
-
}
|
|
1469
|
-
};
|
|
1470
|
-
__decorateClass$15([foreignKey("NostrIdentity", { required: true })], MagicLinkToken.prototype, "nostrIdentityId", 2);
|
|
1471
|
-
__decorateClass$15([field({ indexed: true })], MagicLinkToken.prototype, "tokenHash", 2);
|
|
1472
|
-
MagicLinkToken = __decorateClass$15([smrt({
|
|
1473
|
-
tableName: "magic_link_tokens",
|
|
1474
|
-
sensitive: true,
|
|
1475
|
-
api: { exclude: ["*"] },
|
|
1476
|
-
mcp: { exclude: ["*"] },
|
|
1477
|
-
cli: { include: ["list"] }
|
|
1478
|
-
})], MagicLinkToken);
|
|
1479
|
-
var MagicLinkTokenCollection_exports = /* @__PURE__ */ __exportAll$1({ MagicLinkTokenCollection: () => MagicLinkTokenCollection });
|
|
1480
|
-
var MagicLinkTokenCollection = class extends SmrtCollection {
|
|
1481
|
-
static _itemClass = MagicLinkToken;
|
|
1482
|
-
/**
|
|
1483
|
-
* Find token by hash
|
|
1484
|
-
*/
|
|
1485
|
-
async findByTokenHash(tokenHash) {
|
|
1486
|
-
return await this.findOne({ where: { tokenHash } });
|
|
1487
|
-
}
|
|
1488
|
-
/**
|
|
1489
|
-
* Find active (non-expired, non-used) tokens for an email
|
|
1490
|
-
*/
|
|
1491
|
-
async findActiveForEmail(email) {
|
|
1492
|
-
return (await this.list({ where: { email: email.toLowerCase() } })).filter((token) => token.isValid());
|
|
1493
|
-
}
|
|
1494
|
-
/**
|
|
1495
|
-
* Find tokens for a NostrIdentity
|
|
1496
|
-
*/
|
|
1497
|
-
async findByIdentity(nostrIdentityId) {
|
|
1498
|
-
return await this.list({ where: { nostrIdentityId } });
|
|
1499
|
-
}
|
|
1500
|
-
/**
|
|
1501
|
-
* Count tokens created for an email within a time window (for rate limiting)
|
|
1502
|
-
* @param email - Email address
|
|
1503
|
-
* @param withinMinutes - Time window in minutes
|
|
1504
|
-
*/
|
|
1505
|
-
async countRecentByEmail(email, withinMinutes) {
|
|
1506
|
-
const cutoff = /* @__PURE__ */ new Date(Date.now() - withinMinutes * 60 * 1e3);
|
|
1507
|
-
return (await this.list({ where: { email: email.toLowerCase() } })).filter((token) => {
|
|
1508
|
-
const createdAt = token.createdAt;
|
|
1509
|
-
return createdAt && new Date(createdAt) > cutoff;
|
|
1510
|
-
}).length;
|
|
1511
|
-
}
|
|
1512
|
-
/**
|
|
1513
|
-
* Count tokens created from an IP within a time window (for rate limiting)
|
|
1514
|
-
* @param ip - IP address
|
|
1515
|
-
* @param withinMinutes - Time window in minutes
|
|
1516
|
-
*/
|
|
1517
|
-
async countRecentByIp(ip, withinMinutes) {
|
|
1518
|
-
const cutoff = /* @__PURE__ */ new Date(Date.now() - withinMinutes * 60 * 1e3);
|
|
1519
|
-
return (await this.list({ where: { requestedFromIp: ip } })).filter((token) => {
|
|
1520
|
-
const createdAt = token.createdAt;
|
|
1521
|
-
return createdAt && new Date(createdAt) > cutoff;
|
|
1522
|
-
}).length;
|
|
1523
|
-
}
|
|
1524
|
-
/**
|
|
1525
|
-
* Verify a token and return it if valid
|
|
1526
|
-
*/
|
|
1527
|
-
async verify(token) {
|
|
1528
|
-
const tokenHash = MagicLinkToken.hashToken(token);
|
|
1529
|
-
const magicLinkToken = await this.findByTokenHash(tokenHash);
|
|
1530
|
-
if (!magicLinkToken) return null;
|
|
1531
|
-
if (!magicLinkToken.isValid()) return null;
|
|
1532
|
-
return magicLinkToken;
|
|
1533
|
-
}
|
|
1534
|
-
/**
|
|
1535
|
-
* Clean up expired tokens by deleting them
|
|
1536
|
-
* @returns Number of tokens deleted
|
|
1537
|
-
*/
|
|
1538
|
-
async cleanupExpired() {
|
|
1539
|
-
const allTokens = await this.list({});
|
|
1540
|
-
let deleted = 0;
|
|
1541
|
-
for (const token of allTokens) if (token.isExpired() || token.isUsed()) {
|
|
1542
|
-
await token.delete();
|
|
1543
|
-
deleted++;
|
|
1544
|
-
}
|
|
1545
|
-
return deleted;
|
|
1546
|
-
}
|
|
1547
|
-
/**
|
|
1548
|
-
* Revoke all tokens for a NostrIdentity (e.g., when identity is deleted)
|
|
1549
|
-
*/
|
|
1550
|
-
async revokeForIdentity(nostrIdentityId) {
|
|
1551
|
-
const tokens = await this.findByIdentity(nostrIdentityId);
|
|
1552
|
-
let revoked = 0;
|
|
1553
|
-
for (const token of tokens) if (!token.isUsed()) {
|
|
1554
|
-
await token.markUsed();
|
|
1555
|
-
revoked++;
|
|
1556
|
-
}
|
|
1557
|
-
return revoked;
|
|
1558
|
-
}
|
|
1559
|
-
/**
|
|
1560
|
-
* Check if rate limit is exceeded for email
|
|
1561
|
-
* @param email - Email address
|
|
1562
|
-
* @param maxPerHour - Maximum tokens allowed per hour (default: 5)
|
|
1563
|
-
*/
|
|
1564
|
-
async isRateLimitedByEmail(email, maxPerHour = 5) {
|
|
1565
|
-
return await this.countRecentByEmail(email, 60) >= maxPerHour;
|
|
1566
|
-
}
|
|
1567
|
-
/**
|
|
1568
|
-
* Check if rate limit is exceeded for IP
|
|
1569
|
-
* @param ip - IP address
|
|
1570
|
-
* @param maxPerHour - Maximum tokens allowed per hour (default: 10)
|
|
1571
|
-
*/
|
|
1572
|
-
async isRateLimitedByIp(ip, maxPerHour = 10) {
|
|
1573
|
-
return await this.countRecentByIp(ip, 60) >= maxPerHour;
|
|
1574
|
-
}
|
|
1575
|
-
};
|
|
1576
|
-
//#endregion
|
|
1577
|
-
//#region ../users/dist/chunks/types-DFqeph0R.js
|
|
1578
|
-
var DEFAULT_ROLE_SLUGS = {
|
|
1579
|
-
OWNER: "owner",
|
|
1580
|
-
ADMIN: "admin",
|
|
1581
|
-
MEMBER: "member",
|
|
1582
|
-
VIEWER: "viewer"
|
|
1583
|
-
};
|
|
1584
|
-
DEFAULT_ROLE_SLUGS.OWNER, DEFAULT_ROLE_SLUGS.ADMIN, DEFAULT_ROLE_SLUGS.MEMBER, DEFAULT_ROLE_SLUGS.VIEWER;
|
|
1585
|
-
//#endregion
|
|
1586
|
-
//#region ../users/dist/chunks/TerminalAuthService-BDKUbg4N.js
|
|
1587
|
-
var __defProp$14 = Object.defineProperty;
|
|
1588
|
-
var __exportAll = (all, no_symbols) => {
|
|
1589
|
-
let target = {};
|
|
1590
|
-
for (var name in all) __defProp$14(target, name, {
|
|
1591
|
-
get: all[name],
|
|
1592
|
-
enumerable: true
|
|
1593
|
-
});
|
|
1594
|
-
if (!no_symbols) __defProp$14(target, Symbol.toStringTag, { value: "Module" });
|
|
1595
|
-
return target;
|
|
1596
|
-
};
|
|
1597
|
-
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-users\",\"packageVersion\":\"0.51.39\",\"objects\":{\"@happyvertical/smrt-users:AccessRequestCollection\":{\"name\":\"accessrequestcollection\",\"className\":\"AccessRequestCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:AccessRequestCollection\",\"collection\":\"accessrequests\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/AccessRequestCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByEmail\":{\"name\":\"findByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AccessRequest[]>\",\"isStatic\":false,\"isPublic\":true},\"findOpenByEmail\":{\"name\":\"findOpenByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AccessRequest | null>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"AccessRequestStatus\",\"optional\":false}],\"returnType\":\"Promise<AccessRequest[]>\",\"isStatic\":false,\"isPublic\":true},\"findOpen\":{\"name\":\"findOpen\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AccessRequest[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"access_requests\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AccessRequest\",\"exportName\":\"AccessRequestCollection\",\"collectionExportName\":\"AccessRequestCollectionCollection\",\"schema\":{\"tableName\":\"access_requests\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"access_requests\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"email\\\" TEXT NOT NULL DEFAULT '',\\n \\\"name\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"source\\\" TEXT DEFAULT '',\\n \\\"request_context\\\" TEXT DEFAULT '{}',\\n \\\"note\\\" TEXT,\\n \\\"requested_at\\\" TIMESTAMP,\\n \\\"decided_at\\\" TIMESTAMP,\\n \\\"decided_by\\\" TEXT,\\n \\\"resulting_user_id\\\" TEXT,\\n \\\"tenant_hint\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"email\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"request_context\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"{}\"},\"note\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"requested_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"decided_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"decided_by\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"resulting_user_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_hint\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"access_requests_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"access_requests_email_idx\",\"columns\":[\"email\"]},{\"name\":\"access_requests_status_idx\",\"columns\":[\"status\"]},{\"name\":\"access_requests_source_idx\",\"columns\":[\"source\"]},{\"name\":\"access_requests_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"f396996f\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:UsersCliAuthApproveLimitCollection\":{\"name\":\"userscliauthapprovelimitcollection\",\"className\":\"UsersCliAuthApproveLimitCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:UsersCliAuthApproveLimitCollection\",\"collection\":\"userscliauthapprovelimits\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/CliAuthApproveLimitCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"reserveAttempt\":{\"name\":\"reserveAttempt\",\"async\":true,\"parameters\":[{\"name\":\"input\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"number\",\"string\"]}],\"returnType\":\"Promise<CliAuthApproveReservation>\",\"isStatic\":false,\"isPublic\":true},\"releaseAttempt\":{\"name\":\"releaseAttempt\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false},{\"name\":\"windowStartedAt\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"users_cli_auth_approve_limits\",\"api\":false,\"mcp\":false,\"cli\":false},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"UsersCliAuthApproveLimit\",\"exportName\":\"UsersCliAuthApproveLimitCollection\",\"collectionExportName\":\"UsersCliAuthApproveLimitCollectionCollection\",\"schema\":{\"tableName\":\"users_cli_auth_approve_limits\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users_cli_auth_approve_limits\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_id\\\" UUID NOT NULL UNIQUE,\\n \\\"attempt_count\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"window_started_at\\\" TIMESTAMP NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":true,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"attempt_count\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"window_started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"users_cli_auth_approve_limits_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_cli_auth_approve_limits_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"c45c02de\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:UsersCliAuthRequestCollection\":{\"name\":\"userscliauthrequestcollection\",\"className\":\"UsersCliAuthRequestCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:UsersCliAuthRequestCollection\",\"collection\":\"userscliauthrequests\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/CliAuthRequestCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"approvePendingRequest\":{\"name\":\"approvePendingRequest\",\"async\":true,\"parameters\":[{\"name\":\"input\",\"type\":\"ApprovePendingCliAuthRequestInput\",\"optional\":false}],\"returnType\":\"Promise<ApprovedCliAuthRequestSnapshot | null>\",\"isStatic\":false,\"isPublic\":true},\"consumeApprovedSession\":{\"name\":\"consumeApprovedSession\",\"async\":true,\"parameters\":[{\"name\":\"deviceCodeHash\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string | null>\",\"isStatic\":false,\"isPublic\":true},\"findByUserCode\":{\"name\":\"findByUserCode\",\"async\":true,\"parameters\":[{\"name\":\"userCode\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<UsersCliAuthRequest | null>\",\"isStatic\":false,\"isPublic\":true},\"findByDeviceCodeHash\":{\"name\":\"findByDeviceCodeHash\",\"async\":true,\"parameters\":[{\"name\":\"deviceCodeHash\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<UsersCliAuthRequest | null>\",\"isStatic\":false,\"isPublic\":true},\"deleteExpired\":{\"name\":\"deleteExpired\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"boolean\"]}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"users_cli_auth_requests\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"UsersCliAuthRequest\",\"exportName\":\"UsersCliAuthRequestCollection\",\"collectionExportName\":\"UsersCliAuthRequestCollectionCollection\",\"schema\":{\"tableName\":\"users_cli_auth_requests\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users_cli_auth_requests\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_code\\\" TEXT NOT NULL UNIQUE,\\n \\\"device_code_hash\\\" TEXT NOT NULL UNIQUE,\\n \\\"status\\\" TEXT,\\n \\\"user_id\\\" UUID,\\n \\\"tenant_id\\\" UUID,\\n \\\"session_id\\\" UUID,\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"approved_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_code\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"device_code_hash\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"session_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"sessions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"approved_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"users_cli_auth_requests_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_cli_auth_requests_expires_at_idx\",\"columns\":[\"expires_at\"]},{\"name\":\"users_cli_auth_requests_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"users_cli_auth_requests_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"users_cli_auth_requests_tenant_id_idx\",\"columns\":[\"tenant_id\"]},{\"name\":\"users_cli_auth_requests_session_id_idx\",\"columns\":[\"session_id\"]}],\"version\":\"713ae04c\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:GroupCollection\":{\"name\":\"groupcollection\",\"className\":\"GroupCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:GroupCollection\",\"collection\":\"groups\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/GroupCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Group[]>\",\"isStatic\":false,\"isPublic\":true},\"findBySlug\":{\"name\":\"findBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Group | null>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Group\",\"exportName\":\"GroupCollection\",\"collectionExportName\":\"GroupCollectionCollection\",\"schema\":{\"tableName\":\"groups\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"groups\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"groups_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"groups_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"groups_tenant_id_idx\",\"columns\":[\"tenant_id\"]}],\"version\":\"1824c19b\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:GroupMemberCollection\":{\"name\":\"groupmembercollection\",\"className\":\"GroupMemberCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:GroupMemberCollection\",\"collection\":\"groupmembers\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/GroupMemberCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByGroup\":{\"name\":\"findByGroup\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<GroupMember[]>\",\"isStatic\":false,\"isPublic\":true},\"findByUser\":{\"name\":\"findByUser\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<GroupMember[]>\",\"isStatic\":false,\"isPublic\":true},\"isMember\":{\"name\":\"isMember\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false},{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"addMember\":{\"name\":\"addMember\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false},{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<GroupMember>\",\"isStatic\":false,\"isPublic\":true},\"removeMember\":{\"name\":\"removeMember\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false},{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getGroupIds\":{\"name\":\"getGroupIds\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"getGroupIdsForTenant\":{\"name\":\"getGroupIdsForTenant\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"getUserIds\":{\"name\":\"getUserIds\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"GroupMember\",\"exportName\":\"GroupMemberCollection\",\"collectionExportName\":\"GroupMemberCollectionCollection\",\"schema\":{\"tableName\":\"group_members\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"group_members\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"group_id\\\" UUID NOT NULL,\\n \\\"user_id\\\" UUID NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"group_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"groups\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"group_members_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"group_members_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"group_members_group_id_idx\",\"columns\":[\"group_id\"]},{\"name\":\"group_members_user_id_idx\",\"columns\":[\"user_id\"]}],\"version\":\"ed4d1187\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:GroupRoleCollection\":{\"name\":\"grouprolecollection\",\"className\":\"GroupRoleCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:GroupRoleCollection\",\"collection\":\"grouproles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/GroupRoleCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByGroup\":{\"name\":\"findByGroup\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<GroupRole[]>\",\"isStatic\":false,\"isPublic\":true},\"findByRole\":{\"name\":\"findByRole\",\"async\":true,\"parameters\":[{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<GroupRole[]>\",\"isStatic\":false,\"isPublic\":true},\"hasRole\":{\"name\":\"hasRole\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false},{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"addRole\":{\"name\":\"addRole\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false},{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<GroupRole>\",\"isStatic\":false,\"isPublic\":true},\"removeRole\":{\"name\":\"removeRole\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false},{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getRoleIds\":{\"name\":\"getRoleIds\",\"async\":true,\"parameters\":[{\"name\":\"groupId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"GroupRole\",\"exportName\":\"GroupRoleCollection\",\"collectionExportName\":\"GroupRoleCollectionCollection\",\"schema\":{\"tableName\":\"group_roles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"group_roles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"group_id\\\" UUID NOT NULL,\\n \\\"role_id\\\" UUID NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"group_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"groups\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"role_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"roles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"group_roles_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"group_roles_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"group_roles_group_id_idx\",\"columns\":[\"group_id\"]},{\"name\":\"group_roles_role_id_idx\",\"columns\":[\"role_id\"]}],\"version\":\"b1e35f93\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:UsersMagicLinkTokenCollection\":{\"name\":\"usersmagiclinktokencollection\",\"className\":\"UsersMagicLinkTokenCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:UsersMagicLinkTokenCollection\",\"collection\":\"usersmagiclinktokens\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/MagicLinkTokenCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByNonce\":{\"name\":\"findByNonce\",\"async\":true,\"parameters\":[{\"name\":\"nonce\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<UsersMagicLinkToken | null>\",\"isStatic\":false,\"isPublic\":true},\"markUsed\":{\"name\":\"markUsed\",\"async\":true,\"parameters\":[{\"name\":\"nonce\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"deleteExpired\":{\"name\":\"deleteExpired\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"boolean\"]}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"users_magic_link_tokens\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"UsersMagicLinkToken\",\"exportName\":\"UsersMagicLinkTokenCollection\",\"collectionExportName\":\"UsersMagicLinkTokenCollectionCollection\",\"schema\":{\"tableName\":\"users_magic_link_tokens\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users_magic_link_tokens\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"nonce\\\" TEXT NOT NULL UNIQUE DEFAULT '',\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"used\\\" BOOLEAN DEFAULT FALSE,\\n \\\"expires_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"nonce\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true,\"default\":\"\"},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"used\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"users_magic_link_tokens_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_magic_link_tokens_expires_at_idx\",\"columns\":[\"expires_at\"]},{\"name\":\"users_magic_link_tokens_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"537853d3\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:MembershipCollection\":{\"name\":\"membershipcollection\",\"className\":\"MembershipCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:MembershipCollection\",\"collection\":\"memberships\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/MembershipCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByUser\":{\"name\":\"findByUser\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Membership[]>\",\"isStatic\":false,\"isPublic\":true},\"findActiveByUser\":{\"name\":\"findActiveByUser\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Membership[]>\",\"isStatic\":false,\"isPublic\":true},\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Membership[]>\",\"isStatic\":false,\"isPublic\":true},\"findActiveByTenant\":{\"name\":\"findActiveByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Membership[]>\",\"isStatic\":false,\"isPublic\":true},\"findByUserAndTenant\":{\"name\":\"findByUserAndTenant\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Membership | null>\",\"isStatic\":false,\"isPublic\":true},\"findByRole\":{\"name\":\"findByRole\",\"async\":true,\"parameters\":[{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Membership[]>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"MembershipStatus\",\"optional\":false}],\"returnType\":\"Promise<Membership[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Membership\",\"exportName\":\"MembershipCollection\",\"collectionExportName\":\"MembershipCollectionCollection\",\"schema\":{\"tableName\":\"memberships\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"memberships\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_id\\\" UUID NOT NULL,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"role_id\\\" UUID NOT NULL,\\n \\\"status\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"role_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"roles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"memberships_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"memberships_tenant_id_user_id_idx\",\"columns\":[\"tenant_id\",\"user_id\"]},{\"name\":\"memberships_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"memberships_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"memberships_role_id_idx\",\"columns\":[\"role_id\"]}],\"version\":\"ebfd11e0\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:MembershipOverrideCollection\":{\"name\":\"membershipoverridecollection\",\"className\":\"MembershipOverrideCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:MembershipOverrideCollection\",\"collection\":\"membershipoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/MembershipOverrideCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByMembership\":{\"name\":\"findByMembership\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MembershipOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"findGrants\":{\"name\":\"findGrants\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MembershipOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"findDenies\":{\"name\":\"findDenies\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MembershipOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"getGrantedPermissionIds\":{\"name\":\"getGrantedPermissionIds\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"getDeniedPermissionIds\":{\"name\":\"getDeniedPermissionIds\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"setOverride\":{\"name\":\"setOverride\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"OverrideEffect\",\"optional\":false}],\"returnType\":\"Promise<MembershipOverride>\",\"isStatic\":false,\"isPublic\":true},\"removeOverride\":{\"name\":\"removeOverride\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"grantPermission\":{\"name\":\"grantPermission\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MembershipOverride>\",\"isStatic\":false,\"isPublic\":true},\"denyPermission\":{\"name\":\"denyPermission\",\"async\":true,\"parameters\":[{\"name\":\"membershipId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<MembershipOverride>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"MembershipOverride\",\"exportName\":\"MembershipOverrideCollection\",\"collectionExportName\":\"MembershipOverrideCollectionCollection\",\"schema\":{\"tableName\":\"membership_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"membership_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"membership_id\\\" UUID NOT NULL,\\n \\\"permission_id\\\" UUID NOT NULL,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"membership_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"memberships\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"permission_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"permissions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"membership_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"membership_overrides_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"membership_overrides_membership_id_idx\",\"columns\":[\"membership_id\"]},{\"name\":\"membership_overrides_permission_id_idx\",\"columns\":[\"permission_id\"]}],\"version\":\"25fe9da8\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:PermissionCollection\":{\"name\":\"permissioncollection\",\"className\":\"PermissionCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:PermissionCollection\",\"collection\":\"permissions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/PermissionCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByCategory\":{\"name\":\"findByCategory\",\"async\":true,\"parameters\":[{\"name\":\"category\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Permission[]>\",\"isStatic\":false,\"isPublic\":true},\"findBySlug\":{\"name\":\"findBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Permission | null>\",\"isStatic\":false,\"isPublic\":true},\"findByIds\":{\"name\":\"findByIds\",\"async\":true,\"parameters\":[{\"name\":\"ids\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"Promise<Map<string, Permission>>\",\"isStatic\":false,\"isPublic\":true},\"getCategories\":{\"name\":\"getCategories\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"findOrCreate\":{\"name\":\"findOrCreate\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"defaults\",\"type\":\"Partial<object>\",\"optional\":true,\"memberTypes\":[\"string\"]}],\"returnType\":\"Promise<Permission>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Permission\",\"exportName\":\"PermissionCollection\",\"collectionExportName\":\"PermissionCollectionCollection\",\"schema\":{\"tableName\":\"permissions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"permissions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"category\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"category\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"permissions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"permissions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"4c81b2af\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:ResourceGrantCollection\":{\"name\":\"resourcegrantcollection\",\"className\":\"ResourceGrantCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:ResourceGrantCollection\",\"collection\":\"resourcegrants\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/ResourceGrantCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findExact\":{\"name\":\"findExact\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"userId\",\"type\":\"string\",\"optional\":false},{\"name\":\"resourceType\",\"type\":\"string\",\"optional\":false},{\"name\":\"resourceId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permission\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ResourceGrant[]>\",\"isStatic\":false,\"isPublic\":true},\"findChildren\":{\"name\":\"findChildren\",\"async\":true,\"parameters\":[{\"name\":\"parentGrantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ResourceGrant[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ResourceGrant\",\"exportName\":\"ResourceGrantCollection\",\"collectionExportName\":\"ResourceGrantCollectionCollection\",\"schema\":{\"tableName\":\"resource_grants\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"resource_grants\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"user_id\\\" UUID NOT NULL,\\n \\\"resource_type\\\" TEXT,\\n \\\"resource_id\\\" TEXT,\\n \\\"permission\\\" TEXT,\\n \\\"effect\\\" TEXT,\\n \\\"can_delegate\\\" BOOLEAN DEFAULT FALSE,\\n \\\"parent_grant_id\\\" UUID,\\n \\\"revoked_at\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"resource_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"resource_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"permission\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"can_delegate\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"parent_grant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"resource_grants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"revoked_at\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"resource_grants_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"resource_grants_lookup_idx\",\"columns\":[\"tenant_id\",\"user_id\"]},{\"name\":\"resource_grants_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"resource_grants_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"resource_grants_parent_grant_id_idx\",\"columns\":[\"parent_grant_id\"]}],\"version\":\"52e03776\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:RoleCollection\":{\"name\":\"rolecollection\",\"className\":\"RoleCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:RoleCollection\",\"collection\":\"roles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/RoleCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findSystemRoles\":{\"name\":\"findSystemRoles\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Role[]>\",\"isStatic\":false,\"isPublic\":true},\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Role[]>\",\"isStatic\":false,\"isPublic\":true},\"findTenantRoles\":{\"name\":\"findTenantRoles\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Role[]>\",\"isStatic\":false,\"isPublic\":true},\"findBySlug\":{\"name\":\"findBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Role | null>\",\"isStatic\":false,\"isPublic\":true},\"findSystemRoleBySlug\":{\"name\":\"findSystemRoleBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Role | null>\",\"isStatic\":false,\"isPublic\":true},\"seedSystemRoles\":{\"name\":\"seedSystemRoles\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"SeedSystemRolesOptions\",\"optional\":true}],\"returnType\":\"Promise<Role[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Role\",\"exportName\":\"RoleCollection\",\"collectionExportName\":\"RoleCollectionCollection\",\"schema\":{\"tableName\":\"roles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"roles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"is_system\\\" BOOLEAN DEFAULT FALSE,\\n \\\"inherits_to_descendants\\\" BOOLEAN DEFAULT FALSE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"is_system\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"inherits_to_descendants\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false}},\"indexes\":[{\"name\":\"roles_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"roles_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"roles_tenant_id_idx\",\"columns\":[\"tenant_id\"]}],\"version\":\"47369d9d\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:RolePermissionCollection\":{\"name\":\"rolepermissioncollection\",\"className\":\"RolePermissionCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:RolePermissionCollection\",\"collection\":\"rolepermissions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/RolePermissionCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByRole\":{\"name\":\"findByRole\",\"async\":true,\"parameters\":[{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<RolePermission[]>\",\"isStatic\":false,\"isPublic\":true},\"findByPermission\":{\"name\":\"findByPermission\",\"async\":true,\"parameters\":[{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<RolePermission[]>\",\"isStatic\":false,\"isPublic\":true},\"hasPermission\":{\"name\":\"hasPermission\",\"async\":true,\"parameters\":[{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"addPermission\":{\"name\":\"addPermission\",\"async\":true,\"parameters\":[{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<RolePermission>\",\"isStatic\":false,\"isPublic\":true},\"removePermission\":{\"name\":\"removePermission\",\"async\":true,\"parameters\":[{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getPermissionIds\":{\"name\":\"getPermissionIds\",\"async\":true,\"parameters\":[{\"name\":\"roleId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"seedRolePermissions\":{\"name\":\"seedRolePermissions\",\"async\":true,\"parameters\":[{\"name\":\"matrix\",\"type\":\"RolePermissionPatternMatrix\",\"optional\":true},{\"name\":\"options\",\"type\":\"SeedRolePermissionsOptions\",\"optional\":true}],\"returnType\":\"Promise<SeedRolePermissionsResult>\",\"isStatic\":false,\"isPublic\":true},\"seedDefaultRolePersonalizationPermissions\":{\"name\":\"seedDefaultRolePersonalizationPermissions\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"Omit<SeedRolePermissionsOptions, 'prune'>\",\"optional\":true}],\"returnType\":\"Promise<SeedRolePermissionsResult>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"RolePermission\",\"exportName\":\"RolePermissionCollection\",\"collectionExportName\":\"RolePermissionCollectionCollection\",\"schema\":{\"tableName\":\"role_permissions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"role_permissions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"role_id\\\" UUID NOT NULL,\\n \\\"permission_id\\\" UUID NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"role_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"roles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"permission_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"permissions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"role_permissions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"role_permissions_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"role_permissions_role_id_idx\",\"columns\":[\"role_id\"]},{\"name\":\"role_permissions_permission_id_idx\",\"columns\":[\"permission_id\"]}],\"version\":\"4dfed3ac\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:SessionCollection\":{\"name\":\"sessioncollection\",\"className\":\"SessionCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:SessionCollection\",\"collection\":\"sessions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/SessionCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"createSession\":{\"name\":\"createSession\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"CreateSessionOptions\",\"optional\":false}],\"returnType\":\"Promise<Session>\",\"isStatic\":false,\"isPublic\":true},\"findValidSession\":{\"name\":\"findValidSession\",\"async\":true,\"parameters\":[{\"name\":\"sessionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Session | null>\",\"isStatic\":false,\"isPublic\":true},\"touch\":{\"name\":\"touch\",\"async\":true,\"parameters\":[{\"name\":\"sessionId\",\"type\":\"string\",\"optional\":false},{\"name\":\"extendTtl\",\"type\":\"boolean\",\"optional\":true},{\"name\":\"ttl\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"findByUser\":{\"name\":\"findByUser\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Session[]>\",\"isStatic\":false,\"isPublic\":true},\"deleteUserSessions\":{\"name\":\"deleteUserSessions\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"revokeUserSessions\":{\"name\":\"revokeUserSessions\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"revokeSession\":{\"name\":\"revokeSession\",\"async\":true,\"parameters\":[{\"name\":\"sessionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"deleteExpired\":{\"name\":\"deleteExpired\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"boolean\"]}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"countUserSessions\":{\"name\":\"countUserSessions\",\"async\":true,\"parameters\":[{\"name\":\"userId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"setSessionTenant\":{\"name\":\"setSessionTenant\",\"async\":true,\"parameters\":[{\"name\":\"sessionId\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"null\"}]}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"setSessionData\":{\"name\":\"setSessionData\",\"async\":true,\"parameters\":[{\"name\":\"sessionId\",\"type\":\"string\",\"optional\":false},{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getSessionData\":{\"name\":\"getSessionData\",\"async\":true,\"parameters\":[{\"name\":\"sessionId\",\"type\":\"string\",\"optional\":false},{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<T | undefined>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Session\",\"exportName\":\"SessionCollection\",\"collectionExportName\":\"SessionCollectionCollection\",\"schema\":{\"tableName\":\"sessions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"sessions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_id\\\" UUID,\\n \\\"tenant_id\\\" UUID,\\n \\\"status\\\" TEXT,\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"user_agent\\\" TEXT DEFAULT '',\\n \\\"ip_address\\\" TEXT DEFAULT '',\\n \\\"last_accessed_at\\\" TIMESTAMP,\\n \\\"data\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"user_agent\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"ip_address\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"last_accessed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"data\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"sessions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"sessions_expires_at_idx\",\"columns\":[\"expires_at\"]},{\"name\":\"sessions_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"sessions_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"sessions_tenant_id_idx\",\"columns\":[\"tenant_id\"]}],\"version\":\"dc55d351\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:TenantCollection\":{\"name\":\"tenantcollection\",\"className\":\"TenantCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:TenantCollection\",\"collection\":\"tenants\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/TenantCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"TenantStatus\",\"optional\":false}],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"findActive\":{\"name\":\"findActive\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"findBySlug\":{\"name\":\"findBySlug\",\"async\":true,\"parameters\":[{\"name\":\"slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant | null>\",\"isStatic\":false,\"isPublic\":true},\"findRoots\":{\"name\":\"findRoots\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"findChildren\":{\"name\":\"findChildren\",\"async\":true,\"parameters\":[{\"name\":\"parentTenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"findParent\":{\"name\":\"findParent\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant | null>\",\"isStatic\":false,\"isPublic\":true},\"getAncestors\":{\"name\":\"getAncestors\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"getAncestorsFromRoot\":{\"name\":\"getAncestorsFromRoot\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"getDescendants\":{\"name\":\"getDescendants\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"getSiblings\":{\"name\":\"getSiblings\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant[]>\",\"isStatic\":false,\"isPublic\":true},\"isAncestorOf\":{\"name\":\"isAncestorOf\",\"async\":true,\"parameters\":[{\"name\":\"potentialAncestorId\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"isDescendantOf\":{\"name\":\"isDescendantOf\",\"async\":true,\"parameters\":[{\"name\":\"potentialDescendantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"createChild\":{\"name\":\"createChild\",\"async\":true,\"parameters\":[{\"name\":\"parentTenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"CreateChildTenantOptions\",\"optional\":false}],\"returnType\":\"Promise<Tenant>\",\"isStatic\":false,\"isPublic\":true},\"moveToParent\":{\"name\":\"moveToParent\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"newParentId\",\"type\":\"string | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"null\"}]}],\"returnType\":\"Promise<Tenant>\",\"isStatic\":false,\"isPublic\":true},\"makeRoot\":{\"name\":\"makeRoot\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Tenant>\",\"isStatic\":false,\"isPublic\":true},\"validateHierarchy\":{\"name\":\"validateHierarchy\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"getTree\":{\"name\":\"getTree\",\"async\":true,\"parameters\":[{\"name\":\"rootTenantId\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"any\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Tenant\",\"exportName\":\"TenantCollection\",\"collectionExportName\":\"TenantCollectionCollection\",\"schema\":{\"tableName\":\"tenants\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"tenants\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"status\\\" TEXT,\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"parent_tenant_id\\\" UUID,\\n \\\"hierarchy_level\\\" INTEGER DEFAULT 0,\\n \\\"hierarchy_path\\\" TEXT DEFAULT '',\\n \\\"cascade_permissions\\\" BOOLEAN DEFAULT TRUE,\\n \\\"inherit_permissions\\\" BOOLEAN DEFAULT TRUE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"status\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"parent_tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"hierarchy_level\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"hierarchy_path\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"cascade_permissions\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true},\"inherit_permissions\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true}},\"indexes\":[{\"name\":\"tenants_slug_context_meta_type_idx\",\"columns\":[\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"tenants_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"tenants_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"tenants_parent_tenant_id_idx\",\"columns\":[\"parent_tenant_id\"]}],\"version\":\"934f7025\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:TenantIntegrationCollection\":{\"name\":\"tenantintegrationcollection\",\"className\":\"TenantIntegrationCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:TenantIntegrationCollection\",\"collection\":\"tenantintegrations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/TenantIntegrationCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"listForTenant\":{\"name\":\"listForTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantIntegration[]>\",\"isStatic\":false,\"isPublic\":true},\"findFor\":{\"name\":\"findFor\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"provider\",\"type\":\"TenantIntegrationProvider\",\"optional\":false}],\"returnType\":\"Promise<TenantIntegration | null>\",\"isStatic\":false,\"isPublic\":true},\"findOrInit\":{\"name\":\"findOrInit\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"provider\",\"type\":\"TenantIntegrationProvider\",\"optional\":false}],\"returnType\":\"Promise<TenantIntegration>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"tenant_integrations\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"TenantIntegration\",\"exportName\":\"TenantIntegrationCollection\",\"collectionExportName\":\"TenantIntegrationCollectionCollection\",\"schema\":{\"tableName\":\"tenant_integrations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"tenant_integrations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"provider\\\" TEXT DEFAULT 'aws',\\n \\\"external_ids\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'unprovisioned',\\n \\\"last_checked_at\\\" TIMESTAMP,\\n \\\"last_check_summary\\\" TEXT,\\n \\\"last_error\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"provider\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"aws\"},\"external_ids\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"unprovisioned\"},\"last_checked_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"last_check_summary\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_error\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"tenant_integrations_tenant_id_provider_idx\",\"columns\":[\"tenant_id\",\"provider\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"tenant_integrations_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"tenant_integrations_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"3ed31966\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:TenantPermissionOverrideCollection\":{\"name\":\"tenantpermissionoverridecollection\",\"className\":\"TenantPermissionOverrideCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:TenantPermissionOverrideCollection\",\"collection\":\"tenantpermissionoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/TenantPermissionOverrideCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"findGrants\":{\"name\":\"findGrants\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"findDenies\":{\"name\":\"findDenies\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"findInherits\":{\"name\":\"findInherits\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"getGrantedPermissionIds\":{\"name\":\"getGrantedPermissionIds\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"getDeniedPermissionIds\":{\"name\":\"getDeniedPermissionIds\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<string[]>\",\"isStatic\":false,\"isPublic\":true},\"getOverridesByEffect\":{\"name\":\"getOverridesByEffect\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverrideResult>\",\"isStatic\":false,\"isPublic\":true},\"getOverridesByEffectBatch\":{\"name\":\"getOverridesByEffectBatch\",\"async\":true,\"parameters\":[{\"name\":\"tenantIds\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"Promise<Map<string, TenantPermissionOverrideResult>>\",\"isStatic\":false,\"isPublic\":true},\"setOverride\":{\"name\":\"setOverride\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"TenantPermissionEffect\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride>\",\"isStatic\":false,\"isPublic\":true},\"removeOverride\":{\"name\":\"removeOverride\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"removeAllOverrides\":{\"name\":\"removeAllOverrides\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<number>\",\"isStatic\":false,\"isPublic\":true},\"grantPermission\":{\"name\":\"grantPermission\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride>\",\"isStatic\":false,\"isPublic\":true},\"denyPermission\":{\"name\":\"denyPermission\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride>\",\"isStatic\":false,\"isPublic\":true},\"inheritPermission\":{\"name\":\"inheritPermission\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"permissionId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride>\",\"isStatic\":false,\"isPublic\":true},\"bulkSetOverrides\":{\"name\":\"bulkSetOverrides\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"overrides\",\"type\":\"Array<object>\",\"optional\":false,\"memberTypes\":[\"string\",\"TenantPermissionEffect\"]}],\"returnType\":\"Promise<TenantPermissionOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"copyOverrides\":{\"name\":\"copyOverrides\",\"async\":true,\"parameters\":[{\"name\":\"fromTenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"toTenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<TenantPermissionOverride[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"TenantPermissionOverride\",\"exportName\":\"TenantPermissionOverrideCollection\",\"collectionExportName\":\"TenantPermissionOverrideCollectionCollection\",\"schema\":{\"tableName\":\"tenant_permission_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"tenant_permission_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"permission_id\\\" UUID NOT NULL,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"permission_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"permissions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"tenant_permission_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"tenant_permission_overrides_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"tenant_permission_overrides_tenant_id_idx\",\"columns\":[\"tenant_id\"]},{\"name\":\"tenant_permission_overrides_permission_id_idx\",\"columns\":[\"permission_id\"]}],\"version\":\"95b78bdd\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:UserCollection\":{\"name\":\"usercollection\",\"className\":\"UserCollection\",\"qualifiedName\":\"@happyvertical/smrt-users:UserCollection\",\"collection\":\"users\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/collections/UserCollection.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{},\"methods\":{\"findByEmail\":{\"name\":\"findByEmail\",\"async\":true,\"parameters\":[{\"name\":\"email\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<User | null>\",\"isStatic\":false,\"isPublic\":true},\"findByProfile\":{\"name\":\"findByProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<User | null>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"UserStatus\",\"optional\":false}],\"returnType\":\"Promise<User[]>\",\"isStatic\":false,\"isPublic\":true},\"findActive\":{\"name\":\"findActive\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<User[]>\",\"isStatic\":false,\"isPublic\":true},\"findPending\":{\"name\":\"findPending\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<User[]>\",\"isStatic\":false,\"isPublic\":true},\"getOrCreateForProfile\":{\"name\":\"getOrCreateForProfile\",\"async\":true,\"parameters\":[{\"name\":\"profileId\",\"type\":\"string\",\"optional\":false},{\"name\":\"email\",\"type\":\"string\",\"optional\":false},{\"name\":\"defaults\",\"type\":\"Partial<object>\",\"optional\":true,\"memberTypes\":[\"UserStatus\"]}],\"returnType\":\"Promise<User>\",\"isStatic\":false,\"isPublic\":true},\"getOrCreateFromOidc\":{\"name\":\"getOrCreateFromOidc\",\"async\":true,\"parameters\":[{\"name\":\"claims\",\"type\":\"OidcClaims\",\"optional\":false},{\"name\":\"provider\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"GetOrCreateFromOidcOptions\",\"optional\":true}],\"returnType\":\"Promise<OidcIdentityResult>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"User\",\"exportName\":\"UserCollection\",\"collectionExportName\":\"UserCollectionCollection\",\"schema\":{\"tableName\":\"users\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID UNIQUE,\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"email_key\\\" TEXT UNIQUE,\\n \\\"status\\\" TEXT,\\n \\\"last_login_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":true},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"email_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":true},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_login_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"users_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_email_idx\",\"columns\":[\"email\"]},{\"name\":\"users_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"38fd1677\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:AccessRequest\":{\"name\":\"accessrequest\",\"className\":\"AccessRequest\",\"qualifiedName\":\"@happyvertical/smrt-users:AccessRequest\",\"collection\":\"accessrequests\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/AccessRequest.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"email\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true,\"indexed\":true}},\"name\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"indexed\":true}},\"source\":{\"type\":\"text\",\"required\":false,\"default\":\"\",\"_meta\":{\"indexed\":true}},\"requestContext\":{\"type\":\"text\",\"required\":false,\"default\":\"{}\"},\"note\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"requestedAt\":{\"type\":\"datetime\",\"required\":false},\"decidedAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"nullable\":true}},\"decidedBy\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"resultingUserId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"tenantHint\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{\"getRequestContext\":{\"name\":\"getRequestContext\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setRequestContext\":{\"name\":\"setRequestContext\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getTenantHint\":{\"name\":\"getTenantHint\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown> | null\",\"isStatic\":false,\"isPublic\":true},\"setTenantHint\":{\"name\":\"setTenantHint\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"Record<string, unknown> | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"Record<string, unknown>\"},{\"type\":\"null\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"isOpen\":{\"name\":\"isOpen\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isApproved\":{\"name\":\"isApproved\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isTerminal\":{\"name\":\"isTerminal\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"access_requests\",\"conflictColumns\":[\"id\"],\"api\":{\"include\":[]},\"mcp\":{\"include\":[]},\"cli\":{\"include\":[]}},\"extends\":\"SmrtObject\",\"exportName\":\"AccessRequest\",\"collectionExportName\":\"AccessRequestCollection\",\"validationRules\":[{\"field\":\"email\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"access_requests\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"access_requests\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"email\\\" TEXT NOT NULL DEFAULT '',\\n \\\"name\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"source\\\" TEXT DEFAULT '',\\n \\\"request_context\\\" TEXT DEFAULT '{}',\\n \\\"note\\\" TEXT,\\n \\\"requested_at\\\" TIMESTAMP,\\n \\\"decided_at\\\" TIMESTAMP,\\n \\\"decided_by\\\" TEXT,\\n \\\"resulting_user_id\\\" TEXT,\\n \\\"tenant_hint\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"email\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"request_context\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"{}\"},\"note\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"requested_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"decided_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"decided_by\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"resulting_user_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"tenant_hint\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"access_requests_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"access_requests_email_idx\",\"columns\":[\"email\"]},{\"name\":\"access_requests_status_idx\",\"columns\":[\"status\"]},{\"name\":\"access_requests_source_idx\",\"columns\":[\"source\"]},{\"name\":\"access_requests_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"f396996f\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:UsersCliAuthApproveLimit\":{\"name\":\"userscliauthapprovelimit\",\"className\":\"UsersCliAuthApproveLimit\",\"qualifiedName\":\"@happyvertical/smrt-users:UsersCliAuthApproveLimit\",\"collection\":\"userscliauthapprovelimits\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/CliAuthApproveLimit.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"userId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"User\",\"_meta\":{\"required\":true,\"unique\":true}},\"attemptCount\":{\"type\":\"integer\",\"required\":true,\"default\":0,\"_meta\":{\"required\":true,\"default\":0}},\"windowStartedAt\":{\"type\":\"datetime\",\"required\":true,\"_meta\":{\"required\":true}}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"users_cli_auth_approve_limits\",\"api\":false,\"cli\":false,\"mcp\":false},\"extends\":\"SmrtObject\",\"exportName\":\"UsersCliAuthApproveLimit\",\"collectionExportName\":\"UsersCliAuthApproveLimitCollection\",\"validationRules\":[{\"field\":\"userId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"attemptCount\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"windowStartedAt\",\"rule\":\"required\",\"fieldType\":\"datetime\"}],\"schema\":{\"tableName\":\"users_cli_auth_approve_limits\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users_cli_auth_approve_limits\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_id\\\" UUID NOT NULL UNIQUE,\\n \\\"attempt_count\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"window_started_at\\\" TIMESTAMP NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":true,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"attempt_count\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":0},\"window_started_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"unique\":false}},\"indexes\":[{\"name\":\"users_cli_auth_approve_limits_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_cli_auth_approve_limits_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"c45c02de\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:UsersCliAuthRequest\":{\"name\":\"userscliauthrequest\",\"className\":\"UsersCliAuthRequest\",\"qualifiedName\":\"@happyvertical/smrt-users:UsersCliAuthRequest\",\"collection\":\"userscliauthrequests\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/CliAuthRequest.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"userCode\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true,\"unique\":true}},\"deviceCodeHash\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true,\"unique\":true}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"userId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"User\",\"_meta\":{\"nullable\":true}},\"tenantId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Tenant\",\"_meta\":{\"nullable\":true}},\"sessionId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Session\",\"_meta\":{\"nullable\":true}},\"expiresAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"indexed\":true}},\"approvedAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"users_cli_auth_requests\",\"sensitive\":true,\"api\":{\"include\":[]},\"cli\":{\"include\":[]},\"mcp\":{\"include\":[]}},\"extends\":\"SmrtObject\",\"exportName\":\"UsersCliAuthRequest\",\"collectionExportName\":\"UsersCliAuthRequestCollection\",\"validationRules\":[{\"field\":\"userCode\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"deviceCodeHash\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"users_cli_auth_requests\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users_cli_auth_requests\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_code\\\" TEXT NOT NULL UNIQUE,\\n \\\"device_code_hash\\\" TEXT NOT NULL UNIQUE,\\n \\\"status\\\" TEXT,\\n \\\"user_id\\\" UUID,\\n \\\"tenant_id\\\" UUID,\\n \\\"session_id\\\" UUID,\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"approved_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_code\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"device_code_hash\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"session_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"sessions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"approved_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"users_cli_auth_requests_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_cli_auth_requests_expires_at_idx\",\"columns\":[\"expires_at\"]},{\"name\":\"users_cli_auth_requests_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"users_cli_auth_requests_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"users_cli_auth_requests_tenant_id_idx\",\"columns\":[\"tenant_id\"]},{\"name\":\"users_cli_auth_requests_session_id_idx\",\"columns\":[\"session_id\"]}],\"version\":\"713ae04c\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:Group\":{\"name\":\"group\",\"className\":\"Group\",\"qualifiedName\":\"@happyvertical/smrt-users:Group\",\"collection\":\"groups\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/Group.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"tenantId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Tenant\",\"_meta\":{\"required\":true}},\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":true},\"extends\":\"SmrtObject\",\"exportName\":\"Group\",\"collectionExportName\":\"GroupCollection\",\"validationRules\":[{\"field\":\"tenantId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"groups\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"groups\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"groups_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"groups_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"groups_tenant_id_idx\",\"columns\":[\"tenant_id\"]}],\"version\":\"1824c19b\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:GroupMember\":{\"name\":\"groupmember\",\"className\":\"GroupMember\",\"qualifiedName\":\"@happyvertical/smrt-users:GroupMember\",\"collection\":\"groupmembers\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/GroupMember.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"groupId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Group\",\"_meta\":{\"required\":true}},\"userId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"User\",\"_meta\":{\"required\":true}}},\"methods\":{},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":true},\"extends\":\"SmrtObject\",\"exportName\":\"GroupMember\",\"collectionExportName\":\"GroupMemberCollection\",\"validationRules\":[{\"field\":\"groupId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"userId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"group_members\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"group_members\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"group_id\\\" UUID NOT NULL,\\n \\\"user_id\\\" UUID NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"group_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"groups\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"group_members_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"group_members_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"group_members_group_id_idx\",\"columns\":[\"group_id\"]},{\"name\":\"group_members_user_id_idx\",\"columns\":[\"user_id\"]}],\"version\":\"ed4d1187\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:GroupRole\":{\"name\":\"grouprole\",\"className\":\"GroupRole\",\"qualifiedName\":\"@happyvertical/smrt-users:GroupRole\",\"collection\":\"grouproles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/GroupRole.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"groupId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Group\",\"_meta\":{\"required\":true}},\"roleId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Role\",\"_meta\":{\"required\":true}}},\"methods\":{},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":true},\"extends\":\"SmrtObject\",\"exportName\":\"GroupRole\",\"collectionExportName\":\"GroupRoleCollection\",\"validationRules\":[{\"field\":\"groupId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"roleId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"group_roles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"group_roles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"group_id\\\" UUID NOT NULL,\\n \\\"role_id\\\" UUID NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"group_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"groups\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"role_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"roles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"group_roles_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"group_roles_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"group_roles_group_id_idx\",\"columns\":[\"group_id\"]},{\"name\":\"group_roles_role_id_idx\",\"columns\":[\"role_id\"]}],\"version\":\"b1e35f93\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:UsersMagicLinkToken\":{\"name\":\"usersmagiclinktoken\",\"className\":\"UsersMagicLinkToken\",\"qualifiedName\":\"@happyvertical/smrt-users:UsersMagicLinkToken\",\"collection\":\"usersmagiclinktokens\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/MagicLinkToken.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"nonce\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true,\"unique\":true}},\"email\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"used\":{\"type\":\"boolean\",\"required\":false,\"default\":false},\"expiresAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"indexed\":true}}},\"methods\":{\"isExpired\":{\"name\":\"isExpired\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isValid\":{\"name\":\"isValid\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"users_magic_link_tokens\",\"sensitive\":true,\"api\":{\"include\":[]},\"mcp\":{\"include\":[]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"UsersMagicLinkToken\",\"collectionExportName\":\"UsersMagicLinkTokenCollection\",\"validationRules\":[{\"field\":\"nonce\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"users_magic_link_tokens\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users_magic_link_tokens\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"nonce\\\" TEXT NOT NULL UNIQUE DEFAULT '',\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"used\\\" BOOLEAN DEFAULT FALSE,\\n \\\"expires_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"nonce\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":true,\"default\":\"\"},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"used\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"users_magic_link_tokens_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_magic_link_tokens_expires_at_idx\",\"columns\":[\"expires_at\"]},{\"name\":\"users_magic_link_tokens_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"537853d3\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:Membership\":{\"name\":\"membership\",\"className\":\"Membership\",\"qualifiedName\":\"@happyvertical/smrt-users:Membership\",\"collection\":\"memberships\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/Membership.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"userId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"User\",\"_meta\":{\"required\":true}},\"tenantId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Tenant\",\"_meta\":{\"required\":true}},\"roleId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Role\",\"_meta\":{\"required\":true}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"isActive\":{\"name\":\"isActive\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isPending\":{\"name\":\"isPending\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"indexes\":[{\"name\":\"memberships_tenant_id_user_id_idx\",\"columns\":[\"tenantId\",\"userId\"]}]},\"extends\":\"SmrtObject\",\"exportName\":\"Membership\",\"collectionExportName\":\"MembershipCollection\",\"validationRules\":[{\"field\":\"userId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"tenantId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"roleId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"memberships\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"memberships\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_id\\\" UUID NOT NULL,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"role_id\\\" UUID NOT NULL,\\n \\\"status\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"role_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"roles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"memberships_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"memberships_tenant_id_user_id_idx\",\"columns\":[\"tenant_id\",\"user_id\"]},{\"name\":\"memberships_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"memberships_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"memberships_role_id_idx\",\"columns\":[\"role_id\"]}],\"version\":\"ebfd11e0\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:MembershipOverride\":{\"name\":\"membershipoverride\",\"className\":\"MembershipOverride\",\"qualifiedName\":\"@happyvertical/smrt-users:MembershipOverride\",\"collection\":\"membershipoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/MembershipOverride.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"membershipId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Membership\",\"_meta\":{\"required\":true}},\"permissionId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Permission\",\"_meta\":{\"required\":true}},\"effect\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"isGrant\":{\"name\":\"isGrant\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isDeny\":{\"name\":\"isDeny\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"MembershipOverride\",\"collectionExportName\":\"MembershipOverrideCollection\",\"validationRules\":[{\"field\":\"membershipId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"permissionId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"membership_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"membership_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"membership_id\\\" UUID NOT NULL,\\n \\\"permission_id\\\" UUID NOT NULL,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"membership_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"memberships\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"permission_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"permissions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"membership_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"membership_overrides_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"membership_overrides_membership_id_idx\",\"columns\":[\"membership_id\"]},{\"name\":\"membership_overrides_permission_id_idx\",\"columns\":[\"permission_id\"]}],\"version\":\"25fe9da8\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:Permission\":{\"name\":\"permission\",\"className\":\"Permission\",\"qualifiedName\":\"@happyvertical/smrt-users:Permission\",\"collection\":\"permissions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/Permission.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"category\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{\"parseSlug\":{\"name\":\"parseSlug\",\"async\":false,\"parameters\":[],\"returnType\":\"ParsedPermissionSlug\",\"isStatic\":false,\"isPublic\":true},\"getResource\":{\"name\":\"getResource\",\"async\":false,\"parameters\":[],\"returnType\":\"string\",\"isStatic\":false,\"isPublic\":true},\"getAction\":{\"name\":\"getAction\",\"async\":false,\"parameters\":[],\"returnType\":\"string\",\"isStatic\":false,\"isPublic\":true},\"isValidSlug\":{\"name\":\"isValidSlug\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"Permission\",\"collectionExportName\":\"PermissionCollection\",\"schema\":{\"tableName\":\"permissions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"permissions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"category\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"category\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"permissions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"permissions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"4c81b2af\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:ResourceGrant\":{\"name\":\"resourcegrant\",\"className\":\"ResourceGrant\",\"qualifiedName\":\"@happyvertical/smrt-users:ResourceGrant\",\"collection\":\"resourcegrants\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/ResourceGrant.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"tenantId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Tenant\",\"_meta\":{\"required\":true,\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"mode\":\"required\",\"field\":\"tenantId\",\"autoFilter\":true,\"autoPopulate\":true,\"allowSuperAdminBypass\":false}}},\"userId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"User\",\"_meta\":{\"required\":true}},\"resourceType\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"resourceId\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"permission\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"effect\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"canDelegate\":{\"type\":\"boolean\",\"required\":false,\"default\":false},\"parentGrantId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"ResourceGrant\"},\"revokedAt\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"isActive\":{\"name\":\"isActive\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tenantScoped\":true,\"api\":{\"include\":[]},\"mcp\":{\"include\":[]},\"cli\":{\"skipApiCheck\":true},\"indexes\":[{\"name\":\"resource_grants_lookup_idx\",\"columns\":[\"tenantId\",\"userId\"]}],\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ResourceGrant\",\"collectionExportName\":\"ResourceGrantCollection\",\"validationRules\":[{\"field\":\"userId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"resource_grants\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"resource_grants\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"user_id\\\" UUID NOT NULL,\\n \\\"resource_type\\\" TEXT,\\n \\\"resource_id\\\" TEXT,\\n \\\"permission\\\" TEXT,\\n \\\"effect\\\" TEXT,\\n \\\"can_delegate\\\" BOOLEAN DEFAULT FALSE,\\n \\\"parent_grant_id\\\" UUID,\\n \\\"revoked_at\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"resource_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"resource_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"permission\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"can_delegate\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"parent_grant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"resource_grants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"revoked_at\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"resource_grants_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true},{\"name\":\"resource_grants_lookup_idx\",\"columns\":[\"tenant_id\",\"user_id\"]},{\"name\":\"resource_grants_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"resource_grants_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"resource_grants_parent_grant_id_idx\",\"columns\":[\"parent_grant_id\"]}],\"version\":\"52e03776\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:Role\":{\"name\":\"role\",\"className\":\"Role\",\"qualifiedName\":\"@happyvertical/smrt-users:Role\",\"collection\":\"roles\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/Role.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"tenantId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Tenant\",\"_meta\":{\"nullable\":true}},\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"isSystem\":{\"type\":\"boolean\",\"required\":false,\"default\":false},\"inheritsToDescendants\":{\"type\":\"boolean\",\"required\":false,\"default\":false}},\"methods\":{\"isSystemRole\":{\"name\":\"isSystemRole\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isTenantRole\":{\"name\":\"isTenantRole\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"canDelete\":{\"name\":\"canDelete\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"Role\",\"collectionExportName\":\"RoleCollection\",\"schema\":{\"tableName\":\"roles\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"roles\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"is_system\\\" BOOLEAN DEFAULT FALSE,\\n \\\"inherits_to_descendants\\\" BOOLEAN DEFAULT FALSE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"is_system\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"inherits_to_descendants\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false}},\"indexes\":[{\"name\":\"roles_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"roles_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"roles_tenant_id_idx\",\"columns\":[\"tenant_id\"]}],\"version\":\"47369d9d\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:RolePermission\":{\"name\":\"rolepermission\",\"className\":\"RolePermission\",\"qualifiedName\":\"@happyvertical/smrt-users:RolePermission\",\"collection\":\"rolepermissions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/RolePermission.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"roleId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Role\",\"_meta\":{\"required\":true}},\"permissionId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Permission\",\"_meta\":{\"required\":true}}},\"methods\":{},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":true},\"extends\":\"SmrtObject\",\"exportName\":\"RolePermission\",\"collectionExportName\":\"RolePermissionCollection\",\"validationRules\":[{\"field\":\"roleId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"permissionId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"role_permissions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"role_permissions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"role_id\\\" UUID NOT NULL,\\n \\\"permission_id\\\" UUID NOT NULL\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"role_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"roles\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"permission_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"permissions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}}},\"indexes\":[{\"name\":\"role_permissions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"role_permissions_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"role_permissions_role_id_idx\",\"columns\":[\"role_id\"]},{\"name\":\"role_permissions_permission_id_idx\",\"columns\":[\"permission_id\"]}],\"version\":\"4dfed3ac\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:Session\":{\"name\":\"session\",\"className\":\"Session\",\"qualifiedName\":\"@happyvertical/smrt-users:Session\",\"collection\":\"sessions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/Session.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"userId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"User\"},\"tenantId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Tenant\",\"_meta\":{\"nullable\":true}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"expiresAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"indexed\":true}},\"userAgent\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"ipAddress\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"lastAccessedAt\":{\"type\":\"datetime\",\"required\":false},\"data\":{\"type\":\"json\",\"required\":false,\"default\":{}}},\"methods\":{\"isValid\":{\"name\":\"isValid\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isExpired\":{\"name\":\"isExpired\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isRevoked\":{\"name\":\"isRevoked\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"touch\":{\"name\":\"touch\",\"async\":false,\"parameters\":[],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"extend\":{\"name\":\"extend\",\"async\":false,\"parameters\":[{\"name\":\"ttlSeconds\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"recordActivity\":{\"name\":\"recordActivity\",\"async\":true,\"parameters\":[{\"name\":\"extendTtl\",\"type\":\"any\",\"optional\":true},{\"name\":\"ttlSeconds\",\"type\":\"number\",\"optional\":true}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"revoke\":{\"name\":\"revoke\",\"async\":false,\"parameters\":[],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"setTenant\":{\"name\":\"setTenant\",\"async\":false,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"null\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getData\":{\"name\":\"getData\",\"async\":false,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"T | undefined\",\"isStatic\":false,\"isPublic\":true},\"setData\":{\"name\":\"setData\",\"async\":false,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"removeData\":{\"name\":\"removeData\",\"async\":false,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"sensitive\":true,\"api\":{\"include\":[\"get\",\"delete\"]},\"mcp\":{\"include\":[]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"Session\",\"collectionExportName\":\"SessionCollection\",\"schema\":{\"tableName\":\"sessions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"sessions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"user_id\\\" UUID,\\n \\\"tenant_id\\\" UUID,\\n \\\"status\\\" TEXT,\\n \\\"expires_at\\\" TIMESTAMP,\\n \\\"user_agent\\\" TEXT DEFAULT '',\\n \\\"ip_address\\\" TEXT DEFAULT '',\\n \\\"last_accessed_at\\\" TIMESTAMP,\\n \\\"data\\\" JSON DEFAULT '{}'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"user_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"users\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"expires_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"user_agent\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"ip_address\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"last_accessed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"data\":{\"type\":\"JSON\",\"notNull\":false,\"unique\":false,\"default\":{}}},\"indexes\":[{\"name\":\"sessions_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"sessions_expires_at_idx\",\"columns\":[\"expires_at\"]},{\"name\":\"sessions_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"sessions_user_id_idx\",\"columns\":[\"user_id\"]},{\"name\":\"sessions_tenant_id_idx\",\"columns\":[\"tenant_id\"]}],\"version\":\"dc55d351\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:Tenant\":{\"name\":\"tenant\",\"className\":\"Tenant\",\"qualifiedName\":\"@happyvertical/smrt-users:Tenant\",\"collection\":\"tenants\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/Tenant.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"parentTenantId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Tenant\",\"_meta\":{\"nullable\":true}},\"hierarchyLevel\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"hierarchyPath\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"cascadePermissions\":{\"type\":\"boolean\",\"required\":false,\"default\":true},\"inheritPermissions\":{\"type\":\"boolean\",\"required\":false,\"default\":true}},\"methods\":{\"isActive\":{\"name\":\"isActive\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isSuspended\":{\"name\":\"isSuspended\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isRoot\":{\"name\":\"isRoot\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"canCascadeToChildren\":{\"name\":\"canCascadeToChildren\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"acceptsInheritance\":{\"name\":\"acceptsInheritance\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"SmrtSaveOptions\",\"optional\":true}],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"getAncestorIds\":{\"name\":\"getAncestorIds\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableStrategy\":\"sti\",\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"Tenant\",\"collectionExportName\":\"TenantCollection\",\"schema\":{\"tableName\":\"tenants\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"tenants\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"status\\\" TEXT,\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"parent_tenant_id\\\" UUID,\\n \\\"hierarchy_level\\\" INTEGER DEFAULT 0,\\n \\\"hierarchy_path\\\" TEXT DEFAULT '',\\n \\\"cascade_permissions\\\" BOOLEAN DEFAULT TRUE,\\n \\\"inherit_permissions\\\" BOOLEAN DEFAULT TRUE\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"status\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"parent_tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"hierarchy_level\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"hierarchy_path\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"},\"cascade_permissions\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true},\"inherit_permissions\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true}},\"indexes\":[{\"name\":\"tenants_slug_context_meta_type_idx\",\"columns\":[\"slug\",\"context\",\"_meta_type\"],\"unique\":true},{\"name\":\"tenants_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"tenants_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"tenants_parent_tenant_id_idx\",\"columns\":[\"parent_tenant_id\"]}],\"version\":\"934f7025\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:TenantIntegration\":{\"name\":\"tenantintegration\",\"className\":\"TenantIntegration\",\"qualifiedName\":\"@happyvertical/smrt-users:TenantIntegration\",\"collection\":\"tenantintegrations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/TenantIntegration.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"provider\":{\"type\":\"text\",\"required\":false,\"default\":\"aws\"},\"externalIds\":{\"type\":\"text\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":false,\"default\":\"unprovisioned\"},\"lastCheckedAt\":{\"type\":\"datetime\",\"required\":false},\"lastCheckSummary\":{\"type\":\"text\",\"required\":false},\"lastError\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"initialize\":{\"name\":\"initialize\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true},\"getExternalIds\":{\"name\":\"getExternalIds\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, string>\",\"isStatic\":false,\"isPublic\":true},\"setExternalIds\":{\"name\":\"setExternalIds\",\"async\":false,\"parameters\":[{\"name\":\"externalIds\",\"type\":\"Record<string, string> | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"Record<string, string>\"},{\"type\":\"string\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getExternalId\":{\"name\":\"getExternalId\",\"async\":false,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"string | undefined\",\"isStatic\":false,\"isPublic\":true},\"setExternalId\":{\"name\":\"setExternalId\",\"async\":false,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"string | undefined\",\"optional\":false,\"unionBranches\":[{\"type\":\"string\"},{\"type\":\"undefined\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getLastCheckSummary\":{\"name\":\"getLastCheckSummary\",\"async\":false,\"parameters\":[],\"returnType\":\"TenantIntegrationCheckSummary[]\",\"isStatic\":false,\"isPublic\":true},\"setLastCheckSummary\":{\"name\":\"setLastCheckSummary\",\"async\":false,\"parameters\":[{\"name\":\"summary\",\"type\":\"TenantIntegrationCheckSummary[] | string\",\"optional\":false,\"unionBranches\":[{\"type\":\"TenantIntegrationCheckSummary[]\"},{\"type\":\"string\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"recordDoctorRun\":{\"name\":\"recordDoctorRun\",\"async\":false,\"parameters\":[{\"name\":\"outcome\",\"type\":\"object\",\"optional\":false,\"memberTypes\":[\"TenantIntegrationStatus\",\"TenantIntegrationCheckSummary[]\",\"string | null\"]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"tenant_integrations\",\"conflictColumns\":[\"tenant_id\",\"provider\"],\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"required\"}},\"extends\":\"SmrtObject\",\"exportName\":\"TenantIntegration\",\"collectionExportName\":\"TenantIntegrationCollection\",\"validationRules\":[],\"schema\":{\"tableName\":\"tenant_integrations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"tenant_integrations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"provider\\\" TEXT DEFAULT 'aws',\\n \\\"external_ids\\\" TEXT,\\n \\\"status\\\" TEXT DEFAULT 'unprovisioned',\\n \\\"last_checked_at\\\" TIMESTAMP,\\n \\\"last_check_summary\\\" TEXT,\\n \\\"last_error\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"provider\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"aws\"},\"external_ids\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"unprovisioned\"},\"last_checked_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"last_check_summary\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_error\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"tenant_integrations_tenant_id_provider_idx\",\"columns\":[\"tenant_id\",\"provider\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"tenant_integrations_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"tenant_integrations_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"3ed31966\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:TenantPermissionOverride\":{\"name\":\"tenantpermissionoverride\",\"className\":\"TenantPermissionOverride\",\"qualifiedName\":\"@happyvertical/smrt-users:TenantPermissionOverride\",\"collection\":\"tenantpermissionoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/TenantPermissionOverride.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"tenantId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Tenant\",\"_meta\":{\"required\":true}},\"permissionId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Permission\",\"_meta\":{\"required\":true}},\"effect\":{\"type\":\"text\",\"required\":false,\"_meta\":{}}},\"methods\":{\"isInherit\":{\"name\":\"isInherit\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isGrant\":{\"name\":\"isGrant\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isDeny\":{\"name\":\"isDeny\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"hasExplicitEffect\":{\"name\":\"hasExplicitEffect\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"TenantPermissionOverride\",\"collectionExportName\":\"TenantPermissionOverrideCollection\",\"validationRules\":[{\"field\":\"tenantId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"permissionId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"tenant_permission_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"tenant_permission_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"permission_id\\\" UUID NOT NULL,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"tenants\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"permission_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"permissions\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"tenant_permission_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"tenant_permission_overrides_created_at_idx\",\"columns\":[\"created_at\"]},{\"name\":\"tenant_permission_overrides_tenant_id_idx\",\"columns\":[\"tenant_id\"]},{\"name\":\"tenant_permission_overrides_permission_id_idx\",\"columns\":[\"permission_id\"]}],\"version\":\"95b78bdd\"},\"importPath\":\"@happyvertical/smrt-users\"},\"@happyvertical/smrt-users:User\":{\"name\":\"user\",\"className\":\"User\",\"qualifiedName\":\"@happyvertical/smrt-users:User\",\"collection\":\"users\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/users/src/models/User.ts\",\"packageName\":\"@happyvertical/smrt-users\",\"fields\":{\"profileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"unique\":true}},\"email\":{\"type\":\"text\",\"required\":false,\"default\":\"\",\"_meta\":{\"indexed\":true}},\"emailKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true,\"unique\":true,\"readonly\":true},\"readonly\":true},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"lastLoginAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{\"hasValidEmail\":{\"name\":\"hasValidEmail\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isActive\":{\"name\":\"isActive\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isSuspended\":{\"name\":\"isSuspended\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isPending\":{\"name\":\"isPending\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"recordLogin\":{\"name\":\"recordLogin\",\"async\":false,\"parameters\":[],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"save\":{\"name\":\"save\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<this>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true}},\"extends\":\"SmrtObject\",\"exportName\":\"User\",\"collectionExportName\":\"UserCollection\",\"schema\":{\"tableName\":\"users\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"users\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"profile_id\\\" UUID UNIQUE,\\n \\\"email\\\" TEXT DEFAULT '',\\n \\\"email_key\\\" TEXT UNIQUE,\\n \\\"status\\\" TEXT,\\n \\\"last_login_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":true},\"email\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"email_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":true},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"last_login_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"users_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true},{\"name\":\"users_email_idx\",\"columns\":[\"email\"]},{\"name\":\"users_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"38fd1677\"},\"importPath\":\"@happyvertical/smrt-users\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-mobile-contract\",\"@happyvertical/smrt-profiles\",\"@happyvertical/smrt-tenancy\"]}"));
|
|
1598
|
-
var __defProp$13 = Object.defineProperty;
|
|
1599
|
-
var __getOwnPropDesc$13 = Object.getOwnPropertyDescriptor;
|
|
1600
|
-
var __decorateClass$13 = (decorators, target, key, kind) => {
|
|
1601
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$13(target, key) : target;
|
|
1602
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1603
|
-
if (kind && result) __defProp$13(target, key, result);
|
|
1604
|
-
return result;
|
|
1605
|
-
};
|
|
1606
|
-
var UsersCliAuthRequest = class extends SmrtObject {
|
|
1607
|
-
userCode = "";
|
|
1608
|
-
deviceCodeHash = "";
|
|
1609
|
-
status = "pending";
|
|
1610
|
-
userId = null;
|
|
1611
|
-
tenantId = null;
|
|
1612
|
-
sessionId = null;
|
|
1613
|
-
expiresAt = /* @__PURE__ */ new Date();
|
|
1614
|
-
approvedAt = null;
|
|
1615
|
-
};
|
|
1616
|
-
__decorateClass$13([field({
|
|
1617
|
-
type: "text",
|
|
1618
|
-
required: true,
|
|
1619
|
-
unique: true
|
|
1620
|
-
})], UsersCliAuthRequest.prototype, "userCode", 2);
|
|
1621
|
-
__decorateClass$13([field({
|
|
1622
|
-
type: "text",
|
|
1623
|
-
required: true,
|
|
1624
|
-
unique: true
|
|
1625
|
-
})], UsersCliAuthRequest.prototype, "deviceCodeHash", 2);
|
|
1626
|
-
__decorateClass$13([field({ type: "text" })], UsersCliAuthRequest.prototype, "status", 2);
|
|
1627
|
-
__decorateClass$13([foreignKey("User", { nullable: true })], UsersCliAuthRequest.prototype, "userId", 2);
|
|
1628
|
-
__decorateClass$13([foreignKey("Tenant", { nullable: true })], UsersCliAuthRequest.prototype, "tenantId", 2);
|
|
1629
|
-
__decorateClass$13([foreignKey("Session", { nullable: true })], UsersCliAuthRequest.prototype, "sessionId", 2);
|
|
1630
|
-
__decorateClass$13([field({
|
|
1631
|
-
type: "datetime",
|
|
1632
|
-
indexed: true
|
|
1633
|
-
})], UsersCliAuthRequest.prototype, "expiresAt", 2);
|
|
1634
|
-
__decorateClass$13([field({
|
|
1635
|
-
type: "datetime",
|
|
1636
|
-
nullable: true
|
|
1637
|
-
})], UsersCliAuthRequest.prototype, "approvedAt", 2);
|
|
1638
|
-
UsersCliAuthRequest = __decorateClass$13([smrt({
|
|
1639
|
-
tableName: "users_cli_auth_requests",
|
|
1640
|
-
sensitive: true,
|
|
1641
|
-
api: { include: [] },
|
|
1642
|
-
cli: { include: [] },
|
|
1643
|
-
mcp: { include: [] }
|
|
1644
|
-
})], UsersCliAuthRequest);
|
|
1645
|
-
var __defProp$12 = Object.defineProperty;
|
|
1646
|
-
var __getOwnPropDesc$12 = Object.getOwnPropertyDescriptor;
|
|
1647
|
-
var __decorateClass$12 = (decorators, target, key, kind) => {
|
|
1648
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$12(target, key) : target;
|
|
1649
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1650
|
-
if (kind && result) __defProp$12(target, key, result);
|
|
1651
|
-
return result;
|
|
1652
|
-
};
|
|
1653
|
-
var DEFAULT_SESSION_TTL = 10080 * 60;
|
|
1654
|
-
function generateSessionId() {
|
|
1655
|
-
return crypto.randomUUID();
|
|
1656
|
-
}
|
|
1657
|
-
var Session = class extends SmrtObject {
|
|
1658
|
-
userId = "";
|
|
1659
|
-
tenantId = null;
|
|
1660
|
-
status = SessionStatus.ACTIVE;
|
|
1661
|
-
expiresAt = /* @__PURE__ */ new Date();
|
|
1662
|
-
/**
|
|
1663
|
-
* User agent string from the browser
|
|
1664
|
-
*/
|
|
1665
|
-
userAgent = "";
|
|
1666
|
-
/**
|
|
1667
|
-
* IP address of the client
|
|
1668
|
-
*/
|
|
1669
|
-
ipAddress = "";
|
|
1670
|
-
/**
|
|
1671
|
-
* Last activity timestamp (updated on each request)
|
|
1672
|
-
*/
|
|
1673
|
-
lastAccessedAt = /* @__PURE__ */ new Date();
|
|
1674
|
-
/**
|
|
1675
|
-
* Custom session data (JSON serializable)
|
|
1676
|
-
*/
|
|
1677
|
-
data = {};
|
|
1678
|
-
constructor(options = {}) {
|
|
1679
|
-
super(options);
|
|
1680
|
-
if (options.userId !== void 0) this.userId = options.userId;
|
|
1681
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
1682
|
-
if (options.status !== void 0) this.status = options.status;
|
|
1683
|
-
if (options.expiresAt !== void 0) this.expiresAt = options.expiresAt instanceof Date ? options.expiresAt : new Date(options.expiresAt);
|
|
1684
|
-
if (options.userAgent !== void 0) this.userAgent = options.userAgent;
|
|
1685
|
-
if (options.ipAddress !== void 0) this.ipAddress = options.ipAddress;
|
|
1686
|
-
if (options.lastAccessedAt !== void 0) this.lastAccessedAt = options.lastAccessedAt instanceof Date ? options.lastAccessedAt : new Date(options.lastAccessedAt);
|
|
1687
|
-
if (options.data !== void 0) this.data = options.data;
|
|
1688
|
-
}
|
|
1689
|
-
/**
|
|
1690
|
-
* Check if the session is currently valid (active and not expired)
|
|
1691
|
-
*/
|
|
1692
|
-
isValid() {
|
|
1693
|
-
return this.status === SessionStatus.ACTIVE && /* @__PURE__ */ new Date() < this.expiresAt;
|
|
1694
|
-
}
|
|
1695
|
-
/**
|
|
1696
|
-
* Check if the session has expired
|
|
1697
|
-
*/
|
|
1698
|
-
isExpired() {
|
|
1699
|
-
return /* @__PURE__ */ new Date() >= this.expiresAt;
|
|
1700
|
-
}
|
|
1701
|
-
/**
|
|
1702
|
-
* Check if the session was revoked
|
|
1703
|
-
*/
|
|
1704
|
-
isRevoked() {
|
|
1705
|
-
return this.status === SessionStatus.REVOKED;
|
|
1706
|
-
}
|
|
1707
|
-
/**
|
|
1708
|
-
* Update the last accessed timestamp
|
|
1709
|
-
*/
|
|
1710
|
-
touch() {
|
|
1711
|
-
this.lastAccessedAt = /* @__PURE__ */ new Date();
|
|
1712
|
-
}
|
|
1713
|
-
/**
|
|
1714
|
-
* Extend the session expiration by the given TTL (in seconds)
|
|
1715
|
-
*/
|
|
1716
|
-
extend(ttlSeconds = DEFAULT_SESSION_TTL) {
|
|
1717
|
-
this.expiresAt = new Date(Date.now() + ttlSeconds * 1e3);
|
|
1718
|
-
this.touch();
|
|
1719
|
-
}
|
|
1720
|
-
/** Persist routine session activity without failing concurrent requests. */
|
|
1721
|
-
async recordActivity(extendTtl = false, ttlSeconds = DEFAULT_SESSION_TTL) {
|
|
1722
|
-
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
1723
|
-
if (attempt > 0 && !await this.reloadValidActivityState()) return false;
|
|
1724
|
-
if (extendTtl) this.extend(ttlSeconds);
|
|
1725
|
-
else this.touch();
|
|
1726
|
-
try {
|
|
1727
|
-
await this.save();
|
|
1728
|
-
return true;
|
|
1729
|
-
} catch (error) {
|
|
1730
|
-
if (!(error instanceof Error && "code" in error && error.code === "RUNTIME_REVISION_CONFLICT")) throw error;
|
|
1731
|
-
if (attempt === 3) return this.reloadValidActivityState();
|
|
1732
|
-
}
|
|
1733
|
-
}
|
|
1734
|
-
return false;
|
|
1735
|
-
}
|
|
1736
|
-
async reloadValidActivityState() {
|
|
1737
|
-
if (!this.id) return false;
|
|
1738
|
-
const current = await this.getCanonicalPersistedRow({ id: this.id });
|
|
1739
|
-
if (!current) return false;
|
|
1740
|
-
await this.loadDataFromDb(current);
|
|
1741
|
-
return this.isValid();
|
|
1742
|
-
}
|
|
1743
|
-
/**
|
|
1744
|
-
* Revoke the session
|
|
1745
|
-
*/
|
|
1746
|
-
revoke() {
|
|
1747
|
-
this.status = SessionStatus.REVOKED;
|
|
1748
|
-
}
|
|
1749
|
-
/**
|
|
1750
|
-
* Set the tenant context for this session
|
|
1751
|
-
*/
|
|
1752
|
-
setTenant(tenantId) {
|
|
1753
|
-
this.tenantId = tenantId;
|
|
1754
|
-
}
|
|
1755
|
-
/**
|
|
1756
|
-
* Get or set custom session data
|
|
1757
|
-
*/
|
|
1758
|
-
getData(key) {
|
|
1759
|
-
return this.data[key];
|
|
1760
|
-
}
|
|
1761
|
-
/**
|
|
1762
|
-
* Set custom session data
|
|
1763
|
-
*/
|
|
1764
|
-
setData(key, value) {
|
|
1765
|
-
this.data[key] = value;
|
|
1766
|
-
}
|
|
1767
|
-
/**
|
|
1768
|
-
* Remove custom session data
|
|
1769
|
-
*/
|
|
1770
|
-
removeData(key) {
|
|
1771
|
-
delete this.data[key];
|
|
1772
|
-
}
|
|
1773
|
-
};
|
|
1774
|
-
__decorateClass$12([foreignKey("User")], Session.prototype, "userId", 2);
|
|
1775
|
-
__decorateClass$12([foreignKey("Tenant", { nullable: true })], Session.prototype, "tenantId", 2);
|
|
1776
|
-
__decorateClass$12([field({ type: "text" })], Session.prototype, "status", 2);
|
|
1777
|
-
__decorateClass$12([field({
|
|
1778
|
-
type: "datetime",
|
|
1779
|
-
indexed: true
|
|
1780
|
-
})], Session.prototype, "expiresAt", 2);
|
|
1781
|
-
Session = __decorateClass$12([smrt({
|
|
1782
|
-
sensitive: true,
|
|
1783
|
-
api: { include: ["get", "delete"] },
|
|
1784
|
-
mcp: { include: [] },
|
|
1785
|
-
cli: { skipApiCheck: true }
|
|
1786
|
-
})], Session);
|
|
1787
|
-
var SessionCollection = class extends SmrtCollection {
|
|
1788
|
-
static _itemClass = Session;
|
|
1789
|
-
async revokeWithRetry(sessionId) {
|
|
1790
|
-
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
1791
|
-
const session = await this.get(sessionId);
|
|
1792
|
-
if (!session) return false;
|
|
1793
|
-
if (session.status !== SessionStatus.ACTIVE) return true;
|
|
1794
|
-
session.revoke();
|
|
1795
|
-
try {
|
|
1796
|
-
await session.save();
|
|
1797
|
-
return true;
|
|
1798
|
-
} catch (error) {
|
|
1799
|
-
if (attempt === 3 || !(error instanceof Error && "code" in error && error.code === "RUNTIME_REVISION_CONFLICT")) throw error;
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
return false;
|
|
1803
|
-
}
|
|
1804
|
-
/**
|
|
1805
|
-
* Create a new session with a secure ID
|
|
1806
|
-
*/
|
|
1807
|
-
async createSession(options) {
|
|
1808
|
-
const ttl = options.ttl ?? 604800;
|
|
1809
|
-
const expiresAt = new Date(Date.now() + ttl * 1e3);
|
|
1810
|
-
const session = await this.create({
|
|
1811
|
-
id: generateSessionId(),
|
|
1812
|
-
userId: options.userId,
|
|
1813
|
-
tenantId: options.tenantId ?? null,
|
|
1814
|
-
status: SessionStatus.ACTIVE,
|
|
1815
|
-
expiresAt,
|
|
1816
|
-
userAgent: options.userAgent ?? "",
|
|
1817
|
-
ipAddress: options.ipAddress ?? "",
|
|
1818
|
-
lastAccessedAt: /* @__PURE__ */ new Date(),
|
|
1819
|
-
data: options.data ?? {}
|
|
1820
|
-
});
|
|
1821
|
-
await session.save();
|
|
1822
|
-
return session;
|
|
1823
|
-
}
|
|
1824
|
-
/**
|
|
1825
|
-
* Find a valid session by ID
|
|
1826
|
-
* Returns null if session doesn't exist, is expired, or is revoked
|
|
1827
|
-
*/
|
|
1828
|
-
async findValidSession(sessionId) {
|
|
1829
|
-
const session = await this.get(sessionId);
|
|
1830
|
-
if (!session) return null;
|
|
1831
|
-
if (!session.isValid()) {
|
|
1832
|
-
if (session.isExpired() && session.status === SessionStatus.ACTIVE) {
|
|
1833
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1834
|
-
await this.db.query(`UPDATE ${this.tableName}
|
|
1835
|
-
SET status = ?, updated_at = ?
|
|
1836
|
-
WHERE id = ? AND status = ? AND expires_at < ?`, SessionStatus.EXPIRED, now, sessionId, SessionStatus.ACTIVE, now);
|
|
1837
|
-
}
|
|
1838
|
-
return null;
|
|
1839
|
-
}
|
|
1840
|
-
return session;
|
|
1841
|
-
}
|
|
1842
|
-
/**
|
|
1843
|
-
* Update last accessed time and optionally extend session
|
|
1844
|
-
*/
|
|
1845
|
-
async touch(sessionId, extendTtl = false, ttl = DEFAULT_SESSION_TTL) {
|
|
1846
|
-
const session = await this.findValidSession(sessionId);
|
|
1847
|
-
if (!session) return false;
|
|
1848
|
-
return session.recordActivity(extendTtl, ttl);
|
|
1849
|
-
}
|
|
1850
|
-
/**
|
|
1851
|
-
* Find all active sessions for a user
|
|
1852
|
-
*/
|
|
1853
|
-
async findByUser(userId) {
|
|
1854
|
-
return (await this.list({
|
|
1855
|
-
where: {
|
|
1856
|
-
userId,
|
|
1857
|
-
status: SessionStatus.ACTIVE
|
|
1858
|
-
},
|
|
1859
|
-
orderBy: "last_accessed_at DESC"
|
|
1860
|
-
})).filter((session) => session.isValid());
|
|
1861
|
-
}
|
|
1862
|
-
/**
|
|
1863
|
-
* Delete all sessions for a user (logout from all devices)
|
|
1864
|
-
*/
|
|
1865
|
-
async deleteUserSessions(userId) {
|
|
1866
|
-
const sessions = await this.list({ where: { userId } });
|
|
1867
|
-
let count = 0;
|
|
1868
|
-
for (const session of sessions) {
|
|
1869
|
-
await session.delete();
|
|
1870
|
-
count++;
|
|
1871
|
-
}
|
|
1872
|
-
return count;
|
|
1873
|
-
}
|
|
1874
|
-
/**
|
|
1875
|
-
* Revoke all sessions for a user (soft delete)
|
|
1876
|
-
*/
|
|
1877
|
-
async revokeUserSessions(userId) {
|
|
1878
|
-
const sessions = await this.list({ where: {
|
|
1879
|
-
userId,
|
|
1880
|
-
status: SessionStatus.ACTIVE
|
|
1881
|
-
} });
|
|
1882
|
-
let count = 0;
|
|
1883
|
-
for (const session of sessions) if (session.id && await this.revokeWithRetry(session.id)) count++;
|
|
1884
|
-
return count;
|
|
1885
|
-
}
|
|
1886
|
-
/**
|
|
1887
|
-
* Revoke a specific session
|
|
1888
|
-
*/
|
|
1889
|
-
async revokeSession(sessionId) {
|
|
1890
|
-
return this.revokeWithRetry(sessionId);
|
|
1891
|
-
}
|
|
1892
|
-
/**
|
|
1893
|
-
* Delete expired sessions (cleanup job)
|
|
1894
|
-
*
|
|
1895
|
-
* Scheduled by the framework retention sweep (#2375); `expires_at` carries
|
|
1896
|
-
* an index for this predicate.
|
|
1897
|
-
*
|
|
1898
|
-
* @param options.dryRun - Count the sessions the predicate selects without
|
|
1899
|
-
* deleting them.
|
|
1900
|
-
* @returns Number of sessions deleted (or, under `dryRun`, matched)
|
|
1901
|
-
*/
|
|
1902
|
-
async deleteExpired(options = {}) {
|
|
1903
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1904
|
-
const predicate = "expires_at < ? OR status = ?";
|
|
1905
|
-
const counted = await this.db.query(`SELECT COUNT(*) AS total FROM ${this.tableName} WHERE ${predicate}`, now, SessionStatus.REVOKED);
|
|
1906
|
-
const total = Number(counted.rows?.[0]?.total ?? 0);
|
|
1907
|
-
if (!Number.isFinite(total) || total <= 0) return 0;
|
|
1908
|
-
if (!options.dryRun) await this.db.query(`DELETE FROM ${this.tableName} WHERE ${predicate}`, now, SessionStatus.REVOKED);
|
|
1909
|
-
return total;
|
|
1910
|
-
}
|
|
1911
|
-
/**
|
|
1912
|
-
* Count active sessions for a user
|
|
1913
|
-
*/
|
|
1914
|
-
async countUserSessions(userId) {
|
|
1915
|
-
return (await this.findByUser(userId)).length;
|
|
1916
|
-
}
|
|
1917
|
-
/**
|
|
1918
|
-
* Update tenant context for a session (low-level primitive).
|
|
1919
|
-
*
|
|
1920
|
-
* SECURITY (#1400): this does NOT verify that the session's user is a member
|
|
1921
|
-
* of `tenantId` — it is the unguarded storage primitive. Application/route
|
|
1922
|
-
* code must go through {@link SessionService.switchTenant}, which fail-closes
|
|
1923
|
-
* on a missing/inactive membership before calling this. Calling it directly
|
|
1924
|
-
* with an untrusted `tenantId` reintroduces the cross-tenant access bug.
|
|
1925
|
-
*/
|
|
1926
|
-
async setSessionTenant(sessionId, tenantId) {
|
|
1927
|
-
const session = await this.findValidSession(sessionId);
|
|
1928
|
-
if (!session) return false;
|
|
1929
|
-
session.setTenant(tenantId);
|
|
1930
|
-
await session.save();
|
|
1931
|
-
return true;
|
|
1932
|
-
}
|
|
1933
|
-
/**
|
|
1934
|
-
* Set custom session data
|
|
1935
|
-
*/
|
|
1936
|
-
async setSessionData(sessionId, key, value) {
|
|
1937
|
-
const session = await this.findValidSession(sessionId);
|
|
1938
|
-
if (!session) return false;
|
|
1939
|
-
session.setData(key, value);
|
|
1940
|
-
await session.save();
|
|
1941
|
-
return true;
|
|
1942
|
-
}
|
|
1943
|
-
/**
|
|
1944
|
-
* Get custom session data
|
|
1945
|
-
*/
|
|
1946
|
-
async getSessionData(sessionId, key) {
|
|
1947
|
-
const session = await this.findValidSession(sessionId);
|
|
1948
|
-
if (!session) return void 0;
|
|
1949
|
-
return session.getData(key);
|
|
1950
|
-
}
|
|
1951
|
-
};
|
|
1952
|
-
var CliAuthApprovalLostError = class extends Error {};
|
|
1953
|
-
var UsersCliAuthRequestCollection = class extends SmrtCollection {
|
|
1954
|
-
static _itemClass = UsersCliAuthRequest;
|
|
1955
|
-
/**
|
|
1956
|
-
* Atomically approve one pending request and mint its bearer session.
|
|
1957
|
-
*
|
|
1958
|
-
* The session is created inside the same transaction as the conditional
|
|
1959
|
-
* pending-to-approved transition. If another approver wins, or persisting
|
|
1960
|
-
* the approval fails, throwing rolls the losing session back with the
|
|
1961
|
-
* request write so no usable orphan credential can remain.
|
|
1962
|
-
*/
|
|
1963
|
-
async approvePendingRequest(input) {
|
|
1964
|
-
const transaction = this.db.transaction?.bind(this.db);
|
|
1965
|
-
if (!transaction) throw new Error("Terminal approval requires database transaction support.");
|
|
1966
|
-
try {
|
|
1967
|
-
return await transaction(async (tx) => {
|
|
1968
|
-
const createdSessionId = (await (await SessionCollection.create({ db: tx })).createSession({
|
|
1969
|
-
data: {
|
|
1970
|
-
approvedBy: input.approvedBy,
|
|
1971
|
-
kind: "terminal"
|
|
1972
|
-
},
|
|
1973
|
-
ipAddress: input.ipAddress,
|
|
1974
|
-
tenantId: input.tenantId,
|
|
1975
|
-
ttl: input.sessionTtlSeconds,
|
|
1976
|
-
userAgent: input.userAgent,
|
|
1977
|
-
userId: input.userId
|
|
1978
|
-
})).id;
|
|
1979
|
-
if (!createdSessionId) throw new Error("Terminal approval failed to mint a session.");
|
|
1980
|
-
const approvedAt = /* @__PURE__ */ new Date();
|
|
1981
|
-
const now = approvedAt.toISOString();
|
|
1982
|
-
const approved = await tx.query(`UPDATE ${this.tableName}
|
|
1983
|
-
SET approved_at = ?, session_id = ?, status = 'approved',
|
|
1984
|
-
tenant_id = ?, user_id = ?, updated_at = ?
|
|
1985
|
-
WHERE user_code = ? AND status = 'pending' AND expires_at > ?
|
|
1986
|
-
RETURNING id`, now, createdSessionId, input.tenantId, input.userId, now, input.userCode.trim().toUpperCase(), now);
|
|
1987
|
-
if (approved.rows?.length !== 1) throw new CliAuthApprovalLostError();
|
|
1988
|
-
const id = approved.rows[0]?.id;
|
|
1989
|
-
if (typeof id !== "string") throw new Error("Terminal approval did not return its request id.");
|
|
1990
|
-
return {
|
|
1991
|
-
approvedAt,
|
|
1992
|
-
id,
|
|
1993
|
-
sessionId: createdSessionId,
|
|
1994
|
-
tenantId: input.tenantId,
|
|
1995
|
-
userId: input.userId
|
|
1996
|
-
};
|
|
1997
|
-
});
|
|
1998
|
-
} catch (error) {
|
|
1999
|
-
if (error instanceof CliAuthApprovalLostError) return null;
|
|
2000
|
-
throw error;
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
/**
|
|
2004
|
-
* Atomically consume the bearer session attached to an approved request.
|
|
2005
|
-
*
|
|
2006
|
-
* The conditional update is the arbiter: concurrent exchangers may observe
|
|
2007
|
-
* the same candidate, but only one can change `approved` to `consumed` while
|
|
2008
|
-
* matching the same session id. The winning transaction returns the token
|
|
2009
|
-
* from its locked candidate and clears it from durable storage.
|
|
2010
|
-
*/
|
|
2011
|
-
async consumeApprovedSession(deviceCodeHash) {
|
|
2012
|
-
const transaction = this.db.transaction?.bind(this.db);
|
|
2013
|
-
if (!transaction) throw new Error("Terminal device exchange requires database transaction support.");
|
|
2014
|
-
return transaction(async (tx) => {
|
|
2015
|
-
const candidate = (await tx.query(`SELECT id, session_id FROM ${this.tableName}
|
|
2016
|
-
WHERE device_code_hash = ? AND status = 'approved' AND session_id IS NOT NULL
|
|
2017
|
-
LIMIT 1`, deviceCodeHash)).rows?.[0];
|
|
2018
|
-
const id = typeof candidate?.id === "string" ? candidate.id : null;
|
|
2019
|
-
const sessionId = typeof candidate?.session_id === "string" ? candidate.session_id : null;
|
|
2020
|
-
if (!id || !sessionId) return null;
|
|
2021
|
-
return (await tx.query(`UPDATE ${this.tableName}
|
|
2022
|
-
SET status = 'consumed', session_id = NULL, updated_at = ?
|
|
2023
|
-
WHERE id = ? AND status = 'approved' AND session_id = ?
|
|
2024
|
-
RETURNING id`, (/* @__PURE__ */ new Date()).toISOString(), id, sessionId)).rows?.length === 1 ? sessionId : null;
|
|
2025
|
-
});
|
|
2026
|
-
}
|
|
2027
|
-
/**
|
|
2028
|
-
* Look up a pending or completed request by the short user code shown in the CLI.
|
|
2029
|
-
*/
|
|
2030
|
-
async findByUserCode(userCode) {
|
|
2031
|
-
const [request] = await this.list({
|
|
2032
|
-
limit: 1,
|
|
2033
|
-
where: { userCode: userCode.trim().toUpperCase() }
|
|
2034
|
-
});
|
|
2035
|
-
return request ?? null;
|
|
2036
|
-
}
|
|
2037
|
-
/**
|
|
2038
|
-
* Look up a request by the hash of its device code (the CLI's polling key).
|
|
2039
|
-
*/
|
|
2040
|
-
async findByDeviceCodeHash(deviceCodeHash) {
|
|
2041
|
-
const [request] = await this.list({
|
|
2042
|
-
limit: 1,
|
|
2043
|
-
where: { deviceCodeHash }
|
|
2044
|
-
});
|
|
2045
|
-
return request ?? null;
|
|
2046
|
-
}
|
|
2047
|
-
/**
|
|
2048
|
-
* Delete expired pending, lazily-expired, or already-consumed requests.
|
|
2049
|
-
*
|
|
2050
|
-
* Scheduled by the framework retention sweep (#2375); `expiresAt` carries an
|
|
2051
|
-
* index for this predicate.
|
|
2052
|
-
*
|
|
2053
|
-
* @param options.dryRun - Count the requests the predicate selects without
|
|
2054
|
-
* deleting them.
|
|
2055
|
-
* @returns Number of requests deleted (or, under `dryRun`, matched)
|
|
2056
|
-
*/
|
|
2057
|
-
async deleteExpired(options = {}) {
|
|
2058
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2059
|
-
const predicate = "status IN ('pending', 'expired', 'consumed') AND expires_at < ?";
|
|
2060
|
-
const counted = await this.db.query(`SELECT COUNT(*) AS total FROM ${this.tableName} WHERE ${predicate}`, now);
|
|
2061
|
-
const total = Number(counted.rows?.[0]?.total ?? 0);
|
|
2062
|
-
if (!Number.isFinite(total) || total <= 0) return 0;
|
|
2063
|
-
if (!options.dryRun) await this.db.query(`DELETE FROM ${this.tableName} WHERE ${predicate}`, now);
|
|
2064
|
-
return total;
|
|
2065
|
-
}
|
|
2066
|
-
};
|
|
2067
|
-
var __defProp$11 = Object.defineProperty;
|
|
2068
|
-
var __getOwnPropDesc$11 = Object.getOwnPropertyDescriptor;
|
|
2069
|
-
var __decorateClass$11 = (decorators, target, key, kind) => {
|
|
2070
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$11(target, key) : target;
|
|
2071
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2072
|
-
if (kind && result) __defProp$11(target, key, result);
|
|
2073
|
-
return result;
|
|
2074
|
-
};
|
|
2075
|
-
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2076
|
-
function isValidEmail(email) {
|
|
2077
|
-
if (!email || typeof email !== "string") return false;
|
|
2078
|
-
return EMAIL_REGEX.test(email.trim());
|
|
2079
|
-
}
|
|
2080
|
-
function normalizeEmail(email) {
|
|
2081
|
-
if (!email || typeof email !== "string") return "";
|
|
2082
|
-
return email.trim() ? normalizeIdentityEmail(email) : "";
|
|
2083
|
-
}
|
|
2084
|
-
var User = class extends SmrtObject {
|
|
2085
|
-
profileId = "";
|
|
2086
|
-
email = "";
|
|
2087
|
-
emailKey = null;
|
|
2088
|
-
status = UserStatus.ACTIVE;
|
|
2089
|
-
/**
|
|
2090
|
-
* Last login timestamp
|
|
2091
|
-
*/
|
|
2092
|
-
lastLoginAt = null;
|
|
2093
|
-
constructor(options = {}) {
|
|
2094
|
-
super(options);
|
|
2095
|
-
if (options.profileId !== void 0) this.profileId = options.profileId;
|
|
2096
|
-
if (options.email !== void 0) this.email = normalizeEmail(options.email);
|
|
2097
|
-
if (options.status !== void 0) this.status = options.status;
|
|
2098
|
-
if (options.lastLoginAt !== void 0) this.lastLoginAt = options.lastLoginAt;
|
|
2099
|
-
}
|
|
2100
|
-
/**
|
|
2101
|
-
* Validate the user's email format.
|
|
2102
|
-
* @returns true if email is valid
|
|
2103
|
-
*/
|
|
2104
|
-
hasValidEmail() {
|
|
2105
|
-
return isValidEmail(this.email);
|
|
2106
|
-
}
|
|
2107
|
-
/**
|
|
2108
|
-
* Check if user is active
|
|
2109
|
-
*/
|
|
2110
|
-
isActive() {
|
|
2111
|
-
return this.status === UserStatus.ACTIVE;
|
|
2112
|
-
}
|
|
2113
|
-
/**
|
|
2114
|
-
* Check if user is suspended
|
|
2115
|
-
*/
|
|
2116
|
-
isSuspended() {
|
|
2117
|
-
return this.status === UserStatus.SUSPENDED;
|
|
2118
|
-
}
|
|
2119
|
-
/**
|
|
2120
|
-
* Check if user is pending verification
|
|
2121
|
-
*/
|
|
2122
|
-
isPending() {
|
|
2123
|
-
return this.status === UserStatus.PENDING;
|
|
2124
|
-
}
|
|
2125
|
-
/**
|
|
2126
|
-
* Record a login event
|
|
2127
|
-
*/
|
|
2128
|
-
recordLogin() {
|
|
2129
|
-
this.lastLoginAt = /* @__PURE__ */ new Date();
|
|
2130
|
-
}
|
|
2131
|
-
/** Keep the durable email key derived from the public email field. */
|
|
2132
|
-
async save() {
|
|
2133
|
-
this.email = normalizeEmail(this.email);
|
|
2134
|
-
this.emailKey = this.email || null;
|
|
2135
|
-
return super.save();
|
|
2136
|
-
}
|
|
2137
|
-
};
|
|
2138
|
-
__decorateClass$11([crossPackageRef("@happyvertical/smrt-profiles:Profile", { unique: true })], User.prototype, "profileId", 2);
|
|
2139
|
-
__decorateClass$11([field({ indexed: true })], User.prototype, "email", 2);
|
|
2140
|
-
__decorateClass$11([field({
|
|
2141
|
-
type: "text",
|
|
2142
|
-
nullable: true,
|
|
2143
|
-
unique: true,
|
|
2144
|
-
readonly: true
|
|
2145
|
-
})], User.prototype, "emailKey", 2);
|
|
2146
|
-
__decorateClass$11([field({ type: "text" })], User.prototype, "status", 2);
|
|
2147
|
-
User = __decorateClass$11([smrt({
|
|
2148
|
-
api: { include: ["list", "get"] },
|
|
2149
|
-
mcp: { include: ["list", "get"] },
|
|
2150
|
-
cli: { skipApiCheck: true }
|
|
2151
|
-
})], User);
|
|
2152
|
-
var __defProp$10 = Object.defineProperty;
|
|
2153
|
-
var __getOwnPropDesc$10 = Object.getOwnPropertyDescriptor;
|
|
2154
|
-
var __decorateClass$10 = (decorators, target, key, kind) => {
|
|
2155
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$10(target, key) : target;
|
|
2156
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2157
|
-
if (kind && result) __defProp$10(target, key, result);
|
|
2158
|
-
return result;
|
|
2159
|
-
};
|
|
2160
|
-
var UsersCliAuthApproveLimit = class extends SmrtObject {
|
|
2161
|
-
userId = "";
|
|
2162
|
-
attemptCount = 0;
|
|
2163
|
-
windowStartedAt = /* @__PURE__ */ new Date();
|
|
2164
|
-
};
|
|
2165
|
-
__decorateClass$10([foreignKey("User", {
|
|
2166
|
-
required: true,
|
|
2167
|
-
unique: true
|
|
2168
|
-
})], UsersCliAuthApproveLimit.prototype, "userId", 2);
|
|
2169
|
-
__decorateClass$10([field({
|
|
2170
|
-
type: "integer",
|
|
2171
|
-
required: true,
|
|
2172
|
-
default: 0
|
|
2173
|
-
})], UsersCliAuthApproveLimit.prototype, "attemptCount", 2);
|
|
2174
|
-
__decorateClass$10([field({
|
|
2175
|
-
type: "datetime",
|
|
2176
|
-
required: true
|
|
2177
|
-
})], UsersCliAuthApproveLimit.prototype, "windowStartedAt", 2);
|
|
2178
|
-
UsersCliAuthApproveLimit = __decorateClass$10([smrt({
|
|
2179
|
-
tableName: "users_cli_auth_approve_limits",
|
|
2180
|
-
api: false,
|
|
2181
|
-
cli: false,
|
|
2182
|
-
mcp: false
|
|
2183
|
-
})], UsersCliAuthApproveLimit);
|
|
2184
|
-
var __defProp$9 = Object.defineProperty;
|
|
2185
|
-
var __getOwnPropDesc$9 = Object.getOwnPropertyDescriptor;
|
|
2186
|
-
var __decorateClass$9 = (decorators, target, key, kind) => {
|
|
2187
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$9(target, key) : target;
|
|
2188
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2189
|
-
if (kind && result) __defProp$9(target, key, result);
|
|
2190
|
-
return result;
|
|
2191
|
-
};
|
|
2192
|
-
var Group = class extends SmrtObject {
|
|
2193
|
-
tenantId;
|
|
2194
|
-
/**
|
|
2195
|
-
* Display name for the group
|
|
2196
|
-
*/
|
|
2197
|
-
name = "";
|
|
2198
|
-
/**
|
|
2199
|
-
* Description of the group
|
|
2200
|
-
*/
|
|
2201
|
-
description = "";
|
|
2202
|
-
constructor(options = {}) {
|
|
2203
|
-
super(options);
|
|
2204
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
2205
|
-
if (options.name !== void 0) this.name = options.name;
|
|
2206
|
-
if (options.description !== void 0) this.description = options.description;
|
|
2207
|
-
}
|
|
2208
|
-
};
|
|
2209
|
-
__decorateClass$9([foreignKey("Tenant", { required: true })], Group.prototype, "tenantId", 2);
|
|
2210
|
-
Group = __decorateClass$9([smrt({
|
|
2211
|
-
api: { include: ["list", "get"] },
|
|
2212
|
-
mcp: { include: ["list", "get"] },
|
|
2213
|
-
cli: true
|
|
2214
|
-
})], Group);
|
|
2215
|
-
var __defProp$8 = Object.defineProperty;
|
|
2216
|
-
var __getOwnPropDesc$8 = Object.getOwnPropertyDescriptor;
|
|
2217
|
-
var __decorateClass$8 = (decorators, target, key, kind) => {
|
|
2218
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$8(target, key) : target;
|
|
2219
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2220
|
-
if (kind && result) __defProp$8(target, key, result);
|
|
2221
|
-
return result;
|
|
2222
|
-
};
|
|
2223
|
-
var GroupMember = class extends SmrtObject {
|
|
2224
|
-
groupId;
|
|
2225
|
-
userId;
|
|
2226
|
-
constructor(options = {}) {
|
|
2227
|
-
super(options);
|
|
2228
|
-
if (options.groupId !== void 0) this.groupId = options.groupId;
|
|
2229
|
-
if (options.userId !== void 0) this.userId = options.userId;
|
|
2230
|
-
}
|
|
2231
|
-
};
|
|
2232
|
-
__decorateClass$8([foreignKey("Group", { required: true })], GroupMember.prototype, "groupId", 2);
|
|
2233
|
-
__decorateClass$8([foreignKey("User", { required: true })], GroupMember.prototype, "userId", 2);
|
|
2234
|
-
GroupMember = __decorateClass$8([smrt({
|
|
2235
|
-
api: { include: ["list", "get"] },
|
|
2236
|
-
mcp: { include: ["list", "get"] },
|
|
2237
|
-
cli: true
|
|
2238
|
-
})], GroupMember);
|
|
2239
|
-
var __defProp$7 = Object.defineProperty;
|
|
2240
|
-
var __getOwnPropDesc$7 = Object.getOwnPropertyDescriptor;
|
|
2241
|
-
var __decorateClass$7 = (decorators, target, key, kind) => {
|
|
2242
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$7(target, key) : target;
|
|
2243
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2244
|
-
if (kind && result) __defProp$7(target, key, result);
|
|
2245
|
-
return result;
|
|
2246
|
-
};
|
|
2247
|
-
var GroupRole = class extends SmrtObject {
|
|
2248
|
-
groupId;
|
|
2249
|
-
roleId;
|
|
2250
|
-
constructor(options = {}) {
|
|
2251
|
-
super(options);
|
|
2252
|
-
if (options.groupId !== void 0) this.groupId = options.groupId;
|
|
2253
|
-
if (options.roleId !== void 0) this.roleId = options.roleId;
|
|
2254
|
-
}
|
|
2255
|
-
};
|
|
2256
|
-
__decorateClass$7([foreignKey("Group", { required: true })], GroupRole.prototype, "groupId", 2);
|
|
2257
|
-
__decorateClass$7([foreignKey("Role", { required: true })], GroupRole.prototype, "roleId", 2);
|
|
2258
|
-
GroupRole = __decorateClass$7([smrt({
|
|
2259
|
-
api: { include: ["list", "get"] },
|
|
2260
|
-
mcp: { include: ["list", "get"] },
|
|
2261
|
-
cli: true
|
|
2262
|
-
})], GroupRole);
|
|
2263
|
-
var __defProp$6 = Object.defineProperty;
|
|
2264
|
-
var __getOwnPropDesc$6 = Object.getOwnPropertyDescriptor;
|
|
2265
|
-
var __decorateClass$6 = (decorators, target, key, kind) => {
|
|
2266
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$6(target, key) : target;
|
|
2267
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2268
|
-
if (kind && result) __defProp$6(target, key, result);
|
|
2269
|
-
return result;
|
|
2270
|
-
};
|
|
2271
|
-
var Membership = class extends SmrtObject {
|
|
2272
|
-
userId;
|
|
2273
|
-
tenantId;
|
|
2274
|
-
roleId;
|
|
2275
|
-
status = MembershipStatus.ACTIVE;
|
|
2276
|
-
constructor(options = {}) {
|
|
2277
|
-
super(options);
|
|
2278
|
-
if (options.userId !== void 0) this.userId = options.userId;
|
|
2279
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
2280
|
-
if (options.roleId !== void 0) this.roleId = options.roleId;
|
|
2281
|
-
if (options.status !== void 0) this.status = options.status;
|
|
2282
|
-
}
|
|
2283
|
-
/**
|
|
2284
|
-
* Check if membership is active
|
|
2285
|
-
*/
|
|
2286
|
-
isActive() {
|
|
2287
|
-
return this.status === MembershipStatus.ACTIVE;
|
|
2288
|
-
}
|
|
2289
|
-
/**
|
|
2290
|
-
* Check if membership is pending (invitation not yet accepted)
|
|
2291
|
-
*/
|
|
2292
|
-
isPending() {
|
|
2293
|
-
return this.status === MembershipStatus.PENDING;
|
|
2294
|
-
}
|
|
2295
|
-
};
|
|
2296
|
-
__decorateClass$6([foreignKey("User", { required: true })], Membership.prototype, "userId", 2);
|
|
2297
|
-
__decorateClass$6([foreignKey("Tenant", { required: true })], Membership.prototype, "tenantId", 2);
|
|
2298
|
-
__decorateClass$6([foreignKey("Role", { required: true })], Membership.prototype, "roleId", 2);
|
|
2299
|
-
__decorateClass$6([field({ type: "text" })], Membership.prototype, "status", 2);
|
|
2300
|
-
Membership = __decorateClass$6([smrt({
|
|
2301
|
-
api: { include: ["list", "get"] },
|
|
2302
|
-
mcp: { include: ["list", "get"] },
|
|
2303
|
-
cli: { skipApiCheck: true },
|
|
2304
|
-
indexes: [{
|
|
2305
|
-
name: "memberships_tenant_id_user_id_idx",
|
|
2306
|
-
columns: ["tenantId", "userId"]
|
|
2307
|
-
}]
|
|
2308
|
-
})], Membership);
|
|
2309
|
-
var __defProp$5 = Object.defineProperty;
|
|
2310
|
-
var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
|
|
2311
|
-
var __decorateClass$5 = (decorators, target, key, kind) => {
|
|
2312
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$5(target, key) : target;
|
|
2313
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2314
|
-
if (kind && result) __defProp$5(target, key, result);
|
|
2315
|
-
return result;
|
|
2316
|
-
};
|
|
2317
|
-
var MembershipOverride = class extends SmrtObject {
|
|
2318
|
-
membershipId;
|
|
2319
|
-
permissionId;
|
|
2320
|
-
effect = OverrideEffect.GRANT;
|
|
2321
|
-
constructor(options = {}) {
|
|
2322
|
-
super(options);
|
|
2323
|
-
if (options.membershipId !== void 0) this.membershipId = options.membershipId;
|
|
2324
|
-
if (options.permissionId !== void 0) this.permissionId = options.permissionId;
|
|
2325
|
-
if (options.effect !== void 0) this.effect = options.effect;
|
|
2326
|
-
}
|
|
2327
|
-
/**
|
|
2328
|
-
* Check if this override grants the permission
|
|
2329
|
-
*/
|
|
2330
|
-
isGrant() {
|
|
2331
|
-
return this.effect === OverrideEffect.GRANT;
|
|
2332
|
-
}
|
|
2333
|
-
/**
|
|
2334
|
-
* Check if this override denies the permission
|
|
2335
|
-
*/
|
|
2336
|
-
isDeny() {
|
|
2337
|
-
return this.effect === OverrideEffect.DENY;
|
|
2338
|
-
}
|
|
2339
|
-
};
|
|
2340
|
-
__decorateClass$5([foreignKey("Membership", { required: true })], MembershipOverride.prototype, "membershipId", 2);
|
|
2341
|
-
__decorateClass$5([foreignKey("Permission", { required: true })], MembershipOverride.prototype, "permissionId", 2);
|
|
2342
|
-
__decorateClass$5([field({ type: "text" })], MembershipOverride.prototype, "effect", 2);
|
|
2343
|
-
MembershipOverride = __decorateClass$5([smrt({
|
|
2344
|
-
api: { include: ["list", "get"] },
|
|
2345
|
-
mcp: { include: ["list", "get"] },
|
|
2346
|
-
cli: { skipApiCheck: true }
|
|
2347
|
-
})], MembershipOverride);
|
|
2348
|
-
var __defProp$4 = Object.defineProperty;
|
|
2349
|
-
var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
|
|
2350
|
-
var __decorateClass$4 = (decorators, target, key, kind) => {
|
|
2351
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
|
|
2352
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2353
|
-
if (kind && result) __defProp$4(target, key, result);
|
|
2354
|
-
return result;
|
|
2355
|
-
};
|
|
2356
|
-
function parsePermissionSlug(slug) {
|
|
2357
|
-
const parts = slug.split(".");
|
|
2358
|
-
if (parts.length >= 2 && parts.every(Boolean)) return {
|
|
2359
|
-
resource: parts[0],
|
|
2360
|
-
action: parts.slice(1).join("."),
|
|
2361
|
-
isValid: true
|
|
2362
|
-
};
|
|
2363
|
-
return {
|
|
2364
|
-
resource: slug,
|
|
2365
|
-
action: "",
|
|
2366
|
-
isValid: false
|
|
2367
|
-
};
|
|
2368
|
-
}
|
|
2369
|
-
var Permission = class extends SmrtObject {
|
|
2370
|
-
/**
|
|
2371
|
-
* Display name for the permission
|
|
2372
|
-
*/
|
|
2373
|
-
name = "";
|
|
2374
|
-
/**
|
|
2375
|
-
* Description of what this permission allows
|
|
2376
|
-
*/
|
|
2377
|
-
description = "";
|
|
2378
|
-
/**
|
|
2379
|
-
* Category for grouping in UI (e.g., 'articles', 'users', 'settings')
|
|
2380
|
-
*/
|
|
2381
|
-
category = "";
|
|
2382
|
-
constructor(options = {}) {
|
|
2383
|
-
super(options);
|
|
2384
|
-
if (options.name !== void 0) this.name = options.name;
|
|
2385
|
-
if (options.description !== void 0) this.description = options.description;
|
|
2386
|
-
if (options.category !== void 0) this.category = options.category;
|
|
2387
|
-
}
|
|
2388
|
-
/**
|
|
2389
|
-
* Parse the permission slug into resource and action components.
|
|
2390
|
-
* @returns Parsed slug with resource, action, and validation status
|
|
2391
|
-
*/
|
|
2392
|
-
parseSlug() {
|
|
2393
|
-
return parsePermissionSlug(this.slug ?? "");
|
|
2394
|
-
}
|
|
2395
|
-
/**
|
|
2396
|
-
* Get the resource part of the permission slug
|
|
2397
|
-
* e.g., 'articles.create' -> 'articles'
|
|
2398
|
-
*/
|
|
2399
|
-
getResource() {
|
|
2400
|
-
return this.parseSlug().resource;
|
|
2401
|
-
}
|
|
2402
|
-
/**
|
|
2403
|
-
* Get the action part of the permission slug
|
|
2404
|
-
* e.g., 'articles.create' -> 'create'
|
|
2405
|
-
*/
|
|
2406
|
-
getAction() {
|
|
2407
|
-
return this.parseSlug().action;
|
|
2408
|
-
}
|
|
2409
|
-
/**
|
|
2410
|
-
* Check if the permission slug is valid (follows 'resource.action' pattern)
|
|
2411
|
-
*/
|
|
2412
|
-
isValidSlug() {
|
|
2413
|
-
return this.parseSlug().isValid;
|
|
2414
|
-
}
|
|
2415
|
-
};
|
|
2416
|
-
Permission = __decorateClass$4([smrt({
|
|
2417
|
-
api: { include: ["list", "get"] },
|
|
2418
|
-
mcp: { include: ["list", "get"] },
|
|
2419
|
-
cli: { skipApiCheck: true }
|
|
2420
|
-
})], Permission);
|
|
2421
|
-
var __defProp$3$1 = Object.defineProperty;
|
|
2422
|
-
var __getOwnPropDesc$3$1 = Object.getOwnPropertyDescriptor;
|
|
2423
|
-
var __decorateClass$3$1 = (decorators, target, key, kind) => {
|
|
2424
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3$1(target, key) : target;
|
|
2425
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2426
|
-
if (kind && result) __defProp$3$1(target, key, result);
|
|
2427
|
-
return result;
|
|
2428
|
-
};
|
|
2429
|
-
var Role = class extends SmrtObject {
|
|
2430
|
-
tenantId;
|
|
2431
|
-
/**
|
|
2432
|
-
* Display name for the role
|
|
2433
|
-
*/
|
|
2434
|
-
name = "";
|
|
2435
|
-
/**
|
|
2436
|
-
* Description of the role
|
|
2437
|
-
*/
|
|
2438
|
-
description = "";
|
|
2439
|
-
/**
|
|
2440
|
-
* Whether this is a system role (cannot be deleted)
|
|
2441
|
-
*/
|
|
2442
|
-
isSystem = false;
|
|
2443
|
-
/**
|
|
2444
|
-
* Opt-in hierarchical inheritance: when true, an ACTIVE membership holding
|
|
2445
|
-
* this role also resolves permissions in descendant tenants where the user
|
|
2446
|
-
* has no direct membership (nearest flagged ancestor membership wins).
|
|
2447
|
-
*
|
|
2448
|
-
* Default false: the role's authority is exact-tenant only, which is the
|
|
2449
|
-
* pre-existing resolver behavior. Flag structural roles like a network-level
|
|
2450
|
-
* owner/admin; leave per-tenant roles like member/viewer unflagged.
|
|
2451
|
-
*/
|
|
2452
|
-
inheritsToDescendants = false;
|
|
2453
|
-
constructor(options = {}) {
|
|
2454
|
-
super(options);
|
|
2455
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
2456
|
-
if (options.name !== void 0) this.name = options.name;
|
|
2457
|
-
if (options.description !== void 0) this.description = options.description;
|
|
2458
|
-
if (options.isSystem !== void 0) this.isSystem = options.isSystem;
|
|
2459
|
-
if (options.inheritsToDescendants !== void 0) this.inheritsToDescendants = options.inheritsToDescendants;
|
|
2460
|
-
}
|
|
2461
|
-
/**
|
|
2462
|
-
* Check if this is a system-wide role
|
|
2463
|
-
*/
|
|
2464
|
-
isSystemRole() {
|
|
2465
|
-
return this.tenantId === null || this.tenantId === void 0;
|
|
2466
|
-
}
|
|
2467
|
-
/**
|
|
2468
|
-
* Check if this is a tenant-specific role
|
|
2469
|
-
*/
|
|
2470
|
-
isTenantRole() {
|
|
2471
|
-
return this.tenantId !== null && this.tenantId !== void 0;
|
|
2472
|
-
}
|
|
2473
|
-
/**
|
|
2474
|
-
* Check if this role can be deleted.
|
|
2475
|
-
* System roles (isSystem = true) cannot be deleted.
|
|
2476
|
-
* @returns true if the role can be deleted
|
|
2477
|
-
*/
|
|
2478
|
-
canDelete() {
|
|
2479
|
-
return !this.isSystem;
|
|
2480
|
-
}
|
|
2481
|
-
/**
|
|
2482
|
-
* Delete guard - prevents deletion of system roles.
|
|
2483
|
-
* Override the delete method to check isSystem flag first.
|
|
2484
|
-
*/
|
|
2485
|
-
async delete() {
|
|
2486
|
-
if (this.isSystem) throw new Error(`Cannot delete system role '${this.slug}'. System roles are protected.`);
|
|
2487
|
-
return super.delete();
|
|
2488
|
-
}
|
|
2489
|
-
};
|
|
2490
|
-
__decorateClass$3$1([foreignKey("Tenant", { nullable: true })], Role.prototype, "tenantId", 2);
|
|
2491
|
-
Role = __decorateClass$3$1([smrt({
|
|
2492
|
-
api: { include: ["list", "get"] },
|
|
2493
|
-
mcp: { include: ["list", "get"] },
|
|
2494
|
-
cli: { skipApiCheck: true }
|
|
2495
|
-
})], Role);
|
|
2496
|
-
var __defProp$2$1 = Object.defineProperty;
|
|
2497
|
-
var __getOwnPropDesc$2$1 = Object.getOwnPropertyDescriptor;
|
|
2498
|
-
var __decorateClass$2$1 = (decorators, target, key, kind) => {
|
|
2499
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2$1(target, key) : target;
|
|
2500
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2501
|
-
if (kind && result) __defProp$2$1(target, key, result);
|
|
2502
|
-
return result;
|
|
2503
|
-
};
|
|
2504
|
-
var RolePermission = class extends SmrtObject {
|
|
2505
|
-
roleId;
|
|
2506
|
-
permissionId;
|
|
2507
|
-
constructor(options = {}) {
|
|
2508
|
-
super(options);
|
|
2509
|
-
if (options.roleId !== void 0) this.roleId = options.roleId;
|
|
2510
|
-
if (options.permissionId !== void 0) this.permissionId = options.permissionId;
|
|
2511
|
-
}
|
|
2512
|
-
};
|
|
2513
|
-
__decorateClass$2$1([foreignKey("Role", { required: true })], RolePermission.prototype, "roleId", 2);
|
|
2514
|
-
__decorateClass$2$1([foreignKey("Permission", { required: true })], RolePermission.prototype, "permissionId", 2);
|
|
2515
|
-
RolePermission = __decorateClass$2$1([smrt({
|
|
2516
|
-
api: { include: ["list", "get"] },
|
|
2517
|
-
mcp: { include: ["list", "get"] },
|
|
2518
|
-
cli: true
|
|
2519
|
-
})], RolePermission);
|
|
2520
|
-
DEFAULT_ROLE_SLUGS.OWNER, DEFAULT_ROLE_SLUGS.ADMIN, DEFAULT_ROLE_SLUGS.MEMBER, DEFAULT_ROLE_SLUGS.VIEWER;
|
|
2521
|
-
var logger$1 = createLogger({ level: "info" });
|
|
2522
|
-
var TenantHierarchyError = class extends Error {
|
|
2523
|
-
constructor(message, code) {
|
|
2524
|
-
super(message);
|
|
2525
|
-
this.code = code;
|
|
2526
|
-
this.name = "TenantHierarchyError";
|
|
2527
|
-
}
|
|
2528
|
-
code;
|
|
2529
|
-
};
|
|
2530
|
-
var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2531
|
-
function assertTenantTableName(tableName) {
|
|
2532
|
-
if (!IDENTIFIER.test(tableName)) throw new TenantHierarchyError(`Invalid tenant table name: ${JSON.stringify(tableName)}`, "INVALID_OPERATION");
|
|
2533
|
-
return tableName;
|
|
2534
|
-
}
|
|
2535
|
-
function toId(value) {
|
|
2536
|
-
if (value === null || value === void 0) return null;
|
|
2537
|
-
const id = String(value);
|
|
2538
|
-
return id.length > 0 ? id : null;
|
|
2539
|
-
}
|
|
2540
|
-
function childHierarchyFields(parentId, parent) {
|
|
2541
|
-
return {
|
|
2542
|
-
hierarchyPath: parent.hierarchyPath ? `${parent.hierarchyPath}/${parentId}` : parentId,
|
|
2543
|
-
hierarchyLevel: parent.hierarchyLevel + 1
|
|
2544
|
-
};
|
|
2545
|
-
}
|
|
2546
|
-
async function computeTenantHierarchyFields(db, tableName, tenantId, parentTenantId) {
|
|
2547
|
-
const table = assertTenantTableName(tableName);
|
|
2548
|
-
const ancestors = [];
|
|
2549
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2550
|
-
if (tenantId) seen.add(tenantId);
|
|
2551
|
-
let cursor = toId(parentTenantId);
|
|
2552
|
-
while (cursor) {
|
|
2553
|
-
if (seen.has(cursor)) throw new TenantHierarchyError(`Tenant hierarchy for ${tenantId ?? "a new tenant"} is circular at ${cursor}`, "CIRCULAR_REFERENCE");
|
|
2554
|
-
if (ancestors.length + 1 >= 10) throw new TenantHierarchyError(`Maximum hierarchy depth (10) exceeded`, "MAX_DEPTH_EXCEEDED");
|
|
2555
|
-
seen.add(cursor);
|
|
2556
|
-
const { rows } = await db.query(`SELECT id, parent_tenant_id FROM ${table} WHERE id = ?`, cursor);
|
|
2557
|
-
const row = rows[0];
|
|
2558
|
-
if (!row) throw new TenantHierarchyError(`Parent tenant not found: ${cursor}`, "PARENT_NOT_FOUND");
|
|
2559
|
-
ancestors.unshift(cursor);
|
|
2560
|
-
cursor = toId(row.parent_tenant_id);
|
|
2561
|
-
}
|
|
2562
|
-
return {
|
|
2563
|
-
hierarchyPath: ancestors.join("/"),
|
|
2564
|
-
hierarchyLevel: ancestors.length
|
|
2565
|
-
};
|
|
2566
|
-
}
|
|
2567
|
-
async function planDescendantHierarchy(db, tableName, rootId, root) {
|
|
2568
|
-
const table = assertTenantTableName(tableName);
|
|
2569
|
-
const updates = [];
|
|
2570
|
-
const seen = /* @__PURE__ */ new Set([rootId]);
|
|
2571
|
-
let frontier = [{
|
|
2572
|
-
id: rootId,
|
|
2573
|
-
fields: root
|
|
2574
|
-
}];
|
|
2575
|
-
while (frontier.length > 0) {
|
|
2576
|
-
const next = [];
|
|
2577
|
-
for (const parent of frontier) {
|
|
2578
|
-
const { rows } = await db.query(`SELECT id, hierarchy_path, hierarchy_level FROM ${table} WHERE parent_tenant_id = ?`, parent.id);
|
|
2579
|
-
for (const row of rows) {
|
|
2580
|
-
const id = toId(row.id);
|
|
2581
|
-
if (!id) continue;
|
|
2582
|
-
if (seen.has(id)) throw new TenantHierarchyError(`Tenant hierarchy below ${rootId} is circular at ${id}`, "CIRCULAR_REFERENCE");
|
|
2583
|
-
seen.add(id);
|
|
2584
|
-
const fields = childHierarchyFields(parent.id, parent.fields);
|
|
2585
|
-
if (fields.hierarchyLevel >= 10) throw new TenantHierarchyError(`Moving would exceed maximum hierarchy depth (10)`, "MAX_DEPTH_EXCEEDED");
|
|
2586
|
-
if ((row.hierarchy_path ?? "") !== fields.hierarchyPath || Number(row.hierarchy_level) !== fields.hierarchyLevel) updates.push({
|
|
2587
|
-
id,
|
|
2588
|
-
...fields
|
|
2589
|
-
});
|
|
2590
|
-
next.push({
|
|
2591
|
-
id,
|
|
2592
|
-
fields
|
|
2593
|
-
});
|
|
2594
|
-
}
|
|
2595
|
-
}
|
|
2596
|
-
frontier = next;
|
|
2597
|
-
}
|
|
2598
|
-
return updates;
|
|
2599
|
-
}
|
|
2600
|
-
async function applyTenantHierarchyUpdates(db, tableName, updates) {
|
|
2601
|
-
const table = assertTenantTableName(tableName);
|
|
2602
|
-
for (const update of updates) await db.query(`UPDATE ${table} SET hierarchy_path = ?, hierarchy_level = ? WHERE id = ?`, update.hierarchyPath, update.hierarchyLevel, update.id);
|
|
2603
|
-
}
|
|
2604
|
-
function planTenantHierarchy(rows) {
|
|
2605
|
-
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
2606
|
-
const resolved = /* @__PURE__ */ new Map();
|
|
2607
|
-
const resolve = (id) => {
|
|
2608
|
-
const cached = resolved.get(id);
|
|
2609
|
-
if (cached) return cached;
|
|
2610
|
-
const chain = [];
|
|
2611
|
-
const onChain = /* @__PURE__ */ new Set();
|
|
2612
|
-
let cursor = id;
|
|
2613
|
-
let base;
|
|
2614
|
-
while (cursor) {
|
|
2615
|
-
const known = resolved.get(cursor);
|
|
2616
|
-
if (known) {
|
|
2617
|
-
base = known;
|
|
2618
|
-
break;
|
|
2619
|
-
}
|
|
2620
|
-
if (onChain.has(cursor)) {
|
|
2621
|
-
base = {
|
|
2622
|
-
id,
|
|
2623
|
-
code: "CIRCULAR_REFERENCE",
|
|
2624
|
-
message: `Tenant ${id} has a circular parent chain at ${cursor}.`
|
|
2625
|
-
};
|
|
2626
|
-
break;
|
|
2627
|
-
}
|
|
2628
|
-
const row = byId.get(cursor);
|
|
2629
|
-
if (!row) {
|
|
2630
|
-
base = {
|
|
2631
|
-
id,
|
|
2632
|
-
code: "PARENT_NOT_FOUND",
|
|
2633
|
-
message: `Tenant ${chain[chain.length - 1] ?? id} names missing parent ${cursor}.`
|
|
2634
|
-
};
|
|
2635
|
-
break;
|
|
2636
|
-
}
|
|
2637
|
-
onChain.add(cursor);
|
|
2638
|
-
chain.push(cursor);
|
|
2639
|
-
cursor = row.parentTenantId;
|
|
2640
|
-
}
|
|
2641
|
-
if (!base) {
|
|
2642
|
-
const rootId = chain.pop();
|
|
2643
|
-
base = {
|
|
2644
|
-
hierarchyPath: "",
|
|
2645
|
-
hierarchyLevel: 0
|
|
2646
|
-
};
|
|
2647
|
-
resolved.set(rootId, base);
|
|
2648
|
-
if (rootId === id) return base;
|
|
2649
|
-
}
|
|
2650
|
-
let parentFields = base;
|
|
2651
|
-
for (let i = chain.length - 1; i >= 0; i--) {
|
|
2652
|
-
const current = chain[i];
|
|
2653
|
-
let fields;
|
|
2654
|
-
if ("code" in parentFields) fields = {
|
|
2655
|
-
...parentFields,
|
|
2656
|
-
id: current
|
|
2657
|
-
};
|
|
2658
|
-
else {
|
|
2659
|
-
const parentId = byId.get(current)?.parentTenantId;
|
|
2660
|
-
const child = childHierarchyFields(parentId, parentFields);
|
|
2661
|
-
fields = child.hierarchyLevel >= 10 ? {
|
|
2662
|
-
id: current,
|
|
2663
|
-
code: "MAX_DEPTH_EXCEEDED",
|
|
2664
|
-
message: `Tenant ${current} would sit at level ${child.hierarchyLevel}; the maximum depth is 10.`
|
|
2665
|
-
} : child;
|
|
2666
|
-
}
|
|
2667
|
-
resolved.set(current, fields);
|
|
2668
|
-
parentFields = fields;
|
|
2669
|
-
}
|
|
2670
|
-
return resolved.get(id);
|
|
2671
|
-
};
|
|
2672
|
-
const changes = [];
|
|
2673
|
-
const problems = [];
|
|
2674
|
-
for (const row of rows) {
|
|
2675
|
-
const fields = resolve(row.id);
|
|
2676
|
-
if ("code" in fields) {
|
|
2677
|
-
problems.push({
|
|
2678
|
-
...fields,
|
|
2679
|
-
id: row.id
|
|
2680
|
-
});
|
|
2681
|
-
continue;
|
|
2682
|
-
}
|
|
2683
|
-
if ((row.hierarchyPath ?? "") !== fields.hierarchyPath || row.hierarchyLevel !== fields.hierarchyLevel) changes.push({
|
|
2684
|
-
id: row.id,
|
|
2685
|
-
...fields,
|
|
2686
|
-
previousPath: row.hierarchyPath,
|
|
2687
|
-
previousLevel: row.hierarchyLevel
|
|
2688
|
-
});
|
|
2689
|
-
}
|
|
2690
|
-
const byIdOrder = (a, b) => a.id.localeCompare(b.id);
|
|
2691
|
-
return {
|
|
2692
|
-
total: rows.length,
|
|
2693
|
-
changes: changes.sort(byIdOrder),
|
|
2694
|
-
problems: problems.sort(byIdOrder)
|
|
2695
|
-
};
|
|
2696
|
-
}
|
|
2697
|
-
async function recordTenantHierarchyChanges(db, tableName, rowIds) {
|
|
2698
|
-
const inputs = rowIds === void 0 ? [{
|
|
2699
|
-
table: tableName,
|
|
2700
|
-
rowId: null
|
|
2701
|
-
}] : rowIds.map((rowId) => ({
|
|
2702
|
-
table: tableName,
|
|
2703
|
-
rowId
|
|
2704
|
-
}));
|
|
2705
|
-
for (const input of inputs) try {
|
|
2706
|
-
await bumpChangeFeed(db, {
|
|
2707
|
-
...input,
|
|
2708
|
-
operation: "update"
|
|
2709
|
-
});
|
|
2710
|
-
} catch (error) {
|
|
2711
|
-
logger$1.warn("Failed to record tenant hierarchy change in change feed", {
|
|
2712
|
-
table: tableName,
|
|
2713
|
-
rowId: input.rowId,
|
|
2714
|
-
error: error instanceof Error ? error.message : String(error)
|
|
2715
|
-
});
|
|
2716
|
-
}
|
|
2717
|
-
}
|
|
2718
|
-
var __defProp$1$1 = Object.defineProperty;
|
|
2719
|
-
var __getOwnPropDesc$1$1 = Object.getOwnPropertyDescriptor;
|
|
2720
|
-
var __decorateClass$1$1 = (decorators, target, key, kind) => {
|
|
2721
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1$1(target, key) : target;
|
|
2722
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
2723
|
-
if (kind && result) __defProp$1$1(target, key, result);
|
|
2724
|
-
return result;
|
|
2725
|
-
};
|
|
2726
|
-
var Tenant = class extends SmrtObject {
|
|
2727
|
-
/**
|
|
2728
|
-
* Display name for the tenant
|
|
2729
|
-
*/
|
|
2730
|
-
name = "";
|
|
2731
|
-
status = TenantStatus.ACTIVE;
|
|
2732
|
-
/**
|
|
2733
|
-
* Optional description
|
|
2734
|
-
*/
|
|
2735
|
-
description = "";
|
|
2736
|
-
parentTenantId;
|
|
2737
|
-
/**
|
|
2738
|
-
* Depth in the hierarchy tree (0 = root, 1 = first level child, etc.)
|
|
2739
|
-
* Derived from `parentTenantId` and maintained by {@link Tenant.save};
|
|
2740
|
-
* any value assigned directly is recomputed on save.
|
|
2741
|
-
*/
|
|
2742
|
-
hierarchyLevel = 0;
|
|
2743
|
-
/**
|
|
2744
|
-
* Materialized path for efficient tree traversal.
|
|
2745
|
-
* Format: "ancestor-id/parent-id" (path to parent; does not include this tenant's id)
|
|
2746
|
-
* Empty string for root tenants.
|
|
2747
|
-
* Derived from `parentTenantId` and maintained by {@link Tenant.save};
|
|
2748
|
-
* any value assigned directly is recomputed on save. Rows written before
|
|
2749
|
-
* the framework maintained it are backfilled with
|
|
2750
|
-
* `smrt db:materialize-tenant-hierarchy` (smrt#3036).
|
|
2751
|
-
*/
|
|
2752
|
-
hierarchyPath = "";
|
|
2753
|
-
/**
|
|
2754
|
-
* If true, this tenant's permissions cascade DOWN to child tenants.
|
|
2755
|
-
* Children can still opt-out by setting inheritPermissions: false.
|
|
2756
|
-
* Default: true
|
|
2757
|
-
*/
|
|
2758
|
-
cascadePermissions = true;
|
|
2759
|
-
/**
|
|
2760
|
-
* If true, this tenant ACCEPTS permissions from its parent tenant.
|
|
2761
|
-
* Parent must also have cascadePermissions: true for inheritance to work.
|
|
2762
|
-
* Default: true
|
|
2763
|
-
*/
|
|
2764
|
-
inheritPermissions = true;
|
|
2765
|
-
constructor(options = {}) {
|
|
2766
|
-
super(options);
|
|
2767
|
-
if (options.name !== void 0) this.name = options.name;
|
|
2768
|
-
if (options.status !== void 0) this.status = options.status;
|
|
2769
|
-
if (options.description !== void 0) this.description = options.description;
|
|
2770
|
-
if (options.parentTenantId !== void 0) this.parentTenantId = options.parentTenantId;
|
|
2771
|
-
if (options.hierarchyLevel !== void 0) this.hierarchyLevel = options.hierarchyLevel;
|
|
2772
|
-
if (options.hierarchyPath !== void 0) this.hierarchyPath = options.hierarchyPath;
|
|
2773
|
-
if (options.cascadePermissions !== void 0) this.cascadePermissions = options.cascadePermissions;
|
|
2774
|
-
if (options.inheritPermissions !== void 0) this.inheritPermissions = options.inheritPermissions;
|
|
2775
|
-
}
|
|
2776
|
-
/**
|
|
2777
|
-
* Check if tenant is active
|
|
2778
|
-
*/
|
|
2779
|
-
isActive() {
|
|
2780
|
-
return this.status === TenantStatus.ACTIVE;
|
|
2781
|
-
}
|
|
2782
|
-
/**
|
|
2783
|
-
* Check if tenant is suspended
|
|
2784
|
-
*/
|
|
2785
|
-
isSuspended() {
|
|
2786
|
-
return this.status === TenantStatus.SUSPENDED;
|
|
2787
|
-
}
|
|
2788
|
-
/**
|
|
2789
|
-
* Check if this is a root-level tenant (no parent)
|
|
2790
|
-
*/
|
|
2791
|
-
isRoot() {
|
|
2792
|
-
return !this.parentTenantId;
|
|
2793
|
-
}
|
|
2794
|
-
/**
|
|
2795
|
-
* Check if this tenant is configured to cascade permissions to children.
|
|
2796
|
-
*
|
|
2797
|
-
* Note: This does NOT indicate whether any child tenants actually exist.
|
|
2798
|
-
* Use TenantCollection.findChildren() for accurate child lookup.
|
|
2799
|
-
*/
|
|
2800
|
-
canCascadeToChildren() {
|
|
2801
|
-
return this.cascadePermissions;
|
|
2802
|
-
}
|
|
2803
|
-
/**
|
|
2804
|
-
* Check if permission inheritance is active for this tenant.
|
|
2805
|
-
* Inheritance is active if:
|
|
2806
|
-
* - This tenant has a parent AND
|
|
2807
|
-
* - This tenant has inheritPermissions: true
|
|
2808
|
-
*
|
|
2809
|
-
* Note: The parent must also have cascadePermissions: true
|
|
2810
|
-
* for actual inheritance to occur. Use PermissionResolver
|
|
2811
|
-
* for accurate permission calculation.
|
|
2812
|
-
*/
|
|
2813
|
-
acceptsInheritance() {
|
|
2814
|
-
return !!this.parentTenantId && this.inheritPermissions;
|
|
2815
|
-
}
|
|
2816
|
-
/**
|
|
2817
|
-
* Persist the tenant, keeping the derived hierarchy fields true (smrt#3036).
|
|
2818
|
-
*
|
|
2819
|
-
* `hierarchyPath` / `hierarchyLevel` are recomputed from the real
|
|
2820
|
-
* `parentTenantId` chain on EVERY save — whichever collection, subclass, or
|
|
2821
|
-
* code path produced the object — so a consumer never hand-maintains them.
|
|
2822
|
-
* When they change (a reparent, or healing a stale row), every descendant is
|
|
2823
|
-
* re-materialized too. Both columns are an authorization source for
|
|
2824
|
-
* `inheritsToDescendants` and the declared ancestor-read policy.
|
|
2825
|
-
*
|
|
2826
|
-
* @throws {TenantHierarchyError} before anything is written, when the new
|
|
2827
|
-
* parent is missing, would create a cycle, or would put this tenant or one
|
|
2828
|
-
* of its descendants at or below `MAX_TENANT_HIERARCHY_DEPTH`.
|
|
2829
|
-
*/
|
|
2830
|
-
async save(options = {}) {
|
|
2831
|
-
const db = this.db;
|
|
2832
|
-
const table = this.tableName;
|
|
2833
|
-
await this.assertNewParentVisible(db, table);
|
|
2834
|
-
const fields = await computeTenantHierarchyFields(db, table, this.id, this.parentTenantId);
|
|
2835
|
-
const descendantUpdates = (fields.hierarchyPath !== this.hierarchyPath || fields.hierarchyLevel !== this.hierarchyLevel) && this.id && this.isPersisted ? await planDescendantHierarchy(db, table, this.id, fields) : [];
|
|
2836
|
-
this.hierarchyPath = fields.hierarchyPath;
|
|
2837
|
-
this.hierarchyLevel = fields.hierarchyLevel;
|
|
2838
|
-
await super.save(options);
|
|
2839
|
-
if (descendantUpdates.length > 0) {
|
|
2840
|
-
await applyTenantHierarchyUpdates(db, table, descendantUpdates);
|
|
2841
|
-
await recordTenantHierarchyChanges(this.db, table, descendantUpdates.map((update) => update.id));
|
|
2842
|
-
}
|
|
2843
|
-
return this;
|
|
2844
|
-
}
|
|
2845
|
-
/**
|
|
2846
|
-
* Refuse to link this tenant under a parent the caller cannot see.
|
|
2847
|
-
*
|
|
2848
|
-
* A parent link is authority-bearing: ancestor tenant overrides cascade down
|
|
2849
|
-
* it and `inheritsToDescendants` roles flow along it. The chain itself is
|
|
2850
|
-
* resolved with raw reads (so paths can be derived for any row), so this is
|
|
2851
|
-
* the check that keeps a NEW or CHANGED link subject to the caller's own
|
|
2852
|
-
* tenancy scope, whichever path made it — `createChild`, `moveToParent`,
|
|
2853
|
-
* `create({ parentTenantId })`, or a plain `parentTenantId` assignment and
|
|
2854
|
-
* `save()`. The parent is loaded through `TenantCollection`, i.e. through
|
|
2855
|
-
* the tenancy interceptor: a refused or filtered read fails the save before
|
|
2856
|
-
* anything is written. System context (migrations, backfills, platform
|
|
2857
|
-
* administration) bypasses the interceptor as everywhere else. An unchanged
|
|
2858
|
-
* link is not re-checked, so a tenant can still save itself under its own
|
|
2859
|
-
* scope when its parent is not visible there.
|
|
2860
|
-
*/
|
|
2861
|
-
async assertNewParentVisible(db, table) {
|
|
2862
|
-
const parentId = this.parentTenantId ?? null;
|
|
2863
|
-
if (!parentId) return;
|
|
2864
|
-
if (this.id) {
|
|
2865
|
-
const { rows } = await db.query(`SELECT parent_tenant_id FROM ${table} WHERE id = ?`, this.id);
|
|
2866
|
-
const stored = rows[0]?.parent_tenant_id;
|
|
2867
|
-
if (rows[0] && stored !== null && stored !== void 0 && String(stored) === parentId) return;
|
|
2868
|
-
}
|
|
2869
|
-
const { TenantCollection } = await Promise.resolve().then(() => TenantCollection_exports);
|
|
2870
|
-
if (!(await (await TenantCollection.create({ db: this.db })).get({ id: parentId }))?.id) throw new TenantHierarchyError(`Parent tenant not found: ${parentId}`, "PARENT_NOT_FOUND");
|
|
2871
|
-
}
|
|
2872
|
-
/**
|
|
2873
|
-
* Get ancestor IDs from the hierarchy path.
|
|
2874
|
-
* Returns an array of tenant IDs from root to immediate parent.
|
|
2875
|
-
* Empty array for root tenants.
|
|
2876
|
-
*/
|
|
2877
|
-
getAncestorIds() {
|
|
2878
|
-
if (!this.hierarchyPath) return [];
|
|
2879
|
-
return this.hierarchyPath.split("/").filter((id) => id.length > 0);
|
|
2880
|
-
}
|
|
2881
|
-
};
|
|
2882
|
-
__decorateClass$1$1([field({ type: "text" })], Tenant.prototype, "status", 2);
|
|
2883
|
-
__decorateClass$1$1([foreignKey("Tenant", { nullable: true })], Tenant.prototype, "parentTenantId", 2);
|
|
2884
|
-
Tenant = __decorateClass$1$1([smrt({
|
|
2885
|
-
tableStrategy: "sti",
|
|
2886
|
-
api: { include: ["list", "get"] },
|
|
2887
|
-
mcp: { include: ["list", "get"] },
|
|
2888
|
-
cli: { skipApiCheck: true }
|
|
2889
|
-
})], Tenant);
|
|
2890
|
-
var TenantCollection_exports = /* @__PURE__ */ __exportAll({
|
|
2891
|
-
TenantCollection: () => TenantCollection,
|
|
2892
|
-
TenantHierarchyError: () => TenantHierarchyError
|
|
2893
|
-
});
|
|
2894
|
-
var TenantCollection = class extends SmrtCollection {
|
|
2895
|
-
static _itemClass = Tenant;
|
|
2896
|
-
/**
|
|
2897
|
-
* Find tenants by status
|
|
2898
|
-
*/
|
|
2899
|
-
async findByStatus(status) {
|
|
2900
|
-
return await this.list({
|
|
2901
|
-
where: { status },
|
|
2902
|
-
orderBy: "name ASC"
|
|
2903
|
-
});
|
|
2904
|
-
}
|
|
2905
|
-
/**
|
|
2906
|
-
* Find all active tenants
|
|
2907
|
-
*/
|
|
2908
|
-
async findActive() {
|
|
2909
|
-
return await this.findByStatus(TenantStatus.ACTIVE);
|
|
2910
|
-
}
|
|
2911
|
-
/**
|
|
2912
|
-
* Find tenant by slug
|
|
2913
|
-
*/
|
|
2914
|
-
async findBySlug(slug) {
|
|
2915
|
-
const results = await this.list({
|
|
2916
|
-
where: { slug },
|
|
2917
|
-
limit: 1
|
|
2918
|
-
});
|
|
2919
|
-
return results.length > 0 ? results[0] : null;
|
|
2920
|
-
}
|
|
2921
|
-
/**
|
|
2922
|
-
* Find all root tenants (tenants with no parent)
|
|
2923
|
-
*/
|
|
2924
|
-
async findRoots() {
|
|
2925
|
-
return await this.list({
|
|
2926
|
-
where: { parentTenantId: null },
|
|
2927
|
-
orderBy: "name ASC"
|
|
2928
|
-
});
|
|
2929
|
-
}
|
|
2930
|
-
/**
|
|
2931
|
-
* Find direct children of a tenant
|
|
2932
|
-
*/
|
|
2933
|
-
async findChildren(parentTenantId) {
|
|
2934
|
-
return await this.list({
|
|
2935
|
-
where: { parentTenantId },
|
|
2936
|
-
orderBy: "name ASC"
|
|
2937
|
-
});
|
|
2938
|
-
}
|
|
2939
|
-
/**
|
|
2940
|
-
* Find the parent tenant of a given tenant
|
|
2941
|
-
*/
|
|
2942
|
-
async findParent(tenantId) {
|
|
2943
|
-
const tenant = await this.get({ id: tenantId });
|
|
2944
|
-
if (!tenant?.parentTenantId) return null;
|
|
2945
|
-
return await this.get({ id: tenant.parentTenantId });
|
|
2946
|
-
}
|
|
2947
|
-
/**
|
|
2948
|
-
* Get all ancestors of a tenant, from immediate parent to root.
|
|
2949
|
-
* Uses the hierarchyPath for efficient lookup.
|
|
2950
|
-
*/
|
|
2951
|
-
async getAncestors(tenantId) {
|
|
2952
|
-
const tenant = await this.get({ id: tenantId });
|
|
2953
|
-
if (!tenant) return [];
|
|
2954
|
-
const ancestorIds = tenant.getAncestorIds();
|
|
2955
|
-
if (ancestorIds.length === 0) return [];
|
|
2956
|
-
const ancestorsList = await this.listByIds(ancestorIds);
|
|
2957
|
-
const ancestorsMap = new Map(ancestorsList.map((a) => [a.id, a]));
|
|
2958
|
-
const ancestors = [];
|
|
2959
|
-
for (let i = ancestorIds.length - 1; i >= 0; i--) {
|
|
2960
|
-
const ancestor = ancestorsMap.get(ancestorIds[i]);
|
|
2961
|
-
if (ancestor) ancestors.push(ancestor);
|
|
2962
|
-
}
|
|
2963
|
-
return ancestors;
|
|
2964
|
-
}
|
|
2965
|
-
/**
|
|
2966
|
-
* Get all ancestors in order from root to immediate parent.
|
|
2967
|
-
* Reverse of getAncestors.
|
|
2968
|
-
*/
|
|
2969
|
-
async getAncestorsFromRoot(tenantId) {
|
|
2970
|
-
return (await this.getAncestors(tenantId)).reverse();
|
|
2971
|
-
}
|
|
2972
|
-
/**
|
|
2973
|
-
* Get all descendants of a tenant (all children, grandchildren, etc.)
|
|
2974
|
-
* Uses hierarchyPath prefix matching for efficient lookup.
|
|
2975
|
-
*/
|
|
2976
|
-
async getDescendants(tenantId) {
|
|
2977
|
-
const tenant = await this.get({ id: tenantId });
|
|
2978
|
-
if (!tenant?.id) return [];
|
|
2979
|
-
const pathPrefix = tenant.hierarchyPath ? `${tenant.hierarchyPath}/${tenant.id}` : tenant.id;
|
|
2980
|
-
return (await this.list({ where: { "hierarchyPath like": `${pathPrefix}%` } })).filter((t) => t.hierarchyPath === pathPrefix || t.hierarchyPath?.startsWith(`${pathPrefix}/`));
|
|
2981
|
-
}
|
|
2982
|
-
/**
|
|
2983
|
-
* Get siblings of a tenant (other tenants with the same parent)
|
|
2984
|
-
*/
|
|
2985
|
-
async getSiblings(tenantId) {
|
|
2986
|
-
const tenant = await this.get({ id: tenantId });
|
|
2987
|
-
if (!tenant) return [];
|
|
2988
|
-
return (await this.list({
|
|
2989
|
-
where: { parentTenantId: tenant.parentTenantId ?? null },
|
|
2990
|
-
orderBy: "name ASC"
|
|
2991
|
-
})).filter((s) => s.id !== tenantId);
|
|
2992
|
-
}
|
|
2993
|
-
/**
|
|
2994
|
-
* Check if a tenant is an ancestor of another tenant
|
|
2995
|
-
*/
|
|
2996
|
-
async isAncestorOf(potentialAncestorId, tenantId) {
|
|
2997
|
-
const tenant = await this.get({ id: tenantId });
|
|
2998
|
-
if (!tenant) return false;
|
|
2999
|
-
return tenant.getAncestorIds().includes(potentialAncestorId);
|
|
3000
|
-
}
|
|
3001
|
-
/**
|
|
3002
|
-
* Check if a tenant is a descendant of another tenant
|
|
3003
|
-
*/
|
|
3004
|
-
async isDescendantOf(potentialDescendantId, tenantId) {
|
|
3005
|
-
return await this.isAncestorOf(tenantId, potentialDescendantId);
|
|
3006
|
-
}
|
|
3007
|
-
/**
|
|
3008
|
-
* Create a child tenant under a parent.
|
|
3009
|
-
* `hierarchyLevel` and `hierarchyPath` are derived by {@link Tenant.save}.
|
|
3010
|
-
*
|
|
3011
|
-
* @throws {TenantHierarchyError} `PARENT_NOT_FOUND` or `MAX_DEPTH_EXCEEDED`.
|
|
3012
|
-
*/
|
|
3013
|
-
async createChild(parentTenantId, options) {
|
|
3014
|
-
return await this.create({
|
|
3015
|
-
name: options.name,
|
|
3016
|
-
slug: options.slug,
|
|
3017
|
-
description: options.description ?? "",
|
|
3018
|
-
status: options.status ?? TenantStatus.ACTIVE,
|
|
3019
|
-
parentTenantId,
|
|
3020
|
-
cascadePermissions: options.cascadePermissions ?? true,
|
|
3021
|
-
inheritPermissions: options.inheritPermissions ?? true
|
|
3022
|
-
});
|
|
3023
|
-
}
|
|
3024
|
-
/**
|
|
3025
|
-
* Move a tenant to a new parent (or to the root with `null`).
|
|
3026
|
-
*
|
|
3027
|
-
* {@link Tenant.save} checks the new parent is visible under the caller's
|
|
3028
|
-
* tenancy scope, recomputes the tenant's hierarchy fields from the real
|
|
3029
|
-
* parent chain and re-materializes every descendant, refusing the move
|
|
3030
|
-
* before writing anything when it would create a cycle or push any
|
|
3031
|
-
* descendant past `MAX_TENANT_HIERARCHY_DEPTH`.
|
|
3032
|
-
*/
|
|
3033
|
-
async moveToParent(tenantId, newParentId) {
|
|
3034
|
-
const tenant = await this.get({ id: tenantId });
|
|
3035
|
-
if (!tenant?.id) throw new TenantHierarchyError(`Tenant not found: ${tenantId}`, "INVALID_OPERATION");
|
|
3036
|
-
if (newParentId === tenantId) throw new TenantHierarchyError("Cannot move tenant to itself", "CIRCULAR_REFERENCE");
|
|
3037
|
-
tenant.parentTenantId = newParentId;
|
|
3038
|
-
await tenant.save();
|
|
3039
|
-
return tenant;
|
|
3040
|
-
}
|
|
3041
|
-
/**
|
|
3042
|
-
* Make a tenant a root tenant (remove from hierarchy)
|
|
3043
|
-
*/
|
|
3044
|
-
async makeRoot(tenantId) {
|
|
3045
|
-
return await this.moveToParent(tenantId, null);
|
|
3046
|
-
}
|
|
3047
|
-
/**
|
|
3048
|
-
* Validate that a tenant hierarchy is consistent.
|
|
3049
|
-
* Returns validation errors if any.
|
|
3050
|
-
*/
|
|
3051
|
-
async validateHierarchy(tenantId) {
|
|
3052
|
-
const errors = [];
|
|
3053
|
-
const tenant = await this.get({ id: tenantId });
|
|
3054
|
-
if (!tenant) return [`Tenant not found: ${tenantId}`];
|
|
3055
|
-
if (tenant.parentTenantId) {
|
|
3056
|
-
const parent = await this.get({ id: tenant.parentTenantId });
|
|
3057
|
-
if (!parent) errors.push(`Parent tenant not found: ${tenant.parentTenantId}`);
|
|
3058
|
-
else {
|
|
3059
|
-
if (tenant.hierarchyLevel !== parent.hierarchyLevel + 1) errors.push(`Hierarchy level mismatch: expected ${parent.hierarchyLevel + 1}, got ${tenant.hierarchyLevel}`);
|
|
3060
|
-
const expectedPath = parent.hierarchyPath ? `${parent.hierarchyPath}/${parent.id}` : parent.id;
|
|
3061
|
-
if (tenant.hierarchyPath !== expectedPath) errors.push(`Hierarchy path mismatch: expected "${expectedPath}", got "${tenant.hierarchyPath}"`);
|
|
3062
|
-
}
|
|
3063
|
-
} else {
|
|
3064
|
-
if (tenant.hierarchyLevel !== 0) errors.push(`Root tenant should have hierarchyLevel 0, got ${tenant.hierarchyLevel}`);
|
|
3065
|
-
if (tenant.hierarchyPath !== "") errors.push(`Root tenant should have empty hierarchyPath, got "${tenant.hierarchyPath}"`);
|
|
3066
|
-
}
|
|
3067
|
-
if (tenant.parentTenantId && tenant.id) {
|
|
3068
|
-
if (tenant.getAncestorIds().includes(tenant.id)) errors.push("Circular reference detected in hierarchy");
|
|
3069
|
-
}
|
|
3070
|
-
return errors;
|
|
3071
|
-
}
|
|
3072
|
-
/**
|
|
3073
|
-
* Get the full hierarchy tree starting from a tenant.
|
|
3074
|
-
* Returns a nested structure useful for UI rendering.
|
|
3075
|
-
*/
|
|
3076
|
-
async getTree(rootTenantId) {
|
|
3077
|
-
const roots = rootTenantId ? [await this.get({ id: rootTenantId })] : await this.findRoots();
|
|
3078
|
-
const buildTree = async (tenant) => {
|
|
3079
|
-
if (!tenant) return null;
|
|
3080
|
-
const children = await this.findChildren(tenant.id);
|
|
3081
|
-
const childTrees = await Promise.all(children.map(buildTree));
|
|
3082
|
-
return Object.assign(tenant, { children: childTrees.filter(Boolean) });
|
|
3083
|
-
};
|
|
3084
|
-
return (await Promise.all(roots.map(buildTree))).filter(Boolean);
|
|
3085
|
-
}
|
|
3086
|
-
};
|
|
3087
|
-
var __defProp$15 = Object.defineProperty;
|
|
3088
|
-
var __getOwnPropDesc$14 = Object.getOwnPropertyDescriptor;
|
|
3089
|
-
var __decorateClass$14 = (decorators, target, key, kind) => {
|
|
3090
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$14(target, key) : target;
|
|
3091
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
3092
|
-
if (kind && result) __defProp$15(target, key, result);
|
|
3093
|
-
return result;
|
|
3094
|
-
};
|
|
3095
|
-
var TenantPermissionOverride = class extends SmrtObject {
|
|
3096
|
-
tenantId;
|
|
3097
|
-
permissionId;
|
|
3098
|
-
effect = TenantPermissionEffect.INHERIT;
|
|
3099
|
-
constructor(options = {}) {
|
|
3100
|
-
super(options);
|
|
3101
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
3102
|
-
if (options.permissionId !== void 0) this.permissionId = options.permissionId;
|
|
3103
|
-
if (options.effect !== void 0) this.effect = options.effect;
|
|
3104
|
-
}
|
|
3105
|
-
/**
|
|
3106
|
-
* Check if this override inherits from parent
|
|
3107
|
-
*/
|
|
3108
|
-
isInherit() {
|
|
3109
|
-
return this.effect === TenantPermissionEffect.INHERIT;
|
|
3110
|
-
}
|
|
3111
|
-
/**
|
|
3112
|
-
* Check if this override grants the permission
|
|
3113
|
-
*/
|
|
3114
|
-
isGrant() {
|
|
3115
|
-
return this.effect === TenantPermissionEffect.GRANT;
|
|
3116
|
-
}
|
|
3117
|
-
/**
|
|
3118
|
-
* Check if this override denies the permission
|
|
3119
|
-
*/
|
|
3120
|
-
isDeny() {
|
|
3121
|
-
return this.effect === TenantPermissionEffect.DENY;
|
|
3122
|
-
}
|
|
3123
|
-
/**
|
|
3124
|
-
* Check if this override has an explicit effect (not inherit)
|
|
3125
|
-
*/
|
|
3126
|
-
hasExplicitEffect() {
|
|
3127
|
-
return this.effect !== TenantPermissionEffect.INHERIT;
|
|
3128
|
-
}
|
|
3129
|
-
};
|
|
3130
|
-
__decorateClass$14([foreignKey("Tenant", { required: true })], TenantPermissionOverride.prototype, "tenantId", 2);
|
|
3131
|
-
__decorateClass$14([foreignKey("Permission", { required: true })], TenantPermissionOverride.prototype, "permissionId", 2);
|
|
3132
|
-
__decorateClass$14([field({ type: "text" })], TenantPermissionOverride.prototype, "effect", 2);
|
|
3133
|
-
TenantPermissionOverride = __decorateClass$14([smrt({
|
|
3134
|
-
api: { include: ["list", "get"] },
|
|
3135
|
-
mcp: { include: ["list", "get"] },
|
|
3136
|
-
cli: { skipApiCheck: true }
|
|
3137
|
-
})], TenantPermissionOverride);
|
|
3138
|
-
new TextEncoder();
|
|
3139
|
-
new TextDecoder();
|
|
3140
|
-
new TextDecoder("utf-8", { fatal: !0 });
|
|
3141
|
-
function table(entries) {
|
|
3142
|
-
const out = { __proto__: null };
|
|
3143
|
-
for (const alg in entries) out[alg] = {
|
|
3144
|
-
...entries[alg],
|
|
3145
|
-
alg
|
|
3146
|
-
};
|
|
3147
|
-
return out;
|
|
3148
|
-
}
|
|
3149
|
-
var sig = [["verify"], ["sign"]];
|
|
3150
|
-
function hmac(bits) {
|
|
3151
|
-
const subtle = {
|
|
3152
|
-
name: "HMAC",
|
|
3153
|
-
hash: `SHA-${bits}`
|
|
3154
|
-
};
|
|
3155
|
-
return {
|
|
3156
|
-
kty: ["oct"],
|
|
3157
|
-
secret: !0,
|
|
3158
|
-
subtle,
|
|
3159
|
-
signing: subtle,
|
|
3160
|
-
usages: sig
|
|
3161
|
-
};
|
|
3162
|
-
}
|
|
3163
|
-
function rsa(bits, saltLength) {
|
|
3164
|
-
const subtle = {
|
|
3165
|
-
name: saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
3166
|
-
hash: `SHA-${bits}`
|
|
3167
|
-
};
|
|
3168
|
-
return {
|
|
3169
|
-
kty: ["RSA"],
|
|
3170
|
-
subtle,
|
|
3171
|
-
signing: saltLength ? {
|
|
3172
|
-
...subtle,
|
|
3173
|
-
saltLength
|
|
3174
|
-
} : subtle,
|
|
3175
|
-
usages: sig,
|
|
3176
|
-
minRsaBits: 2048
|
|
3177
|
-
};
|
|
3178
|
-
}
|
|
3179
|
-
function ecdsa(crv, bits) {
|
|
3180
|
-
return {
|
|
3181
|
-
kty: ["EC"],
|
|
3182
|
-
crv,
|
|
3183
|
-
subtle: {
|
|
3184
|
-
name: "ECDSA",
|
|
3185
|
-
namedCurve: crv
|
|
3186
|
-
},
|
|
3187
|
-
signing: {
|
|
3188
|
-
name: "ECDSA",
|
|
3189
|
-
hash: `SHA-${bits}`
|
|
3190
|
-
},
|
|
3191
|
-
usages: sig
|
|
3192
|
-
};
|
|
3193
|
-
}
|
|
3194
|
-
function eddsa() {
|
|
3195
|
-
const subtle = { name: "Ed25519" };
|
|
3196
|
-
return {
|
|
3197
|
-
kty: ["OKP"],
|
|
3198
|
-
crv: "Ed25519",
|
|
3199
|
-
subtle,
|
|
3200
|
-
signing: subtle,
|
|
3201
|
-
usages: sig
|
|
3202
|
-
};
|
|
3203
|
-
}
|
|
3204
|
-
function mldsa(bits) {
|
|
3205
|
-
const subtle = { name: `ML-DSA-${bits}` };
|
|
3206
|
-
return {
|
|
3207
|
-
kty: ["AKP"],
|
|
3208
|
-
subtle,
|
|
3209
|
-
signing: subtle,
|
|
3210
|
-
usages: sig
|
|
3211
|
-
};
|
|
3212
|
-
}
|
|
3213
|
-
table({
|
|
3214
|
-
HS256: hmac(256),
|
|
3215
|
-
HS384: hmac(384),
|
|
3216
|
-
HS512: hmac(512),
|
|
3217
|
-
RS256: rsa(256),
|
|
3218
|
-
RS384: rsa(384),
|
|
3219
|
-
RS512: rsa(512),
|
|
3220
|
-
PS256: rsa(256, 32),
|
|
3221
|
-
PS384: rsa(384, 48),
|
|
3222
|
-
PS512: rsa(512, 64),
|
|
3223
|
-
ES256: ecdsa("P-256", 256),
|
|
3224
|
-
ES384: ecdsa("P-384", 384),
|
|
3225
|
-
ES512: ecdsa("P-521", 512),
|
|
3226
|
-
EdDSA: eddsa(),
|
|
3227
|
-
Ed25519: eddsa(),
|
|
3228
|
-
"ML-DSA-44": mldsa(44),
|
|
3229
|
-
"ML-DSA-65": mldsa(65),
|
|
3230
|
-
"ML-DSA-87": mldsa(87)
|
|
3231
|
-
});
|
|
3232
|
-
typeof navigator > "u" || navigator.userAgent?.startsWith?.("Mozilla/5.0 ");
|
|
3233
|
-
var PERMISSION_STORAGE_KEY = /* @__PURE__ */ Symbol.for("smrt:session-permission-context-storage");
|
|
3234
|
-
function resolvePermissionContextStorage() {
|
|
3235
|
-
const root = globalThis;
|
|
3236
|
-
root[PERMISSION_STORAGE_KEY] ??= new AsyncLocalStorage();
|
|
3237
|
-
return root[PERMISSION_STORAGE_KEY];
|
|
3238
|
-
}
|
|
3239
|
-
var requestPermissionContextStorage = resolvePermissionContextStorage();
|
|
3240
|
-
function getCurrentSessionPermissionContext() {
|
|
3241
|
-
return requestPermissionContextStorage.getStore();
|
|
3242
|
-
}
|
|
3243
|
-
function getRequestScopedDatabase() {
|
|
3244
|
-
return getCurrentSessionPermissionContext()?.database;
|
|
3245
|
-
}
|
|
3246
|
-
globalThis.__smrtGetRequestPermissionContext ??= getCurrentSessionPermissionContext;
|
|
3247
|
-
globalThis.__smrtGetRequestScopedDatabase ??= getRequestScopedDatabase;
|
|
3248
|
-
//#endregion
|
|
3249
|
-
//#region ../users/dist/index.js
|
|
3250
|
-
var __defProp$3 = Object.defineProperty;
|
|
3251
|
-
var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
|
|
3252
|
-
var __decorateClass$3 = (decorators, target, key, kind) => {
|
|
3253
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
|
|
3254
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
3255
|
-
if (kind && result) __defProp$3(target, key, result);
|
|
3256
|
-
return result;
|
|
3257
|
-
};
|
|
3258
|
-
var UsersMagicLinkToken = class extends SmrtObject {
|
|
3259
|
-
nonce = "";
|
|
3260
|
-
/** Email address this token was generated for */
|
|
3261
|
-
email = "";
|
|
3262
|
-
/** Whether this token has been used */
|
|
3263
|
-
used = false;
|
|
3264
|
-
expiresAt = new Date(Date.now() + 600 * 1e3);
|
|
3265
|
-
constructor(options = {}) {
|
|
3266
|
-
super(options);
|
|
3267
|
-
if (options.nonce !== void 0) this.nonce = options.nonce;
|
|
3268
|
-
if (options.email !== void 0) this.email = options.email;
|
|
3269
|
-
if (options.used !== void 0) this.used = options.used;
|
|
3270
|
-
if (options.expiresAt !== void 0) this.expiresAt = options.expiresAt instanceof Date ? options.expiresAt : new Date(options.expiresAt);
|
|
3271
|
-
}
|
|
3272
|
-
/** Check if the token has expired */
|
|
3273
|
-
isExpired() {
|
|
3274
|
-
return /* @__PURE__ */ new Date() > this.expiresAt;
|
|
3275
|
-
}
|
|
3276
|
-
/** Check if the token is still valid (unused and not expired) */
|
|
3277
|
-
isValid() {
|
|
3278
|
-
return !this.used && !this.isExpired();
|
|
3279
|
-
}
|
|
3280
|
-
};
|
|
3281
|
-
__decorateClass$3([field({
|
|
3282
|
-
required: true,
|
|
3283
|
-
unique: true
|
|
3284
|
-
})], UsersMagicLinkToken.prototype, "nonce", 2);
|
|
3285
|
-
__decorateClass$3([field({
|
|
3286
|
-
type: "datetime",
|
|
3287
|
-
indexed: true
|
|
3288
|
-
})], UsersMagicLinkToken.prototype, "expiresAt", 2);
|
|
3289
|
-
UsersMagicLinkToken = __decorateClass$3([smrt({
|
|
3290
|
-
tableName: "users_magic_link_tokens",
|
|
3291
|
-
sensitive: true,
|
|
3292
|
-
api: { include: [] },
|
|
3293
|
-
mcp: { include: [] },
|
|
3294
|
-
cli: { skipApiCheck: true }
|
|
3295
|
-
})], UsersMagicLinkToken);
|
|
3296
|
-
var UsersMagicLinkTokenCollection = class extends SmrtCollection {
|
|
3297
|
-
static _itemClass = UsersMagicLinkToken;
|
|
3298
|
-
/**
|
|
3299
|
-
* Find a token by its nonce
|
|
3300
|
-
*/
|
|
3301
|
-
async findByNonce(nonce) {
|
|
3302
|
-
return this.findOne({ where: { nonce } });
|
|
3303
|
-
}
|
|
3304
|
-
/**
|
|
3305
|
-
* Atomically mark a token as used (single-use enforcement).
|
|
3306
|
-
*
|
|
3307
|
-
* Returns true if the nonce was successfully claimed (transitioned from
|
|
3308
|
-
* unused to used). Returns false if the nonce was already used, expired,
|
|
3309
|
-
* or doesn't exist — preventing race conditions in concurrent verify() calls.
|
|
3310
|
-
*/
|
|
3311
|
-
async markUsed(nonce) {
|
|
3312
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3313
|
-
const { rowCount } = await this.db.query(`UPDATE ${this.tableName}
|
|
3314
|
-
SET used = ?, updated_at = ?
|
|
3315
|
-
WHERE nonce = ? AND used = ? AND expires_at > ?`, true, now, nonce, false, now);
|
|
3316
|
-
return rowCount > 0;
|
|
3317
|
-
}
|
|
3318
|
-
/**
|
|
3319
|
-
* Delete expired tokens (cleanup job)
|
|
3320
|
-
*
|
|
3321
|
-
* Scheduled by the framework retention sweep (#2375); `expiresAt` carries an
|
|
3322
|
-
* index for this predicate.
|
|
3323
|
-
*
|
|
3324
|
-
* @param options.dryRun - Count the tokens the predicate selects without
|
|
3325
|
-
* deleting them.
|
|
3326
|
-
* @returns Number of tokens deleted (or, under `dryRun`, matched)
|
|
3327
|
-
*/
|
|
3328
|
-
async deleteExpired(options = {}) {
|
|
3329
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3330
|
-
const predicate = "expires_at < ?";
|
|
3331
|
-
const counted = await this.db.query(`SELECT COUNT(*) AS total FROM ${this.tableName} WHERE ${predicate}`, now);
|
|
3332
|
-
const total = Number(counted.rows?.[0]?.total ?? 0);
|
|
3333
|
-
if (!Number.isFinite(total) || total <= 0) return 0;
|
|
3334
|
-
if (!options.dryRun) await this.db.query(`DELETE FROM ${this.tableName} WHERE ${predicate}`, now);
|
|
3335
|
-
return total;
|
|
3336
|
-
}
|
|
3337
|
-
};
|
|
3338
|
-
var SESSIONS_RETENTION_TASK = "users-sessions";
|
|
3339
|
-
var MAGIC_LINK_RETENTION_TASK = "users-magic-link-tokens";
|
|
3340
|
-
var CLI_AUTH_RETENTION_TASK = "users-cli-auth-requests";
|
|
3341
|
-
function registerUserRetentionTasks() {
|
|
3342
|
-
registerRetentionTask({
|
|
3343
|
-
name: SESSIONS_RETENTION_TASK,
|
|
3344
|
-
description: "Delete expired and revoked sessions",
|
|
3345
|
-
run: async (db, context) => {
|
|
3346
|
-
return (await SessionCollection.create({ db })).deleteExpired({ dryRun: context.dryRun });
|
|
3347
|
-
}
|
|
3348
|
-
});
|
|
3349
|
-
registerRetentionTask({
|
|
3350
|
-
name: MAGIC_LINK_RETENTION_TASK,
|
|
3351
|
-
description: "Delete expired magic-link tokens",
|
|
3352
|
-
run: async (db, context) => {
|
|
3353
|
-
return (await UsersMagicLinkTokenCollection.create({ db })).deleteExpired({ dryRun: context.dryRun });
|
|
3354
|
-
}
|
|
3355
|
-
});
|
|
3356
|
-
registerRetentionTask({
|
|
3357
|
-
name: CLI_AUTH_RETENTION_TASK,
|
|
3358
|
-
description: "Delete expired pending, lazily-expired, and consumed CLI auth requests",
|
|
3359
|
-
run: async (db, context) => {
|
|
3360
|
-
return (await UsersCliAuthRequestCollection.create({ db })).deleteExpired({ dryRun: context.dryRun });
|
|
3361
|
-
}
|
|
3362
|
-
});
|
|
3363
|
-
}
|
|
3364
|
-
var __defProp$2 = Object.defineProperty;
|
|
3365
|
-
var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
|
|
3366
|
-
var __decorateClass$2 = (decorators, target, key, kind) => {
|
|
3367
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
|
|
3368
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
3369
|
-
if (kind && result) __defProp$2(target, key, result);
|
|
3370
|
-
return result;
|
|
3371
|
-
};
|
|
3372
|
-
var AccessRequest = class extends SmrtObject {
|
|
3373
|
-
email = "";
|
|
3374
|
-
name = null;
|
|
3375
|
-
status = AccessRequestStatus.REQUESTED;
|
|
3376
|
-
source = "";
|
|
3377
|
-
requestContext = "{}";
|
|
3378
|
-
note = null;
|
|
3379
|
-
requestedAt = /* @__PURE__ */ new Date();
|
|
3380
|
-
decidedAt = null;
|
|
3381
|
-
decidedBy = null;
|
|
3382
|
-
resultingUserId = null;
|
|
3383
|
-
tenantHint = null;
|
|
3384
|
-
constructor(options = {}) {
|
|
3385
|
-
super(options);
|
|
3386
|
-
if (options.email !== void 0) this.email = normalizeEmail(options.email);
|
|
3387
|
-
if (options.name !== void 0) this.name = options.name;
|
|
3388
|
-
if (options.status !== void 0) this.status = options.status;
|
|
3389
|
-
if (options.source !== void 0) this.source = options.source;
|
|
3390
|
-
if (options.requestContext !== void 0) this.requestContext = options.requestContext;
|
|
3391
|
-
if (options.note !== void 0) this.note = options.note;
|
|
3392
|
-
if (options.requestedAt !== void 0) this.requestedAt = options.requestedAt;
|
|
3393
|
-
if (options.decidedAt !== void 0) this.decidedAt = options.decidedAt;
|
|
3394
|
-
if (options.decidedBy !== void 0) this.decidedBy = options.decidedBy;
|
|
3395
|
-
if (options.resultingUserId !== void 0) this.resultingUserId = options.resultingUserId;
|
|
3396
|
-
if (options.tenantHint !== void 0) this.tenantHint = options.tenantHint;
|
|
3397
|
-
}
|
|
3398
|
-
/**
|
|
3399
|
-
* Parse {@link requestContext} into an object. Returns `{}` on missing or
|
|
3400
|
-
* malformed JSON (graceful — never throws).
|
|
3401
|
-
*/
|
|
3402
|
-
getRequestContext() {
|
|
3403
|
-
try {
|
|
3404
|
-
const parsed = JSON.parse(this.requestContext);
|
|
3405
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
3406
|
-
} catch {
|
|
3407
|
-
return {};
|
|
3408
|
-
}
|
|
3409
|
-
}
|
|
3410
|
-
/**
|
|
3411
|
-
* Serialize and store {@link requestContext} from an object.
|
|
3412
|
-
*/
|
|
3413
|
-
setRequestContext(value) {
|
|
3414
|
-
this.requestContext = JSON.stringify(value ?? {});
|
|
3415
|
-
}
|
|
3416
|
-
/**
|
|
3417
|
-
* Parse {@link tenantHint} into an object, or `null` when unset / malformed.
|
|
3418
|
-
*/
|
|
3419
|
-
getTenantHint() {
|
|
3420
|
-
if (!this.tenantHint) return null;
|
|
3421
|
-
try {
|
|
3422
|
-
const parsed = JSON.parse(this.tenantHint);
|
|
3423
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
3424
|
-
} catch {
|
|
3425
|
-
return null;
|
|
3426
|
-
}
|
|
3427
|
-
}
|
|
3428
|
-
/**
|
|
3429
|
-
* Serialize and store {@link tenantHint} from an object (or clear with null).
|
|
3430
|
-
*/
|
|
3431
|
-
setTenantHint(value) {
|
|
3432
|
-
this.tenantHint = value ? JSON.stringify(value) : null;
|
|
3433
|
-
}
|
|
3434
|
-
/**
|
|
3435
|
-
* Whether the request is still open (awaiting a decision).
|
|
3436
|
-
*/
|
|
3437
|
-
isOpen() {
|
|
3438
|
-
return this.status === AccessRequestStatus.REQUESTED;
|
|
3439
|
-
}
|
|
3440
|
-
/**
|
|
3441
|
-
* Whether the request has been approved (and not yet graduated).
|
|
3442
|
-
*/
|
|
3443
|
-
isApproved() {
|
|
3444
|
-
return this.status === AccessRequestStatus.APPROVED;
|
|
3445
|
-
}
|
|
3446
|
-
/**
|
|
3447
|
-
* Whether the request reached a terminal state (declined, graduated, or
|
|
3448
|
-
* canceled) and can no longer transition.
|
|
3449
|
-
*/
|
|
3450
|
-
isTerminal() {
|
|
3451
|
-
return this.status === AccessRequestStatus.DECLINED || this.status === AccessRequestStatus.GRADUATED || this.status === AccessRequestStatus.CANCELED;
|
|
3452
|
-
}
|
|
3453
|
-
};
|
|
3454
|
-
__decorateClass$2([field({
|
|
3455
|
-
required: true,
|
|
3456
|
-
indexed: true
|
|
3457
|
-
})], AccessRequest.prototype, "email", 2);
|
|
3458
|
-
__decorateClass$2([field({ nullable: true })], AccessRequest.prototype, "name", 2);
|
|
3459
|
-
__decorateClass$2([field({
|
|
3460
|
-
type: "text",
|
|
3461
|
-
indexed: true
|
|
3462
|
-
})], AccessRequest.prototype, "status", 2);
|
|
3463
|
-
__decorateClass$2([field({ indexed: true })], AccessRequest.prototype, "source", 2);
|
|
3464
|
-
__decorateClass$2([field()], AccessRequest.prototype, "requestContext", 2);
|
|
3465
|
-
__decorateClass$2([field({ nullable: true })], AccessRequest.prototype, "note", 2);
|
|
3466
|
-
__decorateClass$2([field()], AccessRequest.prototype, "requestedAt", 2);
|
|
3467
|
-
__decorateClass$2([field({ nullable: true })], AccessRequest.prototype, "decidedAt", 2);
|
|
3468
|
-
__decorateClass$2([field({ nullable: true })], AccessRequest.prototype, "decidedBy", 2);
|
|
3469
|
-
__decorateClass$2([field({ nullable: true })], AccessRequest.prototype, "resultingUserId", 2);
|
|
3470
|
-
__decorateClass$2([field({ nullable: true })], AccessRequest.prototype, "tenantHint", 2);
|
|
3471
|
-
AccessRequest = __decorateClass$2([smrt({
|
|
3472
|
-
tableName: "access_requests",
|
|
3473
|
-
conflictColumns: ["id"],
|
|
3474
|
-
api: { include: [] },
|
|
3475
|
-
mcp: { include: [] },
|
|
3476
|
-
cli: { include: [] }
|
|
3477
|
-
})], AccessRequest);
|
|
3478
|
-
var __defProp$1 = Object.defineProperty;
|
|
3479
|
-
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
3480
|
-
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
3481
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
3482
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
3483
|
-
if (kind && result) __defProp$1(target, key, result);
|
|
3484
|
-
return result;
|
|
3485
|
-
};
|
|
3486
|
-
var ResourceGrant = class extends SmrtObject {
|
|
3487
|
-
tenantId;
|
|
3488
|
-
userId;
|
|
3489
|
-
resourceType = "";
|
|
3490
|
-
resourceId = "";
|
|
3491
|
-
permission = "";
|
|
3492
|
-
effect = "grant";
|
|
3493
|
-
canDelegate = false;
|
|
3494
|
-
parentGrantId;
|
|
3495
|
-
revokedAt;
|
|
3496
|
-
constructor(options = {}) {
|
|
3497
|
-
super(options);
|
|
3498
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
3499
|
-
if (options.userId !== void 0) this.userId = options.userId;
|
|
3500
|
-
if (options.resourceType !== void 0) this.resourceType = options.resourceType;
|
|
3501
|
-
if (options.resourceId !== void 0) this.resourceId = options.resourceId;
|
|
3502
|
-
if (options.permission !== void 0) this.permission = options.permission;
|
|
3503
|
-
if (options.effect !== void 0) this.effect = options.effect;
|
|
3504
|
-
if (options.canDelegate !== void 0) this.canDelegate = options.canDelegate;
|
|
3505
|
-
if (options.parentGrantId !== void 0) this.parentGrantId = options.parentGrantId;
|
|
3506
|
-
if (options.revokedAt !== void 0) this.revokedAt = options.revokedAt;
|
|
3507
|
-
}
|
|
3508
|
-
isActive() {
|
|
3509
|
-
return !this.revokedAt;
|
|
3510
|
-
}
|
|
3511
|
-
};
|
|
3512
|
-
__decorateClass$1([foreignKey("Tenant", { required: true })], ResourceGrant.prototype, "tenantId", 2);
|
|
3513
|
-
__decorateClass$1([foreignKey("User", { required: true })], ResourceGrant.prototype, "userId", 2);
|
|
3514
|
-
__decorateClass$1([field({ type: "text" })], ResourceGrant.prototype, "resourceType", 2);
|
|
3515
|
-
__decorateClass$1([field({ type: "text" })], ResourceGrant.prototype, "resourceId", 2);
|
|
3516
|
-
__decorateClass$1([field({ type: "text" })], ResourceGrant.prototype, "permission", 2);
|
|
3517
|
-
__decorateClass$1([field({ type: "text" })], ResourceGrant.prototype, "effect", 2);
|
|
3518
|
-
__decorateClass$1([foreignKey("ResourceGrant")], ResourceGrant.prototype, "parentGrantId", 2);
|
|
3519
|
-
__decorateClass$1([field({ type: "text" })], ResourceGrant.prototype, "revokedAt", 2);
|
|
3520
|
-
ResourceGrant = __decorateClass$1([smrt({
|
|
3521
|
-
tenantScoped: true,
|
|
3522
|
-
api: { include: [] },
|
|
3523
|
-
mcp: { include: [] },
|
|
3524
|
-
cli: { skipApiCheck: true },
|
|
3525
|
-
indexes: [{
|
|
3526
|
-
name: "resource_grants_lookup_idx",
|
|
3527
|
-
columns: ["tenantId", "userId"]
|
|
3528
|
-
}]
|
|
3529
|
-
})], ResourceGrant);
|
|
3530
|
-
var __defProp = Object.defineProperty;
|
|
3531
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3532
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
|
3533
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
3534
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
3535
|
-
if (kind && result) __defProp(target, key, result);
|
|
3536
|
-
return result;
|
|
3537
|
-
};
|
|
3538
|
-
function parseExternalIds(raw) {
|
|
3539
|
-
if (!raw) return {};
|
|
3540
|
-
if (typeof raw === "object" && !Array.isArray(raw)) return Object.fromEntries(Object.entries(raw).filter(([, value]) => typeof value === "string"));
|
|
3541
|
-
if (typeof raw !== "string") return {};
|
|
3542
|
-
try {
|
|
3543
|
-
const parsed = JSON.parse(raw);
|
|
3544
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
3545
|
-
return Object.fromEntries(Object.entries(parsed).filter(([, value]) => typeof value === "string"));
|
|
3546
|
-
} catch {
|
|
3547
|
-
return {};
|
|
3548
|
-
}
|
|
3549
|
-
}
|
|
3550
|
-
function stringifyExternalIds(externalIds) {
|
|
3551
|
-
for (const [key, value] of Object.entries(externalIds)) if (typeof value !== "string") throw new TypeError(`TenantIntegration external id '${key}' must be a string`);
|
|
3552
|
-
return JSON.stringify(externalIds);
|
|
3553
|
-
}
|
|
3554
|
-
function parseCheckSummary(raw) {
|
|
3555
|
-
if (!raw) return [];
|
|
3556
|
-
if (Array.isArray(raw)) return normalizeCheckSummary(raw);
|
|
3557
|
-
if (typeof raw !== "string") return [];
|
|
3558
|
-
try {
|
|
3559
|
-
const parsed = JSON.parse(raw);
|
|
3560
|
-
return Array.isArray(parsed) ? normalizeCheckSummary(parsed) : [];
|
|
3561
|
-
} catch {
|
|
3562
|
-
return [];
|
|
3563
|
-
}
|
|
3564
|
-
}
|
|
3565
|
-
function normalizeCheckSummary(raw) {
|
|
3566
|
-
return raw.filter((entry) => !!entry && typeof entry === "object" && !Array.isArray(entry)).map((entry) => ({
|
|
3567
|
-
name: typeof entry.name === "string" ? entry.name : "",
|
|
3568
|
-
ok: entry.ok === true,
|
|
3569
|
-
...typeof entry.message === "string" ? { message: entry.message } : {}
|
|
3570
|
-
})).filter((entry) => entry.name.length > 0);
|
|
3571
|
-
}
|
|
3572
|
-
function stringifyCheckSummary(summary) {
|
|
3573
|
-
return JSON.stringify(summary);
|
|
3574
|
-
}
|
|
3575
|
-
var TenantIntegration = class extends SmrtObject {
|
|
3576
|
-
tenantId = "";
|
|
3577
|
-
/**
|
|
3578
|
-
* Provider identifier, such as `aws`, `matomo`, `glitchtip`, or an
|
|
3579
|
-
* app-defined provider string.
|
|
3580
|
-
*/
|
|
3581
|
-
provider = "aws";
|
|
3582
|
-
/**
|
|
3583
|
-
* Provider-side identifiers. Shape depends on the provider. This must not
|
|
3584
|
-
* contain provider credentials or secret material.
|
|
3585
|
-
*/
|
|
3586
|
-
externalIds = "{}";
|
|
3587
|
-
/**
|
|
3588
|
-
* Current provisioning/health status.
|
|
3589
|
-
*/
|
|
3590
|
-
status = "unprovisioned";
|
|
3591
|
-
/**
|
|
3592
|
-
* UTC timestamp of the most recent doctor/provisioning check.
|
|
3593
|
-
*/
|
|
3594
|
-
lastCheckedAt = null;
|
|
3595
|
-
/**
|
|
3596
|
-
* Per-check pass/fail summary from the most recent doctor run.
|
|
3597
|
-
*/
|
|
3598
|
-
lastCheckSummary = "[]";
|
|
3599
|
-
/**
|
|
3600
|
-
* Most recent error message when `status === 'failed'`, or null otherwise.
|
|
3601
|
-
*/
|
|
3602
|
-
lastError = null;
|
|
3603
|
-
constructor(options = {}) {
|
|
3604
|
-
super(options);
|
|
3605
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
3606
|
-
if (options.provider !== void 0) this.provider = options.provider;
|
|
3607
|
-
if (options.externalIds !== void 0) this.setExternalIds(options.externalIds);
|
|
3608
|
-
if (options.status !== void 0) this.status = options.status;
|
|
3609
|
-
if (options.lastCheckedAt !== void 0) this.lastCheckedAt = options.lastCheckedAt;
|
|
3610
|
-
if (options.lastCheckSummary !== void 0) this.setLastCheckSummary(options.lastCheckSummary);
|
|
3611
|
-
if (options.lastError !== void 0) this.lastError = options.lastError;
|
|
3612
|
-
}
|
|
3613
|
-
async initialize() {
|
|
3614
|
-
await super.initialize();
|
|
3615
|
-
this.normalizeJsonFields();
|
|
3616
|
-
return this;
|
|
3617
|
-
}
|
|
3618
|
-
normalizeJsonFields() {
|
|
3619
|
-
const fields = this;
|
|
3620
|
-
if (fields.externalIds == null) this.externalIds = "{}";
|
|
3621
|
-
else if (typeof fields.externalIds !== "string") this.setExternalIds(fields.externalIds);
|
|
3622
|
-
if (fields.lastCheckSummary == null) this.lastCheckSummary = "[]";
|
|
3623
|
-
else if (typeof fields.lastCheckSummary !== "string") this.setLastCheckSummary(fields.lastCheckSummary);
|
|
3624
|
-
}
|
|
3625
|
-
getExternalIds() {
|
|
3626
|
-
return parseExternalIds(this.externalIds);
|
|
3627
|
-
}
|
|
3628
|
-
setExternalIds(externalIds) {
|
|
3629
|
-
this.externalIds = typeof externalIds === "string" ? externalIds : stringifyExternalIds(externalIds);
|
|
3630
|
-
}
|
|
3631
|
-
getExternalId(key) {
|
|
3632
|
-
const value = this.getExternalIds()[key];
|
|
3633
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3634
|
-
}
|
|
3635
|
-
setExternalId(key, value) {
|
|
3636
|
-
const externalIds = this.getExternalIds();
|
|
3637
|
-
if (value === void 0) delete externalIds[key];
|
|
3638
|
-
else externalIds[key] = value;
|
|
3639
|
-
this.setExternalIds(externalIds);
|
|
3640
|
-
}
|
|
3641
|
-
getLastCheckSummary() {
|
|
3642
|
-
return parseCheckSummary(this.lastCheckSummary);
|
|
3643
|
-
}
|
|
3644
|
-
setLastCheckSummary(summary) {
|
|
3645
|
-
this.lastCheckSummary = typeof summary === "string" ? summary : stringifyCheckSummary(summary);
|
|
3646
|
-
}
|
|
3647
|
-
recordDoctorRun(outcome) {
|
|
3648
|
-
this.status = outcome.status;
|
|
3649
|
-
this.setLastCheckSummary(outcome.summary);
|
|
3650
|
-
this.lastCheckedAt = /* @__PURE__ */ new Date();
|
|
3651
|
-
this.lastError = outcome.error ?? null;
|
|
3652
|
-
}
|
|
3653
|
-
};
|
|
3654
|
-
__decorateClass([tenantId()], TenantIntegration.prototype, "tenantId", 2);
|
|
3655
|
-
TenantIntegration = __decorateClass([TenantScoped({ mode: "required" }), smrt({
|
|
3656
|
-
tableName: "tenant_integrations",
|
|
3657
|
-
conflictColumns: ["tenant_id", "provider"],
|
|
3658
|
-
api: { include: ["list", "get"] },
|
|
3659
|
-
mcp: { include: ["list", "get"] },
|
|
3660
|
-
cli: { skipApiCheck: true }
|
|
3661
|
-
})], TenantIntegration);
|
|
3662
|
-
var TenantHierarchyMaterializationError = class extends Error {
|
|
3663
|
-
constructor(problems) {
|
|
3664
|
-
super(`Cannot materialize the tenant hierarchy: ${problems.length} tenant(s) have a broken parent chain. ` + problems.map((problem) => problem.message).join(" "));
|
|
3665
|
-
this.problems = problems;
|
|
3666
|
-
this.name = "TenantHierarchyMaterializationError";
|
|
3667
|
-
}
|
|
3668
|
-
problems;
|
|
3669
|
-
};
|
|
3670
|
-
function toRow(row) {
|
|
3671
|
-
const id = row.id === null || row.id === void 0 ? "" : String(row.id);
|
|
3672
|
-
if (!id) throw new Error("Tenant hierarchy backfill found a row without an id.");
|
|
3673
|
-
const parent = row.parent_tenant_id === null || row.parent_tenant_id === void 0 ? null : String(row.parent_tenant_id);
|
|
3674
|
-
const level = row.hierarchy_level === null || row.hierarchy_level === void 0 ? null : Number(row.hierarchy_level);
|
|
3675
|
-
return {
|
|
3676
|
-
id,
|
|
3677
|
-
parentTenantId: parent === "" ? null : parent,
|
|
3678
|
-
hierarchyPath: row.hierarchy_path === null || row.hierarchy_path === void 0 ? null : String(row.hierarchy_path),
|
|
3679
|
-
hierarchyLevel: Number.isFinite(level) ? level : null
|
|
3680
|
-
};
|
|
3681
|
-
}
|
|
3682
|
-
async function planFrom(db, table) {
|
|
3683
|
-
const { rows } = await db.query(`SELECT id, parent_tenant_id, hierarchy_path, hierarchy_level FROM ${table} ORDER BY id`);
|
|
3684
|
-
return planTenantHierarchy(rows.map(toRow));
|
|
3685
|
-
}
|
|
3686
|
-
async function materializeTenantHierarchy(db, options = {}) {
|
|
3687
|
-
const table = assertTenantTableName(options.tableName ?? "tenants");
|
|
3688
|
-
if (options.dryRun) return {
|
|
3689
|
-
...await planFrom(db, table),
|
|
3690
|
-
applied: false
|
|
3691
|
-
};
|
|
3692
|
-
const run = async (handle) => {
|
|
3693
|
-
const plan = await planFrom(handle, table);
|
|
3694
|
-
if (plan.problems.length > 0) throw new TenantHierarchyMaterializationError(plan.problems);
|
|
3695
|
-
await applyTenantHierarchyUpdates(handle, table, plan.changes);
|
|
3696
|
-
return {
|
|
3697
|
-
...plan,
|
|
3698
|
-
applied: true
|
|
3699
|
-
};
|
|
3700
|
-
};
|
|
3701
|
-
if (!db.transaction) throw new Error("Tenant hierarchy materialization requires a database with transaction(); no changes were made.");
|
|
3702
|
-
const result = await db.transaction((tx) => run(tx));
|
|
3703
|
-
if (result.changes.length > 0) await recordTenantHierarchyChanges(db, table);
|
|
3704
|
-
return result;
|
|
3705
|
-
}
|
|
3706
|
-
createLogger({ level: "info" });
|
|
3707
|
-
AccessRequestStatus.REQUESTED;
|
|
3708
|
-
AccessRequestStatus.REQUESTED, AccessRequestStatus.APPROVED;
|
|
3709
|
-
AccessRequestStatus.REQUESTED, AccessRequestStatus.APPROVED;
|
|
3710
|
-
registerUserRetentionTasks();
|
|
3711
|
-
//#endregion
|
|
3712
|
-
export { ApiKeyCollection as A, OidcIdentityCollection as C, AuditLog as D, NostrIdentityCollection_exports as E, AuditLogCollection as O, AmbiguousOidcIdentityError as S, NostrIdentityCollection as T, TenantHierarchyMaterializationError, ProfileMetadataCollection as _, ProfileRelationshipTypeCollection as a, ProfileAssetCollection as b, ProfileRelationshipTermCollection as c, ProfileRelationshipCollection as d, ProfileRelationshipCollection_exports as f, ProfileMetadata as g, ProfileMetafieldCollection_exports as h, resolveIdentity_exports as i, ApiKeyCollection_exports as j, AuditLogCollection_exports as k, ProfileRelationshipTermCollection_exports as l, ProfileMetafieldCollection as m, materializeTenantHierarchy, createProfileFromOidc as n, ProfileRelationshipTypeCollection_exports as o, ProfileMetafield as p, resolveIdentity as r, ProfileRelationshipTerm as s, createProfileFromNostr as t, ProfileRelationship as u, ProfileMetadataCollection_exports as v, OidcIdentityCollection_exports as w, ProfileAssetCollection_exports as x, ProfileAsset as y };
|