@headless-lms/core 0.2.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.
Files changed (225) hide show
  1. package/dist/assets/events.d.ts +39 -21
  2. package/dist/assets/events.js +1 -1
  3. package/dist/assets/events.js.map +1 -1
  4. package/dist/assets/file-urls.d.ts +20 -0
  5. package/dist/assets/file-urls.js +25 -0
  6. package/dist/assets/file-urls.js.map +1 -0
  7. package/dist/assets/index.d.ts +5 -4
  8. package/dist/assets/index.js +3 -2
  9. package/dist/assets/model.d.ts +2 -2
  10. package/dist/assets/ports.d.ts +45 -15
  11. package/dist/assets/service.d.ts +39 -7
  12. package/dist/assets/service.js +291 -38
  13. package/dist/assets/service.js.map +1 -1
  14. package/dist/automations/actions.d.ts +13 -24
  15. package/dist/automations/actions.js +168 -43
  16. package/dist/automations/actions.js.map +1 -1
  17. package/dist/automations/catalog.d.ts +2 -1
  18. package/dist/automations/catalog.js +229 -13
  19. package/dist/automations/catalog.js.map +1 -1
  20. package/dist/automations/community-derivations.d.ts +14 -0
  21. package/dist/automations/community-derivations.js +439 -0
  22. package/dist/automations/community-derivations.js.map +1 -0
  23. package/dist/automations/community-mail.d.ts +112 -0
  24. package/dist/automations/community-mail.js +90 -0
  25. package/dist/automations/community-mail.js.map +1 -0
  26. package/dist/automations/community-notifications.d.ts +16 -0
  27. package/dist/automations/community-notifications.js +84 -0
  28. package/dist/automations/community-notifications.js.map +1 -0
  29. package/dist/automations/events.d.ts +28 -0
  30. package/dist/automations/index.d.ts +4 -2
  31. package/dist/automations/index.js +3 -2
  32. package/dist/automations/model.d.ts +10 -3
  33. package/dist/automations/model.js +15 -2
  34. package/dist/automations/model.js.map +1 -1
  35. package/dist/automations/ports.d.ts +5 -1
  36. package/dist/automations/schedule.d.ts +6 -0
  37. package/dist/automations/schedule.js +41 -0
  38. package/dist/automations/schedule.js.map +1 -0
  39. package/dist/automations/seeds.d.ts +17 -0
  40. package/dist/automations/seeds.js +235 -0
  41. package/dist/automations/seeds.js.map +1 -0
  42. package/dist/automations/service.d.ts +22 -3
  43. package/dist/automations/service.js +306 -43
  44. package/dist/automations/service.js.map +1 -1
  45. package/dist/content/events.d.ts +631 -19
  46. package/dist/content/events.js +44 -1
  47. package/dist/content/events.js.map +1 -1
  48. package/dist/content/index.d.ts +4 -4
  49. package/dist/content/model.d.ts +2 -2
  50. package/dist/content/ports.d.ts +71 -18
  51. package/dist/content/service.d.ts +57 -18
  52. package/dist/content/service.js +502 -23
  53. package/dist/content/service.js.map +1 -1
  54. package/dist/content/types.d.ts +2 -2
  55. package/dist/discussion/authors.d.ts +10 -0
  56. package/dist/discussion/authors.js +23 -0
  57. package/dist/discussion/authors.js.map +1 -0
  58. package/dist/discussion/chats.d.ts +104 -0
  59. package/dist/discussion/chats.js +798 -0
  60. package/dist/discussion/chats.js.map +1 -0
  61. package/dist/discussion/events.d.ts +619 -56
  62. package/dist/discussion/events.js +106 -3
  63. package/dist/discussion/events.js.map +1 -1
  64. package/dist/discussion/index.d.ts +7 -3
  65. package/dist/discussion/index.js +4 -1
  66. package/dist/discussion/ports.d.ts +288 -27
  67. package/dist/discussion/ports.js +6 -1
  68. package/dist/discussion/ports.js.map +1 -0
  69. package/dist/discussion/posts.d.ts +103 -0
  70. package/dist/discussion/posts.js +723 -0
  71. package/dist/discussion/posts.js.map +1 -0
  72. package/dist/discussion/service.d.ts +32 -10
  73. package/dist/discussion/service.js +293 -78
  74. package/dist/discussion/service.js.map +1 -1
  75. package/dist/entitlements/events.d.ts +178 -11
  76. package/dist/entitlements/events.js +28 -1
  77. package/dist/entitlements/events.js.map +1 -1
  78. package/dist/entitlements/index.d.ts +5 -4
  79. package/dist/entitlements/index.js +2 -1
  80. package/dist/entitlements/model.d.ts +3 -2
  81. package/dist/entitlements/ports.d.ts +124 -11
  82. package/dist/entitlements/rules.d.ts +12 -0
  83. package/dist/entitlements/rules.js +17 -0
  84. package/dist/entitlements/rules.js.map +1 -0
  85. package/dist/entitlements/service.d.ts +54 -3
  86. package/dist/entitlements/service.js +472 -2
  87. package/dist/entitlements/service.js.map +1 -1
  88. package/dist/identity/access.d.ts +6 -0
  89. package/dist/identity/access.js +7 -0
  90. package/dist/identity/access.js.map +1 -0
  91. package/dist/identity/index.d.ts +6 -4
  92. package/dist/identity/index.js +3 -1
  93. package/dist/identity/model.d.ts +2 -1
  94. package/dist/identity/notifications.d.ts +27 -0
  95. package/dist/identity/notifications.js +101 -0
  96. package/dist/identity/notifications.js.map +1 -0
  97. package/dist/identity/ports.d.ts +73 -3
  98. package/dist/identity/service.d.ts +14 -3
  99. package/dist/identity/service.js +62 -5
  100. package/dist/identity/service.js.map +1 -1
  101. package/dist/integrations/model.js +1 -1
  102. package/dist/integrations/model.js.map +1 -1
  103. package/dist/integrations/service.js +2 -2
  104. package/dist/integrations/service.js.map +1 -1
  105. package/dist/organizations/access-scopes.d.ts +19 -0
  106. package/dist/organizations/access-scopes.js +89 -0
  107. package/dist/organizations/access-scopes.js.map +1 -0
  108. package/dist/organizations/events.d.ts +74 -32
  109. package/dist/organizations/events.js +6 -0
  110. package/dist/organizations/events.js.map +1 -1
  111. package/dist/organizations/index.d.ts +7 -6
  112. package/dist/organizations/index.js +4 -3
  113. package/dist/organizations/members.d.ts +8 -5
  114. package/dist/organizations/members.js.map +1 -1
  115. package/dist/organizations/ports.d.ts +14 -11
  116. package/dist/organizations/roles.d.ts +6 -10
  117. package/dist/organizations/roles.js +19 -7
  118. package/dist/organizations/roles.js.map +1 -1
  119. package/dist/organizations/service.d.ts +20 -11
  120. package/dist/organizations/service.js +157 -47
  121. package/dist/organizations/service.js.map +1 -1
  122. package/dist/organizations/types.d.ts +1 -10
  123. package/dist/progress/index.d.ts +2 -2
  124. package/dist/progress/ports.d.ts +6 -1
  125. package/dist/progress/service.d.ts +3 -1
  126. package/dist/progress/service.js +6 -2
  127. package/dist/progress/service.js.map +1 -1
  128. package/dist/reporting/admin/index.d.ts +4 -0
  129. package/dist/reporting/admin/index.js +2 -0
  130. package/dist/reporting/admin/model.d.ts +108 -0
  131. package/dist/reporting/admin/ports.d.ts +27 -0
  132. package/dist/reporting/admin/service.d.ts +22 -0
  133. package/dist/reporting/admin/service.js +38 -0
  134. package/dist/reporting/admin/service.js.map +1 -0
  135. package/dist/reporting/member/index.d.ts +5 -0
  136. package/dist/reporting/member/index.js +2 -0
  137. package/dist/reporting/member/model.d.ts +124 -0
  138. package/dist/reporting/member/ports.d.ts +45 -0
  139. package/dist/reporting/member/service.d.ts +73 -0
  140. package/dist/reporting/member/service.js +286 -0
  141. package/dist/reporting/member/service.js.map +1 -0
  142. package/dist/shared/actor.d.ts +9 -0
  143. package/dist/shared/errors.d.ts +7 -1
  144. package/dist/shared/errors.js +10 -1
  145. package/dist/shared/errors.js.map +1 -1
  146. package/dist/shared/id.d.ts +11 -0
  147. package/dist/shared/id.js +12 -1
  148. package/dist/shared/id.js.map +1 -1
  149. package/dist/shared/mailer.d.ts +4 -1
  150. package/dist/shared/mailer.js.map +1 -1
  151. package/dist/shared/network.d.ts +10 -0
  152. package/dist/shared/network.js +211 -0
  153. package/dist/shared/network.js.map +1 -0
  154. package/dist/types/assets.d.ts +2 -2
  155. package/dist/types/automations.d.ts +10 -2
  156. package/dist/types/content.d.ts +2 -2
  157. package/dist/types/discussion.d.ts +11 -3
  158. package/dist/types/email-templates.d.ts +121 -0
  159. package/dist/types/entitlements.d.ts +2 -2
  160. package/dist/types/identity.d.ts +48 -2
  161. package/dist/types/index.d.ts +9 -9
  162. package/dist/types/ports.d.ts +6 -0
  163. package/dist/types/schemas/assets.d.ts +65 -37
  164. package/dist/types/schemas/assets.js +17 -12
  165. package/dist/types/schemas/assets.js.map +1 -1
  166. package/dist/types/schemas/automations.d.ts +18 -1
  167. package/dist/types/schemas/automations.js +15 -6
  168. package/dist/types/schemas/automations.js.map +1 -1
  169. package/dist/types/schemas/content.d.ts +335 -3
  170. package/dist/types/schemas/content.js +139 -3
  171. package/dist/types/schemas/content.js.map +1 -1
  172. package/dist/types/schemas/discussion.d.ts +370 -3
  173. package/dist/types/schemas/discussion.js +199 -4
  174. package/dist/types/schemas/discussion.js.map +1 -1
  175. package/dist/types/schemas/entitlements.d.ts +36 -2
  176. package/dist/types/schemas/entitlements.js +23 -1
  177. package/dist/types/schemas/entitlements.js.map +1 -1
  178. package/dist/types/schemas/identity.d.ts +111 -1
  179. package/dist/types/schemas/identity.js +55 -2
  180. package/dist/types/schemas/identity.js.map +1 -1
  181. package/dist/types/schemas/index.d.ts +8 -8
  182. package/dist/types/schemas/index.js +8 -8
  183. package/dist/types/schemas/organizations.d.ts +8 -0
  184. package/dist/types/schemas/organizations.js +2 -0
  185. package/dist/types/schemas/organizations.js.map +1 -1
  186. package/dist/types/schemas/shared.d.ts +3 -1
  187. package/dist/types/schemas/shared.js +5 -1
  188. package/dist/types/schemas/shared.js.map +1 -1
  189. package/package.json +2 -2
  190. package/dist/reporting/courses/index.d.ts +0 -4
  191. package/dist/reporting/courses/index.js +0 -2
  192. package/dist/reporting/courses/model.d.ts +0 -24
  193. package/dist/reporting/courses/ports.d.ts +0 -13
  194. package/dist/reporting/courses/service.d.ts +0 -19
  195. package/dist/reporting/courses/service.js +0 -20
  196. package/dist/reporting/courses/service.js.map +0 -1
  197. package/dist/reporting/dashboard/index.d.ts +0 -4
  198. package/dist/reporting/dashboard/index.js +0 -2
  199. package/dist/reporting/dashboard/model.d.ts +0 -14
  200. package/dist/reporting/dashboard/ports.d.ts +0 -13
  201. package/dist/reporting/dashboard/service.d.ts +0 -19
  202. package/dist/reporting/dashboard/service.js +0 -20
  203. package/dist/reporting/dashboard/service.js.map +0 -1
  204. package/dist/reporting/learn/index.d.ts +0 -5
  205. package/dist/reporting/learn/index.js +0 -2
  206. package/dist/reporting/learn/model.d.ts +0 -23
  207. package/dist/reporting/learn/ports.d.ts +0 -43
  208. package/dist/reporting/learn/ports.js +0 -1
  209. package/dist/reporting/learn/service.d.ts +0 -49
  210. package/dist/reporting/learn/service.js +0 -116
  211. package/dist/reporting/learn/service.js.map +0 -1
  212. package/dist/reporting/students/index.d.ts +0 -4
  213. package/dist/reporting/students/index.js +0 -2
  214. package/dist/reporting/students/model.d.ts +0 -51
  215. package/dist/reporting/students/model.js +0 -1
  216. package/dist/reporting/students/ports.d.ts +0 -15
  217. package/dist/reporting/students/ports.js +0 -1
  218. package/dist/reporting/students/service.d.ts +0 -20
  219. package/dist/reporting/students/service.js +0 -23
  220. package/dist/reporting/students/service.js.map +0 -1
  221. /package/dist/reporting/{courses → admin}/model.js +0 -0
  222. /package/dist/reporting/{courses → admin}/ports.js +0 -0
  223. /package/dist/reporting/{dashboard → member}/model.js +0 -0
  224. /package/dist/reporting/{dashboard → member}/ports.js +0 -0
  225. /package/dist/{reporting/learn/model.js → shared/actor.js} +0 -0
