@contractspec/lib.identity-rbac 1.57.0 → 1.58.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/dist/browser/contracts/index.js +1045 -0
- package/dist/browser/contracts/organization.js +655 -0
- package/dist/browser/contracts/rbac.js +599 -0
- package/dist/browser/contracts/user.js +235 -0
- package/dist/browser/entities/index.js +464 -0
- package/dist/browser/entities/organization.js +150 -0
- package/dist/browser/entities/rbac.js +124 -0
- package/dist/browser/entities/user.js +168 -0
- package/dist/browser/events.js +374 -0
- package/dist/browser/identity-rbac.capability.js +28 -0
- package/dist/browser/identity-rbac.feature.js +67 -0
- package/dist/browser/index.js +2099 -0
- package/dist/browser/policies/engine.js +154 -0
- package/dist/browser/policies/index.js +154 -0
- package/dist/contracts/index.d.ts +4 -4
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +1045 -4
- package/dist/contracts/organization.d.ts +758 -764
- package/dist/contracts/organization.d.ts.map +1 -1
- package/dist/contracts/organization.js +653 -602
- package/dist/contracts/rbac.d.ts +517 -523
- package/dist/contracts/rbac.d.ts.map +1 -1
- package/dist/contracts/rbac.js +597 -481
- package/dist/contracts/user.d.ts +513 -519
- package/dist/contracts/user.d.ts.map +1 -1
- package/dist/contracts/user.js +222 -319
- package/dist/entities/index.d.ts +164 -169
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +462 -33
- package/dist/entities/organization.d.ts +58 -63
- package/dist/entities/organization.d.ts.map +1 -1
- package/dist/entities/organization.js +145 -145
- package/dist/entities/rbac.d.ts +62 -67
- package/dist/entities/rbac.d.ts.map +1 -1
- package/dist/entities/rbac.js +119 -132
- package/dist/entities/user.d.ts +66 -71
- package/dist/entities/user.d.ts.map +1 -1
- package/dist/entities/user.js +164 -189
- package/dist/events.d.ts +537 -543
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +343 -651
- package/dist/identity-rbac.capability.d.ts +2 -7
- package/dist/identity-rbac.capability.d.ts.map +1 -1
- package/dist/identity-rbac.capability.js +29 -29
- package/dist/identity-rbac.feature.d.ts +1 -6
- package/dist/identity-rbac.feature.d.ts.map +1 -1
- package/dist/identity-rbac.feature.js +66 -193
- package/dist/index.d.ts +6 -12
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2100 -14
- package/dist/node/contracts/index.js +1045 -0
- package/dist/node/contracts/organization.js +655 -0
- package/dist/node/contracts/rbac.js +599 -0
- package/dist/node/contracts/user.js +235 -0
- package/dist/node/entities/index.js +464 -0
- package/dist/node/entities/organization.js +150 -0
- package/dist/node/entities/rbac.js +124 -0
- package/dist/node/entities/user.js +168 -0
- package/dist/node/events.js +374 -0
- package/dist/node/identity-rbac.capability.js +28 -0
- package/dist/node/identity-rbac.feature.js +67 -0
- package/dist/node/index.js +2099 -0
- package/dist/node/policies/engine.js +154 -0
- package/dist/node/policies/index.js +154 -0
- package/dist/policies/engine.d.ts +98 -101
- package/dist/policies/engine.d.ts.map +1 -1
- package/dist/policies/engine.js +151 -164
- package/dist/policies/index.d.ts +2 -2
- package/dist/policies/index.d.ts.map +1 -0
- package/dist/policies/index.js +154 -2
- package/package.json +149 -40
- package/dist/contracts/organization.js.map +0 -1
- package/dist/contracts/rbac.js.map +0 -1
- package/dist/contracts/user.js.map +0 -1
- package/dist/entities/index.js.map +0 -1
- package/dist/entities/organization.js.map +0 -1
- package/dist/entities/rbac.js.map +0 -1
- package/dist/entities/user.js.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/identity-rbac.capability.js.map +0 -1
- package/dist/identity-rbac.feature.js.map +0 -1
- package/dist/policies/engine.js.map +0 -1
|
@@ -0,0 +1,2099 @@
|
|
|
1
|
+
// src/contracts/user.ts
|
|
2
|
+
import { SchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
|
|
3
|
+
import { defineCommand, defineQuery } from "@contractspec/lib.contracts";
|
|
4
|
+
var OWNERS = ["platform.identity-rbac"];
|
|
5
|
+
var UserProfileModel = new SchemaModel({
|
|
6
|
+
name: "UserProfile",
|
|
7
|
+
description: "User profile information",
|
|
8
|
+
fields: {
|
|
9
|
+
id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
10
|
+
email: { type: ScalarTypeEnum.EmailAddress(), isOptional: false },
|
|
11
|
+
emailVerified: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
12
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
13
|
+
firstName: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
14
|
+
lastName: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
15
|
+
locale: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
16
|
+
timezone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
17
|
+
imageUrl: { type: ScalarTypeEnum.URL(), isOptional: true },
|
|
18
|
+
role: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
19
|
+
onboardingCompleted: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
20
|
+
createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
var CreateUserInputModel = new SchemaModel({
|
|
24
|
+
name: "CreateUserInput",
|
|
25
|
+
description: "Input for creating a new user",
|
|
26
|
+
fields: {
|
|
27
|
+
email: { type: ScalarTypeEnum.EmailAddress(), isOptional: false },
|
|
28
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
29
|
+
firstName: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
30
|
+
lastName: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
31
|
+
password: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
var UpdateUserInputModel = new SchemaModel({
|
|
35
|
+
name: "UpdateUserInput",
|
|
36
|
+
description: "Input for updating a user profile",
|
|
37
|
+
fields: {
|
|
38
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
39
|
+
firstName: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
40
|
+
lastName: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
41
|
+
locale: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
42
|
+
timezone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
43
|
+
imageUrl: { type: ScalarTypeEnum.URL(), isOptional: true }
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
var DeleteUserInputModel = new SchemaModel({
|
|
47
|
+
name: "DeleteUserInput",
|
|
48
|
+
description: "Input for deleting a user",
|
|
49
|
+
fields: {
|
|
50
|
+
confirmEmail: { type: ScalarTypeEnum.EmailAddress(), isOptional: false }
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
var SuccessResultModel = new SchemaModel({
|
|
54
|
+
name: "SuccessResult",
|
|
55
|
+
description: "Simple success result",
|
|
56
|
+
fields: {
|
|
57
|
+
success: { type: ScalarTypeEnum.Boolean(), isOptional: false }
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
var UserDeletedPayloadModel = new SchemaModel({
|
|
61
|
+
name: "UserDeletedPayload",
|
|
62
|
+
description: "Payload for user deleted event",
|
|
63
|
+
fields: {
|
|
64
|
+
userId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
var ListUsersInputModel = new SchemaModel({
|
|
68
|
+
name: "ListUsersInput",
|
|
69
|
+
description: "Input for listing users",
|
|
70
|
+
fields: {
|
|
71
|
+
limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
|
|
72
|
+
offset: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
|
|
73
|
+
search: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
var ListUsersOutputModel = new SchemaModel({
|
|
77
|
+
name: "ListUsersOutput",
|
|
78
|
+
description: "Output for listing users",
|
|
79
|
+
fields: {
|
|
80
|
+
users: { type: UserProfileModel, isOptional: false, isArray: true },
|
|
81
|
+
total: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
var CreateUserContract = defineCommand({
|
|
85
|
+
meta: {
|
|
86
|
+
key: "identity.user.create",
|
|
87
|
+
version: "1.0.0",
|
|
88
|
+
stability: "stable",
|
|
89
|
+
owners: [...OWNERS],
|
|
90
|
+
tags: ["identity", "user", "create"],
|
|
91
|
+
description: "Create a new user account.",
|
|
92
|
+
goal: "Register a new user in the system.",
|
|
93
|
+
context: "Used during signup flows. May trigger email verification."
|
|
94
|
+
},
|
|
95
|
+
io: {
|
|
96
|
+
input: CreateUserInputModel,
|
|
97
|
+
output: UserProfileModel,
|
|
98
|
+
errors: {
|
|
99
|
+
EMAIL_EXISTS: {
|
|
100
|
+
description: "A user with this email already exists",
|
|
101
|
+
http: 409,
|
|
102
|
+
gqlCode: "EMAIL_EXISTS",
|
|
103
|
+
when: "Email is already registered"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
policy: {
|
|
108
|
+
auth: "anonymous"
|
|
109
|
+
},
|
|
110
|
+
sideEffects: {
|
|
111
|
+
emits: [
|
|
112
|
+
{
|
|
113
|
+
key: "user.created",
|
|
114
|
+
version: "1.0.0",
|
|
115
|
+
when: "User is successfully created",
|
|
116
|
+
payload: UserProfileModel
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
audit: ["user.created"]
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
var GetCurrentUserContract = defineQuery({
|
|
123
|
+
meta: {
|
|
124
|
+
key: "identity.user.me",
|
|
125
|
+
version: "1.0.0",
|
|
126
|
+
stability: "stable",
|
|
127
|
+
owners: [...OWNERS],
|
|
128
|
+
tags: ["identity", "user", "profile"],
|
|
129
|
+
description: "Get the current authenticated user profile.",
|
|
130
|
+
goal: "Retrieve user profile for the authenticated session.",
|
|
131
|
+
context: "Called on app load and after profile updates."
|
|
132
|
+
},
|
|
133
|
+
io: {
|
|
134
|
+
input: null,
|
|
135
|
+
output: UserProfileModel
|
|
136
|
+
},
|
|
137
|
+
policy: {
|
|
138
|
+
auth: "user"
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
var UpdateUserContract = defineCommand({
|
|
142
|
+
meta: {
|
|
143
|
+
key: "identity.user.update",
|
|
144
|
+
version: "1.0.0",
|
|
145
|
+
stability: "stable",
|
|
146
|
+
owners: [...OWNERS],
|
|
147
|
+
tags: ["identity", "user", "update"],
|
|
148
|
+
description: "Update user profile information.",
|
|
149
|
+
goal: "Allow users to update their profile.",
|
|
150
|
+
context: "Self-service profile updates."
|
|
151
|
+
},
|
|
152
|
+
io: {
|
|
153
|
+
input: UpdateUserInputModel,
|
|
154
|
+
output: UserProfileModel
|
|
155
|
+
},
|
|
156
|
+
policy: {
|
|
157
|
+
auth: "user"
|
|
158
|
+
},
|
|
159
|
+
sideEffects: {
|
|
160
|
+
emits: [
|
|
161
|
+
{
|
|
162
|
+
key: "user.updated",
|
|
163
|
+
version: "1.0.0",
|
|
164
|
+
when: "User profile is updated",
|
|
165
|
+
payload: UserProfileModel
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
audit: ["user.updated"]
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
var DeleteUserContract = defineCommand({
|
|
172
|
+
meta: {
|
|
173
|
+
key: "identity.user.delete",
|
|
174
|
+
version: "1.0.0",
|
|
175
|
+
stability: "stable",
|
|
176
|
+
owners: [...OWNERS],
|
|
177
|
+
tags: ["identity", "user", "delete"],
|
|
178
|
+
description: "Delete user account and all associated data.",
|
|
179
|
+
goal: "Allow users to delete their account (GDPR compliance).",
|
|
180
|
+
context: "Self-service account deletion. Cascades to memberships, sessions, etc."
|
|
181
|
+
},
|
|
182
|
+
io: {
|
|
183
|
+
input: DeleteUserInputModel,
|
|
184
|
+
output: SuccessResultModel
|
|
185
|
+
},
|
|
186
|
+
policy: {
|
|
187
|
+
auth: "user",
|
|
188
|
+
escalate: "human_review"
|
|
189
|
+
},
|
|
190
|
+
sideEffects: {
|
|
191
|
+
emits: [
|
|
192
|
+
{
|
|
193
|
+
key: "user.deleted",
|
|
194
|
+
version: "1.0.0",
|
|
195
|
+
when: "User account is deleted",
|
|
196
|
+
payload: UserDeletedPayloadModel
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
audit: ["user.deleted"]
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
var ListUsersContract = defineQuery({
|
|
203
|
+
meta: {
|
|
204
|
+
key: "identity.user.list",
|
|
205
|
+
version: "1.0.0",
|
|
206
|
+
stability: "stable",
|
|
207
|
+
owners: [...OWNERS],
|
|
208
|
+
tags: ["identity", "user", "admin", "list"],
|
|
209
|
+
description: "List all users (admin only).",
|
|
210
|
+
goal: "Allow admins to browse and manage users.",
|
|
211
|
+
context: "Admin dashboard user management."
|
|
212
|
+
},
|
|
213
|
+
io: {
|
|
214
|
+
input: ListUsersInputModel,
|
|
215
|
+
output: ListUsersOutputModel
|
|
216
|
+
},
|
|
217
|
+
policy: {
|
|
218
|
+
auth: "admin"
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// src/contracts/organization.ts
|
|
223
|
+
import { ScalarTypeEnum as ScalarTypeEnum2, SchemaModel as SchemaModel2 } from "@contractspec/lib.schema";
|
|
224
|
+
import { defineCommand as defineCommand2, defineQuery as defineQuery2 } from "@contractspec/lib.contracts";
|
|
225
|
+
var OWNERS2 = ["platform.identity-rbac"];
|
|
226
|
+
var OrganizationModel = new SchemaModel2({
|
|
227
|
+
name: "Organization",
|
|
228
|
+
description: "Organization details",
|
|
229
|
+
fields: {
|
|
230
|
+
id: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
231
|
+
name: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
232
|
+
slug: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
233
|
+
logo: { type: ScalarTypeEnum2.URL(), isOptional: true },
|
|
234
|
+
description: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
235
|
+
type: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
236
|
+
onboardingCompleted: { type: ScalarTypeEnum2.Boolean(), isOptional: false },
|
|
237
|
+
createdAt: { type: ScalarTypeEnum2.DateTime(), isOptional: false }
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
var MemberUserModel = new SchemaModel2({
|
|
241
|
+
name: "MemberUser",
|
|
242
|
+
description: "Basic user info within a member",
|
|
243
|
+
fields: {
|
|
244
|
+
id: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
245
|
+
email: { type: ScalarTypeEnum2.EmailAddress(), isOptional: false },
|
|
246
|
+
name: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true }
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
var MemberModel = new SchemaModel2({
|
|
250
|
+
name: "Member",
|
|
251
|
+
description: "Organization member",
|
|
252
|
+
fields: {
|
|
253
|
+
id: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
254
|
+
userId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
255
|
+
organizationId: {
|
|
256
|
+
type: ScalarTypeEnum2.String_unsecure(),
|
|
257
|
+
isOptional: false
|
|
258
|
+
},
|
|
259
|
+
role: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
260
|
+
createdAt: { type: ScalarTypeEnum2.DateTime(), isOptional: false },
|
|
261
|
+
user: { type: MemberUserModel, isOptional: false }
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
var InvitationModel = new SchemaModel2({
|
|
265
|
+
name: "Invitation",
|
|
266
|
+
description: "Organization invitation",
|
|
267
|
+
fields: {
|
|
268
|
+
id: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
269
|
+
email: { type: ScalarTypeEnum2.EmailAddress(), isOptional: false },
|
|
270
|
+
role: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
271
|
+
status: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
272
|
+
expiresAt: { type: ScalarTypeEnum2.DateTime(), isOptional: true },
|
|
273
|
+
createdAt: { type: ScalarTypeEnum2.DateTime(), isOptional: false }
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
var CreateOrgInputModel = new SchemaModel2({
|
|
277
|
+
name: "CreateOrgInput",
|
|
278
|
+
description: "Input for creating an organization",
|
|
279
|
+
fields: {
|
|
280
|
+
name: { type: ScalarTypeEnum2.NonEmptyString(), isOptional: false },
|
|
281
|
+
slug: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
282
|
+
description: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
283
|
+
type: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true }
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
var GetOrgInputModel = new SchemaModel2({
|
|
287
|
+
name: "GetOrgInput",
|
|
288
|
+
description: "Input for getting an organization",
|
|
289
|
+
fields: {
|
|
290
|
+
orgId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
var UpdateOrgInputModel = new SchemaModel2({
|
|
294
|
+
name: "UpdateOrgInput",
|
|
295
|
+
description: "Input for updating an organization",
|
|
296
|
+
fields: {
|
|
297
|
+
orgId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
298
|
+
name: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
299
|
+
slug: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
300
|
+
logo: { type: ScalarTypeEnum2.URL(), isOptional: true },
|
|
301
|
+
description: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true }
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
var InviteMemberInputModel = new SchemaModel2({
|
|
305
|
+
name: "InviteMemberInput",
|
|
306
|
+
description: "Input for inviting a member",
|
|
307
|
+
fields: {
|
|
308
|
+
orgId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
309
|
+
email: { type: ScalarTypeEnum2.EmailAddress(), isOptional: false },
|
|
310
|
+
role: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
311
|
+
teamId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true }
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
var AcceptInviteInputModel = new SchemaModel2({
|
|
315
|
+
name: "AcceptInviteInput",
|
|
316
|
+
description: "Input for accepting an invitation",
|
|
317
|
+
fields: {
|
|
318
|
+
invitationId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
var RemoveMemberInputModel = new SchemaModel2({
|
|
322
|
+
name: "RemoveMemberInput",
|
|
323
|
+
description: "Input for removing a member",
|
|
324
|
+
fields: {
|
|
325
|
+
orgId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
326
|
+
userId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
var MemberRemovedPayloadModel = new SchemaModel2({
|
|
330
|
+
name: "MemberRemovedPayload",
|
|
331
|
+
description: "Payload for member removed event",
|
|
332
|
+
fields: {
|
|
333
|
+
orgId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
334
|
+
userId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
var ListMembersInputModel = new SchemaModel2({
|
|
338
|
+
name: "ListMembersInput",
|
|
339
|
+
description: "Input for listing members",
|
|
340
|
+
fields: {
|
|
341
|
+
orgId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
342
|
+
limit: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: true },
|
|
343
|
+
offset: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: true }
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
var ListMembersOutputModel = new SchemaModel2({
|
|
347
|
+
name: "ListMembersOutput",
|
|
348
|
+
description: "Output for listing members",
|
|
349
|
+
fields: {
|
|
350
|
+
members: { type: MemberModel, isOptional: false, isArray: true },
|
|
351
|
+
total: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: false }
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
var OrganizationWithRoleModel = new SchemaModel2({
|
|
355
|
+
name: "OrganizationWithRole",
|
|
356
|
+
description: "Organization with user role",
|
|
357
|
+
fields: {
|
|
358
|
+
id: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
359
|
+
name: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
360
|
+
slug: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
361
|
+
logo: { type: ScalarTypeEnum2.URL(), isOptional: true },
|
|
362
|
+
description: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
|
|
363
|
+
type: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
|
|
364
|
+
onboardingCompleted: { type: ScalarTypeEnum2.Boolean(), isOptional: false },
|
|
365
|
+
createdAt: { type: ScalarTypeEnum2.DateTime(), isOptional: false },
|
|
366
|
+
role: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
var ListUserOrgsOutputModel = new SchemaModel2({
|
|
370
|
+
name: "ListUserOrgsOutput",
|
|
371
|
+
description: "Output for listing user organizations",
|
|
372
|
+
fields: {
|
|
373
|
+
organizations: {
|
|
374
|
+
type: OrganizationWithRoleModel,
|
|
375
|
+
isOptional: false,
|
|
376
|
+
isArray: true
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
var CreateOrgContract = defineCommand2({
|
|
381
|
+
meta: {
|
|
382
|
+
key: "identity.org.create",
|
|
383
|
+
version: "1.0.0",
|
|
384
|
+
stability: "stable",
|
|
385
|
+
owners: [...OWNERS2],
|
|
386
|
+
tags: ["identity", "org", "create"],
|
|
387
|
+
description: "Create a new organization.",
|
|
388
|
+
goal: "Allow users to create new organizations/workspaces.",
|
|
389
|
+
context: "Called during onboarding or when creating additional workspaces."
|
|
390
|
+
},
|
|
391
|
+
io: {
|
|
392
|
+
input: CreateOrgInputModel,
|
|
393
|
+
output: OrganizationModel,
|
|
394
|
+
errors: {
|
|
395
|
+
SLUG_EXISTS: {
|
|
396
|
+
description: "An organization with this slug already exists",
|
|
397
|
+
http: 409,
|
|
398
|
+
gqlCode: "SLUG_EXISTS",
|
|
399
|
+
when: "Slug is already taken"
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
policy: {
|
|
404
|
+
auth: "user"
|
|
405
|
+
},
|
|
406
|
+
sideEffects: {
|
|
407
|
+
emits: [
|
|
408
|
+
{
|
|
409
|
+
key: "org.created",
|
|
410
|
+
version: "1.0.0",
|
|
411
|
+
when: "Organization is created",
|
|
412
|
+
payload: OrganizationModel
|
|
413
|
+
}
|
|
414
|
+
],
|
|
415
|
+
audit: ["org.created"]
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
var GetOrgContract = defineQuery2({
|
|
419
|
+
meta: {
|
|
420
|
+
key: "identity.org.get",
|
|
421
|
+
version: "1.0.0",
|
|
422
|
+
stability: "stable",
|
|
423
|
+
owners: [...OWNERS2],
|
|
424
|
+
tags: ["identity", "org", "get"],
|
|
425
|
+
description: "Get organization details.",
|
|
426
|
+
goal: "Retrieve organization information.",
|
|
427
|
+
context: "Called when viewing organization settings or dashboard."
|
|
428
|
+
},
|
|
429
|
+
io: {
|
|
430
|
+
input: GetOrgInputModel,
|
|
431
|
+
output: OrganizationModel
|
|
432
|
+
},
|
|
433
|
+
policy: {
|
|
434
|
+
auth: "user"
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
var UpdateOrgContract = defineCommand2({
|
|
438
|
+
meta: {
|
|
439
|
+
key: "identity.org.update",
|
|
440
|
+
version: "1.0.0",
|
|
441
|
+
stability: "stable",
|
|
442
|
+
owners: [...OWNERS2],
|
|
443
|
+
tags: ["identity", "org", "update"],
|
|
444
|
+
description: "Update organization details.",
|
|
445
|
+
goal: "Allow org admins to update organization settings.",
|
|
446
|
+
context: "Organization settings page."
|
|
447
|
+
},
|
|
448
|
+
io: {
|
|
449
|
+
input: UpdateOrgInputModel,
|
|
450
|
+
output: OrganizationModel
|
|
451
|
+
},
|
|
452
|
+
policy: {
|
|
453
|
+
auth: "user"
|
|
454
|
+
},
|
|
455
|
+
sideEffects: {
|
|
456
|
+
emits: [
|
|
457
|
+
{
|
|
458
|
+
key: "org.updated",
|
|
459
|
+
version: "1.0.0",
|
|
460
|
+
when: "Organization is updated",
|
|
461
|
+
payload: OrganizationModel
|
|
462
|
+
}
|
|
463
|
+
],
|
|
464
|
+
audit: ["org.updated"]
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
var InviteMemberContract = defineCommand2({
|
|
468
|
+
meta: {
|
|
469
|
+
key: "identity.org.invite",
|
|
470
|
+
version: "1.0.0",
|
|
471
|
+
stability: "stable",
|
|
472
|
+
owners: [...OWNERS2],
|
|
473
|
+
tags: ["identity", "org", "invite", "member"],
|
|
474
|
+
description: "Invite a user to join the organization.",
|
|
475
|
+
goal: "Allow org admins to invite new members.",
|
|
476
|
+
context: "Team management. Sends invitation email."
|
|
477
|
+
},
|
|
478
|
+
io: {
|
|
479
|
+
input: InviteMemberInputModel,
|
|
480
|
+
output: InvitationModel,
|
|
481
|
+
errors: {
|
|
482
|
+
ALREADY_MEMBER: {
|
|
483
|
+
description: "User is already a member of this organization",
|
|
484
|
+
http: 409,
|
|
485
|
+
gqlCode: "ALREADY_MEMBER",
|
|
486
|
+
when: "Invitee is already a member"
|
|
487
|
+
},
|
|
488
|
+
INVITE_PENDING: {
|
|
489
|
+
description: "An invitation for this email is already pending",
|
|
490
|
+
http: 409,
|
|
491
|
+
gqlCode: "INVITE_PENDING",
|
|
492
|
+
when: "Active invitation exists"
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
policy: {
|
|
497
|
+
auth: "user"
|
|
498
|
+
},
|
|
499
|
+
sideEffects: {
|
|
500
|
+
emits: [
|
|
501
|
+
{
|
|
502
|
+
key: "org.invite.sent",
|
|
503
|
+
version: "1.0.0",
|
|
504
|
+
when: "Invitation is sent",
|
|
505
|
+
payload: InvitationModel
|
|
506
|
+
}
|
|
507
|
+
],
|
|
508
|
+
audit: ["org.invite.sent"]
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
var AcceptInviteContract = defineCommand2({
|
|
512
|
+
meta: {
|
|
513
|
+
key: "identity.org.invite.accept",
|
|
514
|
+
version: "1.0.0",
|
|
515
|
+
stability: "stable",
|
|
516
|
+
owners: [...OWNERS2],
|
|
517
|
+
tags: ["identity", "org", "invite", "accept"],
|
|
518
|
+
description: "Accept an organization invitation.",
|
|
519
|
+
goal: "Allow users to join organizations via invitation.",
|
|
520
|
+
context: "Called from invitation email link."
|
|
521
|
+
},
|
|
522
|
+
io: {
|
|
523
|
+
input: AcceptInviteInputModel,
|
|
524
|
+
output: MemberModel,
|
|
525
|
+
errors: {
|
|
526
|
+
INVITE_EXPIRED: {
|
|
527
|
+
description: "The invitation has expired",
|
|
528
|
+
http: 410,
|
|
529
|
+
gqlCode: "INVITE_EXPIRED",
|
|
530
|
+
when: "Invitation is past expiry date"
|
|
531
|
+
},
|
|
532
|
+
INVITE_USED: {
|
|
533
|
+
description: "The invitation has already been used",
|
|
534
|
+
http: 409,
|
|
535
|
+
gqlCode: "INVITE_USED",
|
|
536
|
+
when: "Invitation was already accepted"
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
policy: {
|
|
541
|
+
auth: "user"
|
|
542
|
+
},
|
|
543
|
+
sideEffects: {
|
|
544
|
+
emits: [
|
|
545
|
+
{
|
|
546
|
+
key: "org.member.added",
|
|
547
|
+
version: "1.0.0",
|
|
548
|
+
when: "Member joins org",
|
|
549
|
+
payload: MemberModel
|
|
550
|
+
}
|
|
551
|
+
],
|
|
552
|
+
audit: ["org.member.added"]
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
var RemoveMemberContract = defineCommand2({
|
|
556
|
+
meta: {
|
|
557
|
+
key: "identity.org.member.remove",
|
|
558
|
+
version: "1.0.0",
|
|
559
|
+
stability: "stable",
|
|
560
|
+
owners: [...OWNERS2],
|
|
561
|
+
tags: ["identity", "org", "member", "remove"],
|
|
562
|
+
description: "Remove a member from the organization.",
|
|
563
|
+
goal: "Allow org admins to remove members.",
|
|
564
|
+
context: "Team management."
|
|
565
|
+
},
|
|
566
|
+
io: {
|
|
567
|
+
input: RemoveMemberInputModel,
|
|
568
|
+
output: SuccessResultModel,
|
|
569
|
+
errors: {
|
|
570
|
+
CANNOT_REMOVE_OWNER: {
|
|
571
|
+
description: "Cannot remove the organization owner",
|
|
572
|
+
http: 403,
|
|
573
|
+
gqlCode: "CANNOT_REMOVE_OWNER",
|
|
574
|
+
when: "Target is the org owner"
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
policy: {
|
|
579
|
+
auth: "user"
|
|
580
|
+
},
|
|
581
|
+
sideEffects: {
|
|
582
|
+
emits: [
|
|
583
|
+
{
|
|
584
|
+
key: "org.member.removed",
|
|
585
|
+
version: "1.0.0",
|
|
586
|
+
when: "Member is removed",
|
|
587
|
+
payload: MemberRemovedPayloadModel
|
|
588
|
+
}
|
|
589
|
+
],
|
|
590
|
+
audit: ["org.member.removed"]
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
var ListMembersContract = defineQuery2({
|
|
594
|
+
meta: {
|
|
595
|
+
key: "identity.org.members.list",
|
|
596
|
+
version: "1.0.0",
|
|
597
|
+
stability: "stable",
|
|
598
|
+
owners: [...OWNERS2],
|
|
599
|
+
tags: ["identity", "org", "member", "list"],
|
|
600
|
+
description: "List organization members.",
|
|
601
|
+
goal: "View all members of an organization.",
|
|
602
|
+
context: "Team management page."
|
|
603
|
+
},
|
|
604
|
+
io: {
|
|
605
|
+
input: ListMembersInputModel,
|
|
606
|
+
output: ListMembersOutputModel
|
|
607
|
+
},
|
|
608
|
+
policy: {
|
|
609
|
+
auth: "user"
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
var ListUserOrgsContract = defineQuery2({
|
|
613
|
+
meta: {
|
|
614
|
+
key: "identity.org.list",
|
|
615
|
+
version: "1.0.0",
|
|
616
|
+
stability: "stable",
|
|
617
|
+
owners: [...OWNERS2],
|
|
618
|
+
tags: ["identity", "org", "list"],
|
|
619
|
+
description: "List organizations the current user belongs to.",
|
|
620
|
+
goal: "Show user their organizations for workspace switching.",
|
|
621
|
+
context: "Workspace switcher, org selection."
|
|
622
|
+
},
|
|
623
|
+
io: {
|
|
624
|
+
input: null,
|
|
625
|
+
output: ListUserOrgsOutputModel
|
|
626
|
+
},
|
|
627
|
+
policy: {
|
|
628
|
+
auth: "user"
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
// src/contracts/rbac.ts
|
|
633
|
+
import { SchemaModel as SchemaModel3, ScalarTypeEnum as ScalarTypeEnum3 } from "@contractspec/lib.schema";
|
|
634
|
+
import { defineCommand as defineCommand3, defineQuery as defineQuery3 } from "@contractspec/lib.contracts";
|
|
635
|
+
var RoleModel = new SchemaModel3({
|
|
636
|
+
name: "Role",
|
|
637
|
+
description: "RBAC role definition",
|
|
638
|
+
fields: {
|
|
639
|
+
id: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
640
|
+
name: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
641
|
+
description: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true },
|
|
642
|
+
permissions: {
|
|
643
|
+
type: ScalarTypeEnum3.String_unsecure(),
|
|
644
|
+
isOptional: false,
|
|
645
|
+
isArray: true
|
|
646
|
+
},
|
|
647
|
+
createdAt: { type: ScalarTypeEnum3.DateTime(), isOptional: false }
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
var PolicyBindingModel = new SchemaModel3({
|
|
651
|
+
name: "PolicyBinding",
|
|
652
|
+
description: "Role assignment to a target",
|
|
653
|
+
fields: {
|
|
654
|
+
id: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
655
|
+
roleId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
656
|
+
targetType: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
657
|
+
targetId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
658
|
+
expiresAt: { type: ScalarTypeEnum3.DateTime(), isOptional: true },
|
|
659
|
+
createdAt: { type: ScalarTypeEnum3.DateTime(), isOptional: false },
|
|
660
|
+
role: { type: RoleModel, isOptional: false }
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
var PermissionCheckResultModel = new SchemaModel3({
|
|
664
|
+
name: "PermissionCheckResult",
|
|
665
|
+
description: "Result of a permission check",
|
|
666
|
+
fields: {
|
|
667
|
+
allowed: { type: ScalarTypeEnum3.Boolean(), isOptional: false },
|
|
668
|
+
reason: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true },
|
|
669
|
+
matchedRole: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true }
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
var CreateRoleInputModel = new SchemaModel3({
|
|
673
|
+
name: "CreateRoleInput",
|
|
674
|
+
description: "Input for creating a role",
|
|
675
|
+
fields: {
|
|
676
|
+
name: { type: ScalarTypeEnum3.NonEmptyString(), isOptional: false },
|
|
677
|
+
description: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true },
|
|
678
|
+
permissions: {
|
|
679
|
+
type: ScalarTypeEnum3.String_unsecure(),
|
|
680
|
+
isOptional: false,
|
|
681
|
+
isArray: true
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
var UpdateRoleInputModel = new SchemaModel3({
|
|
686
|
+
name: "UpdateRoleInput",
|
|
687
|
+
description: "Input for updating a role",
|
|
688
|
+
fields: {
|
|
689
|
+
roleId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
690
|
+
name: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true },
|
|
691
|
+
description: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true },
|
|
692
|
+
permissions: {
|
|
693
|
+
type: ScalarTypeEnum3.String_unsecure(),
|
|
694
|
+
isOptional: true,
|
|
695
|
+
isArray: true
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
var DeleteRoleInputModel = new SchemaModel3({
|
|
700
|
+
name: "DeleteRoleInput",
|
|
701
|
+
description: "Input for deleting a role",
|
|
702
|
+
fields: {
|
|
703
|
+
roleId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
var ListRolesOutputModel = new SchemaModel3({
|
|
707
|
+
name: "ListRolesOutput",
|
|
708
|
+
description: "Output for listing roles",
|
|
709
|
+
fields: {
|
|
710
|
+
roles: { type: RoleModel, isOptional: false, isArray: true }
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
var AssignRoleInputModel = new SchemaModel3({
|
|
714
|
+
name: "AssignRoleInput",
|
|
715
|
+
description: "Input for assigning a role",
|
|
716
|
+
fields: {
|
|
717
|
+
roleId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
718
|
+
targetType: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
719
|
+
targetId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
720
|
+
expiresAt: { type: ScalarTypeEnum3.DateTime(), isOptional: true }
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
var RevokeRoleInputModel = new SchemaModel3({
|
|
724
|
+
name: "RevokeRoleInput",
|
|
725
|
+
description: "Input for revoking a role",
|
|
726
|
+
fields: {
|
|
727
|
+
bindingId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
var BindingIdPayloadModel = new SchemaModel3({
|
|
731
|
+
name: "BindingIdPayload",
|
|
732
|
+
description: "Payload with binding ID",
|
|
733
|
+
fields: {
|
|
734
|
+
bindingId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
var CheckPermissionInputModel = new SchemaModel3({
|
|
738
|
+
name: "CheckPermissionInput",
|
|
739
|
+
description: "Input for checking a permission",
|
|
740
|
+
fields: {
|
|
741
|
+
userId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
742
|
+
orgId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true },
|
|
743
|
+
permission: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
var ListUserPermissionsInputModel = new SchemaModel3({
|
|
747
|
+
name: "ListUserPermissionsInput",
|
|
748
|
+
description: "Input for listing user permissions",
|
|
749
|
+
fields: {
|
|
750
|
+
userId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
|
|
751
|
+
orgId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: true }
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
var ListUserPermissionsOutputModel = new SchemaModel3({
|
|
755
|
+
name: "ListUserPermissionsOutput",
|
|
756
|
+
description: "Output for listing user permissions",
|
|
757
|
+
fields: {
|
|
758
|
+
permissions: {
|
|
759
|
+
type: ScalarTypeEnum3.String_unsecure(),
|
|
760
|
+
isOptional: false,
|
|
761
|
+
isArray: true
|
|
762
|
+
},
|
|
763
|
+
roles: { type: RoleModel, isOptional: false, isArray: true }
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
var CreateRoleContract = defineCommand3({
|
|
767
|
+
meta: {
|
|
768
|
+
key: "identity.rbac.role.create",
|
|
769
|
+
version: "1.0.0",
|
|
770
|
+
stability: "stable",
|
|
771
|
+
owners: ["@platform.identity-rbac"],
|
|
772
|
+
tags: ["identity", "rbac", "role", "create"],
|
|
773
|
+
description: "Create a new role with permissions.",
|
|
774
|
+
goal: "Allow admins to define custom roles.",
|
|
775
|
+
context: "Role management in admin settings."
|
|
776
|
+
},
|
|
777
|
+
io: {
|
|
778
|
+
input: CreateRoleInputModel,
|
|
779
|
+
output: RoleModel,
|
|
780
|
+
errors: {
|
|
781
|
+
ROLE_EXISTS: {
|
|
782
|
+
description: "A role with this name already exists",
|
|
783
|
+
http: 409,
|
|
784
|
+
gqlCode: "ROLE_EXISTS",
|
|
785
|
+
when: "Role name is taken"
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
policy: {
|
|
790
|
+
auth: "admin"
|
|
791
|
+
},
|
|
792
|
+
sideEffects: {
|
|
793
|
+
audit: ["role.created"]
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
var UpdateRoleContract = defineCommand3({
|
|
797
|
+
meta: {
|
|
798
|
+
key: "identity.rbac.role.update",
|
|
799
|
+
version: "1.0.0",
|
|
800
|
+
stability: "stable",
|
|
801
|
+
owners: ["@platform.identity-rbac"],
|
|
802
|
+
tags: ["identity", "rbac", "role", "update"],
|
|
803
|
+
description: "Update an existing role.",
|
|
804
|
+
goal: "Allow admins to modify role permissions.",
|
|
805
|
+
context: "Role management in admin settings."
|
|
806
|
+
},
|
|
807
|
+
io: {
|
|
808
|
+
input: UpdateRoleInputModel,
|
|
809
|
+
output: RoleModel
|
|
810
|
+
},
|
|
811
|
+
policy: {
|
|
812
|
+
auth: "admin"
|
|
813
|
+
},
|
|
814
|
+
sideEffects: {
|
|
815
|
+
audit: ["role.updated"]
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
var DeleteRoleContract = defineCommand3({
|
|
819
|
+
meta: {
|
|
820
|
+
key: "identity.rbac.role.delete",
|
|
821
|
+
version: "1.0.0",
|
|
822
|
+
stability: "stable",
|
|
823
|
+
owners: ["@platform.identity-rbac"],
|
|
824
|
+
tags: ["identity", "rbac", "role", "delete"],
|
|
825
|
+
description: "Delete an existing role.",
|
|
826
|
+
goal: "Allow admins to remove unused roles.",
|
|
827
|
+
context: "Role management. Removes all policy bindings using this role."
|
|
828
|
+
},
|
|
829
|
+
io: {
|
|
830
|
+
input: DeleteRoleInputModel,
|
|
831
|
+
output: SuccessResultModel,
|
|
832
|
+
errors: {
|
|
833
|
+
ROLE_IN_USE: {
|
|
834
|
+
description: "Role is still assigned to users or organizations",
|
|
835
|
+
http: 409,
|
|
836
|
+
gqlCode: "ROLE_IN_USE",
|
|
837
|
+
when: "Role has active bindings"
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
},
|
|
841
|
+
policy: {
|
|
842
|
+
auth: "admin"
|
|
843
|
+
},
|
|
844
|
+
sideEffects: {
|
|
845
|
+
audit: ["role.deleted"]
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
var ListRolesContract = defineQuery3({
|
|
849
|
+
meta: {
|
|
850
|
+
key: "identity.rbac.role.list",
|
|
851
|
+
version: "1.0.0",
|
|
852
|
+
stability: "stable",
|
|
853
|
+
owners: ["@platform.identity-rbac"],
|
|
854
|
+
tags: ["identity", "rbac", "role", "list"],
|
|
855
|
+
description: "List all available roles.",
|
|
856
|
+
goal: "Show available roles for assignment.",
|
|
857
|
+
context: "Role assignment UI."
|
|
858
|
+
},
|
|
859
|
+
io: {
|
|
860
|
+
input: null,
|
|
861
|
+
output: ListRolesOutputModel
|
|
862
|
+
},
|
|
863
|
+
policy: {
|
|
864
|
+
auth: "user"
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
var AssignRoleContract = defineCommand3({
|
|
868
|
+
meta: {
|
|
869
|
+
key: "identity.rbac.assign",
|
|
870
|
+
version: "1.0.0",
|
|
871
|
+
stability: "stable",
|
|
872
|
+
owners: ["@platform.identity-rbac"],
|
|
873
|
+
tags: ["identity", "rbac", "assign"],
|
|
874
|
+
description: "Assign a role to a user or organization.",
|
|
875
|
+
goal: "Grant permissions via role assignment.",
|
|
876
|
+
context: "User/org permission management."
|
|
877
|
+
},
|
|
878
|
+
io: {
|
|
879
|
+
input: AssignRoleInputModel,
|
|
880
|
+
output: PolicyBindingModel,
|
|
881
|
+
errors: {
|
|
882
|
+
ROLE_NOT_FOUND: {
|
|
883
|
+
description: "The specified role does not exist",
|
|
884
|
+
http: 404,
|
|
885
|
+
gqlCode: "ROLE_NOT_FOUND",
|
|
886
|
+
when: "Role ID is invalid"
|
|
887
|
+
},
|
|
888
|
+
ALREADY_ASSIGNED: {
|
|
889
|
+
description: "This role is already assigned to the target",
|
|
890
|
+
http: 409,
|
|
891
|
+
gqlCode: "ALREADY_ASSIGNED",
|
|
892
|
+
when: "Binding already exists"
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
},
|
|
896
|
+
policy: {
|
|
897
|
+
auth: "admin"
|
|
898
|
+
},
|
|
899
|
+
sideEffects: {
|
|
900
|
+
emits: [
|
|
901
|
+
{
|
|
902
|
+
key: "role.assigned",
|
|
903
|
+
version: "1.0.0",
|
|
904
|
+
when: "Role is assigned",
|
|
905
|
+
payload: PolicyBindingModel
|
|
906
|
+
}
|
|
907
|
+
],
|
|
908
|
+
audit: ["role.assigned"]
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
var RevokeRoleContract = defineCommand3({
|
|
912
|
+
meta: {
|
|
913
|
+
key: "identity.rbac.revoke",
|
|
914
|
+
version: "1.0.0",
|
|
915
|
+
stability: "stable",
|
|
916
|
+
owners: ["@platform.identity-rbac"],
|
|
917
|
+
tags: ["identity", "rbac", "revoke"],
|
|
918
|
+
description: "Revoke a role from a user or organization.",
|
|
919
|
+
goal: "Remove permissions via role revocation.",
|
|
920
|
+
context: "User/org permission management."
|
|
921
|
+
},
|
|
922
|
+
io: {
|
|
923
|
+
input: RevokeRoleInputModel,
|
|
924
|
+
output: SuccessResultModel,
|
|
925
|
+
errors: {
|
|
926
|
+
BINDING_NOT_FOUND: {
|
|
927
|
+
description: "The policy binding does not exist",
|
|
928
|
+
http: 404,
|
|
929
|
+
gqlCode: "BINDING_NOT_FOUND",
|
|
930
|
+
when: "Binding ID is invalid"
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
policy: {
|
|
935
|
+
auth: "admin"
|
|
936
|
+
},
|
|
937
|
+
sideEffects: {
|
|
938
|
+
emits: [
|
|
939
|
+
{
|
|
940
|
+
key: "role.revoked",
|
|
941
|
+
version: "1.0.0",
|
|
942
|
+
when: "Role is revoked",
|
|
943
|
+
payload: BindingIdPayloadModel
|
|
944
|
+
}
|
|
945
|
+
],
|
|
946
|
+
audit: ["role.revoked"]
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
var CheckPermissionContract = defineQuery3({
|
|
950
|
+
meta: {
|
|
951
|
+
key: "identity.rbac.check",
|
|
952
|
+
version: "1.0.0",
|
|
953
|
+
stability: "stable",
|
|
954
|
+
owners: ["@platform.identity-rbac"],
|
|
955
|
+
tags: ["identity", "rbac", "check", "permission"],
|
|
956
|
+
description: "Check if a user has a specific permission.",
|
|
957
|
+
goal: "Authorization check before sensitive operations.",
|
|
958
|
+
context: "Called by other services to verify permissions."
|
|
959
|
+
},
|
|
960
|
+
io: {
|
|
961
|
+
input: CheckPermissionInputModel,
|
|
962
|
+
output: PermissionCheckResultModel
|
|
963
|
+
},
|
|
964
|
+
policy: {
|
|
965
|
+
auth: "user"
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
var ListUserPermissionsContract = defineQuery3({
|
|
969
|
+
meta: {
|
|
970
|
+
key: "identity.rbac.permissions",
|
|
971
|
+
version: "1.0.0",
|
|
972
|
+
stability: "stable",
|
|
973
|
+
owners: ["@platform.identity-rbac"],
|
|
974
|
+
tags: ["identity", "rbac", "permissions", "user"],
|
|
975
|
+
description: "List all permissions for a user in a context.",
|
|
976
|
+
goal: "Show what a user can do in an org.",
|
|
977
|
+
context: "UI permission display, debugging."
|
|
978
|
+
},
|
|
979
|
+
io: {
|
|
980
|
+
input: ListUserPermissionsInputModel,
|
|
981
|
+
output: ListUserPermissionsOutputModel
|
|
982
|
+
},
|
|
983
|
+
policy: {
|
|
984
|
+
auth: "user"
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
// src/entities/user.ts
|
|
988
|
+
import { defineEntity, field, index } from "@contractspec/lib.schema";
|
|
989
|
+
var UserEntity = defineEntity({
|
|
990
|
+
name: "User",
|
|
991
|
+
description: "A user of the platform. Users hold core profile information and authenticate via Account records.",
|
|
992
|
+
schema: "lssm_sigil",
|
|
993
|
+
map: "user",
|
|
994
|
+
fields: {
|
|
995
|
+
id: field.id({ description: "Unique user identifier" }),
|
|
996
|
+
email: field.email({ isUnique: true, description: "User email address" }),
|
|
997
|
+
emailVerified: field.boolean({
|
|
998
|
+
default: false,
|
|
999
|
+
description: "Whether email has been verified"
|
|
1000
|
+
}),
|
|
1001
|
+
name: field.string({ isOptional: true, description: "Display name" }),
|
|
1002
|
+
firstName: field.string({ isOptional: true, description: "First name" }),
|
|
1003
|
+
lastName: field.string({ isOptional: true, description: "Last name" }),
|
|
1004
|
+
locale: field.string({
|
|
1005
|
+
isOptional: true,
|
|
1006
|
+
description: 'User locale (e.g., "en-US")'
|
|
1007
|
+
}),
|
|
1008
|
+
timezone: field.string({
|
|
1009
|
+
isOptional: true,
|
|
1010
|
+
description: 'Olson timezone (e.g., "Europe/Paris")'
|
|
1011
|
+
}),
|
|
1012
|
+
imageUrl: field.url({
|
|
1013
|
+
isOptional: true,
|
|
1014
|
+
description: "URL of avatar or profile picture"
|
|
1015
|
+
}),
|
|
1016
|
+
image: field.string({
|
|
1017
|
+
isOptional: true,
|
|
1018
|
+
description: "Legacy image field"
|
|
1019
|
+
}),
|
|
1020
|
+
metadata: field.json({
|
|
1021
|
+
isOptional: true,
|
|
1022
|
+
description: "Arbitrary user metadata"
|
|
1023
|
+
}),
|
|
1024
|
+
onboardingCompleted: field.boolean({
|
|
1025
|
+
default: false,
|
|
1026
|
+
description: "Whether onboarding is complete"
|
|
1027
|
+
}),
|
|
1028
|
+
onboardingStep: field.string({
|
|
1029
|
+
isOptional: true,
|
|
1030
|
+
description: "Current onboarding step"
|
|
1031
|
+
}),
|
|
1032
|
+
whitelistedAt: field.dateTime({
|
|
1033
|
+
isOptional: true,
|
|
1034
|
+
description: "When user was whitelisted"
|
|
1035
|
+
}),
|
|
1036
|
+
role: field.string({
|
|
1037
|
+
isOptional: true,
|
|
1038
|
+
default: '"user"',
|
|
1039
|
+
description: "User role (user, admin)"
|
|
1040
|
+
}),
|
|
1041
|
+
banned: field.boolean({
|
|
1042
|
+
default: false,
|
|
1043
|
+
description: "Whether user is banned"
|
|
1044
|
+
}),
|
|
1045
|
+
banReason: field.string({
|
|
1046
|
+
isOptional: true,
|
|
1047
|
+
description: "Reason for ban"
|
|
1048
|
+
}),
|
|
1049
|
+
banExpires: field.dateTime({
|
|
1050
|
+
isOptional: true,
|
|
1051
|
+
description: "When ban expires"
|
|
1052
|
+
}),
|
|
1053
|
+
phoneNumber: field.string({
|
|
1054
|
+
isOptional: true,
|
|
1055
|
+
isUnique: true,
|
|
1056
|
+
description: "Phone number"
|
|
1057
|
+
}),
|
|
1058
|
+
phoneNumberVerified: field.boolean({
|
|
1059
|
+
default: false,
|
|
1060
|
+
description: "Whether phone is verified"
|
|
1061
|
+
}),
|
|
1062
|
+
createdAt: field.createdAt(),
|
|
1063
|
+
updatedAt: field.updatedAt(),
|
|
1064
|
+
sessions: field.hasMany("Session"),
|
|
1065
|
+
accounts: field.hasMany("Account"),
|
|
1066
|
+
memberships: field.hasMany("Member"),
|
|
1067
|
+
invitations: field.hasMany("Invitation"),
|
|
1068
|
+
teamMemberships: field.hasMany("TeamMember"),
|
|
1069
|
+
policyBindings: field.hasMany("PolicyBinding"),
|
|
1070
|
+
apiKeys: field.hasMany("ApiKey"),
|
|
1071
|
+
passkeys: field.hasMany("Passkey")
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
var SessionEntity = defineEntity({
|
|
1075
|
+
name: "Session",
|
|
1076
|
+
description: "Represents a login session (e.g., web session or API token).",
|
|
1077
|
+
schema: "lssm_sigil",
|
|
1078
|
+
map: "session",
|
|
1079
|
+
fields: {
|
|
1080
|
+
id: field.id(),
|
|
1081
|
+
userId: field.foreignKey(),
|
|
1082
|
+
expiresAt: field.dateTime({ description: "Session expiration time" }),
|
|
1083
|
+
token: field.string({ isUnique: true, description: "Session token" }),
|
|
1084
|
+
ipAddress: field.string({
|
|
1085
|
+
isOptional: true,
|
|
1086
|
+
description: "Client IP address"
|
|
1087
|
+
}),
|
|
1088
|
+
userAgent: field.string({
|
|
1089
|
+
isOptional: true,
|
|
1090
|
+
description: "Client user agent"
|
|
1091
|
+
}),
|
|
1092
|
+
impersonatedBy: field.string({
|
|
1093
|
+
isOptional: true,
|
|
1094
|
+
description: "Admin impersonating this session"
|
|
1095
|
+
}),
|
|
1096
|
+
activeOrganizationId: field.string({
|
|
1097
|
+
isOptional: true,
|
|
1098
|
+
description: "Active org context"
|
|
1099
|
+
}),
|
|
1100
|
+
activeTeamId: field.string({
|
|
1101
|
+
isOptional: true,
|
|
1102
|
+
description: "Active team context"
|
|
1103
|
+
}),
|
|
1104
|
+
createdAt: field.createdAt(),
|
|
1105
|
+
updatedAt: field.updatedAt(),
|
|
1106
|
+
user: field.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
var AccountEntity = defineEntity({
|
|
1110
|
+
name: "Account",
|
|
1111
|
+
description: "External authentication accounts (OAuth, password, etc.).",
|
|
1112
|
+
schema: "lssm_sigil",
|
|
1113
|
+
map: "account",
|
|
1114
|
+
fields: {
|
|
1115
|
+
id: field.id(),
|
|
1116
|
+
accountId: field.string({ description: "Account ID from provider" }),
|
|
1117
|
+
providerId: field.string({ description: "Provider identifier" }),
|
|
1118
|
+
userId: field.foreignKey(),
|
|
1119
|
+
accessToken: field.string({ isOptional: true }),
|
|
1120
|
+
refreshToken: field.string({ isOptional: true }),
|
|
1121
|
+
idToken: field.string({ isOptional: true }),
|
|
1122
|
+
accessTokenExpiresAt: field.dateTime({ isOptional: true }),
|
|
1123
|
+
refreshTokenExpiresAt: field.dateTime({ isOptional: true }),
|
|
1124
|
+
scope: field.string({ isOptional: true }),
|
|
1125
|
+
password: field.string({
|
|
1126
|
+
isOptional: true,
|
|
1127
|
+
description: "Hashed password for password providers"
|
|
1128
|
+
}),
|
|
1129
|
+
createdAt: field.createdAt(),
|
|
1130
|
+
updatedAt: field.updatedAt(),
|
|
1131
|
+
user: field.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
1132
|
+
},
|
|
1133
|
+
indexes: [index.unique(["accountId", "providerId"])]
|
|
1134
|
+
});
|
|
1135
|
+
var VerificationEntity = defineEntity({
|
|
1136
|
+
name: "Verification",
|
|
1137
|
+
description: "Verification tokens for email/phone confirmation.",
|
|
1138
|
+
schema: "lssm_sigil",
|
|
1139
|
+
map: "verification",
|
|
1140
|
+
fields: {
|
|
1141
|
+
id: field.uuid(),
|
|
1142
|
+
identifier: field.string({ description: "Email or phone being verified" }),
|
|
1143
|
+
value: field.string({ description: "Verification code/token" }),
|
|
1144
|
+
expiresAt: field.dateTime({ description: "Token expiration" }),
|
|
1145
|
+
createdAt: field.createdAt(),
|
|
1146
|
+
updatedAt: field.updatedAt()
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
// src/entities/organization.ts
|
|
1151
|
+
import {
|
|
1152
|
+
defineEntity as defineEntity2,
|
|
1153
|
+
defineEntityEnum,
|
|
1154
|
+
field as field2,
|
|
1155
|
+
index as index2
|
|
1156
|
+
} from "@contractspec/lib.schema";
|
|
1157
|
+
var OrganizationTypeEnum = defineEntityEnum({
|
|
1158
|
+
name: "OrganizationType",
|
|
1159
|
+
values: ["PLATFORM_ADMIN", "CONTRACT_SPEC_CUSTOMER"],
|
|
1160
|
+
schema: "lssm_sigil",
|
|
1161
|
+
description: "Type of organization in the platform."
|
|
1162
|
+
});
|
|
1163
|
+
var OrganizationEntity = defineEntity2({
|
|
1164
|
+
name: "Organization",
|
|
1165
|
+
description: "An organization is a tenant boundary grouping users.",
|
|
1166
|
+
schema: "lssm_sigil",
|
|
1167
|
+
map: "organization",
|
|
1168
|
+
fields: {
|
|
1169
|
+
id: field2.id({ description: "Unique organization identifier" }),
|
|
1170
|
+
name: field2.string({ description: "Organization display name" }),
|
|
1171
|
+
slug: field2.string({
|
|
1172
|
+
isOptional: true,
|
|
1173
|
+
isUnique: true,
|
|
1174
|
+
description: "URL-friendly identifier"
|
|
1175
|
+
}),
|
|
1176
|
+
logo: field2.url({ isOptional: true, description: "Organization logo URL" }),
|
|
1177
|
+
description: field2.string({
|
|
1178
|
+
isOptional: true,
|
|
1179
|
+
description: "Organization description"
|
|
1180
|
+
}),
|
|
1181
|
+
metadata: field2.json({
|
|
1182
|
+
isOptional: true,
|
|
1183
|
+
description: "Arbitrary organization metadata"
|
|
1184
|
+
}),
|
|
1185
|
+
type: field2.enum("OrganizationType", { description: "Organization type" }),
|
|
1186
|
+
onboardingCompleted: field2.boolean({ default: false }),
|
|
1187
|
+
onboardingStep: field2.string({ isOptional: true }),
|
|
1188
|
+
referralCode: field2.string({
|
|
1189
|
+
isOptional: true,
|
|
1190
|
+
isUnique: true,
|
|
1191
|
+
description: "Unique referral code"
|
|
1192
|
+
}),
|
|
1193
|
+
referredBy: field2.string({
|
|
1194
|
+
isOptional: true,
|
|
1195
|
+
description: "ID of referring user"
|
|
1196
|
+
}),
|
|
1197
|
+
createdAt: field2.createdAt(),
|
|
1198
|
+
updatedAt: field2.updatedAt(),
|
|
1199
|
+
members: field2.hasMany("Member"),
|
|
1200
|
+
invitations: field2.hasMany("Invitation"),
|
|
1201
|
+
teams: field2.hasMany("Team"),
|
|
1202
|
+
policyBindings: field2.hasMany("PolicyBinding")
|
|
1203
|
+
},
|
|
1204
|
+
enums: [OrganizationTypeEnum]
|
|
1205
|
+
});
|
|
1206
|
+
var MemberEntity = defineEntity2({
|
|
1207
|
+
name: "Member",
|
|
1208
|
+
description: "Membership of a user in an organization with a role.",
|
|
1209
|
+
schema: "lssm_sigil",
|
|
1210
|
+
map: "member",
|
|
1211
|
+
fields: {
|
|
1212
|
+
id: field2.id(),
|
|
1213
|
+
userId: field2.foreignKey(),
|
|
1214
|
+
organizationId: field2.foreignKey(),
|
|
1215
|
+
role: field2.string({
|
|
1216
|
+
description: "Role in organization (owner, admin, member)"
|
|
1217
|
+
}),
|
|
1218
|
+
createdAt: field2.createdAt(),
|
|
1219
|
+
user: field2.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" }),
|
|
1220
|
+
organization: field2.belongsTo("Organization", ["organizationId"], ["id"], {
|
|
1221
|
+
onDelete: "Cascade"
|
|
1222
|
+
})
|
|
1223
|
+
},
|
|
1224
|
+
indexes: [index2.unique(["userId", "organizationId"])]
|
|
1225
|
+
});
|
|
1226
|
+
var InvitationEntity = defineEntity2({
|
|
1227
|
+
name: "Invitation",
|
|
1228
|
+
description: "An invitation to join an organization.",
|
|
1229
|
+
schema: "lssm_sigil",
|
|
1230
|
+
map: "invitation",
|
|
1231
|
+
fields: {
|
|
1232
|
+
id: field2.id(),
|
|
1233
|
+
organizationId: field2.foreignKey(),
|
|
1234
|
+
email: field2.email({ description: "Invited email address" }),
|
|
1235
|
+
role: field2.string({
|
|
1236
|
+
isOptional: true,
|
|
1237
|
+
description: "Role to assign on acceptance"
|
|
1238
|
+
}),
|
|
1239
|
+
status: field2.string({
|
|
1240
|
+
default: '"pending"',
|
|
1241
|
+
description: "Invitation status"
|
|
1242
|
+
}),
|
|
1243
|
+
acceptedAt: field2.dateTime({ isOptional: true }),
|
|
1244
|
+
expiresAt: field2.dateTime({ isOptional: true }),
|
|
1245
|
+
inviterId: field2.foreignKey({
|
|
1246
|
+
description: "User who sent the invitation"
|
|
1247
|
+
}),
|
|
1248
|
+
teamId: field2.string({ isOptional: true }),
|
|
1249
|
+
createdAt: field2.createdAt(),
|
|
1250
|
+
updatedAt: field2.updatedAt(),
|
|
1251
|
+
organization: field2.belongsTo("Organization", ["organizationId"], ["id"], {
|
|
1252
|
+
onDelete: "Cascade"
|
|
1253
|
+
}),
|
|
1254
|
+
inviter: field2.belongsTo("User", ["inviterId"], ["id"], {
|
|
1255
|
+
onDelete: "Cascade"
|
|
1256
|
+
}),
|
|
1257
|
+
team: field2.belongsTo("Team", ["teamId"], ["id"], { onDelete: "Cascade" })
|
|
1258
|
+
}
|
|
1259
|
+
});
|
|
1260
|
+
var TeamEntity = defineEntity2({
|
|
1261
|
+
name: "Team",
|
|
1262
|
+
description: "Team within an organization.",
|
|
1263
|
+
schema: "lssm_sigil",
|
|
1264
|
+
map: "team",
|
|
1265
|
+
fields: {
|
|
1266
|
+
id: field2.id(),
|
|
1267
|
+
name: field2.string({ description: "Team name" }),
|
|
1268
|
+
organizationId: field2.foreignKey(),
|
|
1269
|
+
createdAt: field2.createdAt(),
|
|
1270
|
+
updatedAt: field2.updatedAt(),
|
|
1271
|
+
organization: field2.belongsTo("Organization", ["organizationId"], ["id"], {
|
|
1272
|
+
onDelete: "Cascade"
|
|
1273
|
+
}),
|
|
1274
|
+
members: field2.hasMany("TeamMember"),
|
|
1275
|
+
invitations: field2.hasMany("Invitation")
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
var TeamMemberEntity = defineEntity2({
|
|
1279
|
+
name: "TeamMember",
|
|
1280
|
+
description: "Team membership for a user.",
|
|
1281
|
+
schema: "lssm_sigil",
|
|
1282
|
+
map: "team_member",
|
|
1283
|
+
fields: {
|
|
1284
|
+
id: field2.id(),
|
|
1285
|
+
teamId: field2.foreignKey(),
|
|
1286
|
+
userId: field2.foreignKey(),
|
|
1287
|
+
createdAt: field2.createdAt(),
|
|
1288
|
+
team: field2.belongsTo("Team", ["teamId"], ["id"], { onDelete: "Cascade" }),
|
|
1289
|
+
user: field2.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
|
|
1293
|
+
// src/entities/rbac.ts
|
|
1294
|
+
import { defineEntity as defineEntity3, field as field3, index as index3 } from "@contractspec/lib.schema";
|
|
1295
|
+
var RoleEntity = defineEntity3({
|
|
1296
|
+
name: "Role",
|
|
1297
|
+
description: "A role defines a named set of permissions.",
|
|
1298
|
+
schema: "lssm_sigil",
|
|
1299
|
+
map: "role",
|
|
1300
|
+
fields: {
|
|
1301
|
+
id: field3.id(),
|
|
1302
|
+
name: field3.string({ isUnique: true, description: "Unique role name" }),
|
|
1303
|
+
description: field3.string({
|
|
1304
|
+
isOptional: true,
|
|
1305
|
+
description: "Role description"
|
|
1306
|
+
}),
|
|
1307
|
+
permissions: field3.string({
|
|
1308
|
+
isArray: true,
|
|
1309
|
+
description: "Array of permission names"
|
|
1310
|
+
}),
|
|
1311
|
+
createdAt: field3.createdAt(),
|
|
1312
|
+
updatedAt: field3.updatedAt(),
|
|
1313
|
+
policyBindings: field3.hasMany("PolicyBinding")
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
var PermissionEntity = defineEntity3({
|
|
1317
|
+
name: "Permission",
|
|
1318
|
+
description: "A permission represents an atomic access right.",
|
|
1319
|
+
schema: "lssm_sigil",
|
|
1320
|
+
map: "permission",
|
|
1321
|
+
fields: {
|
|
1322
|
+
id: field3.id(),
|
|
1323
|
+
name: field3.string({
|
|
1324
|
+
isUnique: true,
|
|
1325
|
+
description: "Unique permission name"
|
|
1326
|
+
}),
|
|
1327
|
+
description: field3.string({
|
|
1328
|
+
isOptional: true,
|
|
1329
|
+
description: "Permission description"
|
|
1330
|
+
}),
|
|
1331
|
+
createdAt: field3.createdAt(),
|
|
1332
|
+
updatedAt: field3.updatedAt()
|
|
1333
|
+
}
|
|
1334
|
+
});
|
|
1335
|
+
var PolicyBindingEntity = defineEntity3({
|
|
1336
|
+
name: "PolicyBinding",
|
|
1337
|
+
description: "Binds roles to principals (users or organizations).",
|
|
1338
|
+
schema: "lssm_sigil",
|
|
1339
|
+
map: "policy_binding",
|
|
1340
|
+
fields: {
|
|
1341
|
+
id: field3.id(),
|
|
1342
|
+
roleId: field3.foreignKey(),
|
|
1343
|
+
targetType: field3.string({ description: '"user" or "organization"' }),
|
|
1344
|
+
targetId: field3.string({ description: "ID of User or Organization" }),
|
|
1345
|
+
expiresAt: field3.dateTime({
|
|
1346
|
+
isOptional: true,
|
|
1347
|
+
description: "When binding expires"
|
|
1348
|
+
}),
|
|
1349
|
+
createdAt: field3.createdAt(),
|
|
1350
|
+
userId: field3.string({ isOptional: true }),
|
|
1351
|
+
organizationId: field3.string({ isOptional: true }),
|
|
1352
|
+
role: field3.belongsTo("Role", ["roleId"], ["id"], { onDelete: "Cascade" }),
|
|
1353
|
+
user: field3.belongsTo("User", ["userId"], ["id"]),
|
|
1354
|
+
organization: field3.belongsTo("Organization", ["organizationId"], ["id"])
|
|
1355
|
+
},
|
|
1356
|
+
indexes: [index3.on(["targetType", "targetId"])]
|
|
1357
|
+
});
|
|
1358
|
+
var ApiKeyEntity = defineEntity3({
|
|
1359
|
+
name: "ApiKey",
|
|
1360
|
+
description: "API keys for programmatic access.",
|
|
1361
|
+
schema: "lssm_sigil",
|
|
1362
|
+
map: "api_key",
|
|
1363
|
+
fields: {
|
|
1364
|
+
id: field3.id(),
|
|
1365
|
+
name: field3.string({ description: "API key name" }),
|
|
1366
|
+
start: field3.string({
|
|
1367
|
+
description: "Starting characters for identification"
|
|
1368
|
+
}),
|
|
1369
|
+
prefix: field3.string({ description: "API key prefix" }),
|
|
1370
|
+
key: field3.string({ description: "Hashed API key" }),
|
|
1371
|
+
userId: field3.foreignKey(),
|
|
1372
|
+
refillInterval: field3.int({ description: "Refill interval in ms" }),
|
|
1373
|
+
refillAmount: field3.int({ description: "Amount to refill" }),
|
|
1374
|
+
lastRefillAt: field3.dateTime(),
|
|
1375
|
+
remaining: field3.int({ description: "Remaining requests" }),
|
|
1376
|
+
requestCount: field3.int({ description: "Total requests made" }),
|
|
1377
|
+
lastRequest: field3.dateTime(),
|
|
1378
|
+
enabled: field3.boolean({ default: true }),
|
|
1379
|
+
rateLimitEnabled: field3.boolean({ default: true }),
|
|
1380
|
+
rateLimitTimeWindow: field3.int({ description: "Rate limit window in ms" }),
|
|
1381
|
+
rateLimitMax: field3.int({ description: "Max requests in window" }),
|
|
1382
|
+
expiresAt: field3.dateTime(),
|
|
1383
|
+
permissions: field3.string({ isArray: true }),
|
|
1384
|
+
metadata: field3.json({ isOptional: true }),
|
|
1385
|
+
createdAt: field3.createdAt(),
|
|
1386
|
+
updatedAt: field3.updatedAt(),
|
|
1387
|
+
user: field3.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
var PasskeyEntity = defineEntity3({
|
|
1391
|
+
name: "Passkey",
|
|
1392
|
+
description: "WebAuthn passkeys for passwordless authentication.",
|
|
1393
|
+
schema: "lssm_sigil",
|
|
1394
|
+
map: "passkey",
|
|
1395
|
+
fields: {
|
|
1396
|
+
id: field3.id(),
|
|
1397
|
+
name: field3.string({ description: "Passkey name" }),
|
|
1398
|
+
publicKey: field3.string({ description: "Public key" }),
|
|
1399
|
+
userId: field3.foreignKey(),
|
|
1400
|
+
credentialID: field3.string({ description: "Credential ID" }),
|
|
1401
|
+
counter: field3.int({ description: "Counter" }),
|
|
1402
|
+
deviceType: field3.string({ description: "Device type" }),
|
|
1403
|
+
backedUp: field3.boolean({ description: "Whether passkey is backed up" }),
|
|
1404
|
+
transports: field3.string({ description: "Transports" }),
|
|
1405
|
+
aaguid: field3.string({ description: "Authenticator GUID" }),
|
|
1406
|
+
createdAt: field3.createdAt(),
|
|
1407
|
+
user: field3.belongsTo("User", ["userId"], ["id"], { onDelete: "Cascade" })
|
|
1408
|
+
}
|
|
1409
|
+
});
|
|
1410
|
+
// src/entities/index.ts
|
|
1411
|
+
var identityRbacEntities = [
|
|
1412
|
+
UserEntity,
|
|
1413
|
+
SessionEntity,
|
|
1414
|
+
AccountEntity,
|
|
1415
|
+
VerificationEntity,
|
|
1416
|
+
OrganizationEntity,
|
|
1417
|
+
MemberEntity,
|
|
1418
|
+
InvitationEntity,
|
|
1419
|
+
TeamEntity,
|
|
1420
|
+
TeamMemberEntity,
|
|
1421
|
+
RoleEntity,
|
|
1422
|
+
PermissionEntity,
|
|
1423
|
+
PolicyBindingEntity,
|
|
1424
|
+
ApiKeyEntity,
|
|
1425
|
+
PasskeyEntity
|
|
1426
|
+
];
|
|
1427
|
+
var identityRbacSchemaContribution = {
|
|
1428
|
+
moduleId: "@contractspec/lib.identity-rbac",
|
|
1429
|
+
entities: identityRbacEntities,
|
|
1430
|
+
enums: [OrganizationTypeEnum]
|
|
1431
|
+
};
|
|
1432
|
+
|
|
1433
|
+
// src/events.ts
|
|
1434
|
+
import { SchemaModel as SchemaModel4, ScalarTypeEnum as ScalarTypeEnum4 } from "@contractspec/lib.schema";
|
|
1435
|
+
import { defineEvent } from "@contractspec/lib.contracts";
|
|
1436
|
+
var UserCreatedPayload = new SchemaModel4({
|
|
1437
|
+
name: "UserCreatedPayload",
|
|
1438
|
+
description: "Payload for user created event",
|
|
1439
|
+
fields: {
|
|
1440
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1441
|
+
email: { type: ScalarTypeEnum4.EmailAddress(), isOptional: false },
|
|
1442
|
+
name: { type: ScalarTypeEnum4.String_unsecure(), isOptional: true },
|
|
1443
|
+
createdAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1444
|
+
}
|
|
1445
|
+
});
|
|
1446
|
+
var UserUpdatedPayload = new SchemaModel4({
|
|
1447
|
+
name: "UserUpdatedPayload",
|
|
1448
|
+
description: "Payload for user updated event",
|
|
1449
|
+
fields: {
|
|
1450
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1451
|
+
updatedFields: {
|
|
1452
|
+
type: ScalarTypeEnum4.String_unsecure(),
|
|
1453
|
+
isOptional: false,
|
|
1454
|
+
isArray: true
|
|
1455
|
+
},
|
|
1456
|
+
updatedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
var UserDeletedPayload = new SchemaModel4({
|
|
1460
|
+
name: "UserDeletedPayload",
|
|
1461
|
+
description: "Payload for user deleted event",
|
|
1462
|
+
fields: {
|
|
1463
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1464
|
+
email: { type: ScalarTypeEnum4.EmailAddress(), isOptional: false },
|
|
1465
|
+
deletedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
var UserEmailVerifiedPayload = new SchemaModel4({
|
|
1469
|
+
name: "UserEmailVerifiedPayload",
|
|
1470
|
+
description: "Payload for user email verified event",
|
|
1471
|
+
fields: {
|
|
1472
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1473
|
+
email: { type: ScalarTypeEnum4.EmailAddress(), isOptional: false },
|
|
1474
|
+
verifiedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1475
|
+
}
|
|
1476
|
+
});
|
|
1477
|
+
var OrgCreatedPayload = new SchemaModel4({
|
|
1478
|
+
name: "OrgCreatedPayload",
|
|
1479
|
+
description: "Payload for org created event",
|
|
1480
|
+
fields: {
|
|
1481
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1482
|
+
name: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1483
|
+
slug: { type: ScalarTypeEnum4.String_unsecure(), isOptional: true },
|
|
1484
|
+
createdBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1485
|
+
createdAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1488
|
+
var OrgUpdatedPayload = new SchemaModel4({
|
|
1489
|
+
name: "OrgUpdatedPayload",
|
|
1490
|
+
description: "Payload for org updated event",
|
|
1491
|
+
fields: {
|
|
1492
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1493
|
+
updatedFields: {
|
|
1494
|
+
type: ScalarTypeEnum4.String_unsecure(),
|
|
1495
|
+
isOptional: false,
|
|
1496
|
+
isArray: true
|
|
1497
|
+
},
|
|
1498
|
+
updatedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1499
|
+
updatedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
var OrgDeletedPayload = new SchemaModel4({
|
|
1503
|
+
name: "OrgDeletedPayload",
|
|
1504
|
+
description: "Payload for org deleted event",
|
|
1505
|
+
fields: {
|
|
1506
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1507
|
+
name: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1508
|
+
deletedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1509
|
+
deletedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1510
|
+
}
|
|
1511
|
+
});
|
|
1512
|
+
var OrgMemberAddedPayload = new SchemaModel4({
|
|
1513
|
+
name: "OrgMemberAddedPayload",
|
|
1514
|
+
description: "Payload for member added event",
|
|
1515
|
+
fields: {
|
|
1516
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1517
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1518
|
+
role: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1519
|
+
invitedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: true },
|
|
1520
|
+
joinedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
var OrgMemberRemovedPayload = new SchemaModel4({
|
|
1524
|
+
name: "OrgMemberRemovedPayload",
|
|
1525
|
+
description: "Payload for member removed event",
|
|
1526
|
+
fields: {
|
|
1527
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1528
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1529
|
+
removedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: true },
|
|
1530
|
+
reason: { type: ScalarTypeEnum4.String_unsecure(), isOptional: true },
|
|
1531
|
+
removedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
var OrgMemberRoleChangedPayload = new SchemaModel4({
|
|
1535
|
+
name: "OrgMemberRoleChangedPayload",
|
|
1536
|
+
description: "Payload for member role changed event",
|
|
1537
|
+
fields: {
|
|
1538
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1539
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1540
|
+
previousRole: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1541
|
+
newRole: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1542
|
+
changedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1543
|
+
changedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
var OrgInviteSentPayload = new SchemaModel4({
|
|
1547
|
+
name: "OrgInviteSentPayload",
|
|
1548
|
+
description: "Payload for invite sent event",
|
|
1549
|
+
fields: {
|
|
1550
|
+
invitationId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1551
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1552
|
+
email: { type: ScalarTypeEnum4.EmailAddress(), isOptional: false },
|
|
1553
|
+
role: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1554
|
+
invitedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1555
|
+
expiresAt: { type: ScalarTypeEnum4.DateTime(), isOptional: true },
|
|
1556
|
+
sentAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
var OrgInviteAcceptedPayload = new SchemaModel4({
|
|
1560
|
+
name: "OrgInviteAcceptedPayload",
|
|
1561
|
+
description: "Payload for invite accepted event",
|
|
1562
|
+
fields: {
|
|
1563
|
+
invitationId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1564
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1565
|
+
userId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1566
|
+
acceptedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1567
|
+
}
|
|
1568
|
+
});
|
|
1569
|
+
var OrgInviteDeclinedPayload = new SchemaModel4({
|
|
1570
|
+
name: "OrgInviteDeclinedPayload",
|
|
1571
|
+
description: "Payload for invite declined event",
|
|
1572
|
+
fields: {
|
|
1573
|
+
invitationId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1574
|
+
orgId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1575
|
+
declinedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1576
|
+
}
|
|
1577
|
+
});
|
|
1578
|
+
var RoleAssignedPayload = new SchemaModel4({
|
|
1579
|
+
name: "RoleAssignedPayload",
|
|
1580
|
+
description: "Payload for role assigned event",
|
|
1581
|
+
fields: {
|
|
1582
|
+
bindingId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1583
|
+
roleId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1584
|
+
roleName: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1585
|
+
targetType: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1586
|
+
targetId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1587
|
+
assignedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1588
|
+
expiresAt: { type: ScalarTypeEnum4.DateTime(), isOptional: true },
|
|
1589
|
+
assignedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1590
|
+
}
|
|
1591
|
+
});
|
|
1592
|
+
var RoleRevokedPayload = new SchemaModel4({
|
|
1593
|
+
name: "RoleRevokedPayload",
|
|
1594
|
+
description: "Payload for role revoked event",
|
|
1595
|
+
fields: {
|
|
1596
|
+
bindingId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1597
|
+
roleId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1598
|
+
roleName: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1599
|
+
targetType: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1600
|
+
targetId: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1601
|
+
revokedBy: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false },
|
|
1602
|
+
revokedAt: { type: ScalarTypeEnum4.DateTime(), isOptional: false }
|
|
1603
|
+
}
|
|
1604
|
+
});
|
|
1605
|
+
var UserCreatedEvent = defineEvent({
|
|
1606
|
+
meta: {
|
|
1607
|
+
key: "user.created",
|
|
1608
|
+
version: "1.0.0",
|
|
1609
|
+
description: "A new user has been created.",
|
|
1610
|
+
stability: "stable",
|
|
1611
|
+
owners: ["@platform.identity-rbac"],
|
|
1612
|
+
tags: ["user", "created", "identity"]
|
|
1613
|
+
},
|
|
1614
|
+
payload: UserCreatedPayload
|
|
1615
|
+
});
|
|
1616
|
+
var UserUpdatedEvent = defineEvent({
|
|
1617
|
+
meta: {
|
|
1618
|
+
key: "user.updated",
|
|
1619
|
+
version: "1.0.0",
|
|
1620
|
+
description: "A user profile has been updated.",
|
|
1621
|
+
stability: "stable",
|
|
1622
|
+
owners: ["@platform.identity-rbac"],
|
|
1623
|
+
tags: ["user", "updated", "identity"]
|
|
1624
|
+
},
|
|
1625
|
+
payload: UserUpdatedPayload
|
|
1626
|
+
});
|
|
1627
|
+
var UserDeletedEvent = defineEvent({
|
|
1628
|
+
meta: {
|
|
1629
|
+
key: "user.deleted",
|
|
1630
|
+
version: "1.0.0",
|
|
1631
|
+
description: "A user account has been deleted.",
|
|
1632
|
+
stability: "stable",
|
|
1633
|
+
owners: ["@platform.identity-rbac"],
|
|
1634
|
+
tags: ["user", "deleted", "identity"]
|
|
1635
|
+
},
|
|
1636
|
+
pii: ["email"],
|
|
1637
|
+
payload: UserDeletedPayload
|
|
1638
|
+
});
|
|
1639
|
+
var UserEmailVerifiedEvent = defineEvent({
|
|
1640
|
+
meta: {
|
|
1641
|
+
key: "user.email_verified",
|
|
1642
|
+
version: "1.0.0",
|
|
1643
|
+
description: "A user has verified their email address.",
|
|
1644
|
+
stability: "stable",
|
|
1645
|
+
owners: ["@platform.identity-rbac"],
|
|
1646
|
+
tags: ["user", "verified", "identity"]
|
|
1647
|
+
},
|
|
1648
|
+
payload: UserEmailVerifiedPayload
|
|
1649
|
+
});
|
|
1650
|
+
var OrgCreatedEvent = defineEvent({
|
|
1651
|
+
meta: {
|
|
1652
|
+
key: "org.created",
|
|
1653
|
+
version: "1.0.0",
|
|
1654
|
+
description: "A new organization has been created.",
|
|
1655
|
+
stability: "stable",
|
|
1656
|
+
owners: ["@platform.identity-rbac"],
|
|
1657
|
+
tags: ["org", "created", "identity"]
|
|
1658
|
+
},
|
|
1659
|
+
payload: OrgCreatedPayload
|
|
1660
|
+
});
|
|
1661
|
+
var OrgUpdatedEvent = defineEvent({
|
|
1662
|
+
meta: {
|
|
1663
|
+
key: "org.updated",
|
|
1664
|
+
version: "1.0.0",
|
|
1665
|
+
description: "An organization has been updated.",
|
|
1666
|
+
stability: "stable",
|
|
1667
|
+
owners: ["@platform.identity-rbac"],
|
|
1668
|
+
tags: ["org", "updated", "identity"]
|
|
1669
|
+
},
|
|
1670
|
+
payload: OrgUpdatedPayload
|
|
1671
|
+
});
|
|
1672
|
+
var OrgDeletedEvent = defineEvent({
|
|
1673
|
+
meta: {
|
|
1674
|
+
key: "org.deleted",
|
|
1675
|
+
version: "1.0.0",
|
|
1676
|
+
description: "An organization has been deleted.",
|
|
1677
|
+
stability: "stable",
|
|
1678
|
+
owners: ["@platform.identity-rbac"],
|
|
1679
|
+
tags: ["org", "deleted", "identity"]
|
|
1680
|
+
},
|
|
1681
|
+
payload: OrgDeletedPayload
|
|
1682
|
+
});
|
|
1683
|
+
var OrgMemberAddedEvent = defineEvent({
|
|
1684
|
+
meta: {
|
|
1685
|
+
key: "org.member.added",
|
|
1686
|
+
version: "1.0.0",
|
|
1687
|
+
description: "A user has joined an organization.",
|
|
1688
|
+
stability: "stable",
|
|
1689
|
+
owners: ["@platform.identity-rbac"],
|
|
1690
|
+
tags: ["org", "member", "added", "identity"]
|
|
1691
|
+
},
|
|
1692
|
+
payload: OrgMemberAddedPayload
|
|
1693
|
+
});
|
|
1694
|
+
var OrgMemberRemovedEvent = defineEvent({
|
|
1695
|
+
meta: {
|
|
1696
|
+
key: "org.member.removed",
|
|
1697
|
+
version: "1.0.0",
|
|
1698
|
+
description: "A user has left or been removed from an organization.",
|
|
1699
|
+
stability: "stable",
|
|
1700
|
+
owners: ["@platform.identity-rbac"],
|
|
1701
|
+
tags: ["org", "member", "removed", "identity"]
|
|
1702
|
+
},
|
|
1703
|
+
payload: OrgMemberRemovedPayload
|
|
1704
|
+
});
|
|
1705
|
+
var OrgMemberRoleChangedEvent = defineEvent({
|
|
1706
|
+
meta: {
|
|
1707
|
+
key: "org.member.role_changed",
|
|
1708
|
+
version: "1.0.0",
|
|
1709
|
+
description: "A member's role in an organization has changed.",
|
|
1710
|
+
stability: "stable",
|
|
1711
|
+
owners: ["@platform.identity-rbac"],
|
|
1712
|
+
tags: ["org", "member", "role", "changed", "identity"]
|
|
1713
|
+
},
|
|
1714
|
+
payload: OrgMemberRoleChangedPayload
|
|
1715
|
+
});
|
|
1716
|
+
var OrgInviteSentEvent = defineEvent({
|
|
1717
|
+
meta: {
|
|
1718
|
+
key: "org.invite.sent",
|
|
1719
|
+
version: "1.0.0",
|
|
1720
|
+
description: "An invitation to join an organization has been sent.",
|
|
1721
|
+
stability: "stable",
|
|
1722
|
+
owners: ["@platform.identity-rbac"],
|
|
1723
|
+
tags: ["org", "invite", "sent", "identity"]
|
|
1724
|
+
},
|
|
1725
|
+
pii: ["email"],
|
|
1726
|
+
payload: OrgInviteSentPayload
|
|
1727
|
+
});
|
|
1728
|
+
var OrgInviteAcceptedEvent = defineEvent({
|
|
1729
|
+
meta: {
|
|
1730
|
+
key: "org.invite.accepted",
|
|
1731
|
+
version: "1.0.0",
|
|
1732
|
+
description: "An invitation has been accepted.",
|
|
1733
|
+
stability: "stable",
|
|
1734
|
+
owners: ["@platform.identity-rbac"],
|
|
1735
|
+
tags: ["org", "invite", "accepted", "identity"]
|
|
1736
|
+
},
|
|
1737
|
+
payload: OrgInviteAcceptedPayload
|
|
1738
|
+
});
|
|
1739
|
+
var OrgInviteDeclinedEvent = defineEvent({
|
|
1740
|
+
meta: {
|
|
1741
|
+
key: "org.invite.declined",
|
|
1742
|
+
version: "1.0.0",
|
|
1743
|
+
description: "An invitation has been declined.",
|
|
1744
|
+
stability: "stable",
|
|
1745
|
+
owners: ["@platform.identity-rbac"],
|
|
1746
|
+
tags: ["org", "invite", "declined", "identity"]
|
|
1747
|
+
},
|
|
1748
|
+
payload: OrgInviteDeclinedPayload
|
|
1749
|
+
});
|
|
1750
|
+
var RoleAssignedEvent = defineEvent({
|
|
1751
|
+
meta: {
|
|
1752
|
+
key: "role.assigned",
|
|
1753
|
+
version: "1.0.0",
|
|
1754
|
+
description: "A role has been assigned.",
|
|
1755
|
+
stability: "stable",
|
|
1756
|
+
owners: ["@platform.identity-rbac"],
|
|
1757
|
+
tags: ["role", "assigned", "identity"]
|
|
1758
|
+
},
|
|
1759
|
+
payload: RoleAssignedPayload
|
|
1760
|
+
});
|
|
1761
|
+
var RoleRevokedEvent = defineEvent({
|
|
1762
|
+
meta: {
|
|
1763
|
+
key: "role.revoked",
|
|
1764
|
+
version: "1.0.0",
|
|
1765
|
+
description: "A role has been revoked.",
|
|
1766
|
+
stability: "stable",
|
|
1767
|
+
owners: ["@platform.identity-rbac"],
|
|
1768
|
+
tags: ["role", "revoked", "identity"]
|
|
1769
|
+
},
|
|
1770
|
+
payload: RoleRevokedPayload
|
|
1771
|
+
});
|
|
1772
|
+
var IdentityRbacEvents = {
|
|
1773
|
+
UserCreatedEvent,
|
|
1774
|
+
UserUpdatedEvent,
|
|
1775
|
+
UserDeletedEvent,
|
|
1776
|
+
UserEmailVerifiedEvent,
|
|
1777
|
+
OrgCreatedEvent,
|
|
1778
|
+
OrgUpdatedEvent,
|
|
1779
|
+
OrgDeletedEvent,
|
|
1780
|
+
OrgMemberAddedEvent,
|
|
1781
|
+
OrgMemberRemovedEvent,
|
|
1782
|
+
OrgMemberRoleChangedEvent,
|
|
1783
|
+
OrgInviteSentEvent,
|
|
1784
|
+
OrgInviteAcceptedEvent,
|
|
1785
|
+
OrgInviteDeclinedEvent,
|
|
1786
|
+
RoleAssignedEvent,
|
|
1787
|
+
RoleRevokedEvent
|
|
1788
|
+
};
|
|
1789
|
+
|
|
1790
|
+
// src/identity-rbac.feature.ts
|
|
1791
|
+
import { defineFeature } from "@contractspec/lib.contracts";
|
|
1792
|
+
var IdentityRbacFeature = defineFeature({
|
|
1793
|
+
meta: {
|
|
1794
|
+
key: "identity-rbac",
|
|
1795
|
+
version: "1.0.0",
|
|
1796
|
+
title: "Identity & RBAC",
|
|
1797
|
+
description: "User identity, organization management, and role-based access control",
|
|
1798
|
+
domain: "platform",
|
|
1799
|
+
owners: ["@platform.identity-rbac"],
|
|
1800
|
+
tags: ["identity", "rbac", "users", "organizations", "permissions"],
|
|
1801
|
+
stability: "stable"
|
|
1802
|
+
},
|
|
1803
|
+
operations: [
|
|
1804
|
+
{ key: "identity.user.create", version: "1.0.0" },
|
|
1805
|
+
{ key: "identity.user.update", version: "1.0.0" },
|
|
1806
|
+
{ key: "identity.user.delete", version: "1.0.0" },
|
|
1807
|
+
{ key: "identity.user.me", version: "1.0.0" },
|
|
1808
|
+
{ key: "identity.user.list", version: "1.0.0" },
|
|
1809
|
+
{ key: "identity.org.create", version: "1.0.0" },
|
|
1810
|
+
{ key: "identity.org.update", version: "1.0.0" },
|
|
1811
|
+
{ key: "identity.org.get", version: "1.0.0" },
|
|
1812
|
+
{ key: "identity.org.list", version: "1.0.0" },
|
|
1813
|
+
{ key: "identity.org.invite", version: "1.0.0" },
|
|
1814
|
+
{ key: "identity.org.invite.accept", version: "1.0.0" },
|
|
1815
|
+
{ key: "identity.org.member.remove", version: "1.0.0" },
|
|
1816
|
+
{ key: "identity.org.members.list", version: "1.0.0" },
|
|
1817
|
+
{ key: "identity.rbac.role.create", version: "1.0.0" },
|
|
1818
|
+
{ key: "identity.rbac.role.update", version: "1.0.0" },
|
|
1819
|
+
{ key: "identity.rbac.role.delete", version: "1.0.0" },
|
|
1820
|
+
{ key: "identity.rbac.role.list", version: "1.0.0" },
|
|
1821
|
+
{ key: "identity.rbac.assign", version: "1.0.0" },
|
|
1822
|
+
{ key: "identity.rbac.revoke", version: "1.0.0" },
|
|
1823
|
+
{ key: "identity.rbac.check", version: "1.0.0" },
|
|
1824
|
+
{ key: "identity.rbac.permissions", version: "1.0.0" }
|
|
1825
|
+
],
|
|
1826
|
+
events: [
|
|
1827
|
+
{ key: "user.created", version: "1.0.0" },
|
|
1828
|
+
{ key: "user.updated", version: "1.0.0" },
|
|
1829
|
+
{ key: "user.deleted", version: "1.0.0" },
|
|
1830
|
+
{ key: "user.email_verified", version: "1.0.0" },
|
|
1831
|
+
{ key: "org.created", version: "1.0.0" },
|
|
1832
|
+
{ key: "org.updated", version: "1.0.0" },
|
|
1833
|
+
{ key: "org.deleted", version: "1.0.0" },
|
|
1834
|
+
{ key: "org.member.added", version: "1.0.0" },
|
|
1835
|
+
{ key: "org.member.removed", version: "1.0.0" },
|
|
1836
|
+
{ key: "org.member.role_changed", version: "1.0.0" },
|
|
1837
|
+
{ key: "org.invite.sent", version: "1.0.0" },
|
|
1838
|
+
{ key: "org.invite.accepted", version: "1.0.0" },
|
|
1839
|
+
{ key: "org.invite.declined", version: "1.0.0" },
|
|
1840
|
+
{ key: "role.assigned", version: "1.0.0" },
|
|
1841
|
+
{ key: "role.revoked", version: "1.0.0" }
|
|
1842
|
+
],
|
|
1843
|
+
presentations: [],
|
|
1844
|
+
opToPresentation: [],
|
|
1845
|
+
presentationsTargets: [],
|
|
1846
|
+
capabilities: {
|
|
1847
|
+
provides: [
|
|
1848
|
+
{ key: "identity", version: "1.0.0" },
|
|
1849
|
+
{ key: "rbac", version: "1.0.0" }
|
|
1850
|
+
],
|
|
1851
|
+
requires: []
|
|
1852
|
+
}
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
// src/policies/engine.ts
|
|
1856
|
+
var Permission = {
|
|
1857
|
+
USER_CREATE: "user.create",
|
|
1858
|
+
USER_READ: "user.read",
|
|
1859
|
+
USER_UPDATE: "user.update",
|
|
1860
|
+
USER_DELETE: "user.delete",
|
|
1861
|
+
USER_LIST: "user.list",
|
|
1862
|
+
USER_MANAGE: "user.manage",
|
|
1863
|
+
ORG_CREATE: "org.create",
|
|
1864
|
+
ORG_READ: "org.read",
|
|
1865
|
+
ORG_UPDATE: "org.update",
|
|
1866
|
+
ORG_DELETE: "org.delete",
|
|
1867
|
+
ORG_LIST: "org.list",
|
|
1868
|
+
MEMBER_INVITE: "member.invite",
|
|
1869
|
+
MEMBER_REMOVE: "member.remove",
|
|
1870
|
+
MEMBER_UPDATE_ROLE: "member.update_role",
|
|
1871
|
+
MEMBER_LIST: "member.list",
|
|
1872
|
+
MANAGE_MEMBERS: "org.manage_members",
|
|
1873
|
+
TEAM_CREATE: "team.create",
|
|
1874
|
+
TEAM_UPDATE: "team.update",
|
|
1875
|
+
TEAM_DELETE: "team.delete",
|
|
1876
|
+
TEAM_MANAGE: "team.manage",
|
|
1877
|
+
ROLE_CREATE: "role.create",
|
|
1878
|
+
ROLE_UPDATE: "role.update",
|
|
1879
|
+
ROLE_DELETE: "role.delete",
|
|
1880
|
+
ROLE_ASSIGN: "role.assign",
|
|
1881
|
+
ROLE_REVOKE: "role.revoke",
|
|
1882
|
+
BILLING_VIEW: "billing.view",
|
|
1883
|
+
BILLING_MANAGE: "billing.manage",
|
|
1884
|
+
PROJECT_CREATE: "project.create",
|
|
1885
|
+
PROJECT_READ: "project.read",
|
|
1886
|
+
PROJECT_UPDATE: "project.update",
|
|
1887
|
+
PROJECT_DELETE: "project.delete",
|
|
1888
|
+
PROJECT_MANAGE: "project.manage",
|
|
1889
|
+
ADMIN_ACCESS: "admin.access",
|
|
1890
|
+
ADMIN_IMPERSONATE: "admin.impersonate"
|
|
1891
|
+
};
|
|
1892
|
+
var StandardRole = {
|
|
1893
|
+
OWNER: {
|
|
1894
|
+
name: "owner",
|
|
1895
|
+
description: "Organization owner with full access",
|
|
1896
|
+
permissions: Object.values(Permission)
|
|
1897
|
+
},
|
|
1898
|
+
ADMIN: {
|
|
1899
|
+
name: "admin",
|
|
1900
|
+
description: "Administrator with most permissions",
|
|
1901
|
+
permissions: [
|
|
1902
|
+
Permission.USER_READ,
|
|
1903
|
+
Permission.USER_LIST,
|
|
1904
|
+
Permission.ORG_READ,
|
|
1905
|
+
Permission.ORG_UPDATE,
|
|
1906
|
+
Permission.MEMBER_INVITE,
|
|
1907
|
+
Permission.MEMBER_REMOVE,
|
|
1908
|
+
Permission.MEMBER_UPDATE_ROLE,
|
|
1909
|
+
Permission.MEMBER_LIST,
|
|
1910
|
+
Permission.MANAGE_MEMBERS,
|
|
1911
|
+
Permission.TEAM_CREATE,
|
|
1912
|
+
Permission.TEAM_UPDATE,
|
|
1913
|
+
Permission.TEAM_DELETE,
|
|
1914
|
+
Permission.TEAM_MANAGE,
|
|
1915
|
+
Permission.PROJECT_CREATE,
|
|
1916
|
+
Permission.PROJECT_READ,
|
|
1917
|
+
Permission.PROJECT_UPDATE,
|
|
1918
|
+
Permission.PROJECT_DELETE,
|
|
1919
|
+
Permission.PROJECT_MANAGE,
|
|
1920
|
+
Permission.BILLING_VIEW
|
|
1921
|
+
]
|
|
1922
|
+
},
|
|
1923
|
+
MEMBER: {
|
|
1924
|
+
name: "member",
|
|
1925
|
+
description: "Regular organization member",
|
|
1926
|
+
permissions: [
|
|
1927
|
+
Permission.USER_READ,
|
|
1928
|
+
Permission.ORG_READ,
|
|
1929
|
+
Permission.MEMBER_LIST,
|
|
1930
|
+
Permission.PROJECT_READ,
|
|
1931
|
+
Permission.PROJECT_CREATE
|
|
1932
|
+
]
|
|
1933
|
+
},
|
|
1934
|
+
VIEWER: {
|
|
1935
|
+
name: "viewer",
|
|
1936
|
+
description: "Read-only access",
|
|
1937
|
+
permissions: [
|
|
1938
|
+
Permission.USER_READ,
|
|
1939
|
+
Permission.ORG_READ,
|
|
1940
|
+
Permission.MEMBER_LIST,
|
|
1941
|
+
Permission.PROJECT_READ
|
|
1942
|
+
]
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
|
|
1946
|
+
class RBACPolicyEngine {
|
|
1947
|
+
roleCache = new Map;
|
|
1948
|
+
bindingCache = new Map;
|
|
1949
|
+
async checkPermission(input, bindings) {
|
|
1950
|
+
const { userId, orgId, permission } = input;
|
|
1951
|
+
const now = new Date;
|
|
1952
|
+
const userBindings = bindings.filter((b) => b.targetType === "user" && b.targetId === userId);
|
|
1953
|
+
const orgBindings = orgId ? bindings.filter((b) => b.targetType === "organization" && b.targetId === orgId) : [];
|
|
1954
|
+
const allBindings = [...userBindings, ...orgBindings];
|
|
1955
|
+
const activeBindings = allBindings.filter((b) => !b.expiresAt || b.expiresAt > now);
|
|
1956
|
+
if (activeBindings.length === 0) {
|
|
1957
|
+
return {
|
|
1958
|
+
allowed: false,
|
|
1959
|
+
reason: "No active role bindings found"
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
for (const binding of activeBindings) {
|
|
1963
|
+
if (binding.role.permissions.includes(permission)) {
|
|
1964
|
+
return {
|
|
1965
|
+
allowed: true,
|
|
1966
|
+
matchedRole: binding.role.name
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
return {
|
|
1971
|
+
allowed: false,
|
|
1972
|
+
reason: `No role grants the "${permission}" permission`
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
async getPermissions(userId, orgId, bindings) {
|
|
1976
|
+
const now = new Date;
|
|
1977
|
+
const userBindings = bindings.filter((b) => b.targetType === "user" && b.targetId === userId);
|
|
1978
|
+
const orgBindings = orgId ? bindings.filter((b) => b.targetType === "organization" && b.targetId === orgId) : [];
|
|
1979
|
+
const allBindings = [...userBindings, ...orgBindings];
|
|
1980
|
+
const activeBindings = allBindings.filter((b) => !b.expiresAt || b.expiresAt > now);
|
|
1981
|
+
const permissions = new Set;
|
|
1982
|
+
const roles = [];
|
|
1983
|
+
for (const binding of activeBindings) {
|
|
1984
|
+
roles.push(binding.role);
|
|
1985
|
+
for (const perm of binding.role.permissions) {
|
|
1986
|
+
permissions.add(perm);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
return { permissions, roles };
|
|
1990
|
+
}
|
|
1991
|
+
async hasAnyPermission(userId, orgId, permissions, bindings) {
|
|
1992
|
+
const { permissions: userPerms } = await this.getPermissions(userId, orgId, bindings);
|
|
1993
|
+
return permissions.some((p) => userPerms.has(p));
|
|
1994
|
+
}
|
|
1995
|
+
async hasAllPermissions(userId, orgId, permissions, bindings) {
|
|
1996
|
+
const { permissions: userPerms } = await this.getPermissions(userId, orgId, bindings);
|
|
1997
|
+
return permissions.every((p) => userPerms.has(p));
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
function createRBACEngine() {
|
|
2001
|
+
return new RBACPolicyEngine;
|
|
2002
|
+
}
|
|
2003
|
+
export {
|
|
2004
|
+
identityRbacSchemaContribution,
|
|
2005
|
+
identityRbacEntities,
|
|
2006
|
+
createRBACEngine,
|
|
2007
|
+
VerificationEntity,
|
|
2008
|
+
UserUpdatedEvent,
|
|
2009
|
+
UserProfileModel,
|
|
2010
|
+
UserEntity,
|
|
2011
|
+
UserEmailVerifiedEvent,
|
|
2012
|
+
UserDeletedPayloadModel,
|
|
2013
|
+
UserDeletedEvent,
|
|
2014
|
+
UserCreatedEvent,
|
|
2015
|
+
UpdateUserInputModel,
|
|
2016
|
+
UpdateUserContract,
|
|
2017
|
+
UpdateRoleInputModel,
|
|
2018
|
+
UpdateRoleContract,
|
|
2019
|
+
UpdateOrgInputModel,
|
|
2020
|
+
UpdateOrgContract,
|
|
2021
|
+
TeamMemberEntity,
|
|
2022
|
+
TeamEntity,
|
|
2023
|
+
SuccessResultModel,
|
|
2024
|
+
StandardRole,
|
|
2025
|
+
SessionEntity,
|
|
2026
|
+
RoleRevokedEvent,
|
|
2027
|
+
RoleModel,
|
|
2028
|
+
RoleEntity,
|
|
2029
|
+
RoleAssignedEvent,
|
|
2030
|
+
RevokeRoleInputModel,
|
|
2031
|
+
RevokeRoleContract,
|
|
2032
|
+
RemoveMemberInputModel,
|
|
2033
|
+
RemoveMemberContract,
|
|
2034
|
+
RBACPolicyEngine,
|
|
2035
|
+
PolicyBindingModel,
|
|
2036
|
+
PolicyBindingEntity,
|
|
2037
|
+
PermissionEntity,
|
|
2038
|
+
PermissionCheckResultModel,
|
|
2039
|
+
Permission,
|
|
2040
|
+
PasskeyEntity,
|
|
2041
|
+
OrganizationWithRoleModel,
|
|
2042
|
+
OrganizationTypeEnum,
|
|
2043
|
+
OrganizationModel,
|
|
2044
|
+
OrganizationEntity,
|
|
2045
|
+
OrgUpdatedEvent,
|
|
2046
|
+
OrgMemberRoleChangedEvent,
|
|
2047
|
+
OrgMemberRemovedEvent,
|
|
2048
|
+
OrgMemberAddedEvent,
|
|
2049
|
+
OrgInviteSentEvent,
|
|
2050
|
+
OrgInviteDeclinedEvent,
|
|
2051
|
+
OrgInviteAcceptedEvent,
|
|
2052
|
+
OrgDeletedEvent,
|
|
2053
|
+
OrgCreatedEvent,
|
|
2054
|
+
MemberUserModel,
|
|
2055
|
+
MemberRemovedPayloadModel,
|
|
2056
|
+
MemberModel,
|
|
2057
|
+
MemberEntity,
|
|
2058
|
+
ListUsersOutputModel,
|
|
2059
|
+
ListUsersInputModel,
|
|
2060
|
+
ListUsersContract,
|
|
2061
|
+
ListUserPermissionsOutputModel,
|
|
2062
|
+
ListUserPermissionsInputModel,
|
|
2063
|
+
ListUserPermissionsContract,
|
|
2064
|
+
ListUserOrgsOutputModel,
|
|
2065
|
+
ListUserOrgsContract,
|
|
2066
|
+
ListRolesOutputModel,
|
|
2067
|
+
ListRolesContract,
|
|
2068
|
+
ListMembersOutputModel,
|
|
2069
|
+
ListMembersInputModel,
|
|
2070
|
+
ListMembersContract,
|
|
2071
|
+
InviteMemberInputModel,
|
|
2072
|
+
InviteMemberContract,
|
|
2073
|
+
InvitationModel,
|
|
2074
|
+
InvitationEntity,
|
|
2075
|
+
IdentityRbacFeature,
|
|
2076
|
+
IdentityRbacEvents,
|
|
2077
|
+
GetOrgInputModel,
|
|
2078
|
+
GetOrgContract,
|
|
2079
|
+
GetCurrentUserContract,
|
|
2080
|
+
DeleteUserInputModel,
|
|
2081
|
+
DeleteUserContract,
|
|
2082
|
+
DeleteRoleInputModel,
|
|
2083
|
+
DeleteRoleContract,
|
|
2084
|
+
CreateUserInputModel,
|
|
2085
|
+
CreateUserContract,
|
|
2086
|
+
CreateRoleInputModel,
|
|
2087
|
+
CreateRoleContract,
|
|
2088
|
+
CreateOrgInputModel,
|
|
2089
|
+
CreateOrgContract,
|
|
2090
|
+
CheckPermissionInputModel,
|
|
2091
|
+
CheckPermissionContract,
|
|
2092
|
+
BindingIdPayloadModel,
|
|
2093
|
+
AssignRoleInputModel,
|
|
2094
|
+
AssignRoleContract,
|
|
2095
|
+
ApiKeyEntity,
|
|
2096
|
+
AccountEntity,
|
|
2097
|
+
AcceptInviteInputModel,
|
|
2098
|
+
AcceptInviteContract
|
|
2099
|
+
};
|