@headless-lms/core 0.5.0 → 0.6.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/assets/events.d.ts +18 -18
- package/dist/assets/file-urls.d.ts +3 -0
- package/dist/assets/file-urls.js +1 -0
- package/dist/assets/file-urls.js.map +1 -1
- package/dist/assets/index.js +1 -1
- package/dist/assets/ports.d.ts +1 -1
- package/dist/assets/service.d.ts +1 -1
- package/dist/assets/service.js +28 -23
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/catalog.js +1 -1
- package/dist/automations/notifications/processor.js +2 -2
- package/dist/automations/notifications/service.js +1 -1
- package/dist/automations/service.js +1 -1
- package/dist/content/events.d.ts +84 -48
- package/dist/content/index.d.ts +2 -2
- package/dist/content/model.d.ts +2 -2
- package/dist/content/notification-categories.js +1 -1
- package/dist/content/ports.d.ts +11 -11
- package/dist/content/service.d.ts +16 -12
- package/dist/content/service.js +62 -16
- package/dist/content/service.js.map +1 -1
- package/dist/discussion/chats.js +2 -2
- package/dist/discussion/events.d.ts +8 -8
- package/dist/discussion/posts.d.ts +1 -1
- package/dist/discussion/posts.js +3 -3
- package/dist/discussion/posts.js.map +1 -1
- package/dist/discussion/service.js +2 -2
- package/dist/discussion/subscriptions.js +1 -1
- package/dist/entitlements/events.d.ts +48 -48
- package/dist/entitlements/service.js +1 -1
- package/dist/identity/devices.js +1 -1
- package/dist/identity/events.d.ts +2 -2
- package/dist/identity/notification-settings.js +1 -1
- package/dist/identity/service.d.ts +1 -1
- package/dist/identity/service.js +3 -3
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/service.js +2 -2
- package/dist/organizations/effective-permissions.d.ts +3 -1
- package/dist/organizations/effective-permissions.js +8 -3
- package/dist/organizations/effective-permissions.js.map +1 -1
- package/dist/organizations/events.d.ts +29 -23
- package/dist/organizations/index.d.ts +2 -2
- package/dist/organizations/model.d.ts +2 -2
- package/dist/organizations/notification-categories.js +1 -1
- package/dist/organizations/ports.d.ts +6 -3
- package/dist/organizations/service.d.ts +1 -1
- package/dist/organizations/service.js +17 -7
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/testing.js +1 -1
- package/dist/organizations/testing.js.map +1 -1
- package/dist/progress/service.js +2 -2
- package/dist/reporting/member/model.d.ts +3 -0
- package/dist/reporting/member/ports.d.ts +2 -1
- package/dist/reporting/member/service.d.ts +2 -1
- package/dist/reporting/member/service.js +17 -1
- package/dist/reporting/member/service.js.map +1 -1
- package/dist/shared/actor.d.ts +1 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/types/index.d.ts +3 -3
- package/dist/types/organizations.d.ts +2 -2
- package/dist/types/schemas/content.d.ts +68 -6
- package/dist/types/schemas/content.js +19 -2
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +14 -14
- package/dist/types/schemas/entitlements.d.ts +8 -8
- package/dist/types/schemas/index.d.ts +3 -3
- package/dist/types/schemas/index.js +3 -3
- package/dist/types/schemas/notifications.d.ts +4 -4
- package/dist/types/schemas/organizations.d.ts +4 -1
- package/dist/types/schemas/organizations.js +3 -1
- package/dist/types/schemas/organizations.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ declare const entitlementEvents: {
|
|
|
8
8
|
orgUserId: string;
|
|
9
9
|
bundleId: string | null;
|
|
10
10
|
contentId: string | null;
|
|
11
|
-
status: "
|
|
11
|
+
status: "revoked" | "active";
|
|
12
12
|
source: string;
|
|
13
13
|
grantedAt: Date;
|
|
14
14
|
expiresAt: Date | null;
|
|
@@ -20,7 +20,7 @@ declare const entitlementEvents: {
|
|
|
20
20
|
orgUserId: string;
|
|
21
21
|
bundleId: string | null;
|
|
22
22
|
contentId: string | null;
|
|
23
|
-
status: "
|
|
23
|
+
status: "revoked" | "active";
|
|
24
24
|
source: string;
|
|
25
25
|
grantedAt: unknown;
|
|
26
26
|
expiresAt: unknown;
|
|
@@ -29,14 +29,14 @@ declare const entitlementEvents: {
|
|
|
29
29
|
}, import("zod").ZodObject<{
|
|
30
30
|
orgId: import("zod").ZodString;
|
|
31
31
|
id: import("zod").ZodString;
|
|
32
|
-
|
|
33
|
-
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
32
|
+
source: import("zod").ZodString;
|
|
34
33
|
status: import("zod").ZodEnum<{
|
|
35
|
-
active: "active";
|
|
36
34
|
revoked: "revoked";
|
|
35
|
+
active: "active";
|
|
37
36
|
}>;
|
|
38
|
-
source: import("zod").ZodString;
|
|
39
37
|
contentId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
38
|
+
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
39
|
+
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
40
40
|
bundleId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
41
41
|
orgUserId: import("zod").ZodString;
|
|
42
42
|
grantedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -48,7 +48,7 @@ declare const entitlementEvents: {
|
|
|
48
48
|
orgUserId: string;
|
|
49
49
|
bundleId: string | null;
|
|
50
50
|
contentId: string | null;
|
|
51
|
-
status: "
|
|
51
|
+
status: "revoked" | "active";
|
|
52
52
|
source: string;
|
|
53
53
|
grantedAt: Date;
|
|
54
54
|
expiresAt: Date | null;
|
|
@@ -60,7 +60,7 @@ declare const entitlementEvents: {
|
|
|
60
60
|
orgUserId: string;
|
|
61
61
|
bundleId: string | null;
|
|
62
62
|
contentId: string | null;
|
|
63
|
-
status: "
|
|
63
|
+
status: "revoked" | "active";
|
|
64
64
|
source: string;
|
|
65
65
|
grantedAt: unknown;
|
|
66
66
|
expiresAt: unknown;
|
|
@@ -69,14 +69,14 @@ declare const entitlementEvents: {
|
|
|
69
69
|
}, import("zod").ZodObject<{
|
|
70
70
|
orgId: import("zod").ZodString;
|
|
71
71
|
id: import("zod").ZodString;
|
|
72
|
-
|
|
73
|
-
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
72
|
+
source: import("zod").ZodString;
|
|
74
73
|
status: import("zod").ZodEnum<{
|
|
75
|
-
active: "active";
|
|
76
74
|
revoked: "revoked";
|
|
75
|
+
active: "active";
|
|
77
76
|
}>;
|
|
78
|
-
source: import("zod").ZodString;
|
|
79
77
|
contentId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
78
|
+
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
79
|
+
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
80
80
|
bundleId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
81
81
|
orgUserId: import("zod").ZodString;
|
|
82
82
|
grantedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -88,7 +88,7 @@ declare const entitlementEvents: {
|
|
|
88
88
|
orgUserId: string;
|
|
89
89
|
bundleId: string | null;
|
|
90
90
|
contentId: string | null;
|
|
91
|
-
status: "
|
|
91
|
+
status: "revoked" | "active";
|
|
92
92
|
source: string;
|
|
93
93
|
grantedAt: Date;
|
|
94
94
|
expiresAt: Date | null;
|
|
@@ -100,7 +100,7 @@ declare const entitlementEvents: {
|
|
|
100
100
|
orgUserId: string;
|
|
101
101
|
bundleId: string | null;
|
|
102
102
|
contentId: string | null;
|
|
103
|
-
status: "
|
|
103
|
+
status: "revoked" | "active";
|
|
104
104
|
source: string;
|
|
105
105
|
grantedAt: unknown;
|
|
106
106
|
expiresAt: unknown;
|
|
@@ -109,14 +109,14 @@ declare const entitlementEvents: {
|
|
|
109
109
|
}, import("zod").ZodObject<{
|
|
110
110
|
orgId: import("zod").ZodString;
|
|
111
111
|
id: import("zod").ZodString;
|
|
112
|
-
|
|
113
|
-
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
112
|
+
source: import("zod").ZodString;
|
|
114
113
|
status: import("zod").ZodEnum<{
|
|
115
|
-
active: "active";
|
|
116
114
|
revoked: "revoked";
|
|
115
|
+
active: "active";
|
|
117
116
|
}>;
|
|
118
|
-
source: import("zod").ZodString;
|
|
119
117
|
contentId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
118
|
+
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
119
|
+
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
120
120
|
bundleId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
121
121
|
orgUserId: import("zod").ZodString;
|
|
122
122
|
grantedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -128,7 +128,7 @@ declare const entitlementEvents: {
|
|
|
128
128
|
orgUserId: string;
|
|
129
129
|
bundleId: string | null;
|
|
130
130
|
contentId: string | null;
|
|
131
|
-
status: "
|
|
131
|
+
status: "revoked" | "active";
|
|
132
132
|
source: string;
|
|
133
133
|
grantedAt: Date;
|
|
134
134
|
expiresAt: Date | null;
|
|
@@ -140,7 +140,7 @@ declare const entitlementEvents: {
|
|
|
140
140
|
orgUserId: string;
|
|
141
141
|
bundleId: string | null;
|
|
142
142
|
contentId: string | null;
|
|
143
|
-
status: "
|
|
143
|
+
status: "revoked" | "active";
|
|
144
144
|
source: string;
|
|
145
145
|
grantedAt: unknown;
|
|
146
146
|
expiresAt: unknown;
|
|
@@ -149,14 +149,14 @@ declare const entitlementEvents: {
|
|
|
149
149
|
}, import("zod").ZodObject<{
|
|
150
150
|
orgId: import("zod").ZodString;
|
|
151
151
|
id: import("zod").ZodString;
|
|
152
|
-
|
|
153
|
-
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
152
|
+
source: import("zod").ZodString;
|
|
154
153
|
status: import("zod").ZodEnum<{
|
|
155
|
-
active: "active";
|
|
156
154
|
revoked: "revoked";
|
|
155
|
+
active: "active";
|
|
157
156
|
}>;
|
|
158
|
-
source: import("zod").ZodString;
|
|
159
157
|
contentId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
158
|
+
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
159
|
+
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
160
160
|
bundleId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
161
161
|
orgUserId: import("zod").ZodString;
|
|
162
162
|
grantedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -168,7 +168,7 @@ declare const entitlementEvents: {
|
|
|
168
168
|
orgUserId: string;
|
|
169
169
|
bundleId: string | null;
|
|
170
170
|
contentId: string | null;
|
|
171
|
-
status: "
|
|
171
|
+
status: "revoked" | "active";
|
|
172
172
|
source: string;
|
|
173
173
|
grantedAt: Date;
|
|
174
174
|
expiresAt: Date | null;
|
|
@@ -181,7 +181,7 @@ declare const entitlementEvents: {
|
|
|
181
181
|
orgUserId: string;
|
|
182
182
|
bundleId: string | null;
|
|
183
183
|
contentId: string | null;
|
|
184
|
-
status: "
|
|
184
|
+
status: "revoked" | "active";
|
|
185
185
|
source: string;
|
|
186
186
|
grantedAt: unknown;
|
|
187
187
|
expiresAt: unknown;
|
|
@@ -191,14 +191,14 @@ declare const entitlementEvents: {
|
|
|
191
191
|
}, import("zod").ZodObject<{
|
|
192
192
|
orgId: import("zod").ZodString;
|
|
193
193
|
id: import("zod").ZodString;
|
|
194
|
-
|
|
195
|
-
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
194
|
+
source: import("zod").ZodString;
|
|
196
195
|
status: import("zod").ZodEnum<{
|
|
197
|
-
active: "active";
|
|
198
196
|
revoked: "revoked";
|
|
197
|
+
active: "active";
|
|
199
198
|
}>;
|
|
200
|
-
source: import("zod").ZodString;
|
|
201
199
|
contentId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
200
|
+
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
201
|
+
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
202
202
|
bundleId: import("zod").ZodNullable<import("zod").ZodString>;
|
|
203
203
|
orgUserId: import("zod").ZodString;
|
|
204
204
|
grantedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -211,8 +211,8 @@ declare const entitlementEvents: {
|
|
|
211
211
|
communityId: string;
|
|
212
212
|
spaceId: string;
|
|
213
213
|
orgUserId: string;
|
|
214
|
-
status: "
|
|
215
|
-
source: "
|
|
214
|
+
status: "revoked" | "active" | "requested" | "invited";
|
|
215
|
+
source: "manual" | "request" | "invite";
|
|
216
216
|
createdAt: Date;
|
|
217
217
|
updatedAt: Date;
|
|
218
218
|
}, "entitlement.space_member.created", 1>, {
|
|
@@ -221,8 +221,8 @@ declare const entitlementEvents: {
|
|
|
221
221
|
communityId: string;
|
|
222
222
|
spaceId: string;
|
|
223
223
|
orgUserId: string;
|
|
224
|
-
status: "
|
|
225
|
-
source: "
|
|
224
|
+
status: "revoked" | "active" | "requested" | "invited";
|
|
225
|
+
source: "manual" | "request" | "invite";
|
|
226
226
|
createdAt: unknown;
|
|
227
227
|
updatedAt: unknown;
|
|
228
228
|
}, import("zod").ZodObject<{
|
|
@@ -232,15 +232,15 @@ declare const entitlementEvents: {
|
|
|
232
232
|
spaceId: import("zod").ZodString;
|
|
233
233
|
orgUserId: import("zod").ZodString;
|
|
234
234
|
status: import("zod").ZodEnum<{
|
|
235
|
-
active: "active";
|
|
236
235
|
revoked: "revoked";
|
|
236
|
+
active: "active";
|
|
237
237
|
requested: "requested";
|
|
238
238
|
invited: "invited";
|
|
239
239
|
}>;
|
|
240
240
|
source: import("zod").ZodEnum<{
|
|
241
|
+
manual: "manual";
|
|
241
242
|
request: "request";
|
|
242
243
|
invite: "invite";
|
|
243
|
-
manual: "manual";
|
|
244
244
|
}>;
|
|
245
245
|
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
246
246
|
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -251,8 +251,8 @@ declare const entitlementEvents: {
|
|
|
251
251
|
communityId: string;
|
|
252
252
|
spaceId: string;
|
|
253
253
|
orgUserId: string;
|
|
254
|
-
status: "
|
|
255
|
-
source: "
|
|
254
|
+
status: "revoked" | "active" | "requested" | "invited";
|
|
255
|
+
source: "manual" | "request" | "invite";
|
|
256
256
|
createdAt: Date;
|
|
257
257
|
updatedAt: Date;
|
|
258
258
|
}, "entitlement.space_member.updated", 1>, {
|
|
@@ -261,8 +261,8 @@ declare const entitlementEvents: {
|
|
|
261
261
|
communityId: string;
|
|
262
262
|
spaceId: string;
|
|
263
263
|
orgUserId: string;
|
|
264
|
-
status: "
|
|
265
|
-
source: "
|
|
264
|
+
status: "revoked" | "active" | "requested" | "invited";
|
|
265
|
+
source: "manual" | "request" | "invite";
|
|
266
266
|
createdAt: unknown;
|
|
267
267
|
updatedAt: unknown;
|
|
268
268
|
}, import("zod").ZodObject<{
|
|
@@ -272,15 +272,15 @@ declare const entitlementEvents: {
|
|
|
272
272
|
spaceId: import("zod").ZodString;
|
|
273
273
|
orgUserId: import("zod").ZodString;
|
|
274
274
|
status: import("zod").ZodEnum<{
|
|
275
|
-
active: "active";
|
|
276
275
|
revoked: "revoked";
|
|
276
|
+
active: "active";
|
|
277
277
|
requested: "requested";
|
|
278
278
|
invited: "invited";
|
|
279
279
|
}>;
|
|
280
280
|
source: import("zod").ZodEnum<{
|
|
281
|
+
manual: "manual";
|
|
281
282
|
request: "request";
|
|
282
283
|
invite: "invite";
|
|
283
|
-
manual: "manual";
|
|
284
284
|
}>;
|
|
285
285
|
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
286
286
|
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -291,8 +291,8 @@ declare const entitlementEvents: {
|
|
|
291
291
|
communityId: string;
|
|
292
292
|
spaceId: string;
|
|
293
293
|
orgUserId: string;
|
|
294
|
-
status: "
|
|
295
|
-
source: "
|
|
294
|
+
status: "revoked" | "active" | "requested" | "invited";
|
|
295
|
+
source: "manual" | "request" | "invite";
|
|
296
296
|
createdAt: Date;
|
|
297
297
|
updatedAt: Date;
|
|
298
298
|
}, "entitlement.space_member.deleted", 1>, {
|
|
@@ -301,8 +301,8 @@ declare const entitlementEvents: {
|
|
|
301
301
|
communityId: string;
|
|
302
302
|
spaceId: string;
|
|
303
303
|
orgUserId: string;
|
|
304
|
-
status: "
|
|
305
|
-
source: "
|
|
304
|
+
status: "revoked" | "active" | "requested" | "invited";
|
|
305
|
+
source: "manual" | "request" | "invite";
|
|
306
306
|
createdAt: unknown;
|
|
307
307
|
updatedAt: unknown;
|
|
308
308
|
}, import("zod").ZodObject<{
|
|
@@ -312,15 +312,15 @@ declare const entitlementEvents: {
|
|
|
312
312
|
spaceId: import("zod").ZodString;
|
|
313
313
|
orgUserId: import("zod").ZodString;
|
|
314
314
|
status: import("zod").ZodEnum<{
|
|
315
|
-
active: "active";
|
|
316
315
|
revoked: "revoked";
|
|
316
|
+
active: "active";
|
|
317
317
|
requested: "requested";
|
|
318
318
|
invited: "invited";
|
|
319
319
|
}>;
|
|
320
320
|
source: import("zod").ZodEnum<{
|
|
321
|
+
manual: "manual";
|
|
321
322
|
request: "request";
|
|
322
323
|
invite: "invite";
|
|
323
|
-
manual: "manual";
|
|
324
324
|
}>;
|
|
325
325
|
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
326
326
|
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { noopLogger } from "../shared/logger.js";
|
|
2
1
|
import { ConflictError, ForbiddenError, NotFoundError } from "../shared/errors.js";
|
|
2
|
+
import { noopLogger } from "../shared/logger.js";
|
|
3
3
|
import { entitlementEvents } from "./events.js";
|
|
4
4
|
import { opensSpace, seesSpace } from "./rules.js";
|
|
5
5
|
//#region src/entitlements/service.ts
|
package/dist/identity/devices.js
CHANGED
|
@@ -22,9 +22,9 @@ declare const identityEvents: {
|
|
|
22
22
|
id: import("zod").ZodString;
|
|
23
23
|
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
24
24
|
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
25
|
-
email: import("zod").ZodEmail;
|
|
26
25
|
firstName: import("zod").ZodNullable<import("zod").ZodString>;
|
|
27
26
|
lastName: import("zod").ZodNullable<import("zod").ZodString>;
|
|
27
|
+
email: import("zod").ZodEmail;
|
|
28
28
|
}, import("zod/v4/core").$strip>>;
|
|
29
29
|
userUpdated: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
30
30
|
id: string;
|
|
@@ -46,9 +46,9 @@ declare const identityEvents: {
|
|
|
46
46
|
id: import("zod").ZodString;
|
|
47
47
|
createdAt: import("zod").ZodCoercedDate<unknown>;
|
|
48
48
|
updatedAt: import("zod").ZodCoercedDate<unknown>;
|
|
49
|
-
email: import("zod").ZodEmail;
|
|
50
49
|
firstName: import("zod").ZodNullable<import("zod").ZodString>;
|
|
51
50
|
lastName: import("zod").ZodNullable<import("zod").ZodString>;
|
|
51
|
+
email: import("zod").ZodEmail;
|
|
52
52
|
}, import("zod/v4/core").$strip>>;
|
|
53
53
|
userDeleted: RuntimeEventDefinition<VersionedDomainEvent<{
|
|
54
54
|
id: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { noopLogger } from "../shared/logger.js";
|
|
2
1
|
import { NotFoundError, ValidationError } from "../shared/errors.js";
|
|
2
|
+
import { noopLogger } from "../shared/logger.js";
|
|
3
3
|
//#region src/identity/notification-settings.ts
|
|
4
4
|
function communityOf(scope) {
|
|
5
5
|
return scope === "org" ? null : scope.communityId;
|
|
@@ -23,7 +23,7 @@ declare class IdentityServiceImpl implements IdentityService {
|
|
|
23
23
|
logger?: Logger;
|
|
24
24
|
mailer: Mailer;
|
|
25
25
|
uow: IdentityUnitOfWork;
|
|
26
|
-
images: MemberImageReader & Pick<AssetFiles, '
|
|
26
|
+
images: MemberImageReader & Pick<AssetFiles, 'syncPublicImages'>;
|
|
27
27
|
fileUrls: FileUrls;
|
|
28
28
|
});
|
|
29
29
|
createUser(input: CreateUserInput): Promise<User>;
|
package/dist/identity/service.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { noopLogger } from "../shared/logger.js";
|
|
2
|
-
import { ConflictError, NotFoundError } from "../shared/errors.js";
|
|
3
1
|
import { genId } from "../shared/id.js";
|
|
2
|
+
import { ConflictError, NotFoundError } from "../shared/errors.js";
|
|
3
|
+
import { noopLogger } from "../shared/logger.js";
|
|
4
4
|
import { identityEvents } from "./events.js";
|
|
5
5
|
//#region src/identity/service.ts
|
|
6
6
|
const UNNAMED_MEMBER = "A member";
|
|
@@ -141,7 +141,7 @@ var IdentityServiceImpl = class {
|
|
|
141
141
|
imageAssetOrgId
|
|
142
142
|
});
|
|
143
143
|
this.logger.info("profile updated", { userId });
|
|
144
|
-
if (patch.imageAssetId !== void 0) await this.images.
|
|
144
|
+
if (patch.imageAssetId !== void 0) await this.images.syncPublicImages(orgId, orgUserId, profile.imageAssetOrgId === orgId && profile.imageAssetId ? [profile.imageAssetId] : []);
|
|
145
145
|
return this.view(orgId, orgUserId, profile);
|
|
146
146
|
}
|
|
147
147
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../src/identity/service.ts"],"sourcesContent":["import type { IdentityRepository, IdentityService, IdentityUnitOfWork } from './ports.js';\nimport type { User, UserProfile, UserProfileView } from './model.js';\nimport type { MemberActor, UpdateProfileInput } from './ports.js';\nimport type { CreateUserInput, UpdateUserInput } from './types.js';\nimport type { Logger } from '../shared/ports.js';\nimport { noopLogger } from '../shared/logger.js';\nimport { genId } from '../shared/id.js';\nimport { ConflictError, NotFoundError } from '../shared/errors.js';\nimport type { Mailer } from '../shared/mailer.js';\nimport type { AssetFiles, FileUrls, MemberImageReader } from '../assets/index.js';\nimport { identityEvents } from './events.js';\n\nexport const UNNAMED_MEMBER = 'A member';\n\nexport class IdentityServiceImpl implements IdentityService {\n private readonly repo: IdentityRepository;\n private readonly logger: Logger;\n private readonly uow: IdentityUnitOfWork;\n private readonly mailer: Pick<Mailer, 'send'>;\n private readonly images: MemberImageReader & Pick<AssetFiles, 'syncPublicImage'>;\n private readonly fileUrls: FileUrls;\n\n constructor(input: {\n repo: IdentityRepository;\n logger?: Logger;\n mailer: Mailer;\n uow: IdentityUnitOfWork;\n images: MemberImageReader & Pick<AssetFiles, 'syncPublicImage'>;\n fileUrls: FileUrls;\n }) {\n this.repo = input.repo;\n this.mailer = input.mailer;\n this.logger = input.logger ?? noopLogger;\n this.uow = input.uow;\n this.images = input.images;\n this.fileUrls = input.fileUrls;\n }\n\n async createUser(input: CreateUserInput): Promise<User> {\n const created = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.insertUser(input);\n await outbox.append([identityEvents.userCreated.make({ orgId: '-', data: user })]);\n return user;\n });\n this.logger.info('user created', { userId: created.id });\n return created;\n }\n\n async linkOrCreateUser(input: CreateUserInput): Promise<User> {\n const existing = await this.repo.findUserByEmail(input.email);\n if (!existing) {\n const id = input.id ?? genId('user');\n return this.createUser({ ...input, id, externalId: id });\n }\n if (existing.externalId !== null) {\n throw new ConflictError('That email already has an account');\n }\n // Existing user without external link, so invited. update the user with the\n // id.\n const linked = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.updateUser(existing.id, {\n externalId: existing.id,\n ...(input.firstName !== undefined && { firstName: input.firstName }),\n ...(input.lastName !== undefined && { lastName: input.lastName }),\n });\n await outbox.append([identityEvents.userUpdated.make({ orgId: '-', data: user! })]);\n return user!;\n });\n this.logger.info('user linked to auth account', { userId: linked.id });\n return linked;\n }\n\n async updateUser(id: string, input: UpdateUserInput): Promise<User> {\n const person = await this.repo.findUserById(id);\n if (!person) {\n throw new NotFoundError('User', id);\n }\n\n const updated = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.updateUser(id, input);\n await outbox.append([identityEvents.userUpdated.make({ orgId: '-', data: user! })]);\n return user!;\n });\n this.logger.info('user updated', { userId: updated.id });\n return updated;\n }\n\n async getUserByExternalId(externalId: string): Promise<User | null> {\n return this.repo.findUserByExternalId(externalId);\n }\n\n async getUserByEmail(email: string): Promise<User | null> {\n return this.repo.findUserByEmail(email);\n }\n\n async getUserById(id: string): Promise<User | null> {\n return this.repo.findUserById(id);\n }\n\n async sendPasswordReset(input: { email: string; url: string }): Promise<void> {\n await this.mailer.send(input.email, 'passwordReset', { resetUrl: input.url });\n }\n\n async sendPasswordChanged(input: { email: string }): Promise<void> {\n await this.mailer.send(input.email, 'passwordChanged', {});\n }\n\n async sendMagicLink(input: { email: string; url: string }): Promise<void> {\n await this.mailer.send(input.email, 'magicLink', { url: input.url });\n }\n\n async profileOf(actor: MemberActor): Promise<UserProfileView> {\n const userId = actor.userId;\n const stored = await this.repo.findProfile(userId);\n if (stored) {\n return this.view(actor.orgId, actor.id, stored);\n }\n const never = new Date(0);\n return {\n userId,\n displayName: null,\n headline: null,\n bio: null,\n imageAssetOrgId: null,\n imageAssetId: null,\n imageUrl: null,\n extra: {},\n createdAt: never,\n updatedAt: never,\n };\n }\n\n private view(orgId: string, orgUserId: string, profile: UserProfile): UserProfileView {\n const imageAssetId = profile.imageAssetOrgId === orgId ? profile.imageAssetId : null;\n return {\n ...profile,\n imageUrl: imageAssetId ? this.fileUrls.publicImage(orgId, orgUserId, imageAssetId) : null,\n };\n }\n\n async displayName(userId: string | null): Promise<string> {\n if (userId === null) {\n return UNNAMED_MEMBER;\n }\n const [profile, user] = await Promise.all([\n this.repo.findProfile(userId),\n this.repo.findUserById(userId),\n ]);\n const named = profile?.displayName?.trim();\n if (named) {\n return named;\n }\n const composed = [user?.firstName, user?.lastName].filter(Boolean).join(' ').trim();\n return composed || UNNAMED_MEMBER;\n }\n\n async updateProfile(patch: UpdateProfileInput, actor: MemberActor): Promise<UserProfileView> {\n const orgId = actor.orgId;\n const userId = actor.userId;\n const orgUserId = actor.id;\n const user = await this.repo.findUserById(userId);\n if (!user) {\n throw new NotFoundError('User', userId);\n }\n if (patch.imageAssetId != null) {\n const owned = await this.images.ownsImage(orgId, patch.imageAssetId, orgUserId);\n if (!owned) {\n this.logger.debug('profile photo refused', {\n userId,\n orgUserId,\n assetId: patch.imageAssetId,\n });\n throw new NotFoundError('Asset', patch.imageAssetId);\n }\n }\n const imageAssetOrgId =\n patch.imageAssetId === undefined ? undefined : patch.imageAssetId === null ? null : orgId;\n const profile = await this.repo.upsertProfile(userId, { ...patch, imageAssetOrgId });\n this.logger.info('profile updated', { userId });\n if (patch.imageAssetId !== undefined) {\n await this.images.syncPublicImage(\n orgId,\n orgUserId,\n profile.imageAssetOrgId === orgId ? profile.imageAssetId : null,\n );\n }\n return this.view(orgId, orgUserId, profile);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../src/identity/service.ts"],"sourcesContent":["import type { IdentityRepository, IdentityService, IdentityUnitOfWork } from './ports.js';\nimport type { User, UserProfile, UserProfileView } from './model.js';\nimport type { MemberActor, UpdateProfileInput } from './ports.js';\nimport type { CreateUserInput, UpdateUserInput } from './types.js';\nimport type { Logger } from '../shared/ports.js';\nimport { noopLogger } from '../shared/logger.js';\nimport { genId } from '../shared/id.js';\nimport { ConflictError, NotFoundError } from '../shared/errors.js';\nimport type { Mailer } from '../shared/mailer.js';\nimport type { AssetFiles, FileUrls, MemberImageReader } from '../assets/index.js';\nimport { identityEvents } from './events.js';\n\nexport const UNNAMED_MEMBER = 'A member';\n\nexport class IdentityServiceImpl implements IdentityService {\n private readonly repo: IdentityRepository;\n private readonly logger: Logger;\n private readonly uow: IdentityUnitOfWork;\n private readonly mailer: Pick<Mailer, 'send'>;\n private readonly images: MemberImageReader & Pick<AssetFiles, 'syncPublicImages'>;\n private readonly fileUrls: FileUrls;\n\n constructor(input: {\n repo: IdentityRepository;\n logger?: Logger;\n mailer: Mailer;\n uow: IdentityUnitOfWork;\n images: MemberImageReader & Pick<AssetFiles, 'syncPublicImages'>;\n fileUrls: FileUrls;\n }) {\n this.repo = input.repo;\n this.mailer = input.mailer;\n this.logger = input.logger ?? noopLogger;\n this.uow = input.uow;\n this.images = input.images;\n this.fileUrls = input.fileUrls;\n }\n\n async createUser(input: CreateUserInput): Promise<User> {\n const created = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.insertUser(input);\n await outbox.append([identityEvents.userCreated.make({ orgId: '-', data: user })]);\n return user;\n });\n this.logger.info('user created', { userId: created.id });\n return created;\n }\n\n async linkOrCreateUser(input: CreateUserInput): Promise<User> {\n const existing = await this.repo.findUserByEmail(input.email);\n if (!existing) {\n const id = input.id ?? genId('user');\n return this.createUser({ ...input, id, externalId: id });\n }\n if (existing.externalId !== null) {\n throw new ConflictError('That email already has an account');\n }\n // Existing user without external link, so invited. update the user with the\n // id.\n const linked = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.updateUser(existing.id, {\n externalId: existing.id,\n ...(input.firstName !== undefined && { firstName: input.firstName }),\n ...(input.lastName !== undefined && { lastName: input.lastName }),\n });\n await outbox.append([identityEvents.userUpdated.make({ orgId: '-', data: user! })]);\n return user!;\n });\n this.logger.info('user linked to auth account', { userId: linked.id });\n return linked;\n }\n\n async updateUser(id: string, input: UpdateUserInput): Promise<User> {\n const person = await this.repo.findUserById(id);\n if (!person) {\n throw new NotFoundError('User', id);\n }\n\n const updated = await this.uow.run(async ({ identity, outbox }) => {\n const user = await identity.updateUser(id, input);\n await outbox.append([identityEvents.userUpdated.make({ orgId: '-', data: user! })]);\n return user!;\n });\n this.logger.info('user updated', { userId: updated.id });\n return updated;\n }\n\n async getUserByExternalId(externalId: string): Promise<User | null> {\n return this.repo.findUserByExternalId(externalId);\n }\n\n async getUserByEmail(email: string): Promise<User | null> {\n return this.repo.findUserByEmail(email);\n }\n\n async getUserById(id: string): Promise<User | null> {\n return this.repo.findUserById(id);\n }\n\n async sendPasswordReset(input: { email: string; url: string }): Promise<void> {\n await this.mailer.send(input.email, 'passwordReset', { resetUrl: input.url });\n }\n\n async sendPasswordChanged(input: { email: string }): Promise<void> {\n await this.mailer.send(input.email, 'passwordChanged', {});\n }\n\n async sendMagicLink(input: { email: string; url: string }): Promise<void> {\n await this.mailer.send(input.email, 'magicLink', { url: input.url });\n }\n\n async profileOf(actor: MemberActor): Promise<UserProfileView> {\n const userId = actor.userId;\n const stored = await this.repo.findProfile(userId);\n if (stored) {\n return this.view(actor.orgId, actor.id, stored);\n }\n const never = new Date(0);\n return {\n userId,\n displayName: null,\n headline: null,\n bio: null,\n imageAssetOrgId: null,\n imageAssetId: null,\n imageUrl: null,\n extra: {},\n createdAt: never,\n updatedAt: never,\n };\n }\n\n private view(orgId: string, orgUserId: string, profile: UserProfile): UserProfileView {\n const imageAssetId = profile.imageAssetOrgId === orgId ? profile.imageAssetId : null;\n return {\n ...profile,\n imageUrl: imageAssetId ? this.fileUrls.publicImage(orgId, orgUserId, imageAssetId) : null,\n };\n }\n\n async displayName(userId: string | null): Promise<string> {\n if (userId === null) {\n return UNNAMED_MEMBER;\n }\n const [profile, user] = await Promise.all([\n this.repo.findProfile(userId),\n this.repo.findUserById(userId),\n ]);\n const named = profile?.displayName?.trim();\n if (named) {\n return named;\n }\n const composed = [user?.firstName, user?.lastName].filter(Boolean).join(' ').trim();\n return composed || UNNAMED_MEMBER;\n }\n\n async updateProfile(patch: UpdateProfileInput, actor: MemberActor): Promise<UserProfileView> {\n const orgId = actor.orgId;\n const userId = actor.userId;\n const orgUserId = actor.id;\n const user = await this.repo.findUserById(userId);\n if (!user) {\n throw new NotFoundError('User', userId);\n }\n if (patch.imageAssetId != null) {\n const owned = await this.images.ownsImage(orgId, patch.imageAssetId, orgUserId);\n if (!owned) {\n this.logger.debug('profile photo refused', {\n userId,\n orgUserId,\n assetId: patch.imageAssetId,\n });\n throw new NotFoundError('Asset', patch.imageAssetId);\n }\n }\n const imageAssetOrgId =\n patch.imageAssetId === undefined ? undefined : patch.imageAssetId === null ? null : orgId;\n const profile = await this.repo.upsertProfile(userId, { ...patch, imageAssetOrgId });\n this.logger.info('profile updated', { userId });\n if (patch.imageAssetId !== undefined) {\n await this.images.syncPublicImages(\n orgId,\n orgUserId,\n profile.imageAssetOrgId === orgId && profile.imageAssetId ? [profile.imageAssetId] : [],\n );\n }\n return this.view(orgId, orgUserId, profile);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { noopLogger } from "../shared/logger.js";
|
|
2
|
-
import { ConflictError, NotFoundError } from "../shared/errors.js";
|
|
3
1
|
import { genId } from "../shared/id.js";
|
|
2
|
+
import { ConflictError, NotFoundError } from "../shared/errors.js";
|
|
3
|
+
import { noopLogger } from "../shared/logger.js";
|
|
4
4
|
import { ActionInvocationError, AlreadyConnectedError, InvalidConfigError, UnknownIntegrationError } from "./model.js";
|
|
5
5
|
import { integrationEvents } from "./events.js";
|
|
6
6
|
//#region src/integrations/service.ts
|
|
@@ -24,7 +24,8 @@ declare class ResolvedPermissions implements EffectivePermissions {
|
|
|
24
24
|
private readonly orgRole;
|
|
25
25
|
private readonly content;
|
|
26
26
|
private readonly owner;
|
|
27
|
-
|
|
27
|
+
private readonly token;
|
|
28
|
+
constructor(org: Set<Permission>, orgRole: RoleRef, content: Map<ContentId, ContentEntry>, owner: boolean, token: boolean);
|
|
28
29
|
has(permission: Permission, on?: ContentId): boolean;
|
|
29
30
|
require(permission: Permission, on?: ContentId): void;
|
|
30
31
|
anywhere(permission: Permission): boolean;
|
|
@@ -34,6 +35,7 @@ declare class ResolvedPermissions implements EffectivePermissions {
|
|
|
34
35
|
};
|
|
35
36
|
roleOn(on?: ContentId): RoleRef;
|
|
36
37
|
isOwner(): boolean;
|
|
38
|
+
isToken(): boolean;
|
|
37
39
|
orgPermissions(): Permission[];
|
|
38
40
|
contentPermissions(): Record<ContentId, Permission[]>;
|
|
39
41
|
teamOn(on?: ContentId): boolean;
|
|
@@ -23,11 +23,13 @@ var ResolvedPermissions = class {
|
|
|
23
23
|
orgRole;
|
|
24
24
|
content;
|
|
25
25
|
owner;
|
|
26
|
-
|
|
26
|
+
token;
|
|
27
|
+
constructor(org, orgRole, content, owner, token) {
|
|
27
28
|
this.org = org;
|
|
28
29
|
this.orgRole = orgRole;
|
|
29
30
|
this.content = content;
|
|
30
31
|
this.owner = owner;
|
|
32
|
+
this.token = token;
|
|
31
33
|
}
|
|
32
34
|
has(permission, on) {
|
|
33
35
|
if (this.org.has(permission)) return true;
|
|
@@ -66,6 +68,9 @@ var ResolvedPermissions = class {
|
|
|
66
68
|
isOwner() {
|
|
67
69
|
return this.owner;
|
|
68
70
|
}
|
|
71
|
+
isToken() {
|
|
72
|
+
return this.token;
|
|
73
|
+
}
|
|
69
74
|
orgPermissions() {
|
|
70
75
|
return ALL_PERMISSIONS.filter((permission) => this.org.has(permission));
|
|
71
76
|
}
|
|
@@ -98,14 +103,14 @@ function resolvePermissions({ assignments, roles, tokenScopes }) {
|
|
|
98
103
|
});
|
|
99
104
|
}
|
|
100
105
|
const owner = orgRow?.roleKey === "owner" && orgRole !== void 0;
|
|
101
|
-
return new ResolvedPermissions(intersect(orgSet, scopes), orgRole ? refOf(orgRole) : roles.get("member") ? refOf(roles.get(MEMBER_ROLE_KEY)) : MEMBER_REF, content, owner && scopes === null);
|
|
106
|
+
return new ResolvedPermissions(intersect(orgSet, scopes), orgRole ? refOf(orgRole) : roles.get("member") ? refOf(roles.get(MEMBER_ROLE_KEY)) : MEMBER_REF, content, owner && scopes === null, scopes !== null);
|
|
102
107
|
}
|
|
103
108
|
function systemPermissions() {
|
|
104
109
|
return new ResolvedPermissions(new Set(ALL_PERMISSIONS), {
|
|
105
110
|
key: "system",
|
|
106
111
|
name: "System",
|
|
107
112
|
team: false
|
|
108
|
-
}, /* @__PURE__ */ new Map(), false);
|
|
113
|
+
}, /* @__PURE__ */ new Map(), false, false);
|
|
109
114
|
}
|
|
110
115
|
//#endregion
|
|
111
116
|
export { ResolvedPermissions, resolvePermissions, systemPermissions };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effective-permissions.js","names":[],"sources":["../../src/organizations/effective-permissions.ts"],"sourcesContent":["import type { ContentId, ContentType, Permission } from '../types/index.js';\nimport type { EffectivePermissions, RoleRef } from '../shared/actor.js';\nimport { ForbiddenError } from '../shared/errors.js';\nimport { ALL_PERMISSIONS, permissionAbout, withImplied } from './permissions.js';\nimport { MEMBER_ROLE_KEY, OWNER_ROLE_KEY } from './default-roles.js';\nimport type { OrgRole } from './org-roles.js';\n\nexport interface AssignmentRow {\n roleKey: string;\n contentId: ContentId | null;\n contentType: ContentType | null;\n}\n\nexport interface ResolveInput {\n assignments: readonly AssignmentRow[];\n roles: ReadonlyMap<string, OrgRole>;\n tokenScopes?: readonly Permission[];\n}\n\ninterface ContentEntry {\n permissions: Set<Permission>;\n role: RoleRef;\n}\n\nconst MEMBER_REF: RoleRef = { key: MEMBER_ROLE_KEY, name: 'Member', team: false };\n\nfunction refOf(role: OrgRole): RoleRef {\n return { key: role.key, name: role.name, team: role.team };\n}\n\nfunction intersect(set: Set<Permission>, scopes: Set<Permission> | null): Set<Permission> {\n if (!scopes) {\n return set;\n }\n return new Set([...set].filter((permission) => scopes.has(permission)));\n}\n\nexport class ResolvedPermissions implements EffectivePermissions {\n constructor(\n private readonly org: Set<Permission>,\n private readonly orgRole: RoleRef,\n private readonly content: Map<ContentId, ContentEntry>,\n private readonly owner: boolean,\n ) {}\n\n has(permission: Permission, on?: ContentId): boolean {\n if (this.org.has(permission)) {\n return true;\n }\n return on !== undefined && (this.content.get(on)?.permissions.has(permission) ?? false);\n }\n\n require(permission: Permission, on?: ContentId): void {\n if (!this.has(permission, on)) {\n throw Object.assign(new ForbiddenError(`You need ${permission}`), {\n permission,\n ...(on !== undefined && { contentId: on }),\n });\n }\n }\n\n anywhere(permission: Permission): boolean {\n if (this.org.has(permission)) {\n return true;\n }\n for (const entry of this.content.values()) {\n if (entry.permissions.has(permission)) {\n return true;\n }\n }\n return false;\n }\n\n where(permission: Permission): { org: boolean; content: ContentId[] } {\n if (this.org.has(permission)) {\n return { org: true, content: [] };\n }\n const content: ContentId[] = [];\n for (const [id, entry] of this.content) {\n if (entry.permissions.has(permission)) {\n content.push(id);\n }\n }\n return { org: false, content };\n }\n\n roleOn(on?: ContentId): RoleRef {\n if (on !== undefined) {\n const entry = this.content.get(on);\n if (entry) {\n return entry.role;\n }\n }\n return this.orgRole;\n }\n\n isOwner(): boolean {\n return this.owner;\n }\n\n orgPermissions(): Permission[] {\n return ALL_PERMISSIONS.filter((permission) => this.org.has(permission));\n }\n\n contentPermissions(): Record<ContentId, Permission[]> {\n const out: Record<ContentId, Permission[]> = {};\n for (const [id, entry] of this.content) {\n out[id] = ALL_PERMISSIONS.filter((permission) => entry.permissions.has(permission));\n }\n return out;\n }\n\n teamOn(on?: ContentId): boolean {\n if (on !== undefined && this.content.get(on)?.role.team) {\n return true;\n }\n return this.orgRole.team;\n }\n}\n\nexport function resolvePermissions({\n assignments,\n roles,\n tokenScopes,\n}: ResolveInput): ResolvedPermissions {\n const scopes = tokenScopes ? withImplied(tokenScopes) : null;\n const orgRow = assignments.find((row) => row.contentId === null);\n const listed = orgRow ? roles.get(orgRow.roleKey) : undefined;\n const orgRole = listed?.levels.includes('org') ? listed : undefined;\n const orgSet = orgRole ? withImplied(orgRole.permissions) : new Set<Permission>();\n const content = new Map<ContentId, ContentEntry>();\n for (const row of assignments) {\n if (row.contentId === null || row.contentType === null) {\n continue;\n }\n const role = roles.get(row.roleKey);\n if (!role || !role.levels.includes(row.contentType)) {\n continue;\n }\n const type = row.contentType;\n const own = role.permissions.filter((permission) => permissionAbout(permission) === type);\n const expanded = [...withImplied(own)].filter(\n (permission) => permissionAbout(permission) === type,\n );\n content.set(row.contentId, {\n permissions: intersect(new Set(expanded), scopes),\n role: refOf(role),\n });\n }\n const owner = orgRow?.roleKey === OWNER_ROLE_KEY && orgRole !== undefined;\n return new ResolvedPermissions(\n intersect(orgSet, scopes),\n orgRole\n ? refOf(orgRole)\n : roles.get(MEMBER_ROLE_KEY)\n ? refOf(roles.get(MEMBER_ROLE_KEY)!)\n : MEMBER_REF,\n content,\n owner && scopes === null,\n );\n}\n\nexport function systemPermissions(): ResolvedPermissions {\n return new ResolvedPermissions(\n new Set(ALL_PERMISSIONS),\n { key: 'system', name: 'System', team: false },\n new Map(),\n false,\n );\n}\n"],"mappings":";;;;AAwBA,MAAM,aAAsB;CAAE,KAAK;CAAiB,MAAM;CAAU,MAAM;AAAM;AAEhF,SAAS,MAAM,MAAwB;CACrC,OAAO;EAAE,KAAK,KAAK;EAAK,MAAM,KAAK;EAAM,MAAM,KAAK;CAAK;AAC3D;AAEA,SAAS,UAAU,KAAsB,QAAiD;CACxF,IAAI,CAAC,QACH,OAAO;CAET,OAAO,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,eAAe,OAAO,IAAI,UAAU,CAAC,CAAC;AACxE;AAEA,IAAa,sBAAb,MAAiE;CAE5C;CACA;CACA;CACA;
|
|
1
|
+
{"version":3,"file":"effective-permissions.js","names":[],"sources":["../../src/organizations/effective-permissions.ts"],"sourcesContent":["import type { ContentId, ContentType, Permission } from '../types/index.js';\nimport type { EffectivePermissions, RoleRef } from '../shared/actor.js';\nimport { ForbiddenError } from '../shared/errors.js';\nimport { ALL_PERMISSIONS, permissionAbout, withImplied } from './permissions.js';\nimport { MEMBER_ROLE_KEY, OWNER_ROLE_KEY } from './default-roles.js';\nimport type { OrgRole } from './org-roles.js';\n\nexport interface AssignmentRow {\n roleKey: string;\n contentId: ContentId | null;\n contentType: ContentType | null;\n}\n\nexport interface ResolveInput {\n assignments: readonly AssignmentRow[];\n roles: ReadonlyMap<string, OrgRole>;\n tokenScopes?: readonly Permission[];\n}\n\ninterface ContentEntry {\n permissions: Set<Permission>;\n role: RoleRef;\n}\n\nconst MEMBER_REF: RoleRef = { key: MEMBER_ROLE_KEY, name: 'Member', team: false };\n\nfunction refOf(role: OrgRole): RoleRef {\n return { key: role.key, name: role.name, team: role.team };\n}\n\nfunction intersect(set: Set<Permission>, scopes: Set<Permission> | null): Set<Permission> {\n if (!scopes) {\n return set;\n }\n return new Set([...set].filter((permission) => scopes.has(permission)));\n}\n\nexport class ResolvedPermissions implements EffectivePermissions {\n constructor(\n private readonly org: Set<Permission>,\n private readonly orgRole: RoleRef,\n private readonly content: Map<ContentId, ContentEntry>,\n private readonly owner: boolean,\n private readonly token: boolean,\n ) {}\n\n has(permission: Permission, on?: ContentId): boolean {\n if (this.org.has(permission)) {\n return true;\n }\n return on !== undefined && (this.content.get(on)?.permissions.has(permission) ?? false);\n }\n\n require(permission: Permission, on?: ContentId): void {\n if (!this.has(permission, on)) {\n throw Object.assign(new ForbiddenError(`You need ${permission}`), {\n permission,\n ...(on !== undefined && { contentId: on }),\n });\n }\n }\n\n anywhere(permission: Permission): boolean {\n if (this.org.has(permission)) {\n return true;\n }\n for (const entry of this.content.values()) {\n if (entry.permissions.has(permission)) {\n return true;\n }\n }\n return false;\n }\n\n where(permission: Permission): { org: boolean; content: ContentId[] } {\n if (this.org.has(permission)) {\n return { org: true, content: [] };\n }\n const content: ContentId[] = [];\n for (const [id, entry] of this.content) {\n if (entry.permissions.has(permission)) {\n content.push(id);\n }\n }\n return { org: false, content };\n }\n\n roleOn(on?: ContentId): RoleRef {\n if (on !== undefined) {\n const entry = this.content.get(on);\n if (entry) {\n return entry.role;\n }\n }\n return this.orgRole;\n }\n\n isOwner(): boolean {\n return this.owner;\n }\n\n isToken(): boolean {\n return this.token;\n }\n\n orgPermissions(): Permission[] {\n return ALL_PERMISSIONS.filter((permission) => this.org.has(permission));\n }\n\n contentPermissions(): Record<ContentId, Permission[]> {\n const out: Record<ContentId, Permission[]> = {};\n for (const [id, entry] of this.content) {\n out[id] = ALL_PERMISSIONS.filter((permission) => entry.permissions.has(permission));\n }\n return out;\n }\n\n teamOn(on?: ContentId): boolean {\n if (on !== undefined && this.content.get(on)?.role.team) {\n return true;\n }\n return this.orgRole.team;\n }\n}\n\nexport function resolvePermissions({\n assignments,\n roles,\n tokenScopes,\n}: ResolveInput): ResolvedPermissions {\n const scopes = tokenScopes ? withImplied(tokenScopes) : null;\n const orgRow = assignments.find((row) => row.contentId === null);\n const listed = orgRow ? roles.get(orgRow.roleKey) : undefined;\n const orgRole = listed?.levels.includes('org') ? listed : undefined;\n const orgSet = orgRole ? withImplied(orgRole.permissions) : new Set<Permission>();\n const content = new Map<ContentId, ContentEntry>();\n for (const row of assignments) {\n if (row.contentId === null || row.contentType === null) {\n continue;\n }\n const role = roles.get(row.roleKey);\n if (!role || !role.levels.includes(row.contentType)) {\n continue;\n }\n const type = row.contentType;\n const own = role.permissions.filter((permission) => permissionAbout(permission) === type);\n const expanded = [...withImplied(own)].filter(\n (permission) => permissionAbout(permission) === type,\n );\n content.set(row.contentId, {\n permissions: intersect(new Set(expanded), scopes),\n role: refOf(role),\n });\n }\n const owner = orgRow?.roleKey === OWNER_ROLE_KEY && orgRole !== undefined;\n return new ResolvedPermissions(\n intersect(orgSet, scopes),\n orgRole\n ? refOf(orgRole)\n : roles.get(MEMBER_ROLE_KEY)\n ? refOf(roles.get(MEMBER_ROLE_KEY)!)\n : MEMBER_REF,\n content,\n owner && scopes === null,\n scopes !== null,\n );\n}\n\nexport function systemPermissions(): ResolvedPermissions {\n return new ResolvedPermissions(\n new Set(ALL_PERMISSIONS),\n { key: 'system', name: 'System', team: false },\n new Map(),\n false,\n false,\n );\n}\n"],"mappings":"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"}
|