@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.
Files changed (72) hide show
  1. package/dist/assets/events.d.ts +18 -18
  2. package/dist/assets/file-urls.d.ts +3 -0
  3. package/dist/assets/file-urls.js +1 -0
  4. package/dist/assets/file-urls.js.map +1 -1
  5. package/dist/assets/index.js +1 -1
  6. package/dist/assets/ports.d.ts +1 -1
  7. package/dist/assets/service.d.ts +1 -1
  8. package/dist/assets/service.js +28 -23
  9. package/dist/assets/service.js.map +1 -1
  10. package/dist/automations/catalog.js +1 -1
  11. package/dist/automations/notifications/processor.js +2 -2
  12. package/dist/automations/notifications/service.js +1 -1
  13. package/dist/automations/service.js +1 -1
  14. package/dist/content/events.d.ts +84 -48
  15. package/dist/content/index.d.ts +2 -2
  16. package/dist/content/model.d.ts +2 -2
  17. package/dist/content/notification-categories.js +1 -1
  18. package/dist/content/ports.d.ts +11 -11
  19. package/dist/content/service.d.ts +16 -12
  20. package/dist/content/service.js +62 -16
  21. package/dist/content/service.js.map +1 -1
  22. package/dist/discussion/chats.js +2 -2
  23. package/dist/discussion/events.d.ts +8 -8
  24. package/dist/discussion/posts.d.ts +1 -1
  25. package/dist/discussion/posts.js +3 -3
  26. package/dist/discussion/posts.js.map +1 -1
  27. package/dist/discussion/service.js +2 -2
  28. package/dist/discussion/subscriptions.js +1 -1
  29. package/dist/entitlements/events.d.ts +48 -48
  30. package/dist/entitlements/service.js +1 -1
  31. package/dist/identity/devices.js +1 -1
  32. package/dist/identity/events.d.ts +2 -2
  33. package/dist/identity/notification-settings.js +1 -1
  34. package/dist/identity/service.d.ts +1 -1
  35. package/dist/identity/service.js +3 -3
  36. package/dist/identity/service.js.map +1 -1
  37. package/dist/integrations/service.js +2 -2
  38. package/dist/organizations/effective-permissions.d.ts +3 -1
  39. package/dist/organizations/effective-permissions.js +8 -3
  40. package/dist/organizations/effective-permissions.js.map +1 -1
  41. package/dist/organizations/events.d.ts +29 -23
  42. package/dist/organizations/index.d.ts +2 -2
  43. package/dist/organizations/model.d.ts +2 -2
  44. package/dist/organizations/notification-categories.js +1 -1
  45. package/dist/organizations/ports.d.ts +6 -3
  46. package/dist/organizations/service.d.ts +1 -1
  47. package/dist/organizations/service.js +17 -7
  48. package/dist/organizations/service.js.map +1 -1
  49. package/dist/organizations/testing.js +1 -1
  50. package/dist/organizations/testing.js.map +1 -1
  51. package/dist/progress/service.js +2 -2
  52. package/dist/reporting/member/model.d.ts +3 -0
  53. package/dist/reporting/member/ports.d.ts +2 -1
  54. package/dist/reporting/member/service.d.ts +2 -1
  55. package/dist/reporting/member/service.js +17 -1
  56. package/dist/reporting/member/service.js.map +1 -1
  57. package/dist/shared/actor.d.ts +1 -0
  58. package/dist/types/content.d.ts +2 -2
  59. package/dist/types/index.d.ts +3 -3
  60. package/dist/types/organizations.d.ts +2 -2
  61. package/dist/types/schemas/content.d.ts +68 -6
  62. package/dist/types/schemas/content.js +19 -2
  63. package/dist/types/schemas/content.js.map +1 -1
  64. package/dist/types/schemas/discussion.d.ts +14 -14
  65. package/dist/types/schemas/entitlements.d.ts +8 -8
  66. package/dist/types/schemas/index.d.ts +3 -3
  67. package/dist/types/schemas/index.js +3 -3
  68. package/dist/types/schemas/notifications.d.ts +4 -4
  69. package/dist/types/schemas/organizations.d.ts +4 -1
  70. package/dist/types/schemas/organizations.js +3 -1
  71. package/dist/types/schemas/organizations.js.map +1 -1
  72. 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: "active" | "revoked";
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: "active" | "revoked";
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
- createdAt: import("zod").ZodCoercedDate<unknown>;
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: "active" | "revoked";
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: "active" | "revoked";
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
- createdAt: import("zod").ZodCoercedDate<unknown>;
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: "active" | "revoked";
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: "active" | "revoked";
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
- createdAt: import("zod").ZodCoercedDate<unknown>;
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: "active" | "revoked";
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: "active" | "revoked";
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
- createdAt: import("zod").ZodCoercedDate<unknown>;
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: "active" | "revoked";
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: "active" | "revoked";
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
- createdAt: import("zod").ZodCoercedDate<unknown>;
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: "active" | "revoked" | "requested" | "invited";
215
- source: "request" | "invite" | "manual";
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: "active" | "revoked" | "requested" | "invited";
225
- source: "request" | "invite" | "manual";
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: "active" | "revoked" | "requested" | "invited";
255
- source: "request" | "invite" | "manual";
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: "active" | "revoked" | "requested" | "invited";
265
- source: "request" | "invite" | "manual";
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: "active" | "revoked" | "requested" | "invited";
295
- source: "request" | "invite" | "manual";
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: "active" | "revoked" | "requested" | "invited";
305
- source: "request" | "invite" | "manual";
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
@@ -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/devices.ts
4
4
  function pushDevice(device) {
5
5
  return {
@@ -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, 'syncPublicImage'>;
26
+ images: MemberImageReader & Pick<AssetFiles, 'syncPublicImages'>;
27
27
  fileUrls: FileUrls;
28
28
  });
29
29
  createUser(input: CreateUserInput): Promise<User>;
@@ -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.syncPublicImage(orgId, orgUserId, profile.imageAssetOrgId === orgId ? profile.imageAssetId : null);
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
- constructor(org: Set<Permission>, orgRole: RoleRef, content: Map<ContentId, ContentEntry>, owner: boolean);
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
- constructor(org, orgRole, content, owner) {
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":"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"}
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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"}