@uptime.app/contracts 3.0.54 → 3.0.55

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 (239) hide show
  1. package/dist/cjs/draft-hack-generation/draft-hack-generation-events.d.ts +3 -0
  2. package/dist/cjs/draft-hack-generation/draft-hack-generation-events.d.ts.map +1 -1
  3. package/dist/cjs/hack-mapping/access-helper.js +1 -2
  4. package/dist/cjs/hack-mapping/access-helper.js.map +1 -1
  5. package/dist/cjs/hack-mapping/app-full-hack.js +1 -2
  6. package/dist/cjs/hack-mapping/app-full-hack.js.map +1 -1
  7. package/dist/cjs/hack-mapping/app-hack-metadata.js +1 -2
  8. package/dist/cjs/hack-mapping/app-hack-metadata.js.map +1 -1
  9. package/dist/cjs/hack-mapping/app-restricted-hack.js +1 -2
  10. package/dist/cjs/hack-mapping/app-restricted-hack.js.map +1 -1
  11. package/dist/cjs/hack-mapping/remove-undefined-fields.js +1 -2
  12. package/dist/cjs/hack-mapping/remove-undefined-fields.js.map +1 -1
  13. package/dist/cjs/hackbot/hack-generation-commands.d.ts +6 -9
  14. package/dist/cjs/hackbot/hack-generation-commands.d.ts.map +1 -1
  15. package/dist/cjs/hackbot/hack-generation-trigger.d.ts +6 -9
  16. package/dist/cjs/hackbot/hack-generation-trigger.d.ts.map +1 -1
  17. package/dist/cjs/hackbot/hack-generation-trigger.js.map +1 -1
  18. package/dist/cjs/hackbot/knowledge-source-location.d.ts +6 -0
  19. package/dist/cjs/hackbot/knowledge-source-location.d.ts.map +1 -0
  20. package/dist/cjs/hackbot/knowledge-source-location.js +3 -0
  21. package/dist/cjs/hackbot/knowledge-source-location.js.map +1 -0
  22. package/dist/cjs/knowledge-source-parsing/knowledge-source-metadata.d.ts +1 -0
  23. package/dist/cjs/knowledge-source-parsing/knowledge-source-metadata.d.ts.map +1 -1
  24. package/dist/cjs/knowledge-source-parsing/knowledge-source-parsing-commands.d.ts +9 -0
  25. package/dist/cjs/knowledge-source-parsing/knowledge-source-parsing-commands.d.ts.map +1 -1
  26. package/dist/cjs/knowledge-source-parsing/podcast-metadata.d.ts +1 -0
  27. package/dist/cjs/knowledge-source-parsing/podcast-metadata.d.ts.map +1 -1
  28. package/dist/cjs/knowledge-source-parsing/podcast-metadata.js.map +1 -1
  29. package/dist/cjs/localisation/live-locales.js +3 -4
  30. package/dist/cjs/localisation/live-locales.js.map +1 -1
  31. package/dist/cjs/localisation/locale-language.js +1 -2
  32. package/dist/cjs/localisation/locale-language.js.map +1 -1
  33. package/dist/cjs/localisation/supported-languages.js +2 -2
  34. package/dist/cjs/localisation/supported-languages.js.map +1 -1
  35. package/dist/cjs/localisation/supported-locales.js +3 -3
  36. package/dist/cjs/localisation/supported-locales.js.map +1 -1
  37. package/dist/cjs/service-simulator/mock-request-response.d.ts +8 -0
  38. package/dist/cjs/service-simulator/mock-request-response.d.ts.map +1 -1
  39. package/dist/cjs/text-to-speech/supported-voices.js +7 -8
  40. package/dist/cjs/text-to-speech/supported-voices.js.map +1 -1
  41. package/dist/cjs/user-acl/user-acl-utils.js +4 -4
  42. package/dist/cjs/user-acl/user-acl-utils.js.map +1 -1
  43. package/dist/esm/draft-hack-generation/draft-hack-generation-events.d.ts +3 -0
  44. package/dist/esm/draft-hack-generation/draft-hack-generation-events.d.ts.map +1 -1
  45. package/dist/esm/hackbot/hack-generation-commands.d.ts +6 -9
  46. package/dist/esm/hackbot/hack-generation-commands.d.ts.map +1 -1
  47. package/dist/esm/hackbot/hack-generation-trigger.d.ts +6 -9
  48. package/dist/esm/hackbot/hack-generation-trigger.d.ts.map +1 -1
  49. package/dist/esm/hackbot/hack-generation-trigger.js.map +1 -1
  50. package/dist/esm/hackbot/knowledge-source-location.d.ts +6 -0
  51. package/dist/esm/hackbot/knowledge-source-location.d.ts.map +1 -0
  52. package/dist/esm/hackbot/knowledge-source-location.js +2 -0
  53. package/dist/esm/hackbot/knowledge-source-location.js.map +1 -0
  54. package/dist/esm/knowledge-source-parsing/knowledge-source-metadata.d.ts +1 -0
  55. package/dist/esm/knowledge-source-parsing/knowledge-source-metadata.d.ts.map +1 -1
  56. package/dist/esm/knowledge-source-parsing/knowledge-source-parsing-commands.d.ts +9 -0
  57. package/dist/esm/knowledge-source-parsing/knowledge-source-parsing-commands.d.ts.map +1 -1
  58. package/dist/esm/knowledge-source-parsing/podcast-metadata.d.ts +1 -0
  59. package/dist/esm/knowledge-source-parsing/podcast-metadata.d.ts.map +1 -1
  60. package/dist/esm/knowledge-source-parsing/podcast-metadata.js.map +1 -1
  61. package/dist/esm/service-simulator/mock-request-response.d.ts +8 -0
  62. package/dist/esm/service-simulator/mock-request-response.d.ts.map +1 -1
  63. package/package.json +5 -2
  64. package/src/access-control/collection-access-control.ts +0 -28
  65. package/src/access-control/hack-access-control.ts +0 -32
  66. package/src/access-control/profile-access-control.ts +0 -28
  67. package/src/app-hack/app-full-hack.ts +0 -9
  68. package/src/app-hack/app-hack-metadata.ts +0 -61
  69. package/src/app-hack/app-restricted-hack.ts +0 -22
  70. package/src/b2b-content-access/b2b-content-access.ts +0 -57
  71. package/src/b2b-organisation/b2b-carousel.ts +0 -33
  72. package/src/b2b-organisation/b2b-org-idp-mapping.ts +0 -28
  73. package/src/b2b-organisation/b2b-organisation-events.ts +0 -21
  74. package/src/b2b-organisation/b2b-organisation-group-events.ts +0 -21
  75. package/src/b2b-organisation/b2b-organisation-group-membership-events.ts +0 -21
  76. package/src/b2b-organisation/b2b-organisation-group-membership.ts +0 -17
  77. package/src/b2b-organisation/b2b-organisation-group.ts +0 -43
  78. package/src/b2b-organisation/b2b-organisation-invitation.ts +0 -45
  79. package/src/b2b-organisation/b2b-organisation-member-events.ts +0 -21
  80. package/src/b2b-organisation/b2b-organisation-member.ts +0 -20
  81. package/src/b2b-organisation/b2b-organisation.ts +0 -38
  82. package/src/brand/brand-events.ts +0 -21
  83. package/src/brand/brand.ts +0 -78
  84. package/src/catalogue/catalogue.ts +0 -152
  85. package/src/cms-hack/cms-searchable-hack.ts +0 -44
  86. package/src/collection/collection-events.ts +0 -21
  87. package/src/collection/collection.ts +0 -59
  88. package/src/collection/enriched-collection-events.ts +0 -18
  89. package/src/collection/enriched-collection.ts +0 -65
  90. package/src/course/course-events.ts +0 -21
  91. package/src/course/course.ts +0 -25
  92. package/src/course-enrollment/course-enrollment-events.ts +0 -21
  93. package/src/course-enrollment/course-enrollment.ts +0 -36
  94. package/src/creator/creator-events.ts +0 -32
  95. package/src/creator/creator.ts +0 -7
  96. package/src/distribution/collection-distribution.ts +0 -17
  97. package/src/distribution/distribution-events.ts +0 -61
  98. package/src/distribution/hack-distribution.ts +0 -19
  99. package/src/draft-hack/draft-hack-events.ts +0 -21
  100. package/src/draft-hack/draft-hack.ts +0 -190
  101. package/src/draft-hack-generation/draft-hack-generation-commands.ts +0 -10
  102. package/src/draft-hack-generation/draft-hack-generation-events.ts +0 -52
  103. package/src/draft-hack-generation/draft-hack-generation.ts +0 -39
  104. package/src/enriched-b2b-organisation/enriched-b2b-organisation-events.ts +0 -21
  105. package/src/enriched-b2b-organisation/enriched-b2b-organisation.ts +0 -38
  106. package/src/enriched-hack/enriched-hack-events.ts +0 -21
  107. package/src/enriched-hack/enriched-hack.ts +0 -109
  108. package/src/enrichment-asset/hack-enrichment-video-events.ts +0 -55
  109. package/src/enrichment-asset/hack-enrichment-video.ts +0 -40
  110. package/src/entitlement/user-entitlements-commands.ts +0 -54
  111. package/src/entitlement/user-entitlements-events.ts +0 -29
  112. package/src/entitlement/user-entitlements.ts +0 -18
  113. package/src/flashcard/flashcard-events.ts +0 -85
  114. package/src/flashcard/flashcard.ts +0 -138
  115. package/src/hack/extracted-subject.ts +0 -31
  116. package/src/hack/hack-events.ts +0 -21
  117. package/src/hack/hack-published.ts +0 -21
  118. package/src/hack/hack-with-voice-events.ts +0 -21
  119. package/src/hack/hack-with-voice.ts +0 -36
  120. package/src/hack/hack.ts +0 -127
  121. package/src/hack/publish-hack-command.ts +0 -20
  122. package/src/hack/republish-hack-command.ts +0 -20
  123. package/src/hack-mapping/access-helper.ts +0 -6
  124. package/src/hack-mapping/app-full-hack.test.ts +0 -13
  125. package/src/hack-mapping/app-full-hack.ts +0 -14
  126. package/src/hack-mapping/app-hack-metadata.test.ts +0 -22
  127. package/src/hack-mapping/app-hack-metadata.ts +0 -82
  128. package/src/hack-mapping/app-restricted-hack.test.ts +0 -12
  129. package/src/hack-mapping/app-restricted-hack.ts +0 -21
  130. package/src/hack-mapping/remove-undefined-fields.ts +0 -9
  131. package/src/hack-mapping/test-data/enriched-hack.json +0 -2576
  132. package/src/hack-mapping/test-data/expected-app-full-hack.json +0 -2509
  133. package/src/hack-mapping/test-data/expected-app-hack-metadata.json +0 -93
  134. package/src/hack-mapping/test-data/expected-app-restricted-hack.json +0 -799
  135. package/src/hack-metadata/hack-metadata-events.ts +0 -21
  136. package/src/hack-metadata/hack-metadata.ts +0 -17
  137. package/src/hack-of-the-day/hack-of-the-day-events.ts +0 -21
  138. package/src/hack-of-the-day/hack-of-the-day.ts +0 -13
  139. package/src/hack-statistics/hack-statistics-events.ts +0 -21
  140. package/src/hack-statistics/hack-statistics.ts +0 -10
  141. package/src/hackbot/hack-generation-commands.ts +0 -45
  142. package/src/hackbot/hack-generation-trigger-events.ts +0 -21
  143. package/src/hackbot/hack-generation-trigger.ts +0 -57
  144. package/src/history/history-events.ts +0 -21
  145. package/src/history/history.ts +0 -46
  146. package/src/identity-provider/domain-identity-provider-events.ts +0 -21
  147. package/src/identity-provider/domain-identity-provider.ts +0 -11
  148. package/src/identity-provider/identity-provider-events.ts +0 -21
  149. package/src/identity-provider/identity-provider.ts +0 -51
  150. package/src/index.ts +0 -220
  151. package/src/interest/interest-events.ts +0 -21
  152. package/src/interest/interest.ts +0 -15
  153. package/src/knowledge-source/knowledge-source-events.ts +0 -21
  154. package/src/knowledge-source/knowledge-source.ts +0 -43
  155. package/src/knowledge-source-parsing/knowledge-source-metadata.ts +0 -58
  156. package/src/knowledge-source-parsing/knowledge-source-parsing-commands.ts +0 -41
  157. package/src/knowledge-source-parsing/knowledge-source-parsing-events.ts +0 -30
  158. package/src/knowledge-source-parsing/podcast-metadata.ts +0 -44
  159. package/src/knowledge-source-parsing/podcast-parsing-events.ts +0 -28
  160. package/src/knowledge-source-parsing/user-hack-generation-options.ts +0 -7
  161. package/src/learn-upon/get-sqsso-url.ts +0 -13
  162. package/src/learn-upon/learn-upon-commands.ts +0 -33
  163. package/src/learn-upon/learn-upon-course-enrollment-events.ts +0 -21
  164. package/src/learn-upon/learn-upon-course-enrollment.ts +0 -63
  165. package/src/learn-upon/learn-upon-course-events.ts +0 -21
  166. package/src/learn-upon/learn-upon-course.ts +0 -109
  167. package/src/learn-upon/learn-upon-portal-events.ts +0 -21
  168. package/src/learn-upon/learn-upon-portal.ts +0 -13
  169. package/src/learn-upon/learn-upon-user-mapping-events.ts +0 -19
  170. package/src/learn-upon/learn-upon-user-mapping.ts +0 -10
  171. package/src/learn-upon/learn-upon-webhook-events.ts +0 -81
  172. package/src/learn-upon/learn-upon-webhook-types.ts +0 -347
  173. package/src/learn-upon/unenroll.ts +0 -7
  174. package/src/localisation/live-locales.ts +0 -45
  175. package/src/localisation/locale-language.ts +0 -4
  176. package/src/localisation/supported-languages.ts +0 -11
  177. package/src/localisation/supported-locales.ts +0 -67
  178. package/src/message-bus/context.ts +0 -8
  179. package/src/moderation/hack-moderation-result-events.ts +0 -18
  180. package/src/moderation/hack-moderation-result.ts +0 -27
  181. package/src/partner/partner-events.ts +0 -21
  182. package/src/partner/partner.ts +0 -7
  183. package/src/pending-hack/pending-hack-events.ts +0 -21
  184. package/src/pending-hack/pending-hack-with-voice-events.ts +0 -21
  185. package/src/pending-hack/pending-hack-with-voice.ts +0 -25
  186. package/src/pending-hack/pending-hack.ts +0 -78
  187. package/src/preferences/preferences-events.ts +0 -15
  188. package/src/preferences/preferences.ts +0 -35
  189. package/src/profile/profile-events.ts +0 -41
  190. package/src/profile/profile.ts +0 -36
  191. package/src/profile/translated-profile.ts +0 -13
  192. package/src/referral/referral-events.ts +0 -41
  193. package/src/referral/referral.ts +0 -76
  194. package/src/saved/saved-collection-events.ts +0 -19
  195. package/src/saved/saved-collection.ts +0 -8
  196. package/src/segment/segment-commands.ts +0 -75
  197. package/src/segment/segment-events.ts +0 -42
  198. package/src/segment/segment-with-voice.ts +0 -8
  199. package/src/segment/segment.ts +0 -82
  200. package/src/service-simulator/mock-request-response.ts +0 -17
  201. package/src/skin/skin-events.ts +0 -21
  202. package/src/skin/skin.ts +0 -7
  203. package/src/spark/spark-board-read-model.ts +0 -17
  204. package/src/spark/spark-board.ts +0 -12
  205. package/src/spark/spark-events.ts +0 -42
  206. package/src/spark/spark.ts +0 -75
  207. package/src/text-analysis/hack-categories-extracted-events.ts +0 -24
  208. package/src/text-analysis/hack-categories-extracted.ts +0 -31
  209. package/src/text-analysis/hack-entities-extracted-events.ts +0 -24
  210. package/src/text-analysis/hack-entities-extracted.ts +0 -38
  211. package/src/text-analysis/hack-keywords-extracted-events.ts +0 -24
  212. package/src/text-analysis/hack-keywords-extracted.ts +0 -23
  213. package/src/text-analysis/hack-topics-extracted-events.ts +0 -24
  214. package/src/text-analysis/hack-topics-extracted.ts +0 -31
  215. package/src/text-to-speech/create-speech-commands.ts +0 -22
  216. package/src/text-to-speech/speech-created-events.ts +0 -10
  217. package/src/text-to-speech/supported-voices.ts +0 -222
  218. package/src/text-to-speech/text-segment.ts +0 -29
  219. package/src/theme/theme-events.ts +0 -21
  220. package/src/theme/theme.ts +0 -68
  221. package/src/translation/translation-events.ts +0 -73
  222. package/src/translation/translation.ts +0 -25
  223. package/src/trending/trending-events.ts +0 -21
  224. package/src/trending/trending-hacks.ts +0 -8
  225. package/src/user/cognito-user-authentication-log.ts +0 -8
  226. package/src/user/get-user.ts +0 -63
  227. package/src/user/user-events.ts +0 -39
  228. package/src/user-acl/user-acl-utils.test.ts +0 -273
  229. package/src/user-acl/user-acl-utils.ts +0 -177
  230. package/src/user-context/user-context-events.ts +0 -21
  231. package/src/user-context/user-context.ts +0 -16
  232. package/src/user-notification-context/user-notification-context-events.ts +0 -21
  233. package/src/user-notification-context/user-notification-context.ts +0 -10
  234. package/src/user-statistics/user-statistics-events.ts +0 -97
  235. package/src/user-statistics/user-statistics.ts +0 -82
  236. package/src/video-cropping/video-cropping-events.ts +0 -43
  237. package/src/video-cropping/video-metadata.ts +0 -12
  238. package/tsconfig.cjs.json +0 -7
  239. package/tsconfig.npm.json +0 -22
