musora-content-services 2.95.2 → 2.95.3

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 (210) hide show
  1. package/.coderabbit.yaml +0 -0
  2. package/.editorconfig +0 -0
  3. package/.github/pull_request_template.md +0 -0
  4. package/.github/workflows/conventional-commits.yaml +0 -0
  5. package/.github/workflows/docs.js.yml +0 -0
  6. package/.github/workflows/node.js.yml +0 -0
  7. package/.prettierignore +0 -0
  8. package/.prettierrc +0 -0
  9. package/CHANGELOG.md +7 -0
  10. package/CLAUDE.md +0 -0
  11. package/README.md +0 -0
  12. package/babel.config.cjs +0 -0
  13. package/jest.config.js +0 -0
  14. package/jsdoc.json +0 -0
  15. package/package.json +1 -1
  16. package/src/constants/award-assets.js +0 -0
  17. package/src/contentMetaData.js +0 -0
  18. package/src/filterBuilder.js +0 -0
  19. package/src/index.d.ts +0 -0
  20. package/src/index.js +0 -0
  21. package/src/infrastructure/http/HttpClient.ts +0 -0
  22. package/src/infrastructure/http/executors/FetchRequestExecutor.ts +0 -0
  23. package/src/infrastructure/http/index.ts +0 -0
  24. package/src/infrastructure/http/interfaces/HeaderProvider.ts +0 -0
  25. package/src/infrastructure/http/interfaces/HttpError.ts +0 -0
  26. package/src/infrastructure/http/interfaces/NetworkError.ts +0 -0
  27. package/src/infrastructure/http/interfaces/RequestExecutor.ts +0 -0
  28. package/src/infrastructure/http/interfaces/RequestOptions.ts +0 -0
  29. package/src/infrastructure/http/providers/DefaultHeaderProvider.ts +0 -0
  30. package/src/lib/ads/monoid.ts +5 -0
  31. package/src/lib/ads/semigroup.ts +3 -0
  32. package/src/lib/brands.ts +0 -0
  33. package/src/lib/httpHelper.js +0 -0
  34. package/src/lib/lastUpdated.js +0 -0
  35. package/src/lib/sanity/query.ts +125 -28
  36. package/src/services/api/types.js +0 -0
  37. package/src/services/api/types.ts +0 -0
  38. package/src/services/awards/award-callbacks.js +0 -0
  39. package/src/services/awards/award-query.js +0 -0
  40. package/src/services/awards/internal/.indexignore +0 -0
  41. package/src/services/awards/internal/award-definitions.js +0 -0
  42. package/src/services/awards/internal/award-events.js +0 -0
  43. package/src/services/awards/internal/award-manager.js +0 -0
  44. package/src/services/awards/internal/certificate-builder.js +0 -0
  45. package/src/services/awards/internal/completion-data-generator.js +0 -0
  46. package/src/services/awards/internal/content-progress-observer.js +0 -0
  47. package/src/services/awards/internal/image-utils.js +0 -0
  48. package/src/services/awards/internal/message-generator.js +0 -0
  49. package/src/services/awards/internal/types.js +0 -0
  50. package/src/services/awards/types.d.ts +0 -0
  51. package/src/services/awards/types.js +0 -0
  52. package/src/services/config.js +0 -0
  53. package/src/services/content/artist.ts +69 -37
  54. package/src/services/content/content.ts +0 -0
  55. package/src/services/content/genre.ts +67 -39
  56. package/src/services/content/instructor.ts +76 -41
  57. package/src/services/content-org/content-org.js +0 -0
  58. package/src/services/content-org/guided-courses.ts +0 -0
  59. package/src/services/content-org/learning-paths.ts +0 -0
  60. package/src/services/content-org/playlists-types.js +0 -0
  61. package/src/services/content-org/playlists.js +0 -0
  62. package/src/services/content.js +0 -0
  63. package/src/services/contentAggregator.js +0 -0
  64. package/src/services/contentLikes.js +0 -0
  65. package/src/services/contentProgress.js +0 -0
  66. package/src/services/dataContext.js +0 -0
  67. package/src/services/dateUtils.js +0 -0
  68. package/src/services/eventsAPI.js +0 -0
  69. package/src/services/forums/categories.ts +0 -0
  70. package/src/services/forums/forums.ts +0 -0
  71. package/src/services/forums/posts.ts +0 -0
  72. package/src/services/forums/threads.ts +0 -0
  73. package/src/services/forums/types.ts +0 -0
  74. package/src/services/gamification/awards.ts +0 -0
  75. package/src/services/gamification/gamification.js +0 -0
  76. package/src/services/imageSRCBuilder.js +0 -0
  77. package/src/services/imageSRCVerify.js +0 -0
  78. package/src/services/liveTesting.ts +0 -0
  79. package/src/services/permissions/PermissionsAdapter.ts +0 -0
  80. package/src/services/permissions/PermissionsAdapterFactory.ts +0 -0
  81. package/src/services/permissions/PermissionsV1Adapter.ts +0 -0
  82. package/src/services/permissions/PermissionsV2Adapter.ts +0 -0
  83. package/src/services/permissions/README.md +0 -0
  84. package/src/services/permissions/index.ts +0 -0
  85. package/src/services/progress-events.js +0 -0
  86. package/src/services/progress-row/method-card.js +0 -0
  87. package/src/services/railcontent.js +0 -0
  88. package/src/services/recommendations.js +0 -0
  89. package/src/services/reporting/README.md +0 -0
  90. package/src/services/reporting/reporting.ts +0 -0
  91. package/src/services/reporting/types.ts +0 -0
  92. package/src/services/sentry/.indexignore +0 -0
  93. package/src/services/sentry/index.ts +0 -0
  94. package/src/services/sync/.indexignore +0 -0
  95. package/src/services/sync/adapters/factory.ts +0 -0
  96. package/src/services/sync/adapters/lokijs.ts +0 -0
  97. package/src/services/sync/adapters/sqlite.ts +0 -0
  98. package/src/services/sync/concurrency-safety.ts +0 -0
  99. package/src/services/sync/context/index.ts +0 -0
  100. package/src/services/sync/context/providers/base.ts +0 -0
  101. package/src/services/sync/context/providers/connectivity.ts +0 -0
  102. package/src/services/sync/context/providers/durability.ts +0 -0
  103. package/src/services/sync/context/providers/index.ts +0 -0
  104. package/src/services/sync/context/providers/session.ts +0 -0
  105. package/src/services/sync/context/providers/tabs.ts +0 -0
  106. package/src/services/sync/context/providers/visibility.ts +0 -0
  107. package/src/services/sync/database/factory.ts +0 -0
  108. package/src/services/sync/errors/boundary.ts +0 -0
  109. package/src/services/sync/errors/index.ts +0 -0
  110. package/src/services/sync/fetch.ts +0 -0
  111. package/src/services/sync/index.ts +0 -0
  112. package/src/services/sync/manager.ts +0 -0
  113. package/src/services/sync/models/Base.ts +0 -0
  114. package/src/services/sync/models/ContentLike.ts +0 -0
  115. package/src/services/sync/models/ContentProgress.ts +0 -0
  116. package/src/services/sync/models/Practice.ts +0 -0
  117. package/src/services/sync/models/PracticeDayNote.ts +0 -0
  118. package/src/services/sync/models/UserAwardProgress.ts +0 -0
  119. package/src/services/sync/models/index.ts +0 -0
  120. package/src/services/sync/repositories/base.ts +0 -0
  121. package/src/services/sync/repositories/content-likes.ts +0 -0
  122. package/src/services/sync/repositories/content-progress.ts +0 -0
  123. package/src/services/sync/repositories/index.ts +0 -0
  124. package/src/services/sync/repositories/practice-day-notes.ts +0 -0
  125. package/src/services/sync/repositories/practices.ts +0 -0
  126. package/src/services/sync/repositories/user-award-progress.ts +0 -0
  127. package/src/services/sync/repository-proxy.ts +0 -0
  128. package/src/services/sync/resolver.ts +0 -0
  129. package/src/services/sync/retry.ts +0 -0
  130. package/src/services/sync/run-scope.ts +0 -0
  131. package/src/services/sync/schema/index.ts +0 -0
  132. package/src/services/sync/serializers/index.ts +0 -0
  133. package/src/services/sync/serializers/model.ts +0 -0
  134. package/src/services/sync/serializers/raw.ts +0 -0
  135. package/src/services/sync/store/index.ts +0 -0
  136. package/src/services/sync/store/push-coalescer.ts +0 -0
  137. package/src/services/sync/store-configs.ts +0 -0
  138. package/src/services/sync/strategies/base.ts +0 -0
  139. package/src/services/sync/strategies/index.ts +0 -0
  140. package/src/services/sync/strategies/initial.ts +0 -0
  141. package/src/services/sync/strategies/polling.ts +0 -0
  142. package/src/services/sync/telemetry/index.ts +0 -0
  143. package/src/services/sync/telemetry/sampling.ts +0 -0
  144. package/src/services/sync/utils/event-emitter.ts +0 -0
  145. package/src/services/sync/utils/index.ts +0 -0
  146. package/src/services/sync/utils/throttle.ts +0 -0
  147. package/src/services/sync/utils/timers.ts +0 -0
  148. package/src/services/types.js +0 -0
  149. package/src/services/user/account.ts +0 -0
  150. package/src/services/user/chat.js +0 -0
  151. package/src/services/user/interests.js +0 -0
  152. package/src/services/user/management.js +0 -0
  153. package/src/services/user/memberships.ts +0 -0
  154. package/src/services/user/notifications.js +0 -0
  155. package/src/services/user/onboarding.ts +0 -0
  156. package/src/services/user/payments.ts +0 -0
  157. package/src/services/user/permissions.js +0 -0
  158. package/src/services/user/profile.js +0 -0
  159. package/src/services/user/sessions.js +0 -0
  160. package/src/services/user/types.d.ts +0 -0
  161. package/src/services/user/types.js +0 -0
  162. package/src/services/user/user-management-system.js +0 -0
  163. package/src/services/userActivity.js +0 -0
  164. package/test/HttpClient.test.js +0 -0
  165. package/test/awards/award-alacarte-observer.test.js +0 -0
  166. package/test/awards/award-auto-refresh.test.js +0 -0
  167. package/test/awards/award-calculations.test.js +0 -0
  168. package/test/awards/award-certificate-display.test.js +0 -0
  169. package/test/awards/award-collection-edge-cases.test.js +0 -0
  170. package/test/awards/award-collection-filtering.test.js +0 -0
  171. package/test/awards/award-completion-flow.test.js +0 -0
  172. package/test/awards/award-exclusion-handling.test.js +0 -0
  173. package/test/awards/award-multi-lesson.test.js +0 -0
  174. package/test/awards/award-observer-integration.test.js +0 -0
  175. package/test/awards/award-query-messages.test.js +0 -0
  176. package/test/awards/award-user-collection.test.js +0 -0
  177. package/test/awards/duplicate-prevention.test.js +0 -0
  178. package/test/awards/helpers/completion-mock.js +0 -0
  179. package/test/awards/helpers/index.js +0 -0
  180. package/test/awards/helpers/mock-setup.js +0 -0
  181. package/test/awards/helpers/progress-emitter.js +0 -0
  182. package/test/awards/message-generator.test.js +0 -0
  183. package/test/content.test.js +0 -0
  184. package/test/contentLikes.test.js +0 -0
  185. package/test/contentProgress.test.js +0 -0
  186. package/test/dataContext.test.js +0 -0
  187. package/test/forum.test.js +0 -0
  188. package/test/imageSRCBuilder.test.js +0 -0
  189. package/test/imageSRCVerify.test.js +0 -0
  190. package/test/initializeTests.js +0 -0
  191. package/test/learningPaths.test.js +0 -0
  192. package/test/lib/lastUpdated.test.js +0 -0
  193. package/test/live/contentProgressLive.test.js +0 -0
  194. package/test/live/railcontentLive.test.js +0 -0
  195. package/test/localStorageMock.js +0 -0
  196. package/test/log.js +0 -0
  197. package/test/mockData/award-definitions.js +0 -0
  198. package/test/mockData/mockData_fetchByRailContentIds_one_content.json +0 -0
  199. package/test/mockData/mockData_progress_content.json +0 -0
  200. package/test/mockData/mockData_sanity_progress_content.json +0 -0
  201. package/test/mockData/mockData_user_practices.json +0 -0
  202. package/test/notifications.test.js +0 -0
  203. package/test/progressRows.test.js +0 -0
  204. package/test/sanityQueryService.test.js +0 -0
  205. package/test/streakMessage.test.js +0 -0
  206. package/test/sync/models/award-database-integration.test.js +0 -0
  207. package/test/user/permissions.test.js +0 -0
  208. package/test/userActivity.test.js +0 -0
  209. package/tools/generate-index.cjs +0 -0
  210. package/.claude/settings.local.json +0 -18