@@ -6,7 +6,8 @@ declare const assetEvents: {
6
6
  orgId: string;
7
7
  id: string;
8
8
  key: string;
9
- kind: "video" | "download" | "content";
9
+ kind: "image" | "video" | "audio" | "document";
10
+ source: "library" | "member";
10
11
  filename: string;
11
12
  contentType: string;
12
13
  size: number;
@@ -18,7 +19,8 @@ declare const assetEvents: {
18
19
  orgId: string;
19
20
  id: string;
20
21
  key: string;
21
- kind: "video" | "download" | "content";
22
+ kind: "image" | "video" | "audio" | "document";
23
+ source: "library" | "member";
22
24
  filename: string;
23
25
  contentType: string;
24
26
  size: number;
@@ -30,27 +32,32 @@ declare const assetEvents: {
30
32
  orgId: import("zod").ZodString;
31
33
  id: import("zod").ZodString;
32
34
  kind: import("zod").ZodEnum<{
35
+ image: "image";
33
36
  video: "video";
34
- download: "download";
35
- content: "content";
37
+ audio: "audio";
38
+ document: "document";
39
+ }>;
40
+ source: import("zod").ZodEnum<{
41
+ library: "library";
42
+ member: "member";
36
43
  }>;
37
- createdAt: import("zod").ZodCoercedDate<unknown>;
38
- updatedAt: import("zod").ZodCoercedDate<unknown>;
39
44
  status: import("zod").ZodEnum<{
40
45
  pending: "pending";
41
46
  ready: "ready";
42
47
  }>;
43
48
  uploadedBy: import("zod").ZodString;
44
- key: import("zod").ZodString;
45
49
  filename: import("zod").ZodString;
46
50
  contentType: import("zod").ZodString;
47
51
  size: import("zod").ZodNumber;
52
+ createdAt: import("zod").ZodCoercedDate<unknown>;
53
+ updatedAt: import("zod").ZodCoercedDate<unknown>;
48
54
  }, import("zod/v4/core").$strip>>;
49
55
  assetReady: RuntimeEventDefinition<VersionedDomainEvent<{
50
56
  orgId: string;
51
57
  id: string;
52
58
  key: string;
53
- kind: "video" | "download" | "content";
59
+ kind: "image" | "video" | "audio" | "document";
60
+ source: "library" | "member";
54
61
  filename: string;
55
62
  contentType: string;
56
63
  size: number;
@@ -62,7 +69,8 @@ declare const assetEvents: {
62
69
  orgId: string;
63
70
  id: string;
64
71
  key: string;
65
- kind: "video" | "download" | "content";
72
+ kind: "image" | "video" | "audio" | "document";
73
+ source: "library" | "member";
66
74
  filename: string;
67
75
  contentType: string;
68
76
  size: number;
@@ -74,27 +82,32 @@ declare const assetEvents: {
74
82
  orgId: import("zod").ZodString;
75
83
  id: import("zod").ZodString;
76
84
  kind: import("zod").ZodEnum<{
85
+ image: "image";
77
86
  video: "video";
78
- download: "download";
79
- content: "content";
87
+ audio: "audio";
88
+ document: "document";
89
+ }>;
90
+ source: import("zod").ZodEnum<{
91
+ library: "library";
92
+ member: "member";
80
93
  }>;
81
- createdAt: import("zod").ZodCoercedDate<unknown>;
82
- updatedAt: import("zod").ZodCoercedDate<unknown>;
83
94
  status: import("zod").ZodEnum<{
84
95
  pending: "pending";
85
96
  ready: "ready";
86
97
  }>;
87
98
  uploadedBy: import("zod").ZodString;
88
- key: import("zod").ZodString;
89
99
  filename: import("zod").ZodString;
90
100
  contentType: import("zod").ZodString;
91
101
  size: import("zod").ZodNumber;
102
+ createdAt: import("zod").ZodCoercedDate<unknown>;
103
+ updatedAt: import("zod").ZodCoercedDate<unknown>;
92
104
  }, import("zod/v4/core").$strip>>;
93
105
  assetDeleted: RuntimeEventDefinition<VersionedDomainEvent<{
94
106
  orgId: string;
95
107
  id: string;
96
108
  key: string;
97
- kind: "video" | "download" | "content";
109
+ kind: "image" | "video" | "audio" | "document";
110
+ source: "library" | "member";
98
111
  filename: string;
99
112
  contentType: string;
100
113
  size: number;
@@ -106,7 +119,8 @@ declare const assetEvents: {
106
119
  orgId: string;
107
120
  id: string;
108
121
  key: string;
109
- kind: "video" | "download" | "content";
122
+ kind: "image" | "video" | "audio" | "document";
123
+ source: "library" | "member";
110
124
  filename: string;
111
125
  contentType: string;
112
126
  size: number;
@@ -118,21 +132,25 @@ declare const assetEvents: {
118
132
  orgId: import("zod").ZodString;
119
133
  id: import("zod").ZodString;
120
134
  kind: import("zod").ZodEnum<{
135
+ image: "image";
121
136
  video: "video";
122
- download: "download";
123
- content: "content";
137
+ audio: "audio";
138
+ document: "document";
139
+ }>;
140
+ source: import("zod").ZodEnum<{
141
+ library: "library";
142
+ member: "member";
124
143
  }>;
125
- createdAt: import("zod").ZodCoercedDate<unknown>;
126
- updatedAt: import("zod").ZodCoercedDate<unknown>;
127
144
  status: import("zod").ZodEnum<{
128
145
  pending: "pending";
129
146
  ready: "ready";
130
147
  }>;
131
148
  uploadedBy: import("zod").ZodString;
132
- key: import("zod").ZodString;
133
149
  filename: import("zod").ZodString;
134
150
  contentType: import("zod").ZodString;
135
151
  size: import("zod").ZodNumber;
152
+ createdAt: import("zod").ZodCoercedDate<unknown>;
153
+ updatedAt: import("zod").ZodCoercedDate<unknown>;
136
154
  }, import("zod/v4/core").$strip>>;
137
155
  };
138
156
  type AssetCreated = EventOf<typeof assetEvents.assetCreated>;
@@ -4,8 +4,8 @@ import { defineEvent } from "../shared/events.js";
4
4
  const publicAsset = assetSchema.pick({
5
5
  orgId: true,
6
6
  id: true,
7
- key: true,
8
7
  kind: true,
8
+ source: true,
9
9
  filename: true,
10
10
  contentType: true,
11
11
  size: true,
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","names":[],"sources":["../../src/assets/events.ts"],"sourcesContent":["import { assetSchema } from '../types/schemas/index.js';\nimport { defineEvent, type EventOf, type EventOfValues } from '../shared/ports.js';\n\nconst publicAsset = assetSchema\n .pick({\n orgId: true,\n id: true,\n key: true,\n kind: true,\n filename: true,\n contentType: true,\n size: true,\n status: true,\n uploadedBy: true,\n createdAt: true,\n updatedAt: true,\n })\n .strip();\n\nexport const assetEvents = {\n assetCreated: defineEvent({\n type: 'asset.created',\n version: 1,\n data: assetSchema,\n publicData: publicAsset,\n }),\n assetReady: defineEvent({\n type: 'asset.ready',\n version: 1,\n data: assetSchema,\n publicData: publicAsset,\n }),\n assetDeleted: defineEvent({\n type: 'asset.deleted',\n version: 1,\n data: assetSchema,\n publicData: publicAsset,\n }),\n};\n\nexport type AssetCreated = EventOf<typeof assetEvents.assetCreated>;\nexport type AssetReady = EventOf<typeof assetEvents.assetReady>;\nexport type AssetDeleted = EventOf<typeof assetEvents.assetDeleted>;\nexport type AssetEvent = EventOfValues<typeof assetEvents>;\n"],"mappings":";;;AAGA,MAAM,cAAc,YACjB,KAAK;CACJ,OAAO;CACP,IAAI;CACJ,KAAK;CACL,MAAM;CACN,UAAU;CACV,aAAa;CACb,MAAM;CACN,QAAQ;CACR,YAAY;CACZ,WAAW;CACX,WAAW;AACb,CAAC,CAAC,CACD,MAAM;AAET,MAAa,cAAc;CACzB,cAAc,YAAY;EACxB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,YAAY,YAAY;EACtB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,cAAc,YAAY;EACxB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;AACH"}
1
+ {"version":3,"file":"events.js","names":[],"sources":["../../src/assets/events.ts"],"sourcesContent":["import { assetSchema } from '../types/schemas/index.js';\nimport { defineEvent, type EventOf, type EventOfValues } from '../shared/ports.js';\n\nconst publicAsset = assetSchema\n .pick({\n orgId: true,\n id: true,\n kind: true,\n source: true,\n filename: true,\n contentType: true,\n size: true,\n status: true,\n uploadedBy: true,\n createdAt: true,\n updatedAt: true,\n })\n .strip();\n\nexport const assetEvents = {\n assetCreated: defineEvent({\n type: 'asset.created',\n version: 1,\n data: assetSchema,\n publicData: publicAsset,\n }),\n assetReady: defineEvent({\n type: 'asset.ready',\n version: 1,\n data: assetSchema,\n publicData: publicAsset,\n }),\n assetDeleted: defineEvent({\n type: 'asset.deleted',\n version: 1,\n data: assetSchema,\n publicData: publicAsset,\n }),\n};\n\nexport type AssetCreated = EventOf<typeof assetEvents.assetCreated>;\nexport type AssetReady = EventOf<typeof assetEvents.assetReady>;\nexport type AssetDeleted = EventOf<typeof assetEvents.assetDeleted>;\nexport type AssetEvent = EventOfValues<typeof assetEvents>;\n"],"mappings":";;;AAGA,MAAM,cAAc,YACjB,KAAK;CACJ,OAAO;CACP,IAAI;CACJ,MAAM;CACN,QAAQ;CACR,UAAU;CACV,aAAa;CACb,MAAM;CACN,QAAQ;CACR,YAAY;CACZ,WAAW;CACX,WAAW;AACb,CAAC,CAAC,CACD,MAAM;AAET,MAAa,cAAc;CACzB,cAAc,YAAY;EACxB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,YAAY,YAAY;EACtB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;CACD,cAAc,YAAY;EACxB,MAAM;EACN,SAAS;EACT,MAAM;EACN,YAAY;CACd,CAAC;AACH"}
@@ -0,0 +1,20 @@
1
+ //#region src/assets/file-urls.d.ts
2
+ type ThumbnailOwner = 'course' | 'download' | 'community';
3
+ /** Stable, access-checked URLs on the API for every file a response refers to.
4
+ * Each one is answered by a route that checks access, then redirects to a
5
+ * signed storage URL; none of them expires. */
6
+ interface FileUrls {
7
+ thumbnail(owner: ThumbnailOwner, ownerId: string): string;
8
+ activityAsset(activityId: string, assetId: string): string;
9
+ downloadFile(downloadId: string, assetId: string): string;
10
+ postCover(postId: string): string;
11
+ messageAttachment(chatId: string, messageId: string, assetId: string): string;
12
+ personImage(orgUserId: string): string;
13
+ memberUpload(assetId: string): string;
14
+ libraryFile(assetId: string): string;
15
+ libraryDownload(assetId: string): string;
16
+ }
17
+ declare function createFileUrls(apiUrl: string): FileUrls;
18
+ //#endregion
19
+ export { FileUrls, ThumbnailOwner, createFileUrls };
20
+ //# sourceMappingURL=file-urls.d.ts.map
@@ -0,0 +1,25 @@
1
+ //#region src/assets/file-urls.ts
2
+ const THUMBNAIL_PATHS = {
3
+ course: "courses",
4
+ download: "downloads",
5
+ community: "communities"
6
+ };
7
+ function createFileUrls(apiUrl) {
8
+ const base = apiUrl.replace(/\/+$/, "");
9
+ const at = (...segments) => `${base}/api/${segments.map((s) => encodeURIComponent(s)).join("/")}`;
10
+ return {
11
+ thumbnail: (owner, ownerId) => at("member", THUMBNAIL_PATHS[owner], ownerId, "thumbnail"),
12
+ activityAsset: (activityId, assetId) => at("member", "activities", activityId, "assets", assetId),
13
+ downloadFile: (downloadId, assetId) => at("member", "downloads", downloadId, "assets", assetId),
14
+ postCover: (postId) => at("member", "posts", postId, "cover"),
15
+ messageAttachment: (chatId, messageId, assetId) => at("member", "chats", chatId, "messages", messageId, "attachments", assetId),
16
+ personImage: (orgUserId) => at("member", "people", orgUserId, "image"),
17
+ memberUpload: (assetId) => at("member", "uploads", assetId, "file"),
18
+ libraryFile: (assetId) => at("assets", assetId, "file"),
19
+ libraryDownload: (assetId) => at("assets", assetId, "download")
20
+ };
21
+ }
22
+ //#endregion
23
+ export { createFileUrls };
24
+
25
+ //# sourceMappingURL=file-urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-urls.js","names":[],"sources":["../../src/assets/file-urls.ts"],"sourcesContent":["export type ThumbnailOwner = 'course' | 'download' | 'community';\n\n/** Stable, access-checked URLs on the API for every file a response refers to.\n * Each one is answered by a route that checks access, then redirects to a\n * signed storage URL; none of them expires. */\nexport interface FileUrls {\n thumbnail(owner: ThumbnailOwner, ownerId: string): string;\n activityAsset(activityId: string, assetId: string): string;\n downloadFile(downloadId: string, assetId: string): string;\n postCover(postId: string): string;\n messageAttachment(chatId: string, messageId: string, assetId: string): string;\n personImage(orgUserId: string): string;\n memberUpload(assetId: string): string;\n libraryFile(assetId: string): string;\n libraryDownload(assetId: string): string;\n}\n\nconst THUMBNAIL_PATHS: Record<ThumbnailOwner, string> = {\n course: 'courses',\n download: 'downloads',\n community: 'communities',\n};\n\nexport function createFileUrls(apiUrl: string): FileUrls {\n const base = apiUrl.replace(/\\/+$/, '');\n const at = (...segments: string[]) =>\n `${base}/api/${segments.map((s) => encodeURIComponent(s)).join('/')}`;\n return {\n thumbnail: (owner, ownerId) => at('member', THUMBNAIL_PATHS[owner], ownerId, 'thumbnail'),\n activityAsset: (activityId, assetId) =>\n at('member', 'activities', activityId, 'assets', assetId),\n downloadFile: (downloadId, assetId) => at('member', 'downloads', downloadId, 'assets', assetId),\n postCover: (postId) => at('member', 'posts', postId, 'cover'),\n messageAttachment: (chatId, messageId, assetId) =>\n at('member', 'chats', chatId, 'messages', messageId, 'attachments', assetId),\n personImage: (orgUserId) => at('member', 'people', orgUserId, 'image'),\n memberUpload: (assetId) => at('member', 'uploads', assetId, 'file'),\n libraryFile: (assetId) => at('assets', assetId, 'file'),\n libraryDownload: (assetId) => at('assets', assetId, 'download'),\n };\n}\n"],"mappings":";AAiBA,MAAM,kBAAkD;CACtD,QAAQ;CACR,UAAU;CACV,WAAW;AACb;AAEA,SAAgB,eAAe,QAA0B;CACvD,MAAM,OAAO,OAAO,QAAQ,QAAQ,EAAE;CACtC,MAAM,MAAM,GAAG,aACb,GAAG,KAAK,OAAO,SAAS,KAAK,MAAM,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG;CACpE,OAAO;EACL,YAAY,OAAO,YAAY,GAAG,UAAU,gBAAgB,QAAQ,SAAS,WAAW;EACxF,gBAAgB,YAAY,YAC1B,GAAG,UAAU,cAAc,YAAY,UAAU,OAAO;EAC1D,eAAe,YAAY,YAAY,GAAG,UAAU,aAAa,YAAY,UAAU,OAAO;EAC9F,YAAY,WAAW,GAAG,UAAU,SAAS,QAAQ,OAAO;EAC5D,oBAAoB,QAAQ,WAAW,YACrC,GAAG,UAAU,SAAS,QAAQ,YAAY,WAAW,eAAe,OAAO;EAC7E,cAAc,cAAc,GAAG,UAAU,UAAU,WAAW,OAAO;EACrE,eAAe,YAAY,GAAG,UAAU,WAAW,SAAS,MAAM;EAClE,cAAc,YAAY,GAAG,UAAU,SAAS,MAAM;EACtD,kBAAkB,YAAY,GAAG,UAAU,SAAS,UAAU;CAChE;AACF"}
@@ -1,7 +1,8 @@
1
1
  import { Page } from "../types/shared.js";
2
- import { Asset, AssetKind, AssetStatus, AssetsQuery, DownloadTicket, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
2
+ import { Asset, AssetKind, AssetSource, AssetStatus, AssetUrls, AssetView, AssetsQuery, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
3
3
  import { AssetCreated, AssetDeleted, AssetEvent, AssetReady, assetEvents } from "./events.js";
4
+ import { FileUrls, ThumbnailOwner, createFileUrls } from "./file-urls.js";
4
5
  import "./model.js";
5
- import { AssetsRepository, AssetsService } from "./ports.js";
6
- import { AssetsServiceImpl } from "./service.js";
7
- export { type Asset, type AssetCreated, type AssetDeleted, type AssetEvent, type AssetKind, type AssetReady, type AssetStatus, type AssetsQuery, type AssetsRepository, type AssetsService, AssetsServiceImpl, type DownloadTicket, type Page, type RequestUploadInput, type UploadTicket, assetEvents };
6
+ import { AssetFiles, AssetsRepository, AssetsService, LibraryAssetReader, MemberImageReader, MemberUploadInput, ReadyFile } from "./ports.js";
7
+ import { AssetsServiceImpl, MEMBER_IMAGE_TYPE, isMemberImageType, kindOf } from "./service.js";
8
+ export { type Asset, type AssetCreated, type AssetDeleted, type AssetEvent, type AssetFiles, type AssetKind, type AssetReady, type AssetSource, type AssetStatus, type AssetUrls, type AssetView, type AssetsQuery, type AssetsRepository, type AssetsService, AssetsServiceImpl, type FileUrls, type LibraryAssetReader, MEMBER_IMAGE_TYPE, type MemberImageReader, type MemberUploadInput, type Page, type ReadyFile, type RequestUploadInput, type ThumbnailOwner, type UploadTicket, assetEvents, createFileUrls, isMemberImageType, kindOf };
@@ -1,3 +1,4 @@
1
1
  import { assetEvents } from "./events.js";
2
- import { AssetsServiceImpl } from "./service.js";
3
- export { AssetsServiceImpl, assetEvents };
2
+ import { createFileUrls } from "./file-urls.js";
3
+ import { AssetsServiceImpl, MEMBER_IMAGE_TYPE, isMemberImageType, kindOf } from "./service.js";
4
+ export { AssetsServiceImpl, MEMBER_IMAGE_TYPE, assetEvents, createFileUrls, isMemberImageType, kindOf };
@@ -1,4 +1,4 @@
1
1
  import { Page } from "../types/shared.js";
2
- import { Asset, AssetKind, AssetStatus, AssetsQuery, DownloadTicket, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
2
+ import { Asset, AssetKind, AssetSource, AssetStatus, AssetUrls, AssetView, AssetsQuery, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
3
3
  import "../types/index.js";
4
- export type { Asset, AssetKind, AssetStatus, AssetsQuery, DownloadTicket, Page, RequestUploadInput, UploadTicket };
4
+ export type { Asset, AssetKind, AssetSource, AssetStatus, AssetUrls, AssetView, AssetsQuery, Page, RequestUploadInput, UploadTicket };
@@ -1,28 +1,58 @@
1
1
  import { Page } from "../types/shared.js";
2
- import { Asset, AssetsQuery, DownloadTicket, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
2
+ import { Asset, AssetView, AssetsQuery, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
3
3
  import { OutboxAppender, UnitOfWork } from "../shared/ports.js";
4
4
  import "./model.js";
5
5
  //#region src/assets/ports.d.ts
6
- interface AssetsService {
7
- /** Register an asset and return a presigned URL to upload its bytes. */
6
+ interface MemberImageReader {
7
+ ownsImage(orgId: string, assetId: string, orgUserId: string): Promise<boolean>;
8
+ }
9
+ interface LibraryAssetReader {
10
+ libraryAssetsAmong(orgId: string, assetIds: string[]): Promise<string[]>;
11
+ }
12
+ interface ReadyFile {
13
+ filename: string;
14
+ contentType: string;
15
+ size: number;
16
+ }
17
+ interface AssetFiles {
18
+ /** Ready files of the org among these ids, with what a download shows of them. */
19
+ readyFiles(orgId: string, assetIds: readonly string[]): Promise<Record<string, ReadyFile>>;
20
+ /** A signed storage URL for a ready file of the org, after the caller has checked
21
+ * access. `saveAs` makes it a short-lived download under that name. */
22
+ signFile(orgId: string, assetId: string, opts?: {
23
+ saveAs?: string;
24
+ }): Promise<string | null>;
25
+ }
26
+ interface MemberUploadInput {
27
+ filename: string;
28
+ contentType: string;
29
+ }
30
+ interface AssetsService extends MemberImageReader, LibraryAssetReader, AssetFiles {
8
31
  requestUpload(orgId: string, input: RequestUploadInput): Promise<UploadTicket>;
9
- /** After upload, capture size/content-type from storage and mark ready. */
10
- confirm(orgId: string, id: string): Promise<Asset | null>;
11
- list(orgId: string, query: AssetsQuery): Promise<Page<Asset>>;
12
- get(orgId: string, id: string): Promise<Asset | null>;
13
- /** Short-lived presigned URL to download/serve the asset. `expiresInSeconds`
14
- * overrides the adapter default — entitled delivery passes its own. */
15
- requestDownload(orgId: string, id: string, filename?: string, expiresInSeconds?: number): Promise<DownloadTicket | null>;
16
- /** Remove the object from storage and the registry. */
32
+ requestMemberUpload(orgId: string, orgUserId: string, input: MemberUploadInput): Promise<UploadTicket>;
33
+ confirm(orgId: string, id: string): Promise<AssetView | null>;
34
+ confirmOwn(orgId: string, id: string, orgUserId: string): Promise<AssetView | null>;
35
+ list(orgId: string, query: AssetsQuery): Promise<Page<AssetView>>;
36
+ get(orgId: string, id: string): Promise<AssetView | null>;
37
+ libraryFile(orgId: string, assetId: string, opts: {
38
+ download: boolean;
39
+ }): Promise<string | null>;
40
+ ownUploadFile(orgId: string, assetId: string, orgUserId: string): Promise<string | null>;
17
41
  remove(orgId: string, id: string): Promise<boolean>;
42
+ removeOwn(orgId: string, id: string, orgUserId: string): Promise<boolean>;
43
+ hasUnattached(orgId: string, now: Date): Promise<boolean>;
44
+ removeUnattached(orgId: string, now: Date): Promise<number>;
18
45
  }
19
46
  interface AssetsRepository {
20
47
  insert(orgId: string, asset: Asset): Promise<Asset>;
21
48
  list(orgId: string, query: AssetsQuery): Promise<Page<Asset>>;
22
- /** Scoped to the org — returns null if the asset belongs to another org. */
23
49
  findById(orgId: string, id: string): Promise<Asset | null>;
24
- update(id: string, patch: Partial<Pick<Asset, 'size' | 'contentType' | 'status'>>): Promise<Asset | null>;
25
- delete(id: string): Promise<boolean>;
50
+ findByIds(orgId: string, ids: string[]): Promise<Asset[]>;
51
+ markReady(orgId: string, id: string, patch: Pick<Asset, 'key' | 'kind' | 'size' | 'contentType'>): Promise<Asset | null>;
52
+ delete(orgId: string, id: string): Promise<boolean>;
53
+ hasUnreferencedMemberUploads(orgId: string, before: Date): Promise<boolean>;
54
+ listUnreferencedMemberUploads(orgId: string, before: Date): Promise<Asset[]>;
55
+ heldKeys(orgId: string, keys: string[]): Promise<string[]>;
26
56
  }
27
57
  interface AssetsWriteScope {
28
58
  assets: AssetsRepository;
@@ -30,5 +60,5 @@ interface AssetsWriteScope {
30
60
  }
31
61
  type AssetsUnitOfWork = UnitOfWork<AssetsWriteScope>;
32
62
  //#endregion
33
- export { AssetsRepository, AssetsService, AssetsUnitOfWork, AssetsWriteScope };
63
+ export { AssetFiles, AssetsRepository, AssetsService, AssetsUnitOfWork, AssetsWriteScope, LibraryAssetReader, MemberImageReader, MemberUploadInput, ReadyFile };
34
64
  //# sourceMappingURL=ports.d.ts.map
@@ -1,29 +1,61 @@
1
1
  import { Page } from "../types/shared.js";
2
2
  import { Logger, ObjectStorage } from "../types/ports.js";
3
- import { Asset, AssetsQuery, DownloadTicket, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
3
+ import { AssetKind, AssetView, AssetsQuery, RequestUploadInput, UploadTicket } from "../types/schemas/assets.js";
4
4
  import "../shared/ports.js";
5
+ import { FileUrls } from "./file-urls.js";
5
6
  import "./model.js";
6
- import { AssetsRepository, AssetsService, AssetsUnitOfWork } from "./ports.js";
7
+ import { AssetsRepository, AssetsService, AssetsUnitOfWork, MemberUploadInput, ReadyFile } from "./ports.js";
7
8
  //#region src/assets/service.d.ts
9
+ declare const MEMBER_IMAGE_TYPE: RegExp;
10
+ declare function isMemberImageType(contentType: string): boolean;
11
+ declare function kindOf(contentType: string): AssetKind;
8
12
  type AssetsServiceParams = {
9
13
  storage: ObjectStorage;
10
14
  repo: AssetsRepository;
11
15
  uow: AssetsUnitOfWork;
16
+ memberImageMaxBytes: number;
17
+ downloadLinkExpirySeconds: number;
18
+ fileUrls: FileUrls;
12
19
  logger?: Logger;
13
20
  };
14
21
  declare class AssetsServiceImpl implements AssetsService {
15
22
  private readonly storage;
16
23
  private readonly repo;
17
24
  private readonly uow;
25
+ private readonly memberImageMaxBytes;
26
+ private readonly downloadLinkExpirySeconds;
27
+ private readonly fileUrls;
18
28
  private readonly logger;
19
29
  constructor(params: AssetsServiceParams);
20
30
  requestUpload(orgId: string, input: RequestUploadInput): Promise<UploadTicket>;
21
- confirm(orgId: string, id: string): Promise<Asset | null>;
22
- list(orgId: string, query: AssetsQuery): Promise<Page<Asset>>;
23
- get(orgId: string, id: string): Promise<Asset | null>;
24
- requestDownload(orgId: string, id: string, filename?: string, expiresInSeconds?: number): Promise<DownloadTicket | null>;
31
+ requestMemberUpload(orgId: string, orgUserId: string, input: MemberUploadInput): Promise<UploadTicket>;
32
+ confirm(orgId: string, id: string): Promise<AssetView | null>;
33
+ confirmOwn(orgId: string, id: string, orgUserId: string): Promise<AssetView | null>;
34
+ ownUploadFile(orgId: string, assetId: string, orgUserId: string): Promise<string | null>;
35
+ ownsImage(orgId: string, assetId: string, orgUserId: string): Promise<boolean>;
36
+ libraryAssetsAmong(orgId: string, assetIds: string[]): Promise<string[]>;
37
+ list(orgId: string, query: AssetsQuery): Promise<Page<AssetView>>;
38
+ get(orgId: string, id: string): Promise<AssetView | null>;
39
+ readyFiles(orgId: string, assetIds: readonly string[]): Promise<Record<string, ReadyFile>>;
40
+ signFile(orgId: string, assetId: string, opts?: {
41
+ saveAs?: string;
42
+ }): Promise<string | null>;
43
+ libraryFile(orgId: string, assetId: string, opts: {
44
+ download: boolean;
45
+ }): Promise<string | null>;
25
46
  remove(orgId: string, id: string): Promise<boolean>;
47
+ removeOwn(orgId: string, id: string, orgUserId: string): Promise<boolean>;
48
+ hasUnattached(orgId: string, now: Date): Promise<boolean>;
49
+ removeUnattached(orgId: string, now: Date): Promise<number>;
50
+ private strayUploads;
51
+ private finalize;
52
+ private finalizeMember;
53
+ private markReady;
54
+ private readyAmong;
55
+ private view;
56
+ private discard;
57
+ private removeObject;
26
58
  }
27
59
  //#endregion
28
- export { AssetsServiceImpl, AssetsServiceParams };
60
+ export { AssetsServiceImpl, AssetsServiceParams, MEMBER_IMAGE_TYPE, isMemberImageType, kindOf };
29
61
  //# sourceMappingURL=service.d.ts.map