@@ -1,273 +0,0 @@
1
- import { parseAclEntry, getAclValuesByNamespace, aclFor, UserAclBuilder } from './user-acl-utils';
2
-
3
- describe('parseAclEntry', () => {
4
-
5
- test('returns null for empty string', () => {
6
- expect(parseAclEntry('')).toBeNull();
7
- });
8
-
9
- test('returns null for whitespace-only string', () => {
10
- expect(parseAclEntry(' ')).toBeNull();
11
- });
12
-
13
- test('parses a simple namespace-only entry', () => {
14
- expect(parseAclEntry('public')).toEqual({
15
- raw: 'public',
16
- excluded: false,
17
- namespace: 'public',
18
- value: null
19
- });
20
- });
21
-
22
- test('parses a namespace:value entry', () => {
23
- expect(parseAclEntry('catalogue:uptime')).toEqual({
24
- raw: 'catalogue:uptime',
25
- excluded: false,
26
- namespace: 'catalogue',
27
- value: 'uptime'
28
- });
29
- });
30
-
31
- test('parses an excluded namespace-only entry', () => {
32
- expect(parseAclEntry('!public')).toEqual({
33
- raw: '!public',
34
- excluded: true,
35
- namespace: 'public',
36
- value: null
37
- });
38
- });
39
-
40
- test('parses an excluded namespace:value entry', () => {
41
- expect(parseAclEntry('!catalogue:uptime')).toEqual({
42
- raw: '!catalogue:uptime',
43
- excluded: true,
44
- namespace: 'catalogue',
45
- value: 'uptime'
46
- });
47
- });
48
-
49
- test('trims leading and trailing whitespace', () => {
50
- expect(parseAclEntry(' catalogue:uptime ')).toEqual({
51
- raw: 'catalogue:uptime',
52
- excluded: false,
53
- namespace: 'catalogue',
54
- value: 'uptime'
55
- });
56
- });
57
-
58
- test('returns null when namespace is empty (entry starts with colon)', () => {
59
- expect(parseAclEntry(':value')).toBeNull();
60
- });
61
-
62
- test('preserves colons in value', () => {
63
- expect(parseAclEntry('catalogue:b2b:org-123')).toEqual({
64
- raw: 'catalogue:b2b:org-123',
65
- excluded: false,
66
- namespace: 'catalogue',
67
- value: 'b2b:org-123'
68
- });
69
- });
70
- });
71
-
72
- describe('getAclValuesByNamespace', () => {
73
- const acl = [
74
- 'public',
75
- 'catalogue:uptime',
76
- 'catalogue:premium',
77
- '!catalogue:restricted',
78
- 'b2b:org-1',
79
- '!b2b:org-2',
80
- 'user:user-123'
81
- ];
82
-
83
- test('returns included values for a namespace by default', () => {
84
- expect(getAclValuesByNamespace(acl, 'catalogue')).toEqual(['uptime', 'premium']);
85
- });
86
-
87
- test('returns excluded values when mode is "excluded"', () => {
88
- expect(getAclValuesByNamespace(acl, 'catalogue', { mode: 'excluded' })).toEqual(['restricted']);
89
- });
90
-
91
- test('returns all values when mode is "all"', () => {
92
- expect(getAclValuesByNamespace(acl, 'catalogue', { mode: 'all' })).toEqual(['uptime', 'premium', 'restricted']);
93
- });
94
-
95
- test('returns empty array when namespace has no matches', () => {
96
- expect(getAclValuesByNamespace(acl, 'subject')).toEqual([]);
97
- });
98
-
99
- test('deduplicates values by default', () => {
100
- const aclWithDupes = ['catalogue:uptime', 'catalogue:uptime', 'catalogue:premium'];
101
- expect(getAclValuesByNamespace(aclWithDupes, 'catalogue')).toEqual(['uptime', 'premium']);
102
- });
103
-
104
- test('preserves duplicates when dedupe is false', () => {
105
- const aclWithDupes = ['catalogue:uptime', 'catalogue:uptime', 'catalogue:premium'];
106
- expect(getAclValuesByNamespace(aclWithDupes, 'catalogue', { dedupe: false })).toEqual(['uptime', 'uptime', 'premium']);
107
- });
108
-
109
- test('excludes namespace-only entries (no value)', () => {
110
- expect(getAclValuesByNamespace(acl, 'public')).toEqual([]);
111
- });
112
-
113
- test('returns empty array for empty acl', () => {
114
- expect(getAclValuesByNamespace([], 'catalogue')).toEqual([]);
115
- });
116
-
117
- test('skips invalid entries', () => {
118
- const aclWithInvalid = ['', ' ', 'catalogue:uptime'];
119
- expect(getAclValuesByNamespace(aclWithInvalid, 'catalogue')).toEqual(['uptime']);
120
- });
121
- });
122
-
123
- describe('UserAclBuilder', () => {
124
-
125
- test('does not include "public" by default', () => {
126
- const acl = new UserAclBuilder().build();
127
- expect(acl).not.toContain('public');
128
- });
129
-
130
- test('includes "public" when allowPublic is called', () => {
131
- const acl = new UserAclBuilder().allowPublic().build();
132
- expect(acl).toContain('public');
133
- });
134
-
135
- test('includes user entry when allowUser is called', () => {
136
- const acl = new UserAclBuilder().allowUser('user-123').build();
137
- expect(acl).toContain('user:user-123');
138
- });
139
-
140
- test('merges baseAcl entries', () => {
141
- const acl = new UserAclBuilder({ baseAcl: ['catalogue:uptime', '!catalogue:restricted'] }).build();
142
- expect(acl).toContain('catalogue:uptime');
143
- expect(acl).toContain('!catalogue:restricted');
144
- });
145
-
146
- describe('allow', () => {
147
- test('adds namespace:value entry', () => {
148
- const acl = new UserAclBuilder().allow('catalogue', 'uptime').build();
149
- expect(acl).toContain('catalogue:uptime');
150
- });
151
-
152
- test('adds namespace-only entry when no value provided', () => {
153
- const acl = new UserAclBuilder().allow('public').build();
154
- expect(acl).toContain('public');
155
- });
156
-
157
- test('removes entry from excluded when allowed', () => {
158
- const acl = new UserAclBuilder()
159
- .deny('catalogue', 'uptime')
160
- .allow('catalogue', 'uptime')
161
- .build();
162
- expect(acl).toContain('catalogue:uptime');
163
- expect(acl).not.toContain('!catalogue:uptime');
164
- });
165
- });
166
-
167
- describe('deny', () => {
168
- test('adds excluded namespace:value entry', () => {
169
- const acl = new UserAclBuilder().deny('catalogue', 'restricted').build();
170
- expect(acl).toContain('!catalogue:restricted');
171
- });
172
-
173
- test('removes entry from included when denied', () => {
174
- const acl = new UserAclBuilder()
175
- .allow('catalogue', 'uptime')
176
- .deny('catalogue', 'uptime')
177
- .build();
178
- expect(acl).not.toContain('catalogue:uptime');
179
- expect(acl).toContain('!catalogue:uptime');
180
- });
181
- });
182
-
183
- describe('allowCatalogue', () => {
184
- test('adds catalogue:<id> entry', () => {
185
- const acl = new UserAclBuilder().allowCatalogue('premium').build();
186
- expect(acl).toContain('catalogue:premium');
187
- });
188
- });
189
-
190
- describe('denyCatalogue', () => {
191
- test('adds !catalogue:<id> entry', () => {
192
- const acl = new UserAclBuilder().denyCatalogue('restricted').build();
193
- expect(acl).toContain('!catalogue:restricted');
194
- });
195
- });
196
-
197
- describe('allowOrganisation', () => {
198
- test('adds b2b:<id> entry', () => {
199
- const acl = new UserAclBuilder().allowOrganisation('org-1').build();
200
- expect(acl).toContain('b2b:org-1');
201
- });
202
- });
203
-
204
- describe('denySubject', () => {
205
- test('adds !subject:<value> entry', () => {
206
- const acl = new UserAclBuilder().denySubject('some-topic').build();
207
- expect(acl).toContain('!subject:some-topic');
208
- });
209
- });
210
-
211
- describe('addRaw', () => {
212
- test('adds an included raw entry', () => {
213
- const acl = new UserAclBuilder().addRaw('catalogue:uptime').build();
214
- expect(acl).toContain('catalogue:uptime');
215
- });
216
-
217
- test('adds an excluded raw entry', () => {
218
- const acl = new UserAclBuilder().addRaw('!catalogue:restricted').build();
219
- expect(acl).toContain('!catalogue:restricted');
220
- });
221
-
222
- test('ignores invalid raw entries', () => {
223
- const acl = new UserAclBuilder().addRaw('').build();
224
- expect(acl).toEqual([]);
225
- });
226
- });
227
-
228
- describe('addMany', () => {
229
- test('adds multiple entries at once', () => {
230
- const acl = new UserAclBuilder()
231
- .addMany(['catalogue:uptime', 'b2b:org-1', '!catalogue:restricted'])
232
- .build();
233
- expect(acl).toContain('catalogue:uptime');
234
- expect(acl).toContain('b2b:org-1');
235
- expect(acl).toContain('!catalogue:restricted');
236
- });
237
- });
238
- });
239
-
240
- describe('aclFor', () => {
241
- test('includes user entry', () => {
242
- const acl = aclFor({ userId: 'user-abc', organisationIds: [], catalogueIds: [] });
243
- expect(acl).toContain('user:user-abc');
244
- });
245
-
246
- test('always includes catalogue:uptime', () => {
247
- const acl = aclFor({ userId: 'user-abc', organisationIds: [], catalogueIds: [] });
248
- expect(acl).toContain('catalogue:uptime');
249
- });
250
-
251
- test('includes provided catalogue ids', () => {
252
- const acl = aclFor({ userId: 'user-abc', organisationIds: [], catalogueIds: ['premium', 'free'] });
253
- expect(acl).toContain('catalogue:premium');
254
- expect(acl).toContain('catalogue:free');
255
- });
256
-
257
- test('includes b2b catalogue entry for each organisation', () => {
258
- const acl = aclFor({ userId: 'user-abc', organisationIds: ['org-1', 'org-2'], catalogueIds: [] });
259
- expect(acl).toContain('catalogue:b2b:org-1');
260
- expect(acl).toContain('catalogue:b2b:org-2');
261
- });
262
-
263
- test('includes b2b namespace entry for each organisation', () => {
264
- const acl = aclFor({ userId: 'user-abc', organisationIds: ['org-1', 'org-2'], catalogueIds: [] });
265
- expect(acl).toContain('b2b:org-1');
266
- expect(acl).toContain('b2b:org-2');
267
- });
268
-
269
- test('includes public by default', () => {
270
- const acl = aclFor({ userId: 'user-abc', organisationIds: [], catalogueIds: [] });
271
- expect(acl).toContain('public');
272
- });
273
- });
@@ -1,177 +0,0 @@
1
- export type AclQueryMode = 'included' | 'excluded' | 'all';
2
-
3
- export interface ParsedAclEntry {
4
- raw: string;
5
- excluded: boolean;
6
- namespace: string;
7
- value: string | null;
8
- }
9
-
10
- export interface GetAclValuesOptions {
11
- mode?: AclQueryMode;
12
- dedupe?: boolean;
13
- }
14
-
15
- export interface BuildAclOptions {
16
- baseAcl?: string[];
17
- }
18
-
19
- function normalizeAclEntry(entry: string): string {
20
- return entry.trim();
21
- }
22
-
23
- export function parseAclEntry(entry: string): ParsedAclEntry | null {
24
- const raw = normalizeAclEntry(entry);
25
- if (!raw) {
26
- return null;
27
- }
28
-
29
- const excluded = raw.startsWith('!');
30
- const token = excluded ? raw.slice(1) : raw;
31
- const firstColonIndex = token.indexOf(':');
32
-
33
- if (firstColonIndex === -1) {
34
- return {
35
- raw,
36
- excluded,
37
- namespace: token,
38
- value: null
39
- };
40
- }
41
-
42
- const namespace = token.slice(0, firstColonIndex);
43
- const value = token.slice(firstColonIndex + 1);
44
-
45
- if (!namespace) {
46
- return null;
47
- }
48
-
49
- return {
50
- raw,
51
- excluded,
52
- namespace,
53
- value
54
- };
55
- }
56
-
57
- export function getAclValuesByNamespace(
58
- acl: string[],
59
- namespace: string,
60
- options: GetAclValuesOptions = {}
61
- ): string[] {
62
- const mode = options.mode ?? 'included';
63
- const dedupe = options.dedupe ?? true;
64
-
65
- const values = acl
66
- .map(parseAclEntry)
67
- .filter((entry): entry is ParsedAclEntry => Boolean(entry))
68
- .filter(entry => entry.namespace === namespace)
69
- .filter(entry => entry.value !== null)
70
- .filter(entry => {
71
- if (mode === 'all') {
72
- return true;
73
- }
74
- if (mode === 'included') {
75
- return !entry.excluded;
76
- }
77
- return entry.excluded;
78
- })
79
- .map(entry => entry.value as string);
80
-
81
- return dedupe ? Array.from(new Set(values)) : values;
82
- }
83
-
84
- export function aclFor({ userId, organisationIds, catalogueIds }: { userId: string; organisationIds: string[]; catalogueIds: string[] }) {
85
- const builder = new UserAclBuilder()
86
- .allowPublic()
87
- .allowUser(userId);
88
-
89
- // everyone has access to the uptime catalogue
90
- builder.allowCatalogue('uptime');
91
-
92
- catalogueIds.forEach(catalogueId => builder.allowCatalogue(catalogueId));
93
-
94
- // each b2b has a catalogue called b2b:<organisationId> so permit access to this
95
- organisationIds.forEach(organisationId => builder.allowCatalogue(`b2b:${organisationId}`));
96
-
97
- // previously we also had acl of b2b:<organisationId> that is still being used for collections
98
- organisationIds.forEach(organisationId => builder.allowOrganisation(organisationId));
99
-
100
- return builder.build();
101
- }
102
-
103
- export class UserAclBuilder {
104
- private included = new Set<string>();
105
- private excluded = new Set<string>();
106
-
107
- constructor(options: BuildAclOptions = {}) {
108
- if (options.baseAcl?.length) {
109
- this.addMany(options.baseAcl);
110
- }
111
- }
112
-
113
- addRaw(entry: string): this {
114
- const parsed = parseAclEntry(entry);
115
- if (!parsed) {
116
- return this;
117
- }
118
-
119
- if (parsed.excluded) {
120
- this.excluded.add(parsed.raw.slice(1));
121
- } else {
122
- this.included.add(parsed.raw);
123
- }
124
-
125
- return this;
126
- }
127
-
128
- addMany(entries: string[]): this {
129
- entries.forEach(entry => this.addRaw(entry));
130
- return this;
131
- }
132
-
133
- allow(namespace: string, value?: string): this {
134
- const token = value === undefined ? namespace : `${namespace}:${value}`;
135
- this.included.add(token);
136
- this.excluded.delete(token);
137
- return this;
138
- }
139
-
140
- deny(namespace: string, value?: string): this {
141
- const token = value === undefined ? namespace : `${namespace}:${value}`;
142
- this.excluded.add(token);
143
- this.included.delete(token);
144
- return this;
145
- }
146
-
147
- allowCatalogue(catalogueId: string): this {
148
- return this.allow('catalogue', catalogueId);
149
- }
150
-
151
- allowPublic(): this {
152
- return this.allow('public');
153
- }
154
-
155
- allowUser(userId: string): this {
156
- return this.allow('user', userId);
157
- }
158
-
159
- denyCatalogue(catalogueId: string): this {
160
- return this.deny('catalogue', catalogueId);
161
- }
162
-
163
- allowOrganisation(organisationId: string): this {
164
- return this.allow('b2b', organisationId);
165
- }
166
-
167
- denySubject(subject: string): this {
168
- return this.deny('subject', subject);
169
- }
170
-
171
- build(): string[] {
172
- return [
173
- ...this.included,
174
- ...Array.from(this.excluded).map(token => `!${token}`)
175
- ];
176
- }
177
- }
@@ -1,21 +0,0 @@
1
- import { UserContext } from './user-context';
2
-
3
- export interface UserContextCreatedEvent {
4
- id: string;
5
- type: 'UserContextCreated';
6
- payload: UserContext;
7
- }
8
-
9
- export interface UserContextUpdatedEvent {
10
- id: string;
11
- type: 'UserContextUpdated';
12
- payload: UserContext;
13
- }
14
-
15
- export interface UserContextDeletedEvent {
16
- id: string;
17
- type: 'UserContextDeleted';
18
- payload: UserContext;
19
- }
20
-
21
- export type UserContextChangedEvent = UserContextCreatedEvent | UserContextUpdatedEvent | UserContextDeletedEvent;
@@ -1,16 +0,0 @@
1
- import { Entitlement } from '../entitlement/user-entitlements';
2
-
3
- export interface UserContext {
4
- id: string;
5
- v: number;
6
- createdAt: string;
7
- updatedAt: string;
8
- userId: string;
9
- entitlements: Entitlement[];
10
- organisationIds: string[];
11
- roles: string[];
12
- acl: string[];
13
- partnerId?: string;
14
- brandId?: string;
15
- skinId?: string;
16
- }
@@ -1,21 +0,0 @@
1
- import { UserNotificationContext } from './user-notification-context';
2
-
3
- export interface UserNotificationContextCreatedEvent {
4
- id: string;
5
- type: 'UserNotificationContextCreated';
6
- payload: UserNotificationContext;
7
- }
8
-
9
- export interface UserNotificationContextUpdatedEvent {
10
- id: string;
11
- type: 'UserNotificationContextUpdated';
12
- payload: UserNotificationContext;
13
- }
14
-
15
- export interface UserNotificationContextDeletedEvent {
16
- id: string;
17
- type: 'UserNotificationContextDeleted';
18
- payload: UserNotificationContext;
19
- }
20
-
21
- export type UserNotificationContextChangedEvent = UserNotificationContextCreatedEvent | UserNotificationContextUpdatedEvent | UserNotificationContextDeletedEvent;
@@ -1,10 +0,0 @@
1
- export interface UserNotificationContext {
2
- id: string;
3
- userId: string;
4
- v: number;
5
- createdAt: string;
6
- updatedAt: string;
7
- skinId: string;
8
- brandId?: string;
9
- translationVariation: string;
10
- }
@@ -1,97 +0,0 @@
1
- import { DailyInsightCompleted, StreakRepair, UserHackStatistics, UserInsightStreak, ViewedHack } from './user-statistics';
2
-
3
- export interface DailyInsightCompletedCreatedEvent {
4
- id: string;
5
- type: 'DailyInsightCompletedCreated';
6
- payload: DailyInsightCompleted;
7
- }
8
-
9
- export interface DailyInsightCompletedUpdatedEvent {
10
- id: string;
11
- type: 'DailyInsightCompletedUpdated';
12
- payload: DailyInsightCompleted;
13
- }
14
-
15
- export interface DailyInsightCompletedDeletedEvent {
16
- id: string;
17
- type: 'DailyInsightCompletedDeleted';
18
- payload: DailyInsightCompleted;
19
- }
20
-
21
- export interface StreakRepairCreatedEvent {
22
- id: string;
23
- type: 'StreakRepairCreated';
24
- payload: StreakRepair;
25
- }
26
-
27
- export interface StreakRepairUpdatedEvent {
28
- id: string;
29
- type: 'StreakRepairUpdated';
30
- payload: StreakRepair;
31
- }
32
-
33
- export interface StreakRepairDeletedEvent {
34
- id: string;
35
- type: 'StreakRepairDeleted';
36
- payload: StreakRepair;
37
- }
38
-
39
- export interface UserHackStatisticsCreatedEvent {
40
- id: string;
41
- type: 'UserHackStatisticsCreated';
42
- payload: UserHackStatistics;
43
- }
44
-
45
- export interface UserHackStatisticsUpdatedEvent {
46
- id: string;
47
- type: 'UserHackStatisticsUpdated';
48
- payload: UserHackStatistics;
49
- }
50
-
51
- export interface UserHackStatisticsDeletedEvent {
52
- id: string;
53
- type: 'UserHackStatisticsDeleted';
54
- payload: UserHackStatistics;
55
- }
56
-
57
- export interface UserInsightStreakCreatedEvent {
58
- id: string;
59
- type: 'UserInsightStreakCreated';
60
- payload: UserInsightStreak;
61
- }
62
-
63
- export interface UserInsightStreakUpdatedEvent {
64
- id: string;
65
- type: 'UserInsightStreakUpdated';
66
- payload: UserInsightStreak;
67
- }
68
-
69
- export interface UserInsightStreakDeletedEvent {
70
- id: string;
71
- type: 'UserInsightStreakDeleted';
72
- payload: UserInsightStreak;
73
- }
74
-
75
- export interface ViewedHackCreatedEvent {
76
- id: string;
77
- type: 'ViewedHackCreated';
78
- payload: ViewedHack;
79
- }
80
-
81
- export interface ViewedHackUpdatedEvent {
82
- id: string;
83
- type: 'ViewedHackUpdated';
84
- payload: ViewedHack;
85
- }
86
-
87
- export interface ViewedHackDeletedEvent {
88
- id: string;
89
- type: 'ViewedHackDeleted';
90
- payload: ViewedHack;
91
- }
92
-
93
- export type DailyInsightCompletedChangedEvent = DailyInsightCompletedCreatedEvent | DailyInsightCompletedUpdatedEvent | DailyInsightCompletedDeletedEvent;
94
- export type StreakRepairChangedEvent = StreakRepairCreatedEvent | StreakRepairUpdatedEvent | StreakRepairDeletedEvent;
95
- export type UserHackStatisticsChangedEvent = UserHackStatisticsCreatedEvent | UserHackStatisticsUpdatedEvent | UserHackStatisticsDeletedEvent;
96
- export type UserInsightStreakChangedEvent = UserInsightStreakCreatedEvent | UserInsightStreakUpdatedEvent | UserInsightStreakDeletedEvent;
97
- export type ViewedHackChangedEvent = ViewedHackCreatedEvent | ViewedHackUpdatedEvent | ViewedHackDeletedEvent;
@@ -1,82 +0,0 @@
1
- export interface ViewedHack {
2
- id: string;
3
- v: number;
4
- createdAt: string;
5
- updatedAt: string;
6
- userId: string;
7
- hackId: string;
8
- isHackCompleted: boolean;
9
- insightsCompletedCount: number;
10
- /** added Aug 2023 */
11
- percentageComplete: number;
12
- /** added Aug 2023 */
13
- lastViewedAt: string;
14
- hackProgress: {
15
- id: string;
16
- version: number;
17
- createdAt: string;
18
- }
19
- }
20
-
21
- export interface UserInsightStreak {
22
- userId: string;
23
- v: number;
24
- id: string; // deterministic from userId
25
- createdAt: string;
26
- updatedAt: string;
27
- longestStreak: {
28
- length: number;
29
- },
30
- latestStreak: {
31
- // date with format YYYY-MM-DD
32
- latestDayCompleted: string;
33
- length: number;
34
- },
35
- previousStreak: {
36
- length: number;
37
- },
38
- // 30 dates with format YYYY-MM-DD
39
- latestDaysCompleted: string[];
40
- repairs?: {
41
- usedThisMonthCount: number;
42
- }
43
- }
44
-
45
- export interface UserHackStatistics {
46
- userId: string;
47
- v: number;
48
- createdAt: string;
49
- updatedAt: string;
50
-
51
- id: string; // deterministic from userId
52
- insightsCompletedCount: number;
53
- hacksCompletedCount: number;
54
- /** Time saved in minutes. Added Aug 2023 */
55
- totalTimeSaved: number;
56
- perTopic?: PerTopicStatistics[]
57
- }
58
-
59
- export interface PerTopicStatistics {
60
- name: string;
61
- insightsCompletedCount: number;
62
- }
63
-
64
- export interface StreakRepair {
65
- id: string;
66
- v: number;
67
- createdAt: string;
68
- updatedAt: string;
69
- userId: string;
70
- repairDate_streakType : string;
71
- repairDate: string;
72
- streakType: string;
73
- }
74
-
75
- export interface DailyInsightCompleted {
76
- id: string;
77
- v: number;
78
- createdAt: string;
79
- updatedAt: string;
80
- userId: string;
81
- dateInsightCompleted: string;
82
- }