@@ -5,7 +5,7 @@ import { FilterBuilder } from '../../filterBuilder.js'
5
5
  import { filtersToGroq, getFieldsForContentType } from '../../contentTypeConfig.js'
6
6
  import { fetchSanity, getSortOrder } from '../sanity.js'
7
7
  import { Lesson } from './content'
8
- import { buildDataAndTotalQuery } from '../../lib/sanity/query'
8
+ import { BuildQueryOptions, query } from '../../lib/sanity/query'
9
9
  import { Brands } from '../../lib/brands'
10
10
 
11
11
  export interface Instructor {
@@ -16,30 +16,55 @@ export interface Instructor {
16
16
  thumbnail: string
17
17
  }
18
18
 
19
+ export interface Instructors {
20
+ data: Instructor[]
21
+ total: number
22
+ }
23
+
19
24
  /**
20
25
  * Fetch all instructor with lessons available for a specific brand.
21
26
  *
22
27
  * @param {Brands|string} brand - The brand for which to fetch instructors.
23
- * @returns {Promise<Instructor[]>} - A promise that resolves to an array of instructor objects.
28
+ * @returns {Promise<Instructors>} - A promise that resolves to an array of instructor objects.
24
29
  *
25
30
  * @example
26
31
  * fetchInstructors('drumeo')
27
32
  * .then(instructors => console.log(instructors))
28
33
  * .catch(error => console.error(error));
29
34
  */
30
- export async function fetchInstructors(brand: Brands | string): Promise<Instructor[]> {
31
- const filter = await new FilterBuilder(`brand == "${brand}" && references(^._id)`, {
35
+ export async function fetchInstructors(
36
+ brand: Brands | string,
37
+ options: BuildQueryOptions
38
+ ): Promise<Instructor[]> {
39
+ const lessonFilter = await new FilterBuilder(`brand == "${brand}" && references(^._id)`, {
32
40
  bypassPermissions: true,
33
41
  }).buildFilter()
34
42
 
35
- const query = `
36
- *[_type == "instructor"] {
37
- name,
38
- "slug": slug.current,
39
- 'thumbnail': thumbnail_url.asset->url,
40
- "lessonCount": count(*[${filter}])
41
- }[lessonCount > 0] |order(lower(name)) `
42
- return fetchSanity(query, true, { processNeedAccess: false, processPageType: false })
43
+ const data = query()
44
+ .and(`_type == "instructor"`)
45
+ .order(options.sort || 'lower(name) asc')
46
+ .slice(options.offset || 0, (options.offset || 0) + (options.limit || 20))
47
+ .select(
48
+ 'name',
49
+ `"slug": slug.current`,
50
+ `"thumbnail": thumbnail_url.asset->url`,
51
+ `"lessonCount": count(*[${lessonFilter}])`
52
+ )
53
+ .postFilter(`lessonCount > 0`)
54
+ .build()
55
+
56
+ const total = query()
57
+ .and(`_type == "instructor"`)
58
+ .select(`"lessonCount": count(*[${lessonFilter}])`)
59
+ .postFilter(`lessonCount > 0`)
60
+ .build()
61
+
62
+ const q = `{
63
+ "data": ${data},
64
+ "total": count(${total})
65
+ }`
66
+
67
+ return fetchSanity(q, true, { processNeedAccess: false, processPageType: false })
43
68
  }
44
69
 
45
70
  /**
@@ -47,7 +72,7 @@ export async function fetchInstructors(brand: Brands | string): Promise<Instruct
47
72
  *
48
73
  * @param {string} slug - The slug of the instructor to fetch.
49
74
  * @param {Brands|string} [brand] - The brand for which to fetch the instructor. Lesson count will be filtered by this brand if provided.
50
- * @returns {Promise<Instructor[]>} - A promise that resolves to an instructor object or null if not found.
75
+ * @returns {Promise<Instructor | null>} - A promise that resolves to an instructor object or null if not found.
51
76
  *
52
77
  * @example
53
78
  * fetchInstructorBySlug('66samus', 'drumeo')
@@ -63,26 +88,28 @@ export async function fetchInstructorBySlug(
63
88
  bypassPermissions: true,
64
89
  }).buildFilter()
65
90
 
66
- const query = `
67
- *[_type == "instructor" && slug.current == '${slug}'][0] {
68
- name,
69
- "slug": slug.current,
70
- short_bio,
71
- 'thumbnail': thumbnail_url.asset->url,
72
- "lessonCount": count(*[${filter}])
73
- }`
74
- return fetchSanity(query, true, { processNeedAccess: false, processPageType: false })
91
+ const q = query()
92
+ .and(`_type == "instructor"`)
93
+ .and(`slug.current == "${slug}"`)
94
+ .select(
95
+ 'name',
96
+ `"slug": slug.current`,
97
+ 'short_bio',
98
+ `"thumbnail": thumbnail_url.asset->url`,
99
+ `"lessonCount": count(*[${filter}])`
100
+ )
101
+ .first()
102
+ .build()
103
+
104
+ return fetchSanity(q, true, { processNeedAccess: false, processPageType: false })
75
105
  }
76
106
 
77
- export interface FetchInstructorLessonsOptions {
78
- sortOrder?: string
107
+ export interface InstructorLessonsOptions extends BuildQueryOptions {
79
108
  searchTerm?: string
80
- page?: number
81
- limit?: number
82
109
  includedFields?: Array<string>
83
110
  }
84
111
 
85
- export interface InstructorLessonsResponse {
112
+ export interface InstructorLessons {
86
113
  data: Lesson[]
87
114
  total: number
88
115
  }
@@ -99,7 +126,7 @@ export interface InstructorLessonsResponse {
99
126
  * @param {number} [options.limit=10] - The number of items per page.
100
127
  * @param {Array<string>} [options.includedFields=[]] - Additional filters to apply to the query in the format of a key,value array. eg. ['difficulty,Intermediate', 'genre,rock'].
101
128
  *
102
- * @returns {Promise<InstructorLessonsResponse>} - The lessons for the instructor or null if not found.
129
+ * @returns {Promise<InstructorLessons>} - The lessons for the instructor or null if not found.
103
130
  * @example
104
131
  * fetchInstructorLessons('instructor123')
105
132
  * .then(lessons => console.log(lessons))
@@ -109,26 +136,34 @@ export async function fetchInstructorLessons(
109
136
  slug: string,
110
137
  brand: Brands | string,
111
138
  {
112
- sortOrder = '-published_on',
139
+ sort = '-published_on',
113
140
  searchTerm = '',
114
- page = 1,
141
+ offset = 1,
115
142
  limit = 20,
116
143
  includedFields = [],
117
- }: FetchInstructorLessonsOptions = {}
118
- ): Promise<InstructorLessonsResponse> {
144
+ }: InstructorLessonsOptions = {}
145
+ ): Promise<InstructorLessons> {
119
146
  const fieldsString = getFieldsForContentType() as string
120
- const start = (page - 1) * limit
121
- const end = start + limit
122
147
  const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : ''
123
148
  const includedFieldsFilter = includedFields.length > 0 ? filtersToGroq(includedFields) : ''
124
149
  const filter = `brand == '${brand}' ${searchFilter} ${includedFieldsFilter} && references(*[_type=='instructor' && slug.current == '${slug}']._id)`
125
150
  const filterWithRestrictions = await new FilterBuilder(filter).buildFilter()
126
151
 
127
- sortOrder = getSortOrder(sortOrder, brand)
128
- const query = buildDataAndTotalQuery(filterWithRestrictions, fieldsString, {
129
- sort: sortOrder,
130
- start: start,
131
- end: end,
132
- })
133
- return fetchSanity(query, true, { processNeedAccess: false, processPageType: false })
152
+ sort = getSortOrder(sort, brand)
153
+
154
+ const data = query()
155
+ .and(filterWithRestrictions)
156
+ .order(sort)
157
+ .slice(offset, offset + limit)
158
+ .select(...(fieldsString ? [fieldsString] : []))
159
+ .build()
160
+
161
+ const total = query().and(filterWithRestrictions).build()
162
+
163
+ const q = `{
164
+ "data": ${data},
165
+ "total": count(${total})
166
+ }`
167
+
168
+ return fetchSanity(q, true, { processNeedAccess: false, processPageType: false })
134
169
  }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/test/log.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,18 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(find:*)",
5
- "Bash(docker exec:*)",
6
- "Bash(npm test:*)",
7
- "WebSearch",
8
- "WebFetch(domain:watermelondb.dev)",
9
- "WebFetch(domain:github.com)",
10
- "Bash(git checkout:*)",
11
- "Bash(npm run doc:*)",
12
- "Bash(cat:*)",
13
- "Bash(tr:*)"
14
- ],
15
- "deny": [],
16
- "ask": []
17
- }
18
- }