@contractspec/lib.identity-rbac 3.7.6 → 3.7.10
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/README.md +62 -90
- package/dist/browser/contracts/index.js +3 -3
- package/dist/browser/contracts/organization.js +2 -2
- package/dist/browser/contracts/rbac.js +2 -2
- package/dist/browser/contracts/user.js +1 -1
- package/dist/browser/entities/index.js +283 -283
- package/dist/browser/events.js +1 -1
- package/dist/browser/index.js +287 -287
- package/dist/contracts/index.d.ts +3 -3
- package/dist/contracts/index.js +3 -3
- package/dist/contracts/organization.js +2 -2
- package/dist/contracts/rbac.js +2 -2
- package/dist/contracts/user.js +1 -1
- package/dist/entities/index.d.ts +69 -69
- package/dist/entities/index.js +283 -283
- package/dist/events.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +287 -287
- package/dist/node/contracts/index.js +3 -3
- package/dist/node/contracts/organization.js +2 -2
- package/dist/node/contracts/rbac.js +2 -2
- package/dist/node/contracts/user.js +1 -1
- package/dist/node/entities/index.js +283 -283
- package/dist/node/events.js +1 -1
- package/dist/node/index.js +287 -287
- package/dist/policies/index.d.ts +1 -1
- package/package.json +7 -7
package/dist/entities/index.js
CHANGED
|
@@ -1,173 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// src/entities/user.ts
|
|
3
|
-
import { defineEntity, field, index } from "@contractspec/lib.schema";
|
|
4
|
-
var UserEntity = defineEntity({
|
|
5
|
-
name: "User",
|
|
6
|
-
description: "A user of the platform. Users hold core profile information and authenticate via Account records.",
|
|
7
|
-
schema: "lssm_sigil",
|
|
8
|
-
map: "user",
|
|
9
|
-
fields: {
|
|
10
|
-
id: field.id({ description: "Unique user identifier" }),
|
|
11
|
-
email: field.email({ isUnique: true, description: "User email address" }),
|
|
12
|
-
emailVerified: field.boolean({
|
|
13
|
-
default: false,
|
|
14
|
-
description: "Whether email has been verified"
|
|
15
|
-
}),
|
|
16
|
-
name: field.string({ isOptional: true, description: "Display name" }),
|
|
17
|
-
firstName: field.string({ isOptional: true, description: "First name" }),
|
|
18
|
-
lastName: field.string({ isOptional: true, description: "Last name" }),
|
|
19
|
-
locale: field.string({
|
|
20
|
-
isOptional: true,
|
|
21
|
-
description: 'User locale (e.g., "en-US")'
|
|
22
|
-
}),
|
|
23
|
-
timezone: field.string({
|
|
24
|
-
isOptional: true,
|
|
25
|
-
description: 'Olson timezone (e.g., "Europe/Paris")'
|
|
26
|
-
}),
|
|
27
|
-
imageUrl: field.url({
|
|
28
|
-
isOptional: true,
|
|
29
|
-
description: "URL of avatar or profile picture"
|
|
30
|
-
}),
|
|
31
|
-
image: field.string({
|
|
32
|
-
isOptional: true,
|
|
33
|
-
description: "Legacy image field"
|
|
34
|
-
}),
|
|
35
|
-
metadata: field.json({
|
|
36
|
-
isOptional: true,
|
|
37
|
-
description: "Arbitrary user metadata"
|
|
38
|
-
}),
|
|
39
|
-
onboardingCompleted: field.boolean({
|
|
40
|
-
default: false,
|
|
41
|
-
description: "Whether onboarding is complete"
|
|
42
|
-
}),
|
|
43
|
-
onboardingStep: field.string({
|
|
44
|
-
isOptional: true,
|
|
45
|
-
description: "Current onboarding step"
|
|
46
|
-
}),
|
|
47
|
-
whitelistedAt: field.dateTime({
|
|
48
|
-
isOptional: true,
|
|
49
|
-
description: "When user was whitelisted"
|
|
50
|
-
}),
|
|
51
|
-
role: field.string({
|
|
52
|
-
isOptional: true,
|
|
53
|
-
default: '"user"',
|
|
54
|
-
description: "User role (user, admin)"
|
|
55
|
-
}),
|
|
56
|
-
banned: field.boolean({
|
|
57
|
-
default: false,
|
|
58
|
-
description: "Whether user is banned"
|
|
59
|
-
}),
|
|
60
|
-
banReason: field.string({
|
|
61
|
-
isOptional: true,
|
|
62
|
-
description: "Reason for ban"
|
|
63
|
-
}),
|
|
64
|
-
banExpires: field.dateTime({
|
|
65
|
-
isOptional: true,
|
|
66
|
-
description: "When ban expires"
|
|
67
|
-
}),
|
|
68
|
-
phoneNumber: field.string({
|
|
69
|
-
isOptional: true,
|
|
70
|
-
isUnique: true,
|
|
71
|
-
description: "Phone number"
|
|
72
|
-
}),
|
|
73
|
-
phoneNumberVerified: field.boolean({
|
|
74
|
-
default: false,
|
|
75
|
-
description: "Whether phone is verified"
|
|
76
|
-
}),
|
|
77
|
-
createdAt: field.createdAt(),
|
|
78
|
-
updatedAt: field.updatedAt(),
|
|
79
|
-
sessions: field.hasMany("Session"),
|
|
80
|
-
accounts: field.hasMany("Account"),
|
|
81
|
-
memberships: field.hasMany("Member"),
|
|
82
|
-
invitations: field.hasMany("Invitation"),
|
|
83
|
-
teamMemberships: field.hasMany("TeamMember"),
|
|
84
|
-
policyBindings: field.hasMany("PolicyBinding"),
|
|
85
|
-
apiKeys: field.hasMany("ApiKey"),
|
|
86
|
-
passkeys: field.hasMany("Passkey")
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
var SessionEntity = defineEntity({
|
|
90
|
-
name: "Session",
|
|
91
|
-
description: "Represents a login session (e.g., web session or API token).",
|
|
92
|
-
schema: "lssm_sigil",
|
|
93
|
-
map: "session",
|
|
94
|
-
fields: {
|
|
95
|
-
id: field.id(),
|
|
96
|
-
userId: field.foreignKey(),
|
|
97
|
-
expiresAt: field.dateTime({ description: "Session expiration time" }),
|
|
98
|
-
token: field.string({ isUnique: true, description: "Session token" }),
|
|
99
|
-
ipAddress: field.string({
|
|
100
|
-
isOptional: true,
|
|
101
|
-
description: "Client IP address"
|
|
102
|
-
}),
|
|
103
|
-
userAgent: field.string({
|
|
104
|
-
isOptional: true,
|
|
105
|
-
description: "Client user agent"
|
|
106
|
-
}),
|
|
107
|
-
impersonatedBy: field.string({
|
|
108
|
-
isOptional: true,
|
|
109
|
-
description: "Admin impersonating this session"
|
|
110
|
-
}),
|
|
111
|
-
activeOrganizationId: field.string({
|
|
112
|
-
isOptional: true,
|
|
113
|
-
description: "Active org context"
|
|
114
|
-
}),
|
|
115
|
-
activeTeamId: field.string({
|
|
116
|
-
isOptional: true,
|
|
117
|
-
description: "Active team context"
|
|
118
|
-
}),
|
|
119
|
-
createdAt: field.createdAt(),
|
|
120
|
-
updatedAt: field.updatedAt(),
|
|
121
|
-
user: field.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
var AccountEntity = defineEntity({
|
|
125
|
-
name: "Account",
|
|
126
|
-
description: "External authentication accounts (OAuth, password, etc.).",
|
|
127
|
-
schema: "lssm_sigil",
|
|
128
|
-
map: "account",
|
|
129
|
-
fields: {
|
|
130
|
-
id: field.id(),
|
|
131
|
-
accountId: field.string({ description: "Account ID from provider" }),
|
|
132
|
-
providerId: field.string({ description: "Provider identifier" }),
|
|
133
|
-
userId: field.foreignKey(),
|
|
134
|
-
accessToken: field.string({ isOptional: true }),
|
|
135
|
-
refreshToken: field.string({ isOptional: true }),
|
|
136
|
-
idToken: field.string({ isOptional: true }),
|
|
137
|
-
accessTokenExpiresAt: field.dateTime({ isOptional: true }),
|
|
138
|
-
refreshTokenExpiresAt: field.dateTime({ isOptional: true }),
|
|
139
|
-
scope: field.string({ isOptional: true }),
|
|
140
|
-
password: field.string({
|
|
141
|
-
isOptional: true,
|
|
142
|
-
description: "Hashed password for password providers"
|
|
143
|
-
}),
|
|
144
|
-
createdAt: field.createdAt(),
|
|
145
|
-
updatedAt: field.updatedAt(),
|
|
146
|
-
user: field.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
147
|
-
},
|
|
148
|
-
indexes: [index.unique(["accountId", "providerId"])]
|
|
149
|
-
});
|
|
150
|
-
var VerificationEntity = defineEntity({
|
|
151
|
-
name: "Verification",
|
|
152
|
-
description: "Verification tokens for email/phone confirmation.",
|
|
153
|
-
schema: "lssm_sigil",
|
|
154
|
-
map: "verification",
|
|
155
|
-
fields: {
|
|
156
|
-
id: field.uuid(),
|
|
157
|
-
identifier: field.string({ description: "Email or phone being verified" }),
|
|
158
|
-
value: field.string({ description: "Verification code/token" }),
|
|
159
|
-
expiresAt: field.dateTime({ description: "Token expiration" }),
|
|
160
|
-
createdAt: field.createdAt(),
|
|
161
|
-
updatedAt: field.updatedAt()
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
2
|
// src/entities/organization.ts
|
|
166
3
|
import {
|
|
167
|
-
defineEntity
|
|
4
|
+
defineEntity,
|
|
168
5
|
defineEntityEnum,
|
|
169
|
-
field
|
|
170
|
-
index
|
|
6
|
+
field,
|
|
7
|
+
index
|
|
171
8
|
} from "@contractspec/lib.schema";
|
|
172
9
|
var OrganizationTypeEnum = defineEntityEnum({
|
|
173
10
|
name: "OrganizationType",
|
|
@@ -175,251 +12,414 @@ var OrganizationTypeEnum = defineEntityEnum({
|
|
|
175
12
|
schema: "lssm_sigil",
|
|
176
13
|
description: "Type of organization in the platform."
|
|
177
14
|
});
|
|
178
|
-
var OrganizationEntity =
|
|
15
|
+
var OrganizationEntity = defineEntity({
|
|
179
16
|
name: "Organization",
|
|
180
17
|
description: "An organization is a tenant boundary grouping users.",
|
|
181
18
|
schema: "lssm_sigil",
|
|
182
19
|
map: "organization",
|
|
183
20
|
fields: {
|
|
184
|
-
id:
|
|
185
|
-
name:
|
|
186
|
-
slug:
|
|
21
|
+
id: field.id({ description: "Unique organization identifier" }),
|
|
22
|
+
name: field.string({ description: "Organization display name" }),
|
|
23
|
+
slug: field.string({
|
|
187
24
|
isOptional: true,
|
|
188
25
|
isUnique: true,
|
|
189
26
|
description: "URL-friendly identifier"
|
|
190
27
|
}),
|
|
191
|
-
logo:
|
|
192
|
-
description:
|
|
28
|
+
logo: field.url({ isOptional: true, description: "Organization logo URL" }),
|
|
29
|
+
description: field.string({
|
|
193
30
|
isOptional: true,
|
|
194
31
|
description: "Organization description"
|
|
195
32
|
}),
|
|
196
|
-
metadata:
|
|
33
|
+
metadata: field.json({
|
|
197
34
|
isOptional: true,
|
|
198
35
|
description: "Arbitrary organization metadata"
|
|
199
36
|
}),
|
|
200
|
-
type:
|
|
201
|
-
onboardingCompleted:
|
|
202
|
-
onboardingStep:
|
|
203
|
-
referralCode:
|
|
37
|
+
type: field.enum("OrganizationType", { description: "Organization type" }),
|
|
38
|
+
onboardingCompleted: field.boolean({ default: false }),
|
|
39
|
+
onboardingStep: field.string({ isOptional: true }),
|
|
40
|
+
referralCode: field.string({
|
|
204
41
|
isOptional: true,
|
|
205
42
|
isUnique: true,
|
|
206
43
|
description: "Unique referral code"
|
|
207
44
|
}),
|
|
208
|
-
referredBy:
|
|
45
|
+
referredBy: field.string({
|
|
209
46
|
isOptional: true,
|
|
210
47
|
description: "ID of referring user"
|
|
211
48
|
}),
|
|
212
|
-
createdAt:
|
|
213
|
-
updatedAt:
|
|
214
|
-
members:
|
|
215
|
-
invitations:
|
|
216
|
-
teams:
|
|
217
|
-
policyBindings:
|
|
49
|
+
createdAt: field.createdAt(),
|
|
50
|
+
updatedAt: field.updatedAt(),
|
|
51
|
+
members: field.hasMany("Member"),
|
|
52
|
+
invitations: field.hasMany("Invitation"),
|
|
53
|
+
teams: field.hasMany("Team"),
|
|
54
|
+
policyBindings: field.hasMany("PolicyBinding")
|
|
218
55
|
},
|
|
219
56
|
enums: [OrganizationTypeEnum]
|
|
220
57
|
});
|
|
221
|
-
var MemberEntity =
|
|
58
|
+
var MemberEntity = defineEntity({
|
|
222
59
|
name: "Member",
|
|
223
60
|
description: "Membership of a user in an organization with a role.",
|
|
224
61
|
schema: "lssm_sigil",
|
|
225
62
|
map: "member",
|
|
226
63
|
fields: {
|
|
227
|
-
id:
|
|
228
|
-
userId:
|
|
229
|
-
organizationId:
|
|
230
|
-
role:
|
|
64
|
+
id: field.id(),
|
|
65
|
+
userId: field.foreignKey(),
|
|
66
|
+
organizationId: field.foreignKey(),
|
|
67
|
+
role: field.string({
|
|
231
68
|
description: "Role in organization (owner, admin, member)"
|
|
232
69
|
}),
|
|
233
|
-
createdAt:
|
|
234
|
-
user:
|
|
235
|
-
organization:
|
|
70
|
+
createdAt: field.createdAt(),
|
|
71
|
+
user: field.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" }),
|
|
72
|
+
organization: field.belongsTo("Organization", ["organizationId"], ["id"], {
|
|
236
73
|
onDelete: "Cascade"
|
|
237
74
|
})
|
|
238
75
|
},
|
|
239
|
-
indexes: [
|
|
76
|
+
indexes: [index.unique(["userId", "organizationId"])]
|
|
240
77
|
});
|
|
241
|
-
var InvitationEntity =
|
|
78
|
+
var InvitationEntity = defineEntity({
|
|
242
79
|
name: "Invitation",
|
|
243
80
|
description: "An invitation to join an organization.",
|
|
244
81
|
schema: "lssm_sigil",
|
|
245
82
|
map: "invitation",
|
|
246
83
|
fields: {
|
|
247
|
-
id:
|
|
248
|
-
organizationId:
|
|
249
|
-
email:
|
|
250
|
-
role:
|
|
84
|
+
id: field.id(),
|
|
85
|
+
organizationId: field.foreignKey(),
|
|
86
|
+
email: field.email({ description: "Invited email address" }),
|
|
87
|
+
role: field.string({
|
|
251
88
|
isOptional: true,
|
|
252
89
|
description: "Role to assign on acceptance"
|
|
253
90
|
}),
|
|
254
|
-
status:
|
|
91
|
+
status: field.string({
|
|
255
92
|
default: '"pending"',
|
|
256
93
|
description: "Invitation status"
|
|
257
94
|
}),
|
|
258
|
-
acceptedAt:
|
|
259
|
-
expiresAt:
|
|
260
|
-
inviterId:
|
|
95
|
+
acceptedAt: field.dateTime({ isOptional: true }),
|
|
96
|
+
expiresAt: field.dateTime({ isOptional: true }),
|
|
97
|
+
inviterId: field.foreignKey({
|
|
261
98
|
description: "User who sent the invitation"
|
|
262
99
|
}),
|
|
263
|
-
teamId:
|
|
264
|
-
createdAt:
|
|
265
|
-
updatedAt:
|
|
266
|
-
organization:
|
|
100
|
+
teamId: field.string({ isOptional: true }),
|
|
101
|
+
createdAt: field.createdAt(),
|
|
102
|
+
updatedAt: field.updatedAt(),
|
|
103
|
+
organization: field.belongsTo("Organization", ["organizationId"], ["id"], {
|
|
267
104
|
onDelete: "Cascade"
|
|
268
105
|
}),
|
|
269
|
-
inviter:
|
|
106
|
+
inviter: field.belongsTo("User", ["inviterId"], ["id"], {
|
|
270
107
|
onDelete: "Cascade"
|
|
271
108
|
}),
|
|
272
|
-
team:
|
|
109
|
+
team: field.belongsTo("Team", ["teamId"], ["id"], { onDelete: "Cascade" })
|
|
273
110
|
}
|
|
274
111
|
});
|
|
275
|
-
var TeamEntity =
|
|
112
|
+
var TeamEntity = defineEntity({
|
|
276
113
|
name: "Team",
|
|
277
114
|
description: "Team within an organization.",
|
|
278
115
|
schema: "lssm_sigil",
|
|
279
116
|
map: "team",
|
|
280
117
|
fields: {
|
|
281
|
-
id:
|
|
282
|
-
name:
|
|
283
|
-
organizationId:
|
|
284
|
-
createdAt:
|
|
285
|
-
updatedAt:
|
|
286
|
-
organization:
|
|
118
|
+
id: field.id(),
|
|
119
|
+
name: field.string({ description: "Team name" }),
|
|
120
|
+
organizationId: field.foreignKey(),
|
|
121
|
+
createdAt: field.createdAt(),
|
|
122
|
+
updatedAt: field.updatedAt(),
|
|
123
|
+
organization: field.belongsTo("Organization", ["organizationId"], ["id"], {
|
|
287
124
|
onDelete: "Cascade"
|
|
288
125
|
}),
|
|
289
|
-
members:
|
|
290
|
-
invitations:
|
|
126
|
+
members: field.hasMany("TeamMember"),
|
|
127
|
+
invitations: field.hasMany("Invitation")
|
|
291
128
|
}
|
|
292
129
|
});
|
|
293
|
-
var TeamMemberEntity =
|
|
130
|
+
var TeamMemberEntity = defineEntity({
|
|
294
131
|
name: "TeamMember",
|
|
295
132
|
description: "Team membership for a user.",
|
|
296
133
|
schema: "lssm_sigil",
|
|
297
134
|
map: "team_member",
|
|
298
135
|
fields: {
|
|
299
|
-
id:
|
|
300
|
-
teamId:
|
|
301
|
-
userId:
|
|
302
|
-
createdAt:
|
|
303
|
-
team:
|
|
304
|
-
user:
|
|
136
|
+
id: field.id(),
|
|
137
|
+
teamId: field.foreignKey(),
|
|
138
|
+
userId: field.foreignKey(),
|
|
139
|
+
createdAt: field.createdAt(),
|
|
140
|
+
team: field.belongsTo("Team", ["teamId"], ["id"], { onDelete: "Cascade" }),
|
|
141
|
+
user: field.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
305
142
|
}
|
|
306
143
|
});
|
|
307
144
|
|
|
308
145
|
// src/entities/rbac.ts
|
|
309
|
-
import { defineEntity as
|
|
310
|
-
var RoleEntity =
|
|
146
|
+
import { defineEntity as defineEntity2, field as field2, index as index2 } from "@contractspec/lib.schema";
|
|
147
|
+
var RoleEntity = defineEntity2({
|
|
311
148
|
name: "Role",
|
|
312
149
|
description: "A role defines a named set of permissions.",
|
|
313
150
|
schema: "lssm_sigil",
|
|
314
151
|
map: "role",
|
|
315
152
|
fields: {
|
|
316
|
-
id:
|
|
317
|
-
name:
|
|
318
|
-
description:
|
|
153
|
+
id: field2.id(),
|
|
154
|
+
name: field2.string({ isUnique: true, description: "Unique role name" }),
|
|
155
|
+
description: field2.string({
|
|
319
156
|
isOptional: true,
|
|
320
157
|
description: "Role description"
|
|
321
158
|
}),
|
|
322
|
-
permissions:
|
|
159
|
+
permissions: field2.string({
|
|
323
160
|
isArray: true,
|
|
324
161
|
description: "Array of permission names"
|
|
325
162
|
}),
|
|
326
|
-
createdAt:
|
|
327
|
-
updatedAt:
|
|
328
|
-
policyBindings:
|
|
163
|
+
createdAt: field2.createdAt(),
|
|
164
|
+
updatedAt: field2.updatedAt(),
|
|
165
|
+
policyBindings: field2.hasMany("PolicyBinding")
|
|
329
166
|
}
|
|
330
167
|
});
|
|
331
|
-
var PermissionEntity =
|
|
168
|
+
var PermissionEntity = defineEntity2({
|
|
332
169
|
name: "Permission",
|
|
333
170
|
description: "A permission represents an atomic access right.",
|
|
334
171
|
schema: "lssm_sigil",
|
|
335
172
|
map: "permission",
|
|
336
173
|
fields: {
|
|
337
|
-
id:
|
|
338
|
-
name:
|
|
174
|
+
id: field2.id(),
|
|
175
|
+
name: field2.string({
|
|
339
176
|
isUnique: true,
|
|
340
177
|
description: "Unique permission name"
|
|
341
178
|
}),
|
|
342
|
-
description:
|
|
179
|
+
description: field2.string({
|
|
343
180
|
isOptional: true,
|
|
344
181
|
description: "Permission description"
|
|
345
182
|
}),
|
|
346
|
-
createdAt:
|
|
347
|
-
updatedAt:
|
|
183
|
+
createdAt: field2.createdAt(),
|
|
184
|
+
updatedAt: field2.updatedAt()
|
|
348
185
|
}
|
|
349
186
|
});
|
|
350
|
-
var PolicyBindingEntity =
|
|
187
|
+
var PolicyBindingEntity = defineEntity2({
|
|
351
188
|
name: "PolicyBinding",
|
|
352
189
|
description: "Binds roles to principals (users or organizations).",
|
|
353
190
|
schema: "lssm_sigil",
|
|
354
191
|
map: "policy_binding",
|
|
355
192
|
fields: {
|
|
356
|
-
id:
|
|
357
|
-
roleId:
|
|
358
|
-
targetType:
|
|
359
|
-
targetId:
|
|
360
|
-
expiresAt:
|
|
193
|
+
id: field2.id(),
|
|
194
|
+
roleId: field2.foreignKey(),
|
|
195
|
+
targetType: field2.string({ description: '"user" or "organization"' }),
|
|
196
|
+
targetId: field2.string({ description: "ID of User or Organization" }),
|
|
197
|
+
expiresAt: field2.dateTime({
|
|
361
198
|
isOptional: true,
|
|
362
199
|
description: "When binding expires"
|
|
363
200
|
}),
|
|
364
|
-
createdAt:
|
|
365
|
-
userId:
|
|
366
|
-
organizationId:
|
|
367
|
-
role:
|
|
368
|
-
user:
|
|
369
|
-
organization:
|
|
201
|
+
createdAt: field2.createdAt(),
|
|
202
|
+
userId: field2.string({ isOptional: true }),
|
|
203
|
+
organizationId: field2.string({ isOptional: true }),
|
|
204
|
+
role: field2.belongsTo("Role", ["roleId"], ["id"], { onDelete: "Cascade" }),
|
|
205
|
+
user: field2.belongsTo("User", ["userId"], ["id"]),
|
|
206
|
+
organization: field2.belongsTo("Organization", ["organizationId"], ["id"])
|
|
370
207
|
},
|
|
371
|
-
indexes: [
|
|
208
|
+
indexes: [index2.on(["targetType", "targetId"])]
|
|
372
209
|
});
|
|
373
|
-
var ApiKeyEntity =
|
|
210
|
+
var ApiKeyEntity = defineEntity2({
|
|
374
211
|
name: "ApiKey",
|
|
375
212
|
description: "API keys for programmatic access.",
|
|
376
213
|
schema: "lssm_sigil",
|
|
377
214
|
map: "api_key",
|
|
378
215
|
fields: {
|
|
379
|
-
id:
|
|
380
|
-
name:
|
|
381
|
-
start:
|
|
216
|
+
id: field2.id(),
|
|
217
|
+
name: field2.string({ description: "API key name" }),
|
|
218
|
+
start: field2.string({
|
|
382
219
|
description: "Starting characters for identification"
|
|
383
220
|
}),
|
|
384
|
-
prefix:
|
|
385
|
-
key:
|
|
221
|
+
prefix: field2.string({ description: "API key prefix" }),
|
|
222
|
+
key: field2.string({ description: "Hashed API key" }),
|
|
223
|
+
userId: field2.foreignKey(),
|
|
224
|
+
refillInterval: field2.int({ description: "Refill interval in ms" }),
|
|
225
|
+
refillAmount: field2.int({ description: "Amount to refill" }),
|
|
226
|
+
lastRefillAt: field2.dateTime(),
|
|
227
|
+
remaining: field2.int({ description: "Remaining requests" }),
|
|
228
|
+
requestCount: field2.int({ description: "Total requests made" }),
|
|
229
|
+
lastRequest: field2.dateTime(),
|
|
230
|
+
enabled: field2.boolean({ default: true }),
|
|
231
|
+
rateLimitEnabled: field2.boolean({ default: true }),
|
|
232
|
+
rateLimitTimeWindow: field2.int({ description: "Rate limit window in ms" }),
|
|
233
|
+
rateLimitMax: field2.int({ description: "Max requests in window" }),
|
|
234
|
+
expiresAt: field2.dateTime(),
|
|
235
|
+
permissions: field2.string({ isArray: true }),
|
|
236
|
+
metadata: field2.json({ isOptional: true }),
|
|
237
|
+
createdAt: field2.createdAt(),
|
|
238
|
+
updatedAt: field2.updatedAt(),
|
|
239
|
+
user: field2.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
var PasskeyEntity = defineEntity2({
|
|
243
|
+
name: "Passkey",
|
|
244
|
+
description: "WebAuthn passkeys for passwordless authentication.",
|
|
245
|
+
schema: "lssm_sigil",
|
|
246
|
+
map: "passkey",
|
|
247
|
+
fields: {
|
|
248
|
+
id: field2.id(),
|
|
249
|
+
name: field2.string({ description: "Passkey name" }),
|
|
250
|
+
publicKey: field2.string({ description: "Public key" }),
|
|
251
|
+
userId: field2.foreignKey(),
|
|
252
|
+
credentialID: field2.string({ description: "Credential ID" }),
|
|
253
|
+
counter: field2.int({ description: "Counter" }),
|
|
254
|
+
deviceType: field2.string({ description: "Device type" }),
|
|
255
|
+
backedUp: field2.boolean({ description: "Whether passkey is backed up" }),
|
|
256
|
+
transports: field2.string({ description: "Transports" }),
|
|
257
|
+
aaguid: field2.string({ description: "Authenticator GUID" }),
|
|
258
|
+
createdAt: field2.createdAt(),
|
|
259
|
+
user: field2.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// src/entities/user.ts
|
|
264
|
+
import { defineEntity as defineEntity3, field as field3, index as index3 } from "@contractspec/lib.schema";
|
|
265
|
+
var UserEntity = defineEntity3({
|
|
266
|
+
name: "User",
|
|
267
|
+
description: "A user of the platform. Users hold core profile information and authenticate via Account records.",
|
|
268
|
+
schema: "lssm_sigil",
|
|
269
|
+
map: "user",
|
|
270
|
+
fields: {
|
|
271
|
+
id: field3.id({ description: "Unique user identifier" }),
|
|
272
|
+
email: field3.email({ isUnique: true, description: "User email address" }),
|
|
273
|
+
emailVerified: field3.boolean({
|
|
274
|
+
default: false,
|
|
275
|
+
description: "Whether email has been verified"
|
|
276
|
+
}),
|
|
277
|
+
name: field3.string({ isOptional: true, description: "Display name" }),
|
|
278
|
+
firstName: field3.string({ isOptional: true, description: "First name" }),
|
|
279
|
+
lastName: field3.string({ isOptional: true, description: "Last name" }),
|
|
280
|
+
locale: field3.string({
|
|
281
|
+
isOptional: true,
|
|
282
|
+
description: 'User locale (e.g., "en-US")'
|
|
283
|
+
}),
|
|
284
|
+
timezone: field3.string({
|
|
285
|
+
isOptional: true,
|
|
286
|
+
description: 'Olson timezone (e.g., "Europe/Paris")'
|
|
287
|
+
}),
|
|
288
|
+
imageUrl: field3.url({
|
|
289
|
+
isOptional: true,
|
|
290
|
+
description: "URL of avatar or profile picture"
|
|
291
|
+
}),
|
|
292
|
+
image: field3.string({
|
|
293
|
+
isOptional: true,
|
|
294
|
+
description: "Legacy image field"
|
|
295
|
+
}),
|
|
296
|
+
metadata: field3.json({
|
|
297
|
+
isOptional: true,
|
|
298
|
+
description: "Arbitrary user metadata"
|
|
299
|
+
}),
|
|
300
|
+
onboardingCompleted: field3.boolean({
|
|
301
|
+
default: false,
|
|
302
|
+
description: "Whether onboarding is complete"
|
|
303
|
+
}),
|
|
304
|
+
onboardingStep: field3.string({
|
|
305
|
+
isOptional: true,
|
|
306
|
+
description: "Current onboarding step"
|
|
307
|
+
}),
|
|
308
|
+
whitelistedAt: field3.dateTime({
|
|
309
|
+
isOptional: true,
|
|
310
|
+
description: "When user was whitelisted"
|
|
311
|
+
}),
|
|
312
|
+
role: field3.string({
|
|
313
|
+
isOptional: true,
|
|
314
|
+
default: '"user"',
|
|
315
|
+
description: "User role (user, admin)"
|
|
316
|
+
}),
|
|
317
|
+
banned: field3.boolean({
|
|
318
|
+
default: false,
|
|
319
|
+
description: "Whether user is banned"
|
|
320
|
+
}),
|
|
321
|
+
banReason: field3.string({
|
|
322
|
+
isOptional: true,
|
|
323
|
+
description: "Reason for ban"
|
|
324
|
+
}),
|
|
325
|
+
banExpires: field3.dateTime({
|
|
326
|
+
isOptional: true,
|
|
327
|
+
description: "When ban expires"
|
|
328
|
+
}),
|
|
329
|
+
phoneNumber: field3.string({
|
|
330
|
+
isOptional: true,
|
|
331
|
+
isUnique: true,
|
|
332
|
+
description: "Phone number"
|
|
333
|
+
}),
|
|
334
|
+
phoneNumberVerified: field3.boolean({
|
|
335
|
+
default: false,
|
|
336
|
+
description: "Whether phone is verified"
|
|
337
|
+
}),
|
|
338
|
+
createdAt: field3.createdAt(),
|
|
339
|
+
updatedAt: field3.updatedAt(),
|
|
340
|
+
sessions: field3.hasMany("Session"),
|
|
341
|
+
accounts: field3.hasMany("Account"),
|
|
342
|
+
memberships: field3.hasMany("Member"),
|
|
343
|
+
invitations: field3.hasMany("Invitation"),
|
|
344
|
+
teamMemberships: field3.hasMany("TeamMember"),
|
|
345
|
+
policyBindings: field3.hasMany("PolicyBinding"),
|
|
346
|
+
apiKeys: field3.hasMany("ApiKey"),
|
|
347
|
+
passkeys: field3.hasMany("Passkey")
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
var SessionEntity = defineEntity3({
|
|
351
|
+
name: "Session",
|
|
352
|
+
description: "Represents a login session (e.g., web session or API token).",
|
|
353
|
+
schema: "lssm_sigil",
|
|
354
|
+
map: "session",
|
|
355
|
+
fields: {
|
|
356
|
+
id: field3.id(),
|
|
386
357
|
userId: field3.foreignKey(),
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
358
|
+
expiresAt: field3.dateTime({ description: "Session expiration time" }),
|
|
359
|
+
token: field3.string({ isUnique: true, description: "Session token" }),
|
|
360
|
+
ipAddress: field3.string({
|
|
361
|
+
isOptional: true,
|
|
362
|
+
description: "Client IP address"
|
|
363
|
+
}),
|
|
364
|
+
userAgent: field3.string({
|
|
365
|
+
isOptional: true,
|
|
366
|
+
description: "Client user agent"
|
|
367
|
+
}),
|
|
368
|
+
impersonatedBy: field3.string({
|
|
369
|
+
isOptional: true,
|
|
370
|
+
description: "Admin impersonating this session"
|
|
371
|
+
}),
|
|
372
|
+
activeOrganizationId: field3.string({
|
|
373
|
+
isOptional: true,
|
|
374
|
+
description: "Active org context"
|
|
375
|
+
}),
|
|
376
|
+
activeTeamId: field3.string({
|
|
377
|
+
isOptional: true,
|
|
378
|
+
description: "Active team context"
|
|
379
|
+
}),
|
|
400
380
|
createdAt: field3.createdAt(),
|
|
401
381
|
updatedAt: field3.updatedAt(),
|
|
402
382
|
user: field3.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
403
383
|
}
|
|
404
384
|
});
|
|
405
|
-
var
|
|
406
|
-
name: "
|
|
407
|
-
description: "
|
|
385
|
+
var AccountEntity = defineEntity3({
|
|
386
|
+
name: "Account",
|
|
387
|
+
description: "External authentication accounts (OAuth, password, etc.).",
|
|
408
388
|
schema: "lssm_sigil",
|
|
409
|
-
map: "
|
|
389
|
+
map: "account",
|
|
410
390
|
fields: {
|
|
411
391
|
id: field3.id(),
|
|
412
|
-
|
|
413
|
-
|
|
392
|
+
accountId: field3.string({ description: "Account ID from provider" }),
|
|
393
|
+
providerId: field3.string({ description: "Provider identifier" }),
|
|
414
394
|
userId: field3.foreignKey(),
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
395
|
+
accessToken: field3.string({ isOptional: true }),
|
|
396
|
+
refreshToken: field3.string({ isOptional: true }),
|
|
397
|
+
idToken: field3.string({ isOptional: true }),
|
|
398
|
+
accessTokenExpiresAt: field3.dateTime({ isOptional: true }),
|
|
399
|
+
refreshTokenExpiresAt: field3.dateTime({ isOptional: true }),
|
|
400
|
+
scope: field3.string({ isOptional: true }),
|
|
401
|
+
password: field3.string({
|
|
402
|
+
isOptional: true,
|
|
403
|
+
description: "Hashed password for password providers"
|
|
404
|
+
}),
|
|
421
405
|
createdAt: field3.createdAt(),
|
|
406
|
+
updatedAt: field3.updatedAt(),
|
|
422
407
|
user: field3.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
408
|
+
},
|
|
409
|
+
indexes: [index3.unique(["accountId", "providerId"])]
|
|
410
|
+
});
|
|
411
|
+
var VerificationEntity = defineEntity3({
|
|
412
|
+
name: "Verification",
|
|
413
|
+
description: "Verification tokens for email/phone confirmation.",
|
|
414
|
+
schema: "lssm_sigil",
|
|
415
|
+
map: "verification",
|
|
416
|
+
fields: {
|
|
417
|
+
id: field3.uuid(),
|
|
418
|
+
identifier: field3.string({ description: "Email or phone being verified" }),
|
|
419
|
+
value: field3.string({ description: "Verification code/token" }),
|
|
420
|
+
expiresAt: field3.dateTime({ description: "Token expiration" }),
|
|
421
|
+
createdAt: field3.createdAt(),
|
|
422
|
+
updatedAt: field3.updatedAt()
|
|
423
423
|
}
|
|
424
424
|
});
|
|
425
425
|
// src/entities/index.ts
|