@headless-lms/core 0.3.0 → 0.5.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 (307) hide show
  1. package/dist/assets/events.d.ts +24 -18
  2. package/dist/assets/file-urls.d.ts +11 -7
  3. package/dist/assets/file-urls.js +14 -4
  4. package/dist/assets/file-urls.js.map +1 -1
  5. package/dist/assets/index.d.ts +5 -4
  6. package/dist/assets/index.js +4 -3
  7. package/dist/assets/jobs.d.ts +15 -0
  8. package/dist/assets/jobs.js +30 -0
  9. package/dist/assets/jobs.js.map +1 -0
  10. package/dist/assets/ports.d.ts +37 -17
  11. package/dist/assets/service.d.ts +30 -15
  12. package/dist/assets/service.js +229 -59
  13. package/dist/assets/service.js.map +1 -1
  14. package/dist/automations/actions.js +2 -63
  15. package/dist/automations/actions.js.map +1 -1
  16. package/dist/automations/catalog.d.ts +1 -2
  17. package/dist/automations/catalog.js +137 -65
  18. package/dist/automations/catalog.js.map +1 -1
  19. package/dist/automations/community-derivations.js +20 -20
  20. package/dist/automations/community-derivations.js.map +1 -1
  21. package/dist/automations/community-mail.d.ts +36 -20
  22. package/dist/automations/community-mail.js +32 -24
  23. package/dist/automations/community-mail.js.map +1 -1
  24. package/dist/automations/event-permissions.d.ts +12 -0
  25. package/dist/automations/event-permissions.js +38 -0
  26. package/dist/automations/event-permissions.js.map +1 -0
  27. package/dist/automations/events.d.ts +0 -10
  28. package/dist/automations/index.d.ts +12 -4
  29. package/dist/automations/index.js +9 -1
  30. package/dist/automations/notifications/applicable.d.ts +8 -0
  31. package/dist/automations/notifications/applicable.js +12 -0
  32. package/dist/automations/notifications/applicable.js.map +1 -0
  33. package/dist/automations/notifications/debounce.d.ts +25 -0
  34. package/dist/automations/notifications/debounce.js +93 -0
  35. package/dist/automations/notifications/debounce.js.map +1 -0
  36. package/dist/automations/notifications/defaults.d.ts +8 -0
  37. package/dist/automations/notifications/defaults.js +346 -0
  38. package/dist/automations/notifications/defaults.js.map +1 -0
  39. package/dist/automations/notifications/delivery.d.ts +28 -0
  40. package/dist/automations/notifications/delivery.js +88 -0
  41. package/dist/automations/notifications/delivery.js.map +1 -0
  42. package/dist/automations/notifications/processor.d.ts +64 -0
  43. package/dist/automations/notifications/processor.js +270 -0
  44. package/dist/automations/notifications/processor.js.map +1 -0
  45. package/dist/automations/notifications/rules/content.d.ts +6 -0
  46. package/dist/automations/notifications/rules/content.js +96 -0
  47. package/dist/automations/notifications/rules/content.js.map +1 -0
  48. package/dist/automations/notifications/rules/discussion.d.ts +7 -0
  49. package/dist/automations/notifications/rules/discussion.js +678 -0
  50. package/dist/automations/notifications/rules/discussion.js.map +1 -0
  51. package/dist/automations/notifications/rules/entitlements.d.ts +6 -0
  52. package/dist/automations/notifications/rules/entitlements.js +276 -0
  53. package/dist/automations/notifications/rules/entitlements.js.map +1 -0
  54. package/dist/automations/notifications/rules/events.d.ts +9 -0
  55. package/dist/automations/notifications/rules/events.js +27 -0
  56. package/dist/automations/notifications/rules/events.js.map +1 -0
  57. package/dist/automations/notifications/rules/index.d.ts +6 -0
  58. package/dist/automations/notifications/rules/index.js +15 -0
  59. package/dist/automations/notifications/rules/index.js.map +1 -0
  60. package/dist/automations/notifications/rules/organizations.d.ts +6 -0
  61. package/dist/automations/notifications/rules/organizations.js +35 -0
  62. package/dist/automations/notifications/rules/organizations.js.map +1 -0
  63. package/dist/automations/notifications/rules/recipients.d.ts +32 -0
  64. package/dist/automations/notifications/rules/recipients.js +98 -0
  65. package/dist/automations/notifications/rules/recipients.js.map +1 -0
  66. package/dist/automations/notifications/service.d.ts +29 -0
  67. package/dist/automations/notifications/service.js +45 -0
  68. package/dist/automations/notifications/service.js.map +1 -0
  69. package/dist/automations/notifications/types.d.ts +7 -0
  70. package/dist/automations/notifications/types.js +560 -0
  71. package/dist/automations/notifications/types.js.map +1 -0
  72. package/dist/automations/ports.d.ts +134 -21
  73. package/dist/automations/service.d.ts +30 -30
  74. package/dist/automations/service.js +111 -144
  75. package/dist/automations/service.js.map +1 -1
  76. package/dist/content/event-sight.d.ts +11 -0
  77. package/dist/content/event-sight.js +11 -0
  78. package/dist/content/event-sight.js.map +1 -0
  79. package/dist/content/events.d.ts +437 -46
  80. package/dist/content/events.js +45 -1
  81. package/dist/content/events.js.map +1 -1
  82. package/dist/content/index.d.ts +8 -4
  83. package/dist/content/index.js +5 -1
  84. package/dist/content/jobs.d.ts +16 -0
  85. package/dist/content/jobs.js +37 -0
  86. package/dist/content/jobs.js.map +1 -0
  87. package/dist/content/model.d.ts +2 -2
  88. package/dist/content/notification-categories.d.ts +37 -0
  89. package/dist/content/notification-categories.js +73 -0
  90. package/dist/content/notification-categories.js.map +1 -0
  91. package/dist/content/ports.d.ts +132 -68
  92. package/dist/content/service.d.ts +100 -68
  93. package/dist/content/service.js +703 -146
  94. package/dist/content/service.js.map +1 -1
  95. package/dist/content/titles.d.ts +25 -0
  96. package/dist/content/titles.js +82 -0
  97. package/dist/content/titles.js.map +1 -0
  98. package/dist/content/types.d.ts +2 -2
  99. package/dist/discussion/authors.d.ts +4 -2
  100. package/dist/discussion/authors.js +9 -5
  101. package/dist/discussion/authors.js.map +1 -1
  102. package/dist/discussion/chats.d.ts +63 -39
  103. package/dist/discussion/chats.js +455 -190
  104. package/dist/discussion/chats.js.map +1 -1
  105. package/dist/discussion/digests.d.ts +24 -0
  106. package/dist/discussion/digests.js +104 -0
  107. package/dist/discussion/digests.js.map +1 -0
  108. package/dist/discussion/events.d.ts +227 -23
  109. package/dist/discussion/events.js +114 -19
  110. package/dist/discussion/events.js.map +1 -1
  111. package/dist/discussion/index.d.ts +12 -4
  112. package/dist/discussion/index.js +9 -2
  113. package/dist/discussion/jobs.d.ts +16 -0
  114. package/dist/discussion/jobs.js +40 -0
  115. package/dist/discussion/jobs.js.map +1 -0
  116. package/dist/discussion/live.d.ts +106 -0
  117. package/dist/discussion/live.js +642 -0
  118. package/dist/discussion/live.js.map +1 -0
  119. package/dist/discussion/mentions.d.ts +11 -0
  120. package/dist/discussion/mentions.js +35 -0
  121. package/dist/discussion/mentions.js.map +1 -0
  122. package/dist/discussion/ports.d.ts +279 -114
  123. package/dist/discussion/ports.js.map +1 -1
  124. package/dist/discussion/posts.d.ts +60 -44
  125. package/dist/discussion/posts.js +453 -287
  126. package/dist/discussion/posts.js.map +1 -1
  127. package/dist/discussion/rules.d.ts +18 -0
  128. package/dist/discussion/rules.js +22 -0
  129. package/dist/discussion/rules.js.map +1 -0
  130. package/dist/discussion/service.d.ts +50 -35
  131. package/dist/discussion/service.js +333 -205
  132. package/dist/discussion/service.js.map +1 -1
  133. package/dist/discussion/subscriptions.d.ts +37 -0
  134. package/dist/discussion/subscriptions.js +115 -0
  135. package/dist/discussion/subscriptions.js.map +1 -0
  136. package/dist/discussion/titles.d.ts +28 -0
  137. package/dist/discussion/titles.js +98 -0
  138. package/dist/discussion/titles.js.map +1 -0
  139. package/dist/entitlements/events.d.ts +20 -20
  140. package/dist/entitlements/index.d.ts +5 -4
  141. package/dist/entitlements/index.js +3 -2
  142. package/dist/entitlements/jobs.d.ts +12 -0
  143. package/dist/entitlements/jobs.js +18 -0
  144. package/dist/entitlements/jobs.js.map +1 -0
  145. package/dist/entitlements/model.d.ts +2 -2
  146. package/dist/entitlements/ports.d.ts +68 -38
  147. package/dist/entitlements/rules.d.ts +3 -6
  148. package/dist/entitlements/rules.js +5 -10
  149. package/dist/entitlements/rules.js.map +1 -1
  150. package/dist/entitlements/service.d.ts +43 -28
  151. package/dist/entitlements/service.js +387 -160
  152. package/dist/entitlements/service.js.map +1 -1
  153. package/dist/identity/devices.d.ts +30 -0
  154. package/dist/identity/devices.js +109 -0
  155. package/dist/identity/devices.js.map +1 -0
  156. package/dist/identity/index.d.ts +6 -5
  157. package/dist/identity/index.js +4 -3
  158. package/dist/identity/model.d.ts +2 -2
  159. package/dist/identity/notification-settings.d.ts +28 -0
  160. package/dist/identity/notification-settings.js +114 -0
  161. package/dist/identity/notification-settings.js.map +1 -0
  162. package/dist/identity/ports.d.ts +80 -56
  163. package/dist/identity/service.d.ts +8 -7
  164. package/dist/identity/service.js +17 -13
  165. package/dist/identity/service.js.map +1 -1
  166. package/dist/integrations/ports.d.ts +9 -8
  167. package/dist/integrations/service.d.ts +9 -8
  168. package/dist/integrations/service.js +33 -16
  169. package/dist/integrations/service.js.map +1 -1
  170. package/dist/organizations/default-roles.d.ts +22 -0
  171. package/dist/organizations/default-roles.js +89 -0
  172. package/dist/organizations/default-roles.js.map +1 -0
  173. package/dist/organizations/effective-permissions.d.ts +45 -0
  174. package/dist/organizations/effective-permissions.js +113 -0
  175. package/dist/organizations/effective-permissions.js.map +1 -0
  176. package/dist/organizations/events.d.ts +320 -181
  177. package/dist/organizations/events.js +90 -18
  178. package/dist/organizations/events.js.map +1 -1
  179. package/dist/organizations/index.d.ts +15 -10
  180. package/dist/organizations/index.js +8 -3
  181. package/dist/organizations/members.d.ts +66 -8
  182. package/dist/organizations/members.js.map +1 -1
  183. package/dist/organizations/notification-catalog.d.ts +31 -0
  184. package/dist/organizations/notification-catalog.js +32 -0
  185. package/dist/organizations/notification-catalog.js.map +1 -0
  186. package/dist/organizations/notification-categories.d.ts +34 -0
  187. package/dist/organizations/notification-categories.js +66 -0
  188. package/dist/organizations/notification-categories.js.map +1 -0
  189. package/dist/organizations/org-roles.d.ts +33 -0
  190. package/dist/organizations/org-roles.js +49 -0
  191. package/dist/organizations/org-roles.js.map +1 -0
  192. package/dist/organizations/permissions.d.ts +311 -0
  193. package/dist/organizations/permissions.js +327 -0
  194. package/dist/organizations/permissions.js.map +1 -0
  195. package/dist/organizations/ports.d.ts +187 -65
  196. package/dist/organizations/service.d.ts +104 -35
  197. package/dist/organizations/service.js +1247 -323
  198. package/dist/organizations/service.js.map +1 -1
  199. package/dist/organizations/testing.d.ts +18 -0
  200. package/dist/organizations/testing.js +37 -0
  201. package/dist/organizations/testing.js.map +1 -0
  202. package/dist/organizations/types.d.ts +5 -16
  203. package/dist/progress/index.d.ts +2 -2
  204. package/dist/progress/ports.d.ts +11 -3
  205. package/dist/progress/service.d.ts +6 -5
  206. package/dist/progress/service.js +23 -8
  207. package/dist/progress/service.js.map +1 -1
  208. package/dist/reporting/admin/index.d.ts +6 -4
  209. package/dist/reporting/admin/model.d.ts +36 -3
  210. package/dist/reporting/admin/ports.d.ts +39 -14
  211. package/dist/reporting/admin/service.d.ts +32 -11
  212. package/dist/reporting/admin/service.js +102 -18
  213. package/dist/reporting/admin/service.js.map +1 -1
  214. package/dist/reporting/events/index.d.ts +27 -0
  215. package/dist/reporting/events/index.js +20 -0
  216. package/dist/reporting/events/index.js.map +1 -0
  217. package/dist/reporting/member/calendar.d.ts +11 -0
  218. package/dist/reporting/member/calendar.js +75 -0
  219. package/dist/reporting/member/calendar.js.map +1 -0
  220. package/dist/reporting/member/index.d.ts +3 -2
  221. package/dist/reporting/member/model.d.ts +80 -26
  222. package/dist/reporting/member/ports.d.ts +50 -28
  223. package/dist/reporting/member/service.d.ts +81 -35
  224. package/dist/reporting/member/service.js +438 -145
  225. package/dist/reporting/member/service.js.map +1 -1
  226. package/dist/shared/actor.d.ts +22 -3
  227. package/dist/shared/errors.d.ts +15 -2
  228. package/dist/shared/errors.js +21 -2
  229. package/dist/shared/errors.js.map +1 -1
  230. package/dist/shared/id.d.ts +7 -0
  231. package/dist/shared/id.js +8 -1
  232. package/dist/shared/id.js.map +1 -1
  233. package/dist/shared/logger.d.ts +2 -1
  234. package/dist/shared/logger.js +10 -1
  235. package/dist/shared/logger.js.map +1 -1
  236. package/dist/shared/mailer.d.ts +11 -1
  237. package/dist/shared/mailer.js +32 -5
  238. package/dist/shared/mailer.js.map +1 -1
  239. package/dist/shared/notification-categories.d.ts +16 -0
  240. package/dist/shared/notification-categories.js +94 -0
  241. package/dist/shared/notification-categories.js.map +1 -0
  242. package/dist/shared/notification-settings.d.ts +14 -0
  243. package/dist/shared/notification-settings.js +61 -0
  244. package/dist/shared/notification-settings.js.map +1 -0
  245. package/dist/shared/ports.d.ts +68 -2
  246. package/dist/shared/settings.d.ts +2 -1
  247. package/dist/shared/settings.js +1 -0
  248. package/dist/shared/settings.js.map +1 -1
  249. package/dist/types/automations.d.ts +8 -2
  250. package/dist/types/content.d.ts +2 -2
  251. package/dist/types/discussion.d.ts +4 -5
  252. package/dist/types/email-templates.d.ts +119 -6
  253. package/dist/types/entitlements.d.ts +2 -2
  254. package/dist/types/identity.d.ts +14 -17
  255. package/dist/types/index.d.ts +13 -12
  256. package/dist/types/index.js +2 -1
  257. package/dist/types/notifications.d.ts +157 -0
  258. package/dist/types/notifications.js +1 -0
  259. package/dist/types/organizations.d.ts +3 -2
  260. package/dist/types/ports.d.ts +8 -1
  261. package/dist/types/ports.js +7 -1
  262. package/dist/types/ports.js.map +1 -0
  263. package/dist/types/schemas/assets.d.ts +5 -5
  264. package/dist/types/schemas/assets.js +4 -3
  265. package/dist/types/schemas/assets.js.map +1 -1
  266. package/dist/types/schemas/automations.d.ts +1 -10
  267. package/dist/types/schemas/automations.js +1 -3
  268. package/dist/types/schemas/automations.js.map +1 -1
  269. package/dist/types/schemas/content.d.ts +596 -11
  270. package/dist/types/schemas/content.js +225 -9
  271. package/dist/types/schemas/content.js.map +1 -1
  272. package/dist/types/schemas/discussion.d.ts +362 -66
  273. package/dist/types/schemas/discussion.js +123 -15
  274. package/dist/types/schemas/discussion.js.map +1 -1
  275. package/dist/types/schemas/entitlements.d.ts +14 -1
  276. package/dist/types/schemas/entitlements.js +11 -4
  277. package/dist/types/schemas/entitlements.js.map +1 -1
  278. package/dist/types/schemas/identity.d.ts +1 -85
  279. package/dist/types/schemas/identity.js +1 -42
  280. package/dist/types/schemas/identity.js.map +1 -1
  281. package/dist/types/schemas/index.d.ts +8 -7
  282. package/dist/types/schemas/index.js +8 -7
  283. package/dist/types/schemas/notifications.d.ts +96 -0
  284. package/dist/types/schemas/notifications.js +57 -0
  285. package/dist/types/schemas/notifications.js.map +1 -0
  286. package/dist/types/schemas/organizations.d.ts +96 -60
  287. package/dist/types/schemas/organizations.js +78 -27
  288. package/dist/types/schemas/organizations.js.map +1 -1
  289. package/dist/types/schemas/progress.d.ts +0 -1
  290. package/dist/types/schemas/progress.js +0 -1
  291. package/dist/types/schemas/progress.js.map +1 -1
  292. package/package.json +1 -1
  293. package/dist/automations/community-notifications.d.ts +0 -16
  294. package/dist/automations/community-notifications.js +0 -84
  295. package/dist/automations/community-notifications.js.map +0 -1
  296. package/dist/automations/seeds.d.ts +0 -17
  297. package/dist/automations/seeds.js +0 -235
  298. package/dist/automations/seeds.js.map +0 -1
  299. package/dist/identity/notifications.d.ts +0 -27
  300. package/dist/identity/notifications.js +0 -101
  301. package/dist/identity/notifications.js.map +0 -1
  302. package/dist/organizations/access-scopes.d.ts +0 -19
  303. package/dist/organizations/access-scopes.js +0 -89
  304. package/dist/organizations/access-scopes.js.map +0 -1
  305. package/dist/organizations/roles.d.ts +0 -19
  306. package/dist/organizations/roles.js +0 -82
  307. package/dist/organizations/roles.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","names":[],"sources":["../../src/organizations/permissions.ts"],"sourcesContent":["import { PERMISSION_KEYS } from '../types/schemas/organizations.js';\nimport type { Level, Permission } from '../types/index.js';\n\nexport type PermissionGroup =\n | 'organization'\n | 'people'\n | 'access'\n | 'content'\n | 'courses'\n | 'downloads'\n | 'communities'\n | 'events'\n | 'automations';\n\nexport interface PermissionDefinition {\n group: PermissionGroup;\n label: string;\n description: string;\n about: Level;\n implies?: readonly Permission[];\n}\n\nexport const PERMISSIONS = {\n 'organizations:read': {\n group: 'organization',\n label: 'See the organization',\n description: \"See the org's name, slug and general settings.\",\n about: 'org',\n },\n 'organizations:write': {\n group: 'organization',\n label: 'Edit the organization',\n description: \"Change the org's name, slug and general settings.\",\n about: 'org',\n implies: ['organizations:read'],\n },\n 'api_keys:read': {\n group: 'organization',\n label: 'See your API keys',\n description: 'List your own API keys.',\n about: 'org',\n },\n 'api_keys:write': {\n group: 'organization',\n label: 'Create API keys',\n description: 'Create your own API keys.',\n about: 'org',\n implies: ['api_keys:read'],\n },\n 'api_keys:delete': {\n group: 'organization',\n label: 'Revoke API keys',\n description: 'Revoke your own API keys.',\n about: 'org',\n implies: ['api_keys:read'],\n },\n 'notification_categories:read': {\n group: 'organization',\n label: 'See notification categories',\n description: \"See the notification types, channels and the org's categories and defaults.\",\n about: 'org',\n },\n 'notification_categories:write': {\n group: 'organization',\n label: 'Edit notification categories',\n description: \"Edit and reset the org's notification categories.\",\n about: 'org',\n implies: ['notification_categories:read'],\n },\n 'integrations:read': {\n group: 'organization',\n label: 'See integrations',\n description: 'See connected integrations.',\n about: 'org',\n },\n 'integrations:write': {\n group: 'organization',\n label: 'Manage integrations',\n description: 'Connect, configure and run actions on integrations.',\n about: 'org',\n implies: ['integrations:read'],\n },\n 'integrations:delete': {\n group: 'organization',\n label: 'Disconnect integrations',\n description: 'Disconnect integrations.',\n about: 'org',\n implies: ['integrations:read'],\n },\n 'analytics:read': {\n group: 'organization',\n label: 'See the overview',\n description: \"See the org's overview report.\",\n about: 'org',\n },\n 'people:read': {\n group: 'people',\n label: 'See people',\n description:\n \"List the org's people and pending invites, with each person's roles, and open any person's record.\",\n about: 'org',\n implies: ['progress:read'],\n },\n 'people:write': {\n group: 'people',\n label: 'Manage people',\n description:\n \"Invite people, resend and cancel invites, set a person's org role and give and remove roles on content items.\",\n about: 'org',\n implies: ['people:read'],\n },\n 'people:delete': {\n group: 'people',\n label: 'Remove people',\n description: 'Remove a person from the org.',\n about: 'org',\n implies: ['people:read'],\n },\n 'roles:read': {\n group: 'people',\n label: 'See roles',\n description: \"See the org's roles and their permissions.\",\n about: 'org',\n },\n 'roles:write': {\n group: 'people',\n label: 'Manage roles',\n description: 'Rename roles; change, reset and add roles through the API.',\n about: 'org',\n implies: ['roles:read'],\n },\n 'roles:delete': {\n group: 'people',\n label: 'Delete roles',\n description: 'Delete a role the org added.',\n about: 'org',\n implies: ['roles:read'],\n },\n 'access:read': {\n group: 'access',\n label: 'See access',\n description: \"See grants, including a community's roster of grant holders.\",\n about: 'org',\n },\n 'access:write': {\n group: 'access',\n label: 'Manage access',\n description: 'Grant, change and revoke access.',\n about: 'org',\n implies: ['access:read'],\n },\n 'bundles:read': {\n group: 'content',\n label: 'See bundles',\n description: 'See bundles and their names.',\n about: 'org',\n },\n 'bundles:write': {\n group: 'content',\n label: 'Edit bundles',\n description: 'Create and edit bundles.',\n about: 'org',\n implies: ['bundles:read'],\n },\n 'bundles:delete': {\n group: 'content',\n label: 'Delete bundles',\n description: 'Delete bundles.',\n about: 'org',\n implies: ['bundles:read'],\n },\n 'media:read': {\n group: 'content',\n label: 'See the media library',\n description: 'See the whole media library and attach any of its files.',\n about: 'org',\n },\n 'media:write': {\n group: 'content',\n label: 'Upload media',\n description: 'Upload to the media library and edit its files.',\n about: 'org',\n implies: ['media:read'],\n },\n 'media:delete': {\n group: 'content',\n label: 'Delete media',\n description: 'Delete files from the media library.',\n about: 'org',\n implies: ['media:read'],\n },\n 'courses:read': {\n group: 'courses',\n label: 'See courses',\n description:\n 'See the course, its modules and activities in the admin app; open it, its lessons, files and titles without a grant, unpublished included; be reachable for its lesson-comment mentions.',\n about: 'course',\n },\n 'courses:write': {\n group: 'courses',\n label: 'Edit courses',\n description:\n 'Edit and publish the course; add, change and delete its modules and activities; upload media for it and attach media uploaded for it. Creating a course needs it on the org.',\n about: 'course',\n implies: ['courses:read'],\n },\n 'courses:delete': {\n group: 'courses',\n label: 'Delete courses',\n description: 'Delete the course.',\n about: 'course',\n implies: ['courses:read'],\n },\n 'courses:moderate': {\n group: 'courses',\n label: 'Moderate lesson comments',\n description:\n \"See the course's lesson comments, held ones included; approve, remove, restore, reply to and resolve reports on them; be notified of reports. The holder's own lesson comments publish without review.\",\n about: 'course',\n implies: ['courses:read'],\n },\n 'progress:read': {\n group: 'courses',\n label: 'See learners and progress',\n description: \"See the course's learners, their progress and the course's analytics.\",\n about: 'course',\n },\n 'downloads:read': {\n group: 'downloads',\n label: 'See downloads',\n description:\n 'See the download in the admin app, and open it and its files without a grant, unpublished included.',\n about: 'download',\n },\n 'downloads:write': {\n group: 'downloads',\n label: 'Edit downloads',\n description:\n 'Edit and publish the download; upload files for it and attach files uploaded for it. Creating a download needs it on the org.',\n about: 'download',\n implies: ['downloads:read'],\n },\n 'downloads:delete': {\n group: 'downloads',\n label: 'Delete downloads',\n description: 'Delete the download.',\n about: 'download',\n implies: ['downloads:read'],\n },\n 'communities:read': {\n group: 'communities',\n label: 'See communities',\n description:\n 'See the community, its spaces, notification categories and analytics in the admin app; be a member of it without a grant, unpublished included, open every space in it and see its thumbnail while unpublished.',\n about: 'community',\n },\n 'communities:write': {\n group: 'communities',\n label: 'Configure communities',\n description:\n 'Configure the community, its spaces, topics, links, settings and notification categories; publish it; delete its spaces; upload media for it and attach media uploaded for it. Creating a community needs it on the org.',\n about: 'community',\n implies: ['communities:read'],\n },\n 'communities:delete': {\n group: 'communities',\n label: 'Delete communities',\n description: 'Delete the community.',\n about: 'community',\n implies: ['communities:read'],\n },\n 'communities:moderate': {\n group: 'communities',\n label: 'Moderate communities',\n description:\n \"See the review queue, pending and removed posts, held comments and their titles; open every space; approve, remove, restore, pin and lock posts and comments; turn comments and reactions on and off; delete any message, see deleted messages, read reported attachments, lock chats, see the message queue; see every space member and locked spaces' rosters; invite, add, approve, decline and remove space members; resolve reports; be notified of reviews, reports and join requests. The holder's own posts publish without review.\",\n about: 'community',\n },\n 'events:read': {\n group: 'events',\n label: 'See events',\n description:\n 'See the event in the admin app, drafts and canceled included; open it without a grant; see its attendees and analytics.',\n about: 'event',\n },\n 'events:write': {\n group: 'events',\n label: 'Edit events',\n description:\n 'Edit, publish and cancel the event; set its recording; grant and revoke it for others; upload files for it and attach, rename, reorder and remove them. Creating an event needs it on the org.',\n about: 'event',\n implies: ['events:read'],\n },\n 'events:delete': {\n group: 'events',\n label: 'Delete events',\n description: 'Delete the event.',\n about: 'event',\n implies: ['events:read'],\n },\n 'automations:read': {\n group: 'automations',\n label: 'See automations',\n description: 'See workflows, webhooks and their runs.',\n about: 'org',\n },\n 'automations:write': {\n group: 'automations',\n label: 'Edit automations',\n description: \"Create and edit workflows and webhooks, and reveal a webhook's signing secret.\",\n about: 'org',\n implies: ['automations:read'],\n },\n 'automations:delete': {\n group: 'automations',\n label: 'Delete automations',\n description: 'Delete workflows and webhooks.',\n about: 'org',\n implies: ['automations:read'],\n },\n} as const satisfies Record<Permission, PermissionDefinition>;\n\nexport const ALL_PERMISSIONS: readonly Permission[] = PERMISSION_KEYS;\n\nexport function isPermission(value: string): value is Permission {\n return (PERMISSION_KEYS as readonly string[]).includes(value);\n}\n\nexport function permissionAbout(permission: Permission): Level {\n return PERMISSIONS[permission].about;\n}\n\nexport function fitsLevels(permission: Permission, levels: readonly Level[]): boolean {\n const about = permissionAbout(permission);\n if (levels.includes('org')) {\n return true;\n }\n return about !== 'org' && levels.includes(about);\n}\n\nexport function withImplied(permissions: Iterable<Permission>): Set<Permission> {\n const out = new Set<Permission>();\n const queue = [...permissions];\n while (queue.length > 0) {\n const next = queue.pop()!;\n if (out.has(next)) {\n continue;\n }\n out.add(next);\n const def: PermissionDefinition = PERMISSIONS[next];\n for (const implied of def.implies ?? []) {\n queue.push(implied);\n }\n }\n return out;\n}\n\nexport interface PermissionListEntry extends Omit<PermissionDefinition, 'implies'> {\n key: Permission;\n implies?: Permission[];\n}\n\nexport function permissionList(): PermissionListEntry[] {\n return PERMISSION_KEYS.map((key) => {\n const { implies, ...definition }: PermissionDefinition = PERMISSIONS[key];\n return { key, ...definition, ...(implies && { implies: [...implies] }) };\n });\n}\n"],"mappings":";;AAsBA,MAAa,cAAc;CACzB,sBAAsB;EACpB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,uBAAuB;EACrB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,oBAAoB;CAChC;CACA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,kBAAkB;EAChB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,eAAe;CAC3B;CACA,mBAAmB;EACjB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,eAAe;CAC3B;CACA,gCAAgC;EAC9B,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,iCAAiC;EAC/B,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,8BAA8B;CAC1C;CACA,qBAAqB;EACnB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,sBAAsB;EACpB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,mBAAmB;CAC/B;CACA,uBAAuB;EACrB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,mBAAmB;CAC/B;CACA,kBAAkB;EAChB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,eAAe;EACb,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;EACP,SAAS,CAAC,eAAe;CAC3B;CACA,gBAAgB;EACd,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;EACP,SAAS,CAAC,aAAa;CACzB;CACA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,aAAa;CACzB;CACA,cAAc;EACZ,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,eAAe;EACb,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,YAAY;CACxB;CACA,gBAAgB;EACd,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,YAAY;CACxB;CACA,eAAe;EACb,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,gBAAgB;EACd,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,aAAa;CACzB;CACA,gBAAgB;EACd,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,cAAc;CAC1B;CACA,kBAAkB;EAChB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,cAAc;CAC1B;CACA,cAAc;EACZ,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,eAAe;EACb,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,YAAY;CACxB;CACA,gBAAgB;EACd,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,YAAY;CACxB;CACA,gBAAgB;EACd,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;CACT;CACA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;EACP,SAAS,CAAC,cAAc;CAC1B;CACA,kBAAkB;EAChB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,cAAc;CAC1B;CACA,oBAAoB;EAClB,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;EACP,SAAS,CAAC,cAAc;CAC1B;CACA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,kBAAkB;EAChB,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;CACT;CACA,mBAAmB;EACjB,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;EACP,SAAS,CAAC,gBAAgB;CAC5B;CACA,oBAAoB;EAClB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,gBAAgB;CAC5B;CACA,oBAAoB;EAClB,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;CACT;CACA,qBAAqB;EACnB,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;EACP,SAAS,CAAC,kBAAkB;CAC9B;CACA,sBAAsB;EACpB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,kBAAkB;CAC9B;CACA,wBAAwB;EACtB,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;CACT;CACA,eAAe;EACb,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;CACT;CACA,gBAAgB;EACd,OAAO;EACP,OAAO;EACP,aACE;EACF,OAAO;EACP,SAAS,CAAC,aAAa;CACzB;CACA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,aAAa;CACzB;CACA,oBAAoB;EAClB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;CACT;CACA,qBAAqB;EACnB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,kBAAkB;CAC9B;CACA,sBAAsB;EACpB,OAAO;EACP,OAAO;EACP,aAAa;EACb,OAAO;EACP,SAAS,CAAC,kBAAkB;CAC9B;AACF;AAEA,MAAa,kBAAyC;AAEtD,SAAgB,aAAa,OAAoC;CAC/D,OAAQ,gBAAsC,SAAS,KAAK;AAC9D;AAEA,SAAgB,gBAAgB,YAA+B;CAC7D,OAAO,YAAY,WAAW,CAAC;AACjC;AAEA,SAAgB,WAAW,YAAwB,QAAmC;CACpF,MAAM,QAAQ,gBAAgB,UAAU;CACxC,IAAI,OAAO,SAAS,KAAK,GACvB,OAAO;CAET,OAAO,UAAU,SAAS,OAAO,SAAS,KAAK;AACjD;AAEA,SAAgB,YAAY,aAAoD;CAC9E,MAAM,sBAAM,IAAI,IAAgB;CAChC,MAAM,QAAQ,CAAC,GAAG,WAAW;CAC7B,OAAO,MAAM,SAAS,GAAG;EACvB,MAAM,OAAO,MAAM,IAAI;EACvB,IAAI,IAAI,IAAI,IAAI,GACd;EAEF,IAAI,IAAI,IAAI;EACZ,MAAM,MAA4B,YAAY;EAC9C,KAAK,MAAM,WAAW,IAAI,WAAW,CAAC,GACpC,MAAM,KAAK,OAAO;CAEtB;CACA,OAAO;AACT;AAOA,SAAgB,iBAAwC;CACtD,OAAO,gBAAgB,KAAK,QAAQ;EAClC,MAAM,EAAE,SAAS,GAAG,eAAqC,YAAY;EACrE,OAAO;GAAE;GAAK,GAAG;GAAY,GAAI,WAAW,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE;EAAG;CACzE,CAAC;AACH"}
