@headless-lms/core 0.1.0 → 0.3.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 +90 -9
- package/dist/assets/events.js +19 -3
- package/dist/assets/events.js.map +1 -1
- package/dist/assets/file-urls.d.ts +20 -0
- package/dist/assets/file-urls.js +25 -0
- package/dist/assets/file-urls.js.map +1 -0
- package/dist/assets/index.d.ts +5 -4
- package/dist/assets/index.js +3 -2
- package/dist/assets/model.d.ts +2 -2
- package/dist/assets/ports.d.ts +45 -15
- package/dist/assets/service.d.ts +39 -7
- package/dist/assets/service.js +292 -37
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.d.ts +12 -15
- package/dist/automations/actions.js +188 -30
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.d.ts +5 -1
- package/dist/automations/catalog.js +514 -197
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.d.ts +14 -0
- package/dist/automations/community-derivations.js +439 -0
- package/dist/automations/community-derivations.js.map +1 -0
- package/dist/automations/community-mail.d.ts +112 -0
- package/dist/automations/community-mail.js +90 -0
- package/dist/automations/community-mail.js.map +1 -0
- package/dist/automations/community-notifications.d.ts +16 -0
- package/dist/automations/community-notifications.js +84 -0
- package/dist/automations/community-notifications.js.map +1 -0
- package/dist/automations/events.d.ts +74 -24
- package/dist/automations/events.js +5 -5
- package/dist/automations/events.js.map +1 -1
- package/dist/automations/index.d.ts +7 -5
- package/dist/automations/index.js +3 -2
- package/dist/automations/model.d.ts +20 -3
- package/dist/automations/model.js +36 -3
- package/dist/automations/model.js.map +1 -1
- package/dist/automations/ports.d.ts +27 -8
- package/dist/automations/schedule.d.ts +6 -0
- package/dist/automations/schedule.js +41 -0
- package/dist/automations/schedule.js.map +1 -0
- package/dist/automations/seeds.d.ts +17 -0
- package/dist/automations/seeds.js +235 -0
- package/dist/automations/seeds.js.map +1 -0
- package/dist/automations/service.d.ts +41 -6
- package/dist/automations/service.js +542 -59
- package/dist/automations/service.js.map +1 -1
- package/dist/automations/types.d.ts +2 -2
- package/dist/automations/webhook-signing.d.ts +7 -0
- package/dist/automations/webhook-signing.js +22 -0
- package/dist/automations/webhook-signing.js.map +1 -0
- package/dist/content/events.d.ts +1013 -25
- package/dist/content/events.js +168 -19
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +5 -5
- package/dist/content/index.js +2 -2
- package/dist/content/model.d.ts +2 -2
- package/dist/content/ports.d.ts +109 -25
- package/dist/content/service.d.ts +68 -23
- package/dist/content/service.js +647 -60
- package/dist/content/service.js.map +1 -1
- package/dist/content/types.d.ts +2 -2
- package/dist/discussion/authors.d.ts +10 -0
- package/dist/discussion/authors.js +23 -0
- package/dist/discussion/authors.js.map +1 -0
- package/dist/discussion/chats.d.ts +104 -0
- package/dist/discussion/chats.js +798 -0
- package/dist/discussion/chats.js.map +1 -0
- package/dist/discussion/events.d.ts +633 -14
- package/dist/discussion/events.js +134 -5
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +7 -3
- package/dist/discussion/index.js +4 -1
- package/dist/discussion/model.d.ts +1 -2
- package/dist/discussion/ports.d.ts +288 -27
- package/dist/discussion/ports.js +6 -1
- package/dist/discussion/ports.js.map +1 -0
- package/dist/discussion/posts.d.ts +103 -0
- package/dist/discussion/posts.js +723 -0
- package/dist/discussion/posts.js.map +1 -0
- package/dist/discussion/service.d.ts +33 -11
- package/dist/discussion/service.js +297 -81
- package/dist/discussion/service.js.map +1 -1
- package/dist/entitlements/events.d.ts +264 -13
- package/dist/entitlements/events.js +49 -5
- package/dist/entitlements/events.js.map +1 -1
- package/dist/entitlements/index.d.ts +5 -4
- package/dist/entitlements/index.js +2 -1
- package/dist/entitlements/model.d.ts +3 -2
- package/dist/entitlements/ports.d.ts +124 -11
- package/dist/entitlements/rules.d.ts +12 -0
- package/dist/entitlements/rules.js +17 -0
- package/dist/entitlements/rules.js.map +1 -0
- package/dist/entitlements/service.d.ts +54 -3
- package/dist/entitlements/service.js +473 -2
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/access.d.ts +6 -0
- package/dist/identity/access.js +7 -0
- package/dist/identity/access.js.map +1 -0
- package/dist/identity/events.d.ts +17 -3
- package/dist/identity/events.js +12 -2
- package/dist/identity/events.js.map +1 -1
- package/dist/identity/index.d.ts +6 -4
- package/dist/identity/index.js +3 -1
- package/dist/identity/model.d.ts +2 -1
- package/dist/identity/notifications.d.ts +27 -0
- package/dist/identity/notifications.js +101 -0
- package/dist/identity/notifications.js.map +1 -0
- package/dist/identity/ports.d.ts +76 -3
- package/dist/identity/service.d.ts +17 -3
- package/dist/identity/service.js +73 -5
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/events.d.ts +27 -3
- package/dist/integrations/events.js +15 -3
- package/dist/integrations/events.js.map +1 -1
- package/dist/integrations/model.js +1 -1
- package/dist/integrations/model.js.map +1 -1
- package/dist/integrations/service.js +2 -2
- package/dist/integrations/service.js.map +1 -1
- package/dist/organizations/access-scopes.d.ts +19 -0
- package/dist/organizations/access-scopes.js +89 -0
- package/dist/organizations/access-scopes.js.map +1 -0
- package/dist/organizations/events.d.ts +234 -25
- package/dist/organizations/events.js +58 -9
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +8 -7
- package/dist/organizations/index.js +4 -3
- package/dist/organizations/members.d.ts +8 -5
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/ports.d.ts +20 -21
- package/dist/organizations/roles.d.ts +6 -10
- package/dist/organizations/roles.js +19 -7
- package/dist/organizations/roles.js.map +1 -1
- package/dist/organizations/service.d.ts +28 -14
- package/dist/organizations/service.js +274 -105
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/types.d.ts +2 -11
- package/dist/progress/events.d.ts +34 -2
- package/dist/progress/events.js +15 -2
- package/dist/progress/events.js.map +1 -1
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/ports.d.ts +6 -1
- package/dist/progress/service.d.ts +5 -3
- package/dist/progress/service.js +9 -3
- package/dist/progress/service.js.map +1 -1
- package/dist/reporting/admin/index.d.ts +4 -0
- package/dist/reporting/admin/index.js +2 -0
- package/dist/reporting/admin/model.d.ts +108 -0
- package/dist/reporting/admin/ports.d.ts +27 -0
- package/dist/reporting/admin/service.d.ts +22 -0
- package/dist/reporting/admin/service.js +38 -0
- package/dist/reporting/admin/service.js.map +1 -0
- package/dist/reporting/member/index.d.ts +5 -0
- package/dist/reporting/member/index.js +2 -0
- package/dist/reporting/member/model.d.ts +124 -0
- package/dist/reporting/member/ports.d.ts +45 -0
- package/dist/reporting/member/service.d.ts +73 -0
- package/dist/reporting/member/service.js +286 -0
- package/dist/reporting/member/service.js.map +1 -0
- package/dist/shared/actor.d.ts +9 -0
- package/dist/shared/errors.d.ts +7 -1
- package/dist/shared/errors.js +10 -1
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/events.d.ts +5 -3
- package/dist/shared/events.js +1 -0
- package/dist/shared/events.js.map +1 -1
- package/dist/shared/id.d.ts +12 -0
- package/dist/shared/id.js +13 -1
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/mailer.d.ts +6 -1
- package/dist/shared/mailer.js.map +1 -1
- package/dist/shared/network.d.ts +10 -0
- package/dist/shared/network.js +211 -0
- package/dist/shared/network.js.map +1 -0
- package/dist/shared/settings.js.map +1 -1
- package/dist/types/assets.d.ts +2 -2
- package/dist/types/automations.d.ts +21 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +12 -3
- package/dist/types/email-templates.d.ts +124 -1
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/events.d.ts +3 -3
- package/dist/types/identity.d.ts +48 -2
- package/dist/types/index.d.ts +10 -10
- package/dist/types/organizations.d.ts +2 -2
- package/dist/types/ports.d.ts +7 -1
- package/dist/types/schemas/assets.d.ts +67 -36
- package/dist/types/schemas/assets.js +19 -13
- package/dist/types/schemas/assets.js.map +1 -1
- package/dist/types/schemas/automations.d.ts +88 -4
- package/dist/types/schemas/automations.js +46 -6
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +385 -20
- package/dist/types/schemas/content.js +178 -15
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/credentials.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +379 -4
- package/dist/types/schemas/discussion.js +209 -7
- package/dist/types/schemas/discussion.js.map +1 -1
- package/dist/types/schemas/entitlements.d.ts +44 -4
- package/dist/types/schemas/entitlements.js +32 -4
- package/dist/types/schemas/entitlements.js.map +1 -1
- package/dist/types/schemas/identity.d.ts +115 -5
- package/dist/types/schemas/identity.js +59 -6
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +9 -9
- package/dist/types/schemas/index.js +9 -9
- package/dist/types/schemas/integrations.js.map +1 -1
- package/dist/types/schemas/organizations.d.ts +27 -5
- package/dist/types/schemas/organizations.js +14 -7
- package/dist/types/schemas/organizations.js.map +1 -1
- package/dist/types/schemas/outbox.d.ts +1 -0
- package/dist/types/schemas/outbox.js +1 -0
- package/dist/types/schemas/outbox.js.map +1 -1
- package/dist/types/schemas/progress.d.ts +1 -0
- package/dist/types/schemas/progress.js +1 -0
- package/dist/types/schemas/progress.js.map +1 -1
- package/dist/types/schemas/settings.js.map +1 -1
- package/dist/types/schemas/shared.d.ts +4 -1
- package/dist/types/schemas/shared.js +7 -1
- package/dist/types/schemas/shared.js.map +1 -1
- package/dist/types/shared.d.ts +1 -1
- package/package.json +2 -2
- package/dist/reporting/dashboard/index.d.ts +0 -4
- package/dist/reporting/dashboard/index.js +0 -2
- package/dist/reporting/dashboard/model.d.ts +0 -14
- package/dist/reporting/dashboard/ports.d.ts +0 -13
- package/dist/reporting/dashboard/service.d.ts +0 -19
- package/dist/reporting/dashboard/service.js +0 -20
- package/dist/reporting/dashboard/service.js.map +0 -1
- package/dist/reporting/learn/index.d.ts +0 -5
- package/dist/reporting/learn/index.js +0 -2
- package/dist/reporting/learn/model.d.ts +0 -23
- package/dist/reporting/learn/ports.d.ts +0 -42
- package/dist/reporting/learn/service.d.ts +0 -48
- package/dist/reporting/learn/service.js +0 -111
- package/dist/reporting/learn/service.js.map +0 -1
- package/dist/reporting/students/index.d.ts +0 -4
- package/dist/reporting/students/index.js +0 -2
- package/dist/reporting/students/model.d.ts +0 -31
- package/dist/reporting/students/ports.d.ts +0 -13
- package/dist/reporting/students/ports.js +0 -1
- package/dist/reporting/students/service.d.ts +0 -19
- package/dist/reporting/students/service.js +0 -20
- package/dist/reporting/students/service.js.map +0 -1
- /package/dist/reporting/{dashboard → admin}/model.js +0 -0
- /package/dist/reporting/{dashboard → admin}/ports.js +0 -0
- /package/dist/reporting/{learn → member}/model.js +0 -0
- /package/dist/reporting/{learn → member}/ports.js +0 -0
- /package/dist/{reporting/students/model.js → shared/actor.js} +0 -0
|
@@ -1,56 +1,105 @@
|
|
|
1
1
|
import { inviteSchema, orgUserSchema, organizationSchema } from "../types/schemas/organizations.js";
|
|
2
2
|
import { defineEvent } from "../shared/events.js";
|
|
3
3
|
//#region src/organizations/events.ts
|
|
4
|
+
const publicOrganization = organizationSchema.pick({
|
|
5
|
+
id: true,
|
|
6
|
+
name: true,
|
|
7
|
+
slug: true,
|
|
8
|
+
ownerId: true,
|
|
9
|
+
createdAt: true,
|
|
10
|
+
updatedAt: true
|
|
11
|
+
}).strip();
|
|
12
|
+
const publicOrgUser = orgUserSchema.pick({
|
|
13
|
+
id: true,
|
|
14
|
+
orgId: true,
|
|
15
|
+
userId: true,
|
|
16
|
+
role: true,
|
|
17
|
+
status: true,
|
|
18
|
+
createdAt: true,
|
|
19
|
+
updatedAt: true
|
|
20
|
+
}).strip();
|
|
21
|
+
const publicInvite = inviteSchema.pick({
|
|
22
|
+
id: true,
|
|
23
|
+
orgId: true,
|
|
24
|
+
email: true,
|
|
25
|
+
role: true,
|
|
26
|
+
status: true,
|
|
27
|
+
invitedBy: true,
|
|
28
|
+
expiresAt: true,
|
|
29
|
+
createdAt: true,
|
|
30
|
+
updatedAt: true
|
|
31
|
+
}).strip();
|
|
4
32
|
const organizationEvents = {
|
|
5
33
|
organizationCreated: defineEvent({
|
|
6
34
|
type: "organization.created",
|
|
7
35
|
version: 1,
|
|
8
|
-
data: organizationSchema
|
|
36
|
+
data: organizationSchema,
|
|
37
|
+
publicData: publicOrganization
|
|
9
38
|
}),
|
|
10
39
|
organizationUpdated: defineEvent({
|
|
11
40
|
type: "organization.updated",
|
|
12
41
|
version: 1,
|
|
13
|
-
data: organizationSchema
|
|
42
|
+
data: organizationSchema,
|
|
43
|
+
publicData: publicOrganization
|
|
14
44
|
}),
|
|
15
45
|
organizationDeleted: defineEvent({
|
|
16
46
|
type: "organization.deleted",
|
|
17
47
|
version: 1,
|
|
18
|
-
data: organizationSchema
|
|
48
|
+
data: organizationSchema,
|
|
49
|
+
publicData: publicOrganization
|
|
19
50
|
}),
|
|
20
51
|
orgUserLinked: defineEvent({
|
|
21
52
|
type: "organization.user.linked",
|
|
22
53
|
version: 1,
|
|
23
|
-
data: orgUserSchema
|
|
54
|
+
data: orgUserSchema,
|
|
55
|
+
publicData: publicOrgUser
|
|
24
56
|
}),
|
|
25
57
|
orgUserDeleted: defineEvent({
|
|
26
58
|
type: "organization.user.deleted",
|
|
27
59
|
version: 1,
|
|
28
|
-
data: orgUserSchema
|
|
60
|
+
data: orgUserSchema,
|
|
61
|
+
publicData: publicOrgUser
|
|
62
|
+
}),
|
|
63
|
+
orgUserUpdated: defineEvent({
|
|
64
|
+
type: "organization.user.updated",
|
|
65
|
+
version: 1,
|
|
66
|
+
data: orgUserSchema,
|
|
67
|
+
publicData: publicOrgUser
|
|
29
68
|
}),
|
|
30
69
|
inviteCreated: defineEvent({
|
|
31
70
|
type: "organization.invite.created",
|
|
32
71
|
version: 1,
|
|
33
|
-
data: inviteSchema
|
|
72
|
+
data: inviteSchema,
|
|
73
|
+
publicData: publicInvite
|
|
34
74
|
}),
|
|
35
75
|
inviteAccepted: defineEvent({
|
|
36
76
|
type: "organization.invite.accepted",
|
|
37
77
|
version: 1,
|
|
78
|
+
data: inviteSchema,
|
|
79
|
+
publicData: publicInvite
|
|
80
|
+
}),
|
|
81
|
+
inviteCanceled: defineEvent({
|
|
82
|
+
type: "organization.invite.canceled",
|
|
83
|
+
version: 1,
|
|
38
84
|
data: inviteSchema
|
|
39
85
|
}),
|
|
40
86
|
studentCreated: defineEvent({
|
|
41
87
|
type: "organization.student.created",
|
|
42
88
|
version: 1,
|
|
43
|
-
data: orgUserSchema
|
|
89
|
+
data: orgUserSchema,
|
|
90
|
+
publicData: publicOrgUser
|
|
44
91
|
}),
|
|
45
92
|
studentDeleted: defineEvent({
|
|
46
93
|
type: "organization.student.deleted",
|
|
47
94
|
version: 1,
|
|
48
|
-
data: orgUserSchema
|
|
95
|
+
data: orgUserSchema,
|
|
96
|
+
publicData: publicOrgUser
|
|
49
97
|
}),
|
|
50
98
|
studentLinked: defineEvent({
|
|
51
99
|
type: "organization.student.linked",
|
|
52
100
|
version: 1,
|
|
53
|
-
data: orgUserSchema
|
|
101
|
+
data: orgUserSchema,
|
|
102
|
+
publicData: publicOrgUser
|
|
54
103
|
})
|
|
55
104
|
};
|
|
56
105
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":[],"sources":["../../src/organizations/events.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../src/organizations/events.ts"],"sourcesContent":["import { inviteSchema, organizationSchema, orgUserSchema } from '../types/schemas/index.js';\nimport { defineEvent, type EventOf, type EventOfValues } from '../shared/ports.js';\n\nconst publicOrganization = organizationSchema\n .pick({\n id: true,\n name: true,\n slug: true,\n ownerId: true,\n createdAt: true,\n updatedAt: true,\n })\n .strip();\n\nconst publicOrgUser = orgUserSchema\n .pick({\n id: true,\n orgId: true,\n userId: true,\n role: true,\n status: true,\n createdAt: true,\n updatedAt: true,\n })\n .strip();\n\nconst publicInvite = inviteSchema\n .pick({\n id: true,\n orgId: true,\n email: true,\n role: true,\n status: true,\n invitedBy: true,\n expiresAt: true,\n createdAt: true,\n updatedAt: true,\n })\n .strip();\n\nexport const organizationEvents = {\n organizationCreated: defineEvent({\n type: 'organization.created',\n version: 1,\n data: organizationSchema,\n publicData: publicOrganization,\n }),\n organizationUpdated: defineEvent({\n type: 'organization.updated',\n version: 1,\n data: organizationSchema,\n publicData: publicOrganization,\n }),\n organizationDeleted: defineEvent({\n type: 'organization.deleted',\n version: 1,\n data: organizationSchema,\n publicData: publicOrganization,\n }),\n orgUserLinked: defineEvent({\n type: 'organization.user.linked',\n version: 1,\n data: orgUserSchema,\n publicData: publicOrgUser,\n }),\n orgUserDeleted: defineEvent({\n type: 'organization.user.deleted',\n version: 1,\n data: orgUserSchema,\n publicData: publicOrgUser,\n }),\n orgUserUpdated: defineEvent({\n type: 'organization.user.updated',\n version: 1,\n data: orgUserSchema,\n publicData: publicOrgUser,\n }),\n inviteCreated: defineEvent({\n type: 'organization.invite.created',\n version: 1,\n data: inviteSchema,\n publicData: publicInvite,\n }),\n inviteAccepted: defineEvent({\n type: 'organization.invite.accepted',\n version: 1,\n data: inviteSchema,\n publicData: publicInvite,\n }),\n inviteCanceled: defineEvent({\n type: 'organization.invite.canceled',\n version: 1,\n data: inviteSchema,\n }),\n studentCreated: defineEvent({\n type: 'organization.student.created',\n version: 1,\n data: orgUserSchema,\n publicData: publicOrgUser,\n }),\n studentDeleted: defineEvent({\n type: 'organization.student.deleted',\n version: 1,\n data: orgUserSchema,\n publicData: publicOrgUser,\n }),\n studentLinked: defineEvent({\n type: 'organization.student.linked',\n version: 1,\n data: orgUserSchema,\n publicData: publicOrgUser,\n }),\n};\n\nexport type OrganizationCreated = EventOf<typeof organizationEvents.organizationCreated>;\nexport type OrganizationUpdated = EventOf<typeof organizationEvents.organizationUpdated>;\nexport type OrganizationDeleted = EventOf<typeof organizationEvents.organizationDeleted>;\nexport type OrgUserLinked = EventOf<typeof organizationEvents.orgUserLinked>;\nexport type OrgUserDeleted = EventOf<typeof organizationEvents.orgUserDeleted>;\nexport type OrgUserUpdated = EventOf<typeof organizationEvents.orgUserUpdated>;\nexport type InviteCreated = EventOf<typeof organizationEvents.inviteCreated>;\nexport type InviteAccepted = EventOf<typeof organizationEvents.inviteAccepted>;\nexport type InviteCanceled = EventOf<typeof organizationEvents.inviteCanceled>;\nexport type StudentCreated = EventOf<typeof organizationEvents.studentCreated>;\nexport type StudentDeleted = EventOf<typeof organizationEvents.studentDeleted>;\nexport type StudentLinked = EventOf<typeof organizationEvents.studentLinked>;\nexport type OrganizationEvent = EventOfValues<typeof organizationEvents>;\n"],"mappings":";;;AAGA,MAAM,qBAAqB,mBACxB,KAAK;CACJ,IAAI;CACJ,MAAM;CACN,MAAM;CACN,SAAS;CACT,WAAW;CACX,WAAW;AACb,CAAC,CAAC,CACD,MAAM;AAET,MAAM,gBAAgB,cACnB,KAAK;CACJ,IAAI;CACJ,OAAO;CACP,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,WAAW;CACX,WAAW;AACb,CAAC,CAAC,CACD,MAAM;AAET,MAAM,eAAe,aAClB,KAAK;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,MAAM;CACN,QAAQ;CACR,WAAW;CACX,WAAW;CACX,WAAW;CACX,WAAW;AACb,CAAC,CAAC,CACD,MAAM;AAET,MAAa,qBAAqB;CAChC,qBAAqB,YAAY;EAC/B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,qBAAqB,YAAY;EAC/B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,qBAAqB,YAAY;EAC/B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,eAAe,YAAY;EACzB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,gBAAgB,YAAY;EAC1B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,gBAAgB,YAAY;EAC1B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,eAAe,YAAY;EACzB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,gBAAgB,YAAY;EAC1B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,gBAAgB,YAAY;EAC1B,MAAM;EACN,SAAS;EACT,MAAM;CACR,CAAC;CACD,gBAAgB,YAAY;EAC1B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,gBAAgB,YAAY;EAC1B,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,eAAe,YAAY;EACzB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;AACH"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, CreateOrgUserInput, Invite, InviteRole, NewOrganizationInput, OrgUser, OrgUserStatus, Organization, Role } from "../types/schemas/organizations.js";
|
|
1
|
+
import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, CreateOrgUserInput, Invite, InviteRole, NewOrganizationInput, OrgUser, OrgUserStatus, Organization, Role, UpdateOrgUserInput } from "../types/schemas/organizations.js";
|
|
2
2
|
import { InviteId, OrgUserId, OrganizationId } from "../types/organizations.js";
|
|
3
|
-
import { AuthHeaders } from "../identity/ports.js";
|
|
4
|
-
import { InviteAccepted, InviteCreated, OrgUserDeleted, OrgUserLinked, OrganizationCreated, OrganizationDeleted, OrganizationEvent, OrganizationUpdated, StudentCreated, StudentDeleted, StudentLinked, organizationEvents } from "./events.js";
|
|
5
3
|
import "./model.js";
|
|
6
|
-
import { Capability, Permission, ROLES, STAFF_ROLES, STUDENT_ROLE, StaffRole, capability, isRole, isStaffRole, normalizeRole, parseRole } from "./roles.js";
|
|
7
|
-
import { Member, MemberStatus, MembersQuery, OrganizationRuleError, Page } from "./members.js";
|
|
8
|
-
import { CreateOrganizationInput, LinkOrgUserInput, ResendStudentInviteInput, UnlinkOrgUserInput, UpdateOrganizationInput
|
|
4
|
+
import { Capability, Permission, ROLES, STAFF_ROLES, STUDENT_ROLE, StaffRole, TeamRole, canModerate, capability, isRole, isStaffRole, normalizeRole, parseRole } from "./roles.js";
|
|
5
|
+
import { InviteError, Member, MemberRoleChange, MemberStatus, MembersQuery, OrganizationRuleError, Page } from "./members.js";
|
|
6
|
+
import { CreateOrganizationInput, LinkOrgUserInput, ResendStudentInviteInput, UnlinkOrgUserInput, UpdateOrganizationInput } from "./types.js";
|
|
7
|
+
import { AuthHeaders } from "../identity/ports.js";
|
|
9
8
|
import { AuthOrganization, MemberRecord, MemberWriteContext, MembersRepository, NewInviteRow, NewOrganizationRow, OrgAdmin, OrganizationService, OrganizationsRepository } from "./ports.js";
|
|
10
9
|
import { OrganizationServiceImpl } from "./service.js";
|
|
11
|
-
|
|
10
|
+
import { InviteAccepted, InviteCanceled, InviteCreated, OrgUserDeleted, OrgUserLinked, OrgUserUpdated, OrganizationCreated, OrganizationDeleted, OrganizationEvent, OrganizationUpdated, StudentCreated, StudentDeleted, StudentLinked, organizationEvents } from "./events.js";
|
|
11
|
+
import { ACCESS_SCOPES, AccessScope, SCOPE_PERMISSION, ScopeOption, assertRoleHoldsScopes, isAccessScope, isDeleteScope, roleHoldsScope, scopeOptions, scopesForRole } from "./access-scopes.js";
|
|
12
|
+
export { ACCESS_SCOPES, type AcceptInviteInput, AccessScope, type AddOrgUserInput, type AuthHeaders, type AuthOrganization, type Capability, type CreateInviteInput, type CreateOrgUserInput, type CreateOrganizationInput, type Invite, type InviteAccepted, type InviteCanceled, type InviteCreated, InviteError, type InviteId, type InviteRole, type LinkOrgUserInput, type Member, type MemberRecord, type MemberRoleChange, type MemberStatus, type MemberWriteContext, type MembersQuery, type MembersRepository, type NewInviteRow, type NewOrganizationInput, type NewOrganizationRow, type OrgAdmin, type OrgUser, type OrgUserDeleted, type OrgUserId, type OrgUserLinked, type OrgUserStatus, type OrgUserUpdated, type Organization, type OrganizationCreated, type OrganizationDeleted, type OrganizationEvent, type OrganizationId, OrganizationRuleError, type OrganizationService, OrganizationServiceImpl, type OrganizationUpdated, type OrganizationsRepository, type Page, type Permission, ROLES, type ResendStudentInviteInput, type Role, SCOPE_PERMISSION, STAFF_ROLES, STUDENT_ROLE, ScopeOption, type StaffRole, type StudentCreated, type StudentDeleted, type StudentLinked, type TeamRole, type UnlinkOrgUserInput, type UpdateOrgUserInput, type UpdateOrganizationInput, assertRoleHoldsScopes, canModerate, capability, isAccessScope, isDeleteScope, isRole, isStaffRole, normalizeRole, organizationEvents, parseRole, roleHoldsScope, scopeOptions, scopesForRole };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ROLES, STAFF_ROLES, STUDENT_ROLE, capability, isRole, isStaffRole, normalizeRole, parseRole } from "./roles.js";
|
|
2
|
-
import { OrganizationRuleError } from "./members.js";
|
|
1
|
+
import { ROLES, STAFF_ROLES, STUDENT_ROLE, canModerate, capability, isRole, isStaffRole, normalizeRole, parseRole } from "./roles.js";
|
|
2
|
+
import { InviteError, OrganizationRuleError } from "./members.js";
|
|
3
3
|
import { organizationEvents } from "./events.js";
|
|
4
4
|
import { OrganizationServiceImpl } from "./service.js";
|
|
5
|
-
|
|
5
|
+
import { ACCESS_SCOPES, SCOPE_PERMISSION, assertRoleHoldsScopes, isAccessScope, isDeleteScope, roleHoldsScope, scopeOptions, scopesForRole } from "./access-scopes.js";
|
|
6
|
+
export { ACCESS_SCOPES, InviteError, OrganizationRuleError, OrganizationServiceImpl, ROLES, SCOPE_PERMISSION, STAFF_ROLES, STUDENT_ROLE, assertRoleHoldsScopes, canModerate, capability, isAccessScope, isDeleteScope, isRole, isStaffRole, normalizeRole, organizationEvents, parseRole, roleHoldsScope, scopeOptions, scopesForRole };
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import { OrgUserProfile } from "../types/schemas/organizations.js";
|
|
1
|
+
import { OrgUserProfile, Role } from "../types/schemas/organizations.js";
|
|
2
2
|
import "../types/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { TeamRole } from "./roles.js";
|
|
4
4
|
//#region src/organizations/members.d.ts
|
|
5
5
|
type MemberStatus = 'active' | 'invited';
|
|
6
6
|
interface Member extends OrgUserProfile {
|
|
7
|
-
role:
|
|
7
|
+
role: TeamRole;
|
|
8
8
|
status: MemberStatus;
|
|
9
9
|
joinedAt: string | null;
|
|
10
10
|
invitedAt: string | null;
|
|
11
11
|
}
|
|
12
|
+
interface MemberRoleChange extends Omit<Member, 'role'> {
|
|
13
|
+
role: Role;
|
|
14
|
+
}
|
|
12
15
|
interface MembersQuery {
|
|
13
16
|
page: number;
|
|
14
17
|
pageSize: number;
|
|
15
18
|
search?: string | undefined;
|
|
16
19
|
sort?: string | undefined;
|
|
17
|
-
role?:
|
|
20
|
+
role?: TeamRole | undefined;
|
|
18
21
|
status?: MemberStatus | undefined;
|
|
19
22
|
}
|
|
20
23
|
interface Page<T> {
|
|
@@ -28,5 +31,5 @@ declare class InviteError extends Error {
|
|
|
28
31
|
constructor(message: string);
|
|
29
32
|
}
|
|
30
33
|
//#endregion
|
|
31
|
-
export { InviteError, Member, MemberStatus, MembersQuery, OrganizationRuleError, Page };
|
|
34
|
+
export { InviteError, Member, MemberRoleChange, MemberStatus, MembersQuery, OrganizationRuleError, Page };
|
|
32
35
|
//# sourceMappingURL=members.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"members.js","names":[],"sources":["../../src/organizations/members.ts"],"sourcesContent":["// organizations context — member-management types (invite / change-role / remove).\n// The operational surface over the org's members and pending invites. Roles\n// come from ./roles.ts (the single role model); writes go through Better Auth.\nimport type {
|
|
1
|
+
{"version":3,"file":"members.js","names":[],"sources":["../../src/organizations/members.ts"],"sourcesContent":["// organizations context — member-management types (invite / change-role / remove).\n// The operational surface over the org's members and pending invites. Roles\n// come from ./roles.ts (the single role model); writes go through Better Auth.\nimport type { Role, TeamRole } from './roles.js';\nimport type { OrgUserProfile } from '../types/index.js';\n\nexport type MemberStatus = 'active' | 'invited';\n\nexport interface Member extends OrgUserProfile {\n role: TeamRole;\n status: MemberStatus;\n joinedAt: string | null;\n invitedAt: string | null;\n}\n\nexport interface MemberRoleChange extends Omit<Member, 'role'> {\n role: Role;\n}\n\nexport interface MembersQuery {\n page: number;\n pageSize: number;\n search?: string | undefined;\n sort?: string | undefined;\n role?: TeamRole | undefined;\n status?: MemberStatus | undefined;\n}\n\nexport interface Page<T> {\n rows: T[];\n total: number;\n page: number;\n pageSize: number;\n}\n\nexport class OrganizationRuleError extends Error {}\nexport class InviteError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InviteError';\n }\n}\n"],"mappings":";AAmCA,IAAa,wBAAb,cAA2C,MAAM,CAAC;AAClD,IAAa,cAAb,cAAiC,MAAM;CACrC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF"}
|
|
@@ -1,32 +1,35 @@
|
|
|
1
|
-
import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, CreateOrgUserInput, Invite, InviteRole, NewOrganizationInput, OrgUser, Organization, Role } from "../types/schemas/organizations.js";
|
|
1
|
+
import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, CreateOrgUserInput, Invite, InviteRole, NewOrganizationInput, OrgUser, Organization, Role, UpdateOrgUserInput } from "../types/schemas/organizations.js";
|
|
2
2
|
import { OutboxAppender, UnitOfWork } from "../shared/ports.js";
|
|
3
|
-
import {
|
|
4
|
-
import "../identity/index.js";
|
|
3
|
+
import { Actor } from "../shared/actor.js";
|
|
5
4
|
import "./model.js";
|
|
6
5
|
import "./roles.js";
|
|
7
|
-
import { Member, MembersQuery, Page } from "./members.js";
|
|
8
|
-
import { CreateOrganizationInput, ResendStudentInviteInput, UpdateOrganizationInput
|
|
6
|
+
import { Member, MemberRoleChange, MembersQuery, Page } from "./members.js";
|
|
7
|
+
import { CreateOrganizationInput, ResendStudentInviteInput, UpdateOrganizationInput } from "./types.js";
|
|
8
|
+
import { AuthHeaders } from "../identity/ports.js";
|
|
9
|
+
import "../identity/index.js";
|
|
9
10
|
//#region src/organizations/ports.d.ts
|
|
10
11
|
interface OrganizationService {
|
|
11
12
|
createOrganization(input: CreateOrganizationInput): Promise<Organization>;
|
|
12
13
|
updateOrganization(id: string, input: UpdateOrganizationInput): Promise<Organization>;
|
|
13
14
|
deleteOrganization(id: string): Promise<Organization>;
|
|
14
15
|
addOrgUser(input: AddOrgUserInput): Promise<OrgUser>;
|
|
15
|
-
removeOrgUser(orgId: string,
|
|
16
|
+
removeOrgUser(orgId: string, userId: string): Promise<OrgUser>;
|
|
17
|
+
updateOrgUser(orgId: string, userId: string, patch: UpdateOrgUserInput): Promise<OrgUser>;
|
|
16
18
|
getByExternalId(externalId: string): Promise<Organization | null>;
|
|
17
19
|
getOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
|
|
20
|
+
getOrgUserById(orgId: string, id: string): Promise<OrgUser | null>;
|
|
18
21
|
getOrgUsersForUser(userId: string): Promise<OrgUser[]>;
|
|
19
22
|
getById(id: string): Promise<Organization | null>;
|
|
20
|
-
createInvite(input: CreateInviteInput): Promise<Invite>;
|
|
23
|
+
createInvite(actor: Actor, input: CreateInviteInput): Promise<Invite>;
|
|
21
24
|
peekInvite(token: string): Promise<Invite | null>;
|
|
22
25
|
acceptInvite(input: AcceptInviteInput): Promise<OrgUser>;
|
|
23
|
-
deleteOrgUser(orgId: string, id: string): Promise<OrgUser>;
|
|
24
|
-
resendStudentInvite(input: ResendStudentInviteInput): Promise<void>;
|
|
25
|
-
updateStudent(input: UpdateStudentInput): Promise<OrgUser>;
|
|
26
|
+
deleteOrgUser(orgId: string, actor: Actor, id: string): Promise<OrgUser>;
|
|
27
|
+
resendStudentInvite(actor: Actor, input: ResendStudentInviteInput): Promise<void>;
|
|
26
28
|
getBySlug(slug: string): Promise<Organization | null>;
|
|
27
29
|
listMembers(orgId: string, query: MembersQuery): Promise<Page<Member>>;
|
|
28
|
-
updateMemberRole(ctx: MemberWriteContext, id: string, role: Role): Promise<
|
|
29
|
-
removeMember(ctx: MemberWriteContext, id: string): Promise<boolean>;
|
|
30
|
+
updateMemberRole(ctx: MemberWriteContext, actor: Actor, id: string, role: Role): Promise<MemberRoleChange | null>;
|
|
31
|
+
removeMember(ctx: MemberWriteContext, actor: Actor, id: string): Promise<boolean>;
|
|
32
|
+
staffOrgUserIds(orgId: string): Promise<string[]>;
|
|
30
33
|
}
|
|
31
34
|
/** Atomic write scope: tx-bound repo + outbox appender, one transaction. */
|
|
32
35
|
interface OrganizationsWriteScope {
|
|
@@ -59,31 +62,27 @@ interface OrganizationsRepository {
|
|
|
59
62
|
findById(id: string): Promise<Organization | null>;
|
|
60
63
|
findByExternalId(externalId: string): Promise<Organization | null>;
|
|
61
64
|
findBySlug(slug: string): Promise<Organization | null>;
|
|
62
|
-
upsertOrgUser(orgId: string, input: AddOrgUserInput): Promise<OrgUser>;
|
|
63
65
|
/** Inserts a pending invite, or re-issues the org's existing pending one
|
|
64
66
|
* for this email (fresh token/expiry/role) — atomic upsert. */
|
|
65
67
|
upsertPendingInvite(orgId: string, input: NewInviteRow): Promise<Invite>;
|
|
66
68
|
setInviteStatus(orgId: string, id: string, status: string): Promise<Invite | null>;
|
|
67
69
|
findInviteByTokenHash(tokenHash: string): Promise<Invite | null>;
|
|
70
|
+
findPendingInvite(orgId: string, email: string): Promise<Invite | null>;
|
|
71
|
+
setInviteToken(orgId: string, id: string, tokenHash: string, expiresAt: Date): Promise<Invite | null>;
|
|
68
72
|
/** The person's row in one org. `(org_id, user_id)` is unique. */
|
|
69
73
|
findOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
|
|
70
74
|
/** Every org this person belongs to, oldest first. */
|
|
71
75
|
findOrgUsersByUser(userId: string): Promise<OrgUser[]>;
|
|
72
76
|
findOrgUserById(orgId: string, id: string): Promise<OrgUser | null>;
|
|
77
|
+
findOrgUsersByIds(orgId: string, ids: string[]): Promise<OrgUser[]>;
|
|
78
|
+
findOrgUserIdsByRole(orgId: string, roles: Role[]): Promise<string[]>;
|
|
73
79
|
/** Links a user to the org under a role. Throws ConflictError when they
|
|
74
80
|
* already hold a row there. */
|
|
75
81
|
createOrgUser(input: CreateOrgUserInput): Promise<OrgUser>;
|
|
76
|
-
|
|
77
|
-
* promoted to the requested status rather than refused. `created` says
|
|
78
|
-
* whether a row appeared, so `student.created` fires exactly once. */
|
|
79
|
-
ensureOrgUser(input: CreateOrgUserInput): Promise<{
|
|
80
|
-
orgUser: OrgUser;
|
|
81
|
-
created: boolean;
|
|
82
|
-
}>;
|
|
82
|
+
updateOrgUser(orgId: string, id: string, patch: UpdateOrgUserInput): Promise<OrgUser | null>;
|
|
83
83
|
/** Every org this person is a student in — the scope of `student.linked`. */
|
|
84
84
|
findStudentOrgUsers(userId: string): Promise<OrgUser[]>;
|
|
85
85
|
/** Kills the org's pending invite for an address, if any. */
|
|
86
|
-
cancelPendingInvite(orgId: string, email: string): Promise<Invite | null>;
|
|
87
86
|
deleteOrgUser(orgId: string, id: string): Promise<OrgUser | null>;
|
|
88
87
|
}
|
|
89
88
|
/** A member row enriched with the ids needed to drive writes. */
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import { Role } from "../types/schemas/organizations.js";
|
|
2
2
|
import "../types/index.js";
|
|
3
3
|
//#region src/organizations/roles.d.ts
|
|
4
|
-
declare const ROLES: readonly ["owner", "admin", "instructor", "student"];
|
|
5
|
-
|
|
6
|
-
* The roles that operate the back office. `student` belongs to the org but
|
|
7
|
-
* never appears on a staff surface, so the member-management types are typed
|
|
8
|
-
* with this narrower union — the exclusion is a compiler guarantee, not a
|
|
9
|
-
* convention a query has to remember.
|
|
10
|
-
*/
|
|
11
|
-
type StaffRole = Exclude<Role, 'student'>;
|
|
4
|
+
declare const ROLES: readonly ["owner", "admin", "instructor", "moderator", "student"];
|
|
5
|
+
type StaffRole = 'owner' | 'admin' | 'instructor';
|
|
12
6
|
declare const STAFF_ROLES: readonly ["owner", "admin", "instructor"];
|
|
7
|
+
type TeamRole = Exclude<Role, 'student'>;
|
|
13
8
|
declare function isRole(value: string): value is Role;
|
|
14
9
|
declare function isStaffRole(value: string): value is StaffRole;
|
|
15
10
|
declare function parseRole(value: string): Role;
|
|
16
|
-
type Permission = 'manage_billing' | 'manage_org_settings' | 'manage_users' | 'create_course' | 'edit_assigned_course' | 'view_student_progress' | 'consume_content';
|
|
11
|
+
type Permission = 'manage_billing' | 'manage_org_settings' | 'manage_users' | 'create_course' | 'edit_assigned_course' | 'view_student_progress' | 'moderate' | 'consume_content';
|
|
17
12
|
type Capability = true | 'assigned' | 'enrolled';
|
|
18
13
|
declare function capability(role: Role, permission: Permission): Capability | false;
|
|
14
|
+
declare function canModerate(role: Role): boolean;
|
|
19
15
|
declare function normalizeRole(raw: string): Role;
|
|
20
16
|
declare const STUDENT_ROLE = "student";
|
|
21
17
|
//#endregion
|
|
22
|
-
export { Capability, Permission, ROLES, type Role, STAFF_ROLES, STUDENT_ROLE, StaffRole, capability, isRole, isStaffRole, normalizeRole, parseRole };
|
|
18
|
+
export { Capability, Permission, ROLES, type Role, STAFF_ROLES, STUDENT_ROLE, StaffRole, TeamRole, canModerate, capability, isRole, isStaffRole, normalizeRole, parseRole };
|
|
23
19
|
//# sourceMappingURL=roles.d.ts.map
|
|
@@ -3,6 +3,7 @@ const ROLES = [
|
|
|
3
3
|
"owner",
|
|
4
4
|
"admin",
|
|
5
5
|
"instructor",
|
|
6
|
+
"moderator",
|
|
6
7
|
"student"
|
|
7
8
|
];
|
|
8
9
|
const STAFF_ROLES = [
|
|
@@ -27,28 +28,39 @@ const MATRIX = {
|
|
|
27
28
|
manage_users: true,
|
|
28
29
|
create_course: true,
|
|
29
30
|
edit_assigned_course: true,
|
|
30
|
-
view_student_progress: true
|
|
31
|
+
view_student_progress: true,
|
|
32
|
+
moderate: true
|
|
31
33
|
},
|
|
32
34
|
admin: {
|
|
33
35
|
manage_org_settings: true,
|
|
34
36
|
manage_users: true,
|
|
35
37
|
create_course: true,
|
|
36
38
|
edit_assigned_course: true,
|
|
37
|
-
view_student_progress: true
|
|
39
|
+
view_student_progress: true,
|
|
40
|
+
moderate: true
|
|
38
41
|
},
|
|
39
42
|
instructor: {
|
|
40
43
|
edit_assigned_course: "assigned",
|
|
41
|
-
view_student_progress: "assigned"
|
|
44
|
+
view_student_progress: "assigned",
|
|
45
|
+
moderate: true
|
|
46
|
+
},
|
|
47
|
+
moderator: {
|
|
48
|
+
moderate: true,
|
|
49
|
+
consume_content: "enrolled"
|
|
42
50
|
},
|
|
43
51
|
student: { consume_content: "enrolled" }
|
|
44
52
|
};
|
|
45
53
|
function capability(role, permission) {
|
|
46
54
|
return MATRIX[role][permission] ?? false;
|
|
47
55
|
}
|
|
56
|
+
function canModerate(role) {
|
|
57
|
+
return capability(role, "moderate") === true;
|
|
58
|
+
}
|
|
48
59
|
const RANK = {
|
|
49
|
-
owner:
|
|
50
|
-
admin:
|
|
51
|
-
instructor:
|
|
60
|
+
owner: 4,
|
|
61
|
+
admin: 3,
|
|
62
|
+
instructor: 2,
|
|
63
|
+
moderator: 1,
|
|
52
64
|
student: 0
|
|
53
65
|
};
|
|
54
66
|
function normalizeRole(raw) {
|
|
@@ -65,6 +77,6 @@ function normalizeRole(raw) {
|
|
|
65
77
|
}
|
|
66
78
|
const STUDENT_ROLE = "student";
|
|
67
79
|
//#endregion
|
|
68
|
-
export { ROLES, STAFF_ROLES, STUDENT_ROLE, capability, isRole, isStaffRole, normalizeRole, parseRole };
|
|
80
|
+
export { ROLES, STAFF_ROLES, STUDENT_ROLE, canModerate, capability, isRole, isStaffRole, normalizeRole, parseRole };
|
|
69
81
|
|
|
70
82
|
//# sourceMappingURL=roles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roles.js","names":[],"sources":["../../src/organizations/roles.ts"],"sourcesContent":["// organizations context — roles and the authorization matrix.\n// Defined in code (no DB enum). The DB stores role as text; the domain narrows\n// it to Role and answers authorization questions here. The Role type itself is\n// owned by @headless-lms/core/types; RANK/MATRIX below are Record<Role, …>, so the\n// compiler forces this file to cover every role the published type declares.\nimport type { Role } from '../types/index.js';\n\nexport type { Role };\nexport const ROLES = [\n 'owner',\n 'admin',\n 'instructor',\n 'student',\n] as const satisfies readonly Role[];\n\
|
|
1
|
+
{"version":3,"file":"roles.js","names":[],"sources":["../../src/organizations/roles.ts"],"sourcesContent":["// organizations context — roles and the authorization matrix.\n// Defined in code (no DB enum). The DB stores role as text; the domain narrows\n// it to Role and answers authorization questions here. The Role type itself is\n// owned by @headless-lms/core/types; RANK/MATRIX below are Record<Role, …>, so the\n// compiler forces this file to cover every role the published type declares.\nimport type { Role } from '../types/index.js';\n\nexport type { Role };\nexport const ROLES = [\n 'owner',\n 'admin',\n 'instructor',\n 'moderator',\n 'student',\n] as const satisfies readonly Role[];\n\nexport type StaffRole = 'owner' | 'admin' | 'instructor';\nexport const STAFF_ROLES = ['owner', 'admin', 'instructor'] as const satisfies readonly StaffRole[];\n\nexport type TeamRole = Exclude<Role, 'student'>;\n\nexport function isRole(value: string): value is Role {\n return (ROLES as readonly string[]).includes(value);\n}\n\nexport function isStaffRole(value: string): value is StaffRole {\n return (STAFF_ROLES as readonly string[]).includes(value);\n}\n\nexport function parseRole(value: string): Role {\n if (!isRole(value)) {\n throw new Error(`unknown role: ${value}`);\n }\n return value;\n}\n\nexport type Permission =\n | 'manage_billing'\n | 'manage_org_settings'\n | 'manage_users'\n | 'create_course'\n | 'edit_assigned_course'\n | 'view_student_progress'\n | 'moderate'\n | 'consume_content';\n\n// Unconditional (true), course-scoped (\"assigned\"), or enrollment-scoped\n// (\"enrolled\" — access owned by entitlements). Absent ⇒ denied.\n//\n// \"assigned\" is a granted-but-narrowed answer: the role holds the permission,\n// but only over some subset of courses. Nothing narrows it today — there is no\n// course-assignment store — so callers must decide what a narrowed grant means\n// for them. `authorize` treats it as denied; `tools.ts` treats it as granted.\nexport type Capability = true | 'assigned' | 'enrolled';\n\nconst MATRIX: Record<Role, Partial<Record<Permission, Capability>>> = {\n owner: {\n manage_billing: true,\n manage_org_settings: true,\n manage_users: true,\n create_course: true,\n edit_assigned_course: true,\n view_student_progress: true,\n moderate: true,\n },\n admin: {\n manage_org_settings: true,\n manage_users: true,\n create_course: true,\n edit_assigned_course: true,\n view_student_progress: true,\n moderate: true,\n },\n instructor: {\n edit_assigned_course: 'assigned',\n view_student_progress: 'assigned',\n moderate: true,\n },\n moderator: {\n moderate: true,\n consume_content: 'enrolled',\n },\n student: {\n consume_content: 'enrolled',\n },\n};\n\nexport function capability(role: Role, permission: Permission): Capability | false {\n return MATRIX[role][permission] ?? false;\n}\n\nexport function canModerate(role: Role): boolean {\n return capability(role, 'moderate') === true;\n}\n\n// Better Auth's role model is broader than ours: it keeps a built-in `member`\n// role and allows comma-joined multi-role strings. Normalize any incoming role\n// string to a single domain Role before persisting: `member` -> `instructor`, a\n// multi-role string -> its highest-privilege known role, unknown -> `instructor`.\nconst RANK: Record<Role, number> = { owner: 4, admin: 3, instructor: 2, moderator: 1, student: 0 };\n\nexport function normalizeRole(raw: string): Role {\n let best: Role = 'instructor';\n let bestRank = -1;\n for (const token of raw.split(',').map((t) => t.trim())) {\n const r: Role | null = isRole(token) ? token : token === 'member' ? 'instructor' : null;\n if (r && RANK[r] > bestRank) {\n best = r;\n bestRank = RANK[r];\n }\n }\n return best;\n}\n\n// Invites carry either a staff Role or this marker: the invited account is\n// a portal student, not an org member. Owned by the organizations domain — the\n// invite provider adapter reuses it to branch links, emails, and grants.\nexport const STUDENT_ROLE = 'student';\n"],"mappings":";AAQA,MAAa,QAAQ;CACnB;CACA;CACA;CACA;CACA;AACF;AAGA,MAAa,cAAc;CAAC;CAAS;CAAS;AAAY;AAI1D,SAAgB,OAAO,OAA8B;CACnD,OAAQ,MAA4B,SAAS,KAAK;AACpD;AAEA,SAAgB,YAAY,OAAmC;CAC7D,OAAQ,YAAkC,SAAS,KAAK;AAC1D;AAEA,SAAgB,UAAU,OAAqB;CAC7C,IAAI,CAAC,OAAO,KAAK,GACf,MAAM,IAAI,MAAM,iBAAiB,OAAO;CAE1C,OAAO;AACT;AAqBA,MAAM,SAAgE;CACpE,OAAO;EACL,gBAAgB;EAChB,qBAAqB;EACrB,cAAc;EACd,eAAe;EACf,sBAAsB;EACtB,uBAAuB;EACvB,UAAU;CACZ;CACA,OAAO;EACL,qBAAqB;EACrB,cAAc;EACd,eAAe;EACf,sBAAsB;EACtB,uBAAuB;EACvB,UAAU;CACZ;CACA,YAAY;EACV,sBAAsB;EACtB,uBAAuB;EACvB,UAAU;CACZ;CACA,WAAW;EACT,UAAU;EACV,iBAAiB;CACnB;CACA,SAAS,EACP,iBAAiB,WACnB;AACF;AAEA,SAAgB,WAAW,MAAY,YAA4C;CACjF,OAAO,OAAO,KAAK,CAAC,eAAe;AACrC;AAEA,SAAgB,YAAY,MAAqB;CAC/C,OAAO,WAAW,MAAM,UAAU,MAAM;AAC1C;AAMA,MAAM,OAA6B;CAAE,OAAO;CAAG,OAAO;CAAG,YAAY;CAAG,WAAW;CAAG,SAAS;AAAE;AAEjG,SAAgB,cAAc,KAAmB;CAC/C,IAAI,OAAa;CACjB,IAAI,WAAW;CACf,KAAK,MAAM,SAAS,IAAI,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,KAAK,CAAC,GAAG;EACvD,MAAM,IAAiB,OAAO,KAAK,IAAI,QAAQ,UAAU,WAAW,eAAe;EACnF,IAAI,KAAK,KAAK,KAAK,UAAU;GAC3B,OAAO;GACP,WAAW,KAAK;EAClB;CACF;CACA,OAAO;AACT;AAKA,MAAa,eAAe"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Logger } from "../types/ports.js";
|
|
2
|
-
import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, Invite, OrgUser, Organization, Role } from "../types/schemas/organizations.js";
|
|
2
|
+
import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, Invite, OrgUser, Organization, Role, UpdateOrgUserInput } from "../types/schemas/organizations.js";
|
|
3
3
|
import "../shared/ports.js";
|
|
4
|
-
import {
|
|
5
|
-
import { IdentityService } from "../identity/ports.js";
|
|
6
|
-
import "../identity/index.js";
|
|
4
|
+
import { Actor } from "../shared/actor.js";
|
|
7
5
|
import "./model.js";
|
|
8
6
|
import "./roles.js";
|
|
9
|
-
import { Member, MembersQuery, Page } from "./members.js";
|
|
10
|
-
import { CreateOrganizationInput, ResendStudentInviteInput, UpdateOrganizationInput
|
|
11
|
-
import {
|
|
7
|
+
import { Member, MemberRoleChange, MembersQuery, Page } from "./members.js";
|
|
8
|
+
import { CreateOrganizationInput, ResendStudentInviteInput, UpdateOrganizationInput } from "./types.js";
|
|
9
|
+
import { IdentityService } from "../identity/ports.js";
|
|
10
|
+
import { Mailer } from "../shared/mailer.js";
|
|
11
|
+
import "../identity/index.js";
|
|
12
|
+
import { MemberWriteContext, MembersRepository, OrgAdmin, OrganizationService, OrganizationsRepository, OrganizationsUnitOfWork } from "./ports.js";
|
|
12
13
|
//#region src/organizations/service.d.ts
|
|
13
14
|
interface InviteUrls {
|
|
14
15
|
studentPortalUrl: string;
|
|
@@ -19,6 +20,7 @@ type OrganizationServiceParams = {
|
|
|
19
20
|
membersRepo: MembersRepository;
|
|
20
21
|
people: IdentityService;
|
|
21
22
|
uow: OrganizationsUnitOfWork;
|
|
23
|
+
orgAdmin: () => OrgAdmin;
|
|
22
24
|
logger?: Logger;
|
|
23
25
|
mailer?: Pick<Mailer, 'send'>;
|
|
24
26
|
inviteUrls?: InviteUrls;
|
|
@@ -28,30 +30,42 @@ declare class OrganizationServiceImpl implements OrganizationService {
|
|
|
28
30
|
private readonly membersRepo;
|
|
29
31
|
private readonly people;
|
|
30
32
|
private readonly uow;
|
|
33
|
+
private readonly orgAdmin;
|
|
31
34
|
private readonly logger;
|
|
32
35
|
private readonly mailer?;
|
|
33
36
|
private readonly inviteUrls?;
|
|
37
|
+
private readonly memberWrites;
|
|
34
38
|
constructor(params: OrganizationServiceParams);
|
|
35
39
|
createOrganization(input: CreateOrganizationInput): Promise<Organization>;
|
|
36
40
|
updateOrganization(id: string, input: UpdateOrganizationInput): Promise<Organization>;
|
|
37
41
|
deleteOrganization(id: string): Promise<Organization>;
|
|
38
42
|
addOrgUser({ orgId, userId, role }: AddOrgUserInput): Promise<OrgUser>;
|
|
39
|
-
removeOrgUser(orgId: string,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
resendStudentInvite(input: ResendStudentInviteInput): Promise<void>;
|
|
43
|
+
removeOrgUser(orgId: string, userId: string): Promise<OrgUser>;
|
|
44
|
+
updateOrgUser(orgId: string, userId: string, patch: UpdateOrgUserInput): Promise<OrgUser>;
|
|
45
|
+
createInvite(actor: Actor, input: CreateInviteInput): Promise<Invite>;
|
|
46
|
+
resendStudentInvite(actor: Actor, input: ResendStudentInviteInput): Promise<void>;
|
|
43
47
|
peekInvite(token: string): Promise<Invite | null>;
|
|
44
48
|
acceptInvite(input: AcceptInviteInput): Promise<OrgUser>;
|
|
49
|
+
private acceptStudentInvite;
|
|
50
|
+
private acceptStaffInvite;
|
|
51
|
+
getOrgUserById(orgId: string, id: string): Promise<OrgUser | null>;
|
|
45
52
|
getOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
|
|
46
|
-
deleteOrgUser(orgId: string, id: string): Promise<OrgUser>;
|
|
53
|
+
deleteOrgUser(orgId: string, actor: Actor, id: string): Promise<OrgUser>;
|
|
47
54
|
getOrgUsersForUser(userId: string): Promise<OrgUser[]>;
|
|
48
55
|
getById(id: string): Promise<Organization | null>;
|
|
49
56
|
private sendInviteEmail;
|
|
50
57
|
getByExternalId(externalId: string): Promise<Organization | null>;
|
|
51
58
|
getBySlug(slug: string): Promise<Organization | null>;
|
|
59
|
+
staffOrgUserIds(orgId: string): Promise<string[]>;
|
|
52
60
|
listMembers(orgId: string, query: MembersQuery): Promise<Page<Member>>;
|
|
53
|
-
updateMemberRole(ctx: MemberWriteContext, id: string, role: Role): Promise<
|
|
54
|
-
|
|
61
|
+
updateMemberRole(ctx: MemberWriteContext, actor: Actor, id: string, role: Role): Promise<MemberRoleChange | null>;
|
|
62
|
+
private demoteModerator;
|
|
63
|
+
private promoteStudent;
|
|
64
|
+
private asActor;
|
|
65
|
+
private memberWrite;
|
|
66
|
+
private assertManagesUsers;
|
|
67
|
+
private assertNotOwner;
|
|
68
|
+
removeMember(ctx: MemberWriteContext, actor: Actor, id: string): Promise<boolean>;
|
|
55
69
|
}
|
|
56
70
|
//#endregion
|
|
57
71
|
export { InviteUrls, OrganizationServiceImpl, OrganizationServiceParams };
|