@@ -1,44 +1,153 @@
1
- import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, CreateOrgUserInput, Invite, InviteRole, NewOrganizationInput, OrgUser, Organization, Role, UpdateOrgUserInput } from "../types/schemas/organizations.js";
1
+ import { ContentType } from "../types/schemas/content.js";
2
+ import { ApiKeySummary, ConnectedApp, CreatedApiKey } from "../types/identity.js";
3
+ import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, CreateOrgUserInput, Invite, NewOrganizationInput, OrgUser, OrgUserProfile, Organization, Permission, RoleAssignment, UpdateOrgUserInput } from "../types/schemas/organizations.js";
4
+ import "../types/index.js";
5
+ import { Actor, EffectivePermissions } from "../shared/actor.js";
2
6
  import { OutboxAppender, UnitOfWork } from "../shared/ports.js";
3
- import { Actor } from "../shared/actor.js";
4
- import "./model.js";
5
- import "./roles.js";
6
- import { Member, MemberRoleChange, MembersQuery, Page } from "./members.js";
7
- import { CreateOrganizationInput, ResendStudentInviteInput, UpdateOrganizationInput } from "./types.js";
8
7
  import { AuthHeaders } from "../identity/ports.js";
9
8
  import "../identity/index.js";
9
+ import { StoredOrgRole } from "./org-roles.js";
10
+ import { AssignmentRow } from "./effective-permissions.js";
11
+ import "./model.js";
12
+ import { AssignmentView, CreateRoleInput, InviteDetails, Member, MembersQuery, Page, RoleView, UpdateRoleInput, ViewerPermissions } from "./members.js";
13
+ import { PermissionListEntry } from "./permissions.js";
14
+ import { CreateOrganizationInput, UpdateOrganizationInput } from "./types.js";
10
15
  //#region src/organizations/ports.d.ts
16
+ interface TransferOwnershipInput {
17
+ newOwnerOrgUserId: string;
18
+ previousOwnerRoleKey?: string | undefined;
19
+ }
20
+ interface CreateApiKeyInput {
21
+ name: string;
22
+ role: string;
23
+ expiresInDays?: number | undefined;
24
+ }
25
+ interface ApiKeyRole {
26
+ key: string;
27
+ name: string;
28
+ description: string;
29
+ }
30
+ type CallerLimit = {
31
+ scopes: readonly Permission[];
32
+ } | {
33
+ roleKey: string;
34
+ };
35
+ interface PlatformOrganizationInput {
36
+ name: string;
37
+ slug: string;
38
+ keyName?: string | undefined;
39
+ }
40
+ interface PlatformOrganization {
41
+ organization: AuthOrganization;
42
+ apiKey: CreatedApiKey;
43
+ }
44
+ interface PlatformAccount {
45
+ email: string;
46
+ name: string;
47
+ }
11
48
  interface OrganizationService {
12
- createOrganization(input: CreateOrganizationInput): Promise<Organization>;
13
- updateOrganization(id: string, input: UpdateOrganizationInput): Promise<Organization>;
49
+ createOrganization(input: NewOrganizationInput, headers: AuthHeaders): Promise<AuthOrganization>;
50
+ provisionOrganization(input: CreateOrganizationInput): Promise<Organization>;
51
+ updateOrganization(input: UpdateOrganizationInput, actor: Actor): Promise<Organization>;
14
52
  deleteOrganization(id: string): Promise<Organization>;
15
53
  addOrgUser(input: AddOrgUserInput): Promise<OrgUser>;
16
- removeOrgUser(orgId: string, userId: string): Promise<OrgUser>;
17
- updateOrgUser(orgId: string, userId: string, patch: UpdateOrgUserInput): Promise<OrgUser>;
54
+ removeOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
18
55
  getByExternalId(externalId: string): Promise<Organization | null>;
56
+ getBySlug(slug: string): Promise<Organization | null>;
57
+ getById(id: string): Promise<Organization | null>;
58
+ portalIdentity(id: string): Promise<Pick<Organization, 'id' | 'name' | 'slug'>>;
19
59
  getOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
20
60
  getOrgUserById(orgId: string, id: string): Promise<OrgUser | null>;
61
+ getOrgUsersByIds(orgId: string, ids: string[]): Promise<OrgUser[]>;
21
62
  getOrgUsersForUser(userId: string): Promise<OrgUser[]>;
22
- getById(id: string): Promise<Organization | null>;
23
- createInvite(actor: Actor, input: CreateInviteInput): Promise<Invite>;
63
+ orgIds(): Promise<string[]>;
64
+ actorFor(orgId: string, orgUserId: string, limit?: CallerLimit): Promise<Actor | null>;
65
+ resolveCaller(authOrgId: string, authUserId: string, limit?: CallerLimit): Promise<ResolvedCaller | null>;
66
+ systemActor(orgId: string): Actor;
67
+ permissionsOfMany(orgId: string, orgUserIds: string[]): Promise<Map<string, EffectivePermissions>>;
68
+ holders(orgId: string, permission: Permission, on?: string): Promise<string[]>;
69
+ permissionList(): PermissionListEntry[];
70
+ viewerPermissions(actor: Actor): ViewerPermissions;
71
+ auditRoleKeys(): Promise<number>;
72
+ listRoles(actor: Actor): Promise<RoleView[]>;
73
+ getRole(key: string, actor: Actor): Promise<RoleView>;
74
+ updateRole(key: string, input: UpdateRoleInput, actor: Actor): Promise<RoleView>;
75
+ createRole(input: CreateRoleInput, actor: Actor): Promise<RoleView>;
76
+ resetRole(key: string, actor: Actor): Promise<RoleView>;
77
+ deleteRole(key: string, actor: Actor): Promise<void>;
78
+ listTeam(query: MembersQuery, actor: Actor): Promise<Page<Member>>;
79
+ listAssignments(orgUserId: string, actor: Actor): Promise<AssignmentView[]>;
80
+ listAssignmentsOn(contentId: string, actor: Actor): Promise<AssignmentView[]>;
81
+ setOrgRole(orgUserId: string, roleKey: string, actor: Actor): Promise<AssignmentView[]>;
82
+ assignRole(orgUserId: string, contentId: string, roleKey: string, actor: Actor): Promise<AssignmentView[]>;
83
+ unassignRole(orgUserId: string, contentId: string, actor: Actor): Promise<AssignmentView[]>;
84
+ removePerson(orgUserId: string, actor: Actor): Promise<void>;
85
+ transferOwnership(input: TransferOwnershipInput, actor: Actor): Promise<void>;
86
+ createInvite(input: CreateInviteInput, actor: Actor, inviterUserId: string): Promise<Invite>;
87
+ resendInvite(orgUserId: string, actor: Actor, inviterUserId: string): Promise<void>;
88
+ cancelInvite(orgUserId: string, actor: Actor): Promise<void>;
24
89
  peekInvite(token: string): Promise<Invite | null>;
25
- acceptInvite(input: AcceptInviteInput): Promise<OrgUser>;
26
- deleteOrgUser(orgId: string, actor: Actor, id: string): Promise<OrgUser>;
27
- resendStudentInvite(actor: Actor, input: ResendStudentInviteInput): Promise<void>;
28
- getBySlug(slug: string): Promise<Organization | null>;
29
- listMembers(orgId: string, query: MembersQuery): Promise<Page<Member>>;
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[]>;
90
+ describeInvite(token: string): Promise<InviteDetails>;
91
+ acceptInvite(input: AcceptInviteInput, headers: AuthHeaders): Promise<OrgUser>;
92
+ listApiKeys(actor: Actor): Promise<ApiKeySummary[]>;
93
+ listApiKeyRoles(actor: Actor): Promise<ApiKeyRole[]>;
94
+ createApiKey(input: CreateApiKeyInput, actor: Actor): Promise<CreatedApiKey>;
95
+ deleteApiKey(keyId: string, actor: Actor): Promise<void>;
96
+ listConnectedApps(actor: Actor): Promise<ConnectedApp[]>;
97
+ revokeConnectedApp(clientId: string, actor: Actor): Promise<void>;
98
+ createPlatformOrganization(input: PlatformOrganizationInput): Promise<PlatformOrganization>;
99
+ createPlatformApiKey(orgId: string, name: string): Promise<CreatedApiKey>;
100
+ isPlatformAccount(email: string): boolean;
101
+ }
102
+ interface ActorFacts {
103
+ orgUserId: string;
104
+ status: OrgUser['status'];
105
+ assignments: AssignmentRow[];
106
+ storedRoles: StoredOrgRole[];
107
+ }
108
+ interface CallerFacts {
109
+ orgId: string;
110
+ userId: string | null;
111
+ orgUser: ActorFacts | null;
112
+ }
113
+ interface ResolvedCaller {
114
+ orgId: string;
115
+ userId: string | null;
116
+ orgUserId: string | null;
117
+ actor: Actor | null;
118
+ }
119
+ interface RolesRepository {
120
+ actorFacts(orgId: string, orgUserId: string): Promise<ActorFacts | null>;
121
+ callerFacts(authOrgId: string, authUserId: string): Promise<CallerFacts | null>;
122
+ storedRoles(orgId: string): Promise<StoredOrgRole[]>;
123
+ saveStoredRole(orgId: string, role: StoredOrgRole): Promise<void>;
124
+ deleteStoredRole(orgId: string, key: string): Promise<boolean>;
125
+ assignmentsOf(orgId: string, orgUserId: string): Promise<RoleAssignment[]>;
126
+ assignmentsOfMany(orgId: string, orgUserIds: string[]): Promise<Map<string, AssignmentRow[]>>;
127
+ assignmentsOn(orgId: string, contentId: string): Promise<RoleAssignment[]>;
128
+ holdersOf(orgId: string, roleKeys: string[], contentId?: string): Promise<string[]>;
129
+ setOrgRole(orgId: string, orgUserId: string, roleKey: string | null, assignedBy: string): Promise<void>;
130
+ setItemRole(orgId: string, orgUserId: string, contentId: string, contentType: ContentType, roleKey: string, assignedBy: string): Promise<void>;
131
+ removeItemRole(orgId: string, orgUserId: string, contentId: string): Promise<RoleAssignment | null>;
132
+ countHolders(orgId: string, roleKey: string, contentType?: ContentType | 'org'): Promise<number>;
133
+ holderCounts(orgId: string): Promise<Record<string, number>>;
134
+ contentTypeOf(orgId: string, contentId: string): Promise<ContentType | null>;
135
+ ownerOrgUserId(orgId: string): Promise<string | null>;
136
+ roleKeyUsage(): Promise<{
137
+ orgId: string;
138
+ roleKey: string;
139
+ level: string;
140
+ count: number;
141
+ stored: boolean;
142
+ }[]>;
143
+ lock(keys: string[]): Promise<void>;
33
144
  }
34
- /** Atomic write scope: tx-bound repo + outbox appender, one transaction. */
35
145
  interface OrganizationsWriteScope {
36
146
  organizations: OrganizationsRepository;
147
+ roles: RolesRepository;
37
148
  outbox: OutboxAppender;
38
149
  }
39
150
  type OrganizationsUnitOfWork = UnitOfWork<OrganizationsWriteScope>;
40
- /** Repo-facing write shape for a new org row. The service mints the id and
41
- * resolves the defaults, so nothing is optional by the time it lands here. */
42
151
  interface NewOrganizationRow {
43
152
  id: string;
44
153
  externalId?: string | null;
@@ -46,10 +155,9 @@ interface NewOrganizationRow {
46
155
  slug: string;
47
156
  ownerId: string;
48
157
  }
49
- /** Repo-facing write shape for a freshly minted invite. */
50
158
  interface NewInviteRow {
51
159
  email: string;
52
- role: InviteRole;
160
+ roleKey: string;
53
161
  invitedBy: string;
54
162
  tokenHash: string;
55
163
  expiresAt: Date;
@@ -57,70 +165,84 @@ interface NewInviteRow {
57
165
  interface OrganizationsRepository {
58
166
  create(input: NewOrganizationRow): Promise<Organization>;
59
167
  update(id: string, input: UpdateOrganizationInput): Promise<Organization | null>;
60
- /** Drops the org row and its dependents; null when none matched. */
61
168
  delete(id: string): Promise<Organization>;
62
169
  findById(id: string): Promise<Organization | null>;
170
+ listIds(): Promise<string[]>;
63
171
  findByExternalId(externalId: string): Promise<Organization | null>;
64
172
  findBySlug(slug: string): Promise<Organization | null>;
65
- /** Inserts a pending invite, or re-issues the org's existing pending one
66
- * for this email (fresh token/expiry/role) — atomic upsert. */
67
173
  upsertPendingInvite(orgId: string, input: NewInviteRow): Promise<Invite>;
68
174
  setInviteStatus(orgId: string, id: string, status: string): Promise<Invite | null>;
175
+ setInviteRole(orgId: string, id: string, roleKey: string, invitedBy: string): Promise<Invite | null>;
69
176
  findInviteByTokenHash(tokenHash: string): Promise<Invite | null>;
70
177
  findPendingInvite(orgId: string, email: string): Promise<Invite | null>;
71
- setInviteToken(orgId: string, id: string, tokenHash: string, expiresAt: Date): Promise<Invite | null>;
72
- /** The person's row in one org. `(org_id, user_id)` is unique. */
178
+ setInviteToken(orgId: string, id: string, tokenHash: string, expiresAt: Date, invitedBy: string): Promise<Invite | null>;
73
179
  findOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
74
- /** Every org this person belongs to, oldest first. */
75
180
  findOrgUsersByUser(userId: string): Promise<OrgUser[]>;
76
181
  findOrgUserById(orgId: string, id: string): Promise<OrgUser | null>;
77
182
  findOrgUsersByIds(orgId: string, ids: string[]): Promise<OrgUser[]>;
78
- findOrgUserIdsByRole(orgId: string, roles: Role[]): Promise<string[]>;
79
- /** Links a user to the org under a role. Throws ConflictError when they
80
- * already hold a row there. */
81
183
  createOrgUser(input: CreateOrgUserInput): Promise<OrgUser>;
82
184
  updateOrgUser(orgId: string, id: string, patch: UpdateOrgUserInput): Promise<OrgUser | null>;
83
- /** Every org this person is a student in — the scope of `student.linked`. */
84
- findStudentOrgUsers(userId: string): Promise<OrgUser[]>;
85
- /** Kills the org's pending invite for an address, if any. */
86
185
  deleteOrgUser(orgId: string, id: string): Promise<OrgUser | null>;
87
186
  }
88
- /** A member row enriched with the ids needed to drive writes. */
89
- interface MemberRecord extends Member {
90
- kind: 'member' | 'invite';
91
- userExternalId: string | null;
92
- inviteId: string | null;
93
- }
94
- interface MembersRepository {
95
- list(orgId: string, query: MembersQuery): Promise<Page<Member>>;
96
- findByEmail(orgId: string, email: string): Promise<MemberRecord | null>;
97
- findById(orgId: string, id: string): Promise<MemberRecord | null>;
187
+ interface GrantReader {
188
+ holdsAnyGrant(orgId: string, orgUserId: string): Promise<boolean>;
98
189
  }
99
- /** The person as this context reads them back after a correction. */
100
- interface PersonRecord {
101
- id: string;
102
- email: string;
103
- firstName: string | null;
104
- lastName: string | null;
190
+ interface TeamRow extends OrgUserProfile {
191
+ status: OrgUser['status'];
192
+ joinedAt: Date;
193
+ invitedAt: Date | null;
194
+ orgRoleKey: string | null;
195
+ inviteRoleKey: string | null;
196
+ items: {
197
+ contentId: string;
198
+ contentType: ContentType;
199
+ roleKey: string;
200
+ }[];
105
201
  }
106
- /** Context for a write: domain org (reads/rules) + auth org & session (writes). */
107
- interface MemberWriteContext {
108
- orgId: string;
109
- authOrgId: string;
110
- headers: Record<string, string | string[] | undefined>;
202
+ interface MembersRepository {
203
+ teamRows(orgId: string, memberRoleKey: string): Promise<TeamRow[]>;
111
204
  }
112
- /** The provider's view of an org: what it stores itself, minus the fields only
113
- * the domain row carries (`ownerId`, `externalId`, `updatedAt`). */
114
205
  type AuthOrganization = Pick<Organization, 'id' | 'name' | 'slug' | 'createdAt'>;
115
206
  interface OrgAdmin {
116
207
  createOrganization(headers: AuthHeaders, input: NewOrganizationInput): Promise<AuthOrganization>;
208
+ createOrganizationFor(ownerExternalId: string, input: NewOrganizationInput): Promise<AuthOrganization>;
117
209
  setActiveOrganization(headers: AuthHeaders, externalId: string): Promise<void>;
118
- updateOrganization(headers: AuthHeaders, id: string, input: UpdateOrganizationInput): Promise<AuthOrganization>;
119
210
  deleteOrganization(headers: AuthHeaders, externalId: string): Promise<void>;
120
- grantMembership(orgExternalId: string, userExternalId: string, role: string): Promise<void>;
121
- updateRole(ctx: MemberWriteContext, userExternalId: string, role: Role): Promise<void>;
122
- removeMember(ctx: MemberWriteContext, userExternalId: string): Promise<void>;
211
+ updateOrganization(externalId: string, input: UpdateOrganizationInput): Promise<void>;
212
+ grantMembership(orgExternalId: string, userExternalId: string): Promise<void>;
213
+ setMembershipOwner(orgExternalId: string, userExternalId: string, owner: boolean): Promise<void>;
214
+ removeMembership(orgExternalId: string, userExternalId: string): Promise<void>;
215
+ }
216
+ interface Accounts {
217
+ createAccount(input: PlatformAccount): Promise<{
218
+ externalId: string;
219
+ }>;
220
+ }
221
+ interface StoredApiKey {
222
+ id: string;
223
+ name: string | null;
224
+ start: string | null;
225
+ roleKey: string | null;
226
+ createdAt: Date;
227
+ lastUsedAt: Date | null;
228
+ expiresAt: Date | null;
229
+ }
230
+ interface NewApiKey {
231
+ name: string;
232
+ roleKey: string;
233
+ expiresInDays?: number | undefined;
234
+ }
235
+ interface ApiKeys {
236
+ list(orgId: string, userExternalId: string): Promise<StoredApiKey[]>;
237
+ create(orgId: string, userExternalId: string, input: NewApiKey): Promise<StoredApiKey & {
238
+ key: string;
239
+ }>;
240
+ countWithRole(orgId: string, roleKey: string): Promise<number>;
241
+ revoke(orgId: string, userExternalId: string, keyId: string): Promise<void>;
242
+ listApps(orgId: string, userExternalId: string): Promise<ConnectedApp[]>;
243
+ revokeApp(orgId: string, userExternalId: string, clientId: string): Promise<void>;
244
+ revokeAllFor(orgId: string, userExternalId: string): Promise<void>;
123
245
  }
124
246
  //#endregion
125
- export { type AuthHeaders, AuthOrganization, MemberRecord, MemberWriteContext, MembersRepository, NewInviteRow, NewOrganizationRow, OrgAdmin, OrganizationService, OrganizationsRepository, OrganizationsUnitOfWork, OrganizationsWriteScope, PersonRecord };
247
+ export { Accounts, ActorFacts, ApiKeyRole, ApiKeys, type AuthHeaders, AuthOrganization, CallerFacts, CallerLimit, CreateApiKeyInput, GrantReader, MembersRepository, NewApiKey, NewInviteRow, NewOrganizationRow, OrgAdmin, OrganizationService, OrganizationsRepository, OrganizationsUnitOfWork, OrganizationsWriteScope, PlatformAccount, PlatformOrganization, PlatformOrganizationInput, ResolvedCaller, RolesRepository, StoredApiKey, TeamRow, TransferOwnershipInput };
126
248
  //# sourceMappingURL=ports.d.ts.map
@@ -1,15 +1,20 @@
1
1
  import { Logger } from "../types/ports.js";
2
- import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, Invite, OrgUser, Organization, Role, UpdateOrgUserInput } from "../types/schemas/organizations.js";
2
+ import { ApiKeySummary, ConnectedApp, CreatedApiKey } from "../types/identity.js";
3
+ import { AcceptInviteInput, AddOrgUserInput, CreateInviteInput, Invite, NewOrganizationInput, OrgUser, Organization, Permission } from "../types/schemas/organizations.js";
4
+ import "../types/index.js";
5
+ import { Actor, EffectivePermissions } from "../shared/actor.js";
3
6
  import "../shared/ports.js";
4
- import { Actor } from "../shared/actor.js";
5
- import "./model.js";
6
- import "./roles.js";
7
- import { Member, MemberRoleChange, MembersQuery, Page } from "./members.js";
8
- import { CreateOrganizationInput, ResendStudentInviteInput, UpdateOrganizationInput } from "./types.js";
9
- import { IdentityService } from "../identity/ports.js";
7
+ import { AssetFiles } from "../assets/ports.js";
8
+ import "../assets/index.js";
10
9
  import { Mailer } from "../shared/mailer.js";
10
+ import { AuthHeaders, IdentityService, SessionAdmin } from "../identity/ports.js";
11
11
  import "../identity/index.js";
12
- import { MemberWriteContext, MembersRepository, OrgAdmin, OrganizationService, OrganizationsRepository, OrganizationsUnitOfWork } from "./ports.js";
12
+ import { RoleDefinition } from "./default-roles.js";
13
+ import "./model.js";
14
+ import { AssignmentView, CreateRoleInput, InviteDetails, Member, MembersQuery, Page, RoleView, UpdateRoleInput, ViewerPermissions } from "./members.js";
15
+ import { PermissionListEntry } from "./permissions.js";
16
+ import { CreateOrganizationInput, UpdateOrganizationInput } from "./types.js";
17
+ import { Accounts, ApiKeyRole, ApiKeys, AuthOrganization, CallerLimit, CreateApiKeyInput, GrantReader, MembersRepository, OrgAdmin, OrganizationService, OrganizationsRepository, OrganizationsUnitOfWork, PlatformAccount, PlatformOrganization, PlatformOrganizationInput, ResolvedCaller, RolesRepository, TransferOwnershipInput } from "./ports.js";
13
18
  //#region src/organizations/service.d.ts
14
19
  interface InviteUrls {
15
20
  studentPortalUrl: string;
@@ -17,55 +22,119 @@ interface InviteUrls {
17
22
  }
18
23
  type OrganizationServiceParams = {
19
24
  repo: OrganizationsRepository;
25
+ roles: RolesRepository;
20
26
  membersRepo: MembersRepository;
21
27
  people: IdentityService;
28
+ images: Pick<AssetFiles, 'syncPublicImage'>;
22
29
  uow: OrganizationsUnitOfWork;
23
30
  orgAdmin: () => OrgAdmin;
31
+ sessions: () => SessionAdmin;
32
+ apiKeys?: () => ApiKeys;
33
+ accounts?: () => Accounts;
34
+ platform?: PlatformAccount;
35
+ grants?: () => GrantReader;
36
+ defaultRoles?: readonly RoleDefinition[];
24
37
  logger?: Logger;
25
38
  mailer?: Pick<Mailer, 'send'>;
26
39
  inviteUrls?: InviteUrls;
27
40
  };
28
41
  declare class OrganizationServiceImpl implements OrganizationService {
29
42
  private readonly repo;
43
+ private readonly roles;
30
44
  private readonly membersRepo;
31
45
  private readonly people;
46
+ private readonly images;
32
47
  private readonly uow;
33
48
  private readonly orgAdmin;
49
+ private readonly sessions;
50
+ private readonly apiKeysPort?;
51
+ private readonly accountsPort?;
52
+ private readonly platform?;
53
+ private readonly grants?;
54
+ private readonly catalog;
34
55
  private readonly logger;
35
56
  private readonly mailer?;
36
57
  private readonly inviteUrls?;
37
- private readonly memberWrites;
38
58
  constructor(params: OrganizationServiceParams);
39
- createOrganization(input: CreateOrganizationInput): Promise<Organization>;
40
- updateOrganization(id: string, input: UpdateOrganizationInput): Promise<Organization>;
59
+ createOrganization(input: NewOrganizationInput, headers: AuthHeaders): Promise<AuthOrganization>;
60
+ provisionOrganization(input: CreateOrganizationInput): Promise<Organization>;
61
+ updateOrganization(input: UpdateOrganizationInput, actor: Actor): Promise<Organization>;
41
62
  deleteOrganization(id: string): Promise<Organization>;
42
- addOrgUser({ orgId, userId, role }: AddOrgUserInput): Promise<OrgUser>;
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>;
47
- peekInvite(token: string): Promise<Invite | null>;
48
- acceptInvite(input: AcceptInviteInput): Promise<OrgUser>;
49
- private acceptStudentInvite;
50
- private acceptStaffInvite;
51
- getOrgUserById(orgId: string, id: string): Promise<OrgUser | null>;
63
+ addOrgUser({ orgId, userId }: AddOrgUserInput): Promise<OrgUser>;
64
+ removeOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
65
+ getByExternalId(externalId: string): Promise<Organization | null>;
66
+ getBySlug(slug: string): Promise<Organization | null>;
67
+ getById(id: string): Promise<Organization | null>;
68
+ portalIdentity(id: string): Promise<Pick<Organization, 'id' | 'name' | 'slug'>>;
52
69
  getOrgUser(orgId: string, userId: string): Promise<OrgUser | null>;
53
- deleteOrgUser(orgId: string, actor: Actor, id: string): Promise<OrgUser>;
70
+ getOrgUserById(orgId: string, id: string): Promise<OrgUser | null>;
71
+ getOrgUsersByIds(orgId: string, ids: string[]): Promise<OrgUser[]>;
54
72
  getOrgUsersForUser(userId: string): Promise<OrgUser[]>;
55
- getById(id: string): Promise<Organization | null>;
73
+ orgIds(): Promise<string[]>;
74
+ actorFor(orgId: string, orgUserId: string, limit?: CallerLimit): Promise<Actor | null>;
75
+ resolveCaller(authOrgId: string, authUserId: string, limit?: CallerLimit): Promise<ResolvedCaller | null>;
76
+ systemActor(orgId: string): Actor;
77
+ permissionsOfMany(orgId: string, orgUserIds: string[]): Promise<Map<string, EffectivePermissions>>;
78
+ holders(orgId: string, permission: Permission, on?: string): Promise<string[]>;
79
+ permissionList(): PermissionListEntry[];
80
+ viewerPermissions(actor: Actor): ViewerPermissions;
81
+ auditRoleKeys(): Promise<number>;
82
+ listRoles(actor: Actor): Promise<RoleView[]>;
83
+ getRole(key: string, actor: Actor): Promise<RoleView>;
84
+ updateRole(key: string, input: UpdateRoleInput, actor: Actor): Promise<RoleView>;
85
+ createRole(input: CreateRoleInput, actor: Actor): Promise<RoleView>;
86
+ resetRole(key: string, actor: Actor): Promise<RoleView>;
87
+ deleteRole(key: string, actor: Actor): Promise<void>;
88
+ listTeam(query: MembersQuery, actor: Actor): Promise<Page<Member>>;
89
+ listAssignments(orgUserId: string, actor: Actor): Promise<AssignmentView[]>;
90
+ listAssignmentsOn(contentId: string, actor: Actor): Promise<AssignmentView[]>;
91
+ setOrgRole(orgUserId: string, roleKey: string, actor: Actor): Promise<AssignmentView[]>;
92
+ assignRole(orgUserId: string, contentId: string, roleKey: string, actor: Actor): Promise<AssignmentView[]>;
93
+ unassignRole(orgUserId: string, contentId: string, actor: Actor): Promise<AssignmentView[]>;
94
+ removePerson(orgUserId: string, actor: Actor): Promise<void>;
95
+ transferOwnership(input: TransferOwnershipInput, actor: Actor): Promise<void>;
96
+ createInvite(input: CreateInviteInput, actor: Actor, inviterUserId: string): Promise<Invite>;
97
+ resendInvite(orgUserId: string, actor: Actor, inviterUserId: string): Promise<void>;
98
+ cancelInvite(orgUserId: string, actor: Actor): Promise<void>;
99
+ peekInvite(token: string): Promise<Invite | null>;
100
+ describeInvite(token: string): Promise<InviteDetails>;
101
+ acceptInvite(input: AcceptInviteInput, headers: AuthHeaders): Promise<OrgUser>;
102
+ private checkAcceptance;
103
+ listApiKeys(actor: Actor): Promise<ApiKeySummary[]>;
104
+ listApiKeyRoles(actor: Actor): Promise<ApiKeyRole[]>;
105
+ createApiKey(input: CreateApiKeyInput, actor: Actor): Promise<CreatedApiKey>;
106
+ deleteApiKey(keyId: string, actor: Actor): Promise<void>;
107
+ listConnectedApps(actor: Actor): Promise<ConnectedApp[]>;
108
+ revokeConnectedApp(clientId: string, actor: Actor): Promise<void>;
109
+ createPlatformOrganization(input: PlatformOrganizationInput): Promise<PlatformOrganization>;
110
+ createPlatformApiKey(orgId: string, name: string): Promise<CreatedApiKey>;
111
+ isPlatformAccount(email: string): boolean;
112
+ private platformKey;
113
+ private platformAccountId;
114
+ private platformAccount;
115
+ private accounts;
116
+ private keysWithRole;
117
+ private cleanUpAfterRemoval;
118
+ private apiKeys;
119
+ private externalIdsOf;
120
+ private pendingInviteOf;
121
+ private deleteOrgUserRow;
122
+ private deleteOrgUserIn;
56
123
  private sendInviteEmail;
57
- getByExternalId(externalId: string): Promise<Organization | null>;
58
- getBySlug(slug: string): Promise<Organization | null>;
59
- staffOrgUserIds(orgId: string): Promise<string[]>;
60
- listMembers(orgId: string, query: MembersQuery): Promise<Page<Member>>;
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>;
124
+ private toMember;
125
+ private assignmentViews;
126
+ private roleMap;
127
+ private resolveIn;
128
+ private findRole;
129
+ private relockedActor;
130
+ private itemPermissions;
131
+ private assertHolds;
132
+ private assertHoldsOn;
133
+ private assertNotSelf;
134
+ private assertUniqueName;
135
+ private parseLevels;
136
+ private assertFits;
137
+ private assertLevelsNotInUse;
69
138
  }
70
139
  //#endregion
71
140
  export { InviteUrls, OrganizationServiceImpl, OrganizationServiceParams };