musora-content-services 2.76.0 → 2.77.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,49 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [2.77.1](https://github.com/railroadmedia/musora-content-services/compare/v2.77.0...v2.77.1) (2025-11-13)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * difficulty & instructor fields ([#559](https://github.com/railroadmedia/musora-content-services/issues/559)) ([bd12f4e](https://github.com/railroadmedia/musora-content-services/commit/bd12f4e825f89eca3476bd130a23710991dff7a9))
11
+
12
+ ## [2.77.0](https://github.com/railroadmedia/musora-content-services/compare/v2.64.0...v2.77.0) (2025-11-13)
13
+
14
+
15
+ ### Features
16
+
17
+ * returning data updates in fetchLearningPathLessons ([#550](https://github.com/railroadmedia/musora-content-services/issues/550)) ([1753d75](https://github.com/railroadmedia/musora-content-services/commit/1753d754d620fafc387e700f114d67ec7fc9043f))
18
+ * add fields for learning path v2 ([#537](https://github.com/railroadmedia/musora-content-services/issues/537)) ([b2bcbd2](https://github.com/railroadmedia/musora-content-services/commit/b2bcbd2306afa730e5c61d6ee34fe082212dfdbb))
19
+ * Add learning path lessons endpoint ([#538](https://github.com/railroadmedia/musora-content-services/issues/538)) ([372a871](https://github.com/railroadmedia/musora-content-services/commit/372a8718eb354dfee6faef69077f00b7285a0a19))
20
+ * **BEH-1377:** active path ([#533](https://github.com/railroadmedia/musora-content-services/issues/533)) ([1135271](https://github.com/railroadmedia/musora-content-services/commit/11352714d4228e21f5ac2974d59e6c2805fe900f))
21
+ * **forums:** automatically mark threads as read when viewing posts ([7c721e8](https://github.com/railroadmedia/musora-content-services/commit/7c721e898c445076092bdad34b4df054b1d589f1))
22
+ * legacy methods function with mock data ([#534](https://github.com/railroadmedia/musora-content-services/issues/534)) ([76f74d2](https://github.com/railroadmedia/musora-content-services/commit/76f74d255ab6b6b35ef6422a7952b4f75b551b8c))
23
+ * method card progress row ([#553](https://github.com/railroadmedia/musora-content-services/issues/553)) ([a124cfc](https://github.com/railroadmedia/musora-content-services/commit/a124cfcedb4dacf3b6e6a4c435c4301b3eefa55e))
24
+ * **MU2-1211:** Add is_admin to UserResource ([c8ec392](https://github.com/railroadmedia/musora-content-services/commit/c8ec392bd56874dac495dc731118bcb3298aa80c))
25
+ * **MU2-1211:** Add show_admin_toggle to user resource ([46e1d55](https://github.com/railroadmedia/musora-content-services/commit/46e1d5559badf8822d0351c3483d8a55b781be32))
26
+ * **MU2-1211:** Update docs ([58e973e](https://github.com/railroadmedia/musora-content-services/commit/58e973e43125b1220d00aaf7d03c32639a0f3f64))
27
+ * **MU2-1211:** Update HttpClient methods (get, post, etc.) to capitilized to alleviate browser/cors issue, adding use_student_view to usertype, function to toggle student/admin view ([a2662c2](https://github.com/railroadmedia/musora-content-services/commit/a2662c22f706ac924c755b5be8643fdd17f4ebe4))
28
+ * **MU2E1-168:** onboarding status function ([#530](https://github.com/railroadmedia/musora-content-services/issues/530)) ([1e1cf78](https://github.com/railroadmedia/musora-content-services/commit/1e1cf78afb452792a859ab808d3c0ff1d59ddc6f))
29
+ * update children fields in fetchByRailContentId ([#544](https://github.com/railroadmedia/musora-content-services/issues/544)) ([8bdf7d6](https://github.com/railroadmedia/musora-content-services/commit/8bdf7d68b219f83a6e18fed439046e3ffca11642))
30
+ * update fetch learning path lessons ([#551](https://github.com/railroadmedia/musora-content-services/issues/551)) ([a434076](https://github.com/railroadmedia/musora-content-services/commit/a434076a8281af61043c1ec3e09798e7981ff8f3))
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * active user count endpoint ([#542](https://github.com/railroadmedia/musora-content-services/issues/542)) ([be65c1f](https://github.com/railroadmedia/musora-content-services/commit/be65c1f62b4c828772aade616ddd5d7063d83aa3))
36
+ * add all lessons to fetchLearningPathLessons endpoint ([#548](https://github.com/railroadmedia/musora-content-services/issues/548)) ([acdda67](https://github.com/railroadmedia/musora-content-services/commit/acdda67ffa9eb8e44f7239e3ac21c7bda96166b6))
37
+ * Add is_content and page_type to all content ([#507](https://github.com/railroadmedia/musora-content-services/issues/507)) ([174706b](https://github.com/railroadmedia/musora-content-services/commit/174706b736540b9d24ceaee11539df9203d2d135))
38
+ * Add skill-pack support for navigateTo and nextLesson functionality ([d1682d2](https://github.com/railroadmedia/musora-content-services/commit/d1682d237e548c14f9e3d9f90dea08f6dc752d93))
39
+ * changes to how learning path intro video is stored ([#556](https://github.com/railroadmedia/musora-content-services/issues/556)) ([d3ceb76](https://github.com/railroadmedia/musora-content-services/commit/d3ceb764394cd9450d05c0153aac475022822f48))
40
+ * endpoint for followThread ([719adc8](https://github.com/railroadmedia/musora-content-services/commit/719adc8fa73cdcfb7434d132445b93323ecf4b6e))
41
+ * fetch learning path lessons ([69ac2e1](https://github.com/railroadmedia/musora-content-services/commit/69ac2e1e0982289b26e7148cc17d19f1ba389484))
42
+ * **live-testing:** add email as optional parameter for user creation ([#539](https://github.com/railroadmedia/musora-content-services/issues/539)) ([2289707](https://github.com/railroadmedia/musora-content-services/commit/2289707702a8acbe88c2c7f2acbe97459f876451))
43
+ * **live-testing:** post request url ([#543](https://github.com/railroadmedia/musora-content-services/issues/543)) ([b5463f9](https://github.com/railroadmedia/musora-content-services/commit/b5463f9627c11a4df6257995e1deec5a275ef2c8))
44
+ * **T3PS-864:** Remove sneaky console.log ([19a22ee](https://github.com/railroadmedia/musora-content-services/commit/19a22ee560af64448b7a40a6784d4bba9d0794b4))
45
+ * **T3Ps:** Update fetchCustomerPayments with paginate parameters ([c9c784d](https://github.com/railroadmedia/musora-content-services/commit/c9c784da6995f7ff836c0453c1d0ff353535a53e))
46
+ * update video field for method objects ([#541](https://github.com/railroadmedia/musora-content-services/issues/541)) ([a2120f6](https://github.com/railroadmedia/musora-content-services/commit/a2120f63bfa99d9b9ae96712e879161ad4add441))
47
+
5
48
  ## [2.76.0](https://github.com/railroadmedia/musora-content-services/compare/v2.75.0...v2.76.0) (2025-11-12)
6
49
 
7
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.76.0",
3
+ "version": "2.77.1",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -278,6 +278,7 @@ export const getNextLessonLessonParentTypes = [
278
278
  'pack-bundle',
279
279
  'song-tutorial',
280
280
  'learning-path-v2',
281
+ 'skill-pack'
281
282
  ]
282
283
 
283
284
  export const progressTypesMapping = {
@@ -704,6 +705,9 @@ export function getIntroVideoFields(type) {
704
705
  `"id": railcontent_id`,
705
706
  'title',
706
707
  'brand',
708
+ `"instructor": *[_type == "method-v2" && brand == ^.brand && references(^._id)][0].${instructorField}`,
709
+ `"difficulty": *[_type == "method-v2" && brand == ^.brand && references(^._id)][0].difficulty`,
710
+ `"difficulty_string": *[_type == "method-v2" && brand == ^.brand][0].difficulty_string`,
707
711
  `"type": _type`,
708
712
  'brand',
709
713
  `"description": ${descriptionField}`,
@@ -711,9 +715,9 @@ export function getIntroVideoFields(type) {
711
715
  'length_in_seconds',
712
716
  ]
713
717
 
714
- if (type === 'method') {
718
+ if (type === 'method-v2') {
715
719
  fields.push(...['video_desktop', 'video_mobile'])
716
- } else if (type === 'learning-path') {
720
+ } else if (type === 'learning-path-v2') {
717
721
  fields.push('video')
718
722
  }
719
723
 
@@ -67,7 +67,7 @@ export async function getNextLesson(data) {
67
67
  const lastInteractedStatus = childrenStates[lastInteracted]
68
68
 
69
69
  //different nextLesson behaviour for different content types
70
- if (content.type === 'course' || content.type === 'pack-bundle') {
70
+ if (content.type === 'course' || content.type === 'pack-bundle' || content.type === 'skill-pack') {
71
71
  if (lastInteractedStatus === STATE_STARTED) {
72
72
  nextLessonData[content.id] = lastInteracted
73
73
  } else {
@@ -123,7 +123,7 @@ export async function getNavigateTo(data) {
123
123
  const lastInteracted = await getLastInteractedOf(childrenIds)
124
124
  const lastInteractedStatus = childrenStates[lastInteracted]
125
125
 
126
- if (content.type === 'course' || content.type === 'pack-bundle') {
126
+ if (content.type === 'course' || content.type === 'pack-bundle' || content.type === 'skill-pack') {
127
127
  if (lastInteractedStatus === STATE_STARTED) {
128
128
  navigateToData[content.id] = buildNavigateTo(children.get(lastInteracted))
129
129
  } else {
@@ -5,6 +5,7 @@ import { HttpClient } from '../../infrastructure/http/HttpClient'
5
5
  import { globalConfig } from '../config.js'
6
6
  import { ForumPost } from './types'
7
7
  import { PaginatedResponse } from '../api/types'
8
+ import { markThreadAsRead } from './threads'
8
9
 
9
10
  const baseUrl = `/api/forums`
10
11
 
@@ -47,6 +48,7 @@ export interface FetchPostParams {
47
48
  }
48
49
  /**
49
50
  * Fetches posts for the given thread.
51
+ * Automatically marks the thread as read when posts are fetched.
50
52
  *
51
53
  * @param {number} threadId - The ID of the forum thread.
52
54
  * @param {string} brand - The brand context (e.g., "drumeo", "singeo").
@@ -71,6 +73,12 @@ export async function fetchPosts(
71
73
  const query = new URLSearchParams(queryObj).toString()
72
74
 
73
75
  const url = `${baseUrl}/v1/threads/${threadId}/posts?${query}`
76
+
77
+ // Mark thread as read in background (non-blocking)
78
+ markThreadAsRead(threadId, brand).catch(error => {
79
+ console.error('Failed to mark thread as read:', error)
80
+ })
81
+
74
82
  return httpClient.get<PaginatedResponse<ForumPost>>(url)
75
83
  }
76
84
 
@@ -165,6 +173,7 @@ export async function search(
165
173
 
166
174
  /**
167
175
  * Fetches posts for the given post, jumping to the post's location in the thread.
176
+ * Automatically marks the thread as read when posts are fetched.
168
177
  *
169
178
  * @param {number} postId - The ID of the forum post.
170
179
  * @param {string} brand - The brand context (e.g., "drumeo", "singeo").
@@ -189,5 +198,15 @@ export async function jumpToPost(
189
198
  const query = new URLSearchParams(queryObj).toString()
190
199
 
191
200
  const url = `${baseUrl}/v1/posts/${postId}/jump?${query}`
192
- return httpClient.get<PaginatedResponse<ForumPost>>(url)
201
+ const response = await httpClient.get<PaginatedResponse<ForumPost>>(url)
202
+
203
+ // Mark thread as read in background (non-blocking)
204
+ // Extract thread from first post if available
205
+ if (response.data.length > 0 && response.data[0].thread?.id) {
206
+ markThreadAsRead(response.data[0].thread.id, brand).catch(error => {
207
+ console.error('Failed to mark thread as read:', error)
208
+ })
209
+ }
210
+
211
+ return response
193
212
  }
@@ -59,7 +59,7 @@ export async function updateThread(
59
59
  */
60
60
  export async function followThread(threadId: number, brand: string): Promise<void> {
61
61
  const httpClient = new HttpClient(globalConfig.baseUrl)
62
- return httpClient.post<void>(`${baseUrl}/v1/threads/${threadId}/follow`, { brand })
62
+ return httpClient.put<void>(`${baseUrl}/v1/threads/${threadId}/follow`, { brand })
63
63
  }
64
64
 
65
65
  /**
@@ -75,6 +75,19 @@ export async function unfollowThread(threadId: number, brand: string): Promise<v
75
75
  return httpClient.delete<void>(`${baseUrl}/v1/threads/${threadId}/follow?brand=${brand}`)
76
76
  }
77
77
 
78
+ /**
79
+ * Marks a thread as read for the authenticated user.
80
+ *
81
+ * @param {number} threadId - The ID of the thread to mark as read.
82
+ * @param {string} brand - The brand context (e.g., "drumeo", "singeo").
83
+ * @return {Promise<void>} - A promise that resolves when the thread is marked as read.
84
+ * @throws {HttpError} - If the request fails.
85
+ */
86
+ export async function markThreadAsRead(threadId: number, brand: string): Promise<void> {
87
+ const httpClient = new HttpClient(globalConfig.baseUrl)
88
+ return httpClient.put<void>(`${baseUrl}/v1/threads/${threadId}/read?brand=${brand}`, {})
89
+ }
90
+
78
91
  export interface FetchThreadParams {
79
92
  is_followed?: boolean,
80
93
  page?: number,
@@ -13,6 +13,7 @@ export interface ForumPost {
13
13
  author: ForumUser | null
14
14
  like_count: number
15
15
  is_liked: boolean
16
+ thread?: { id: number; title?: string; slug?: string }
16
17
  }
17
18
 
18
19
  export interface ForumThread {
@@ -16,19 +16,20 @@ import { getProgressState } from '../contentProgress'
16
16
 
17
17
  export async function getMethodCard(brand) {
18
18
  const introVideo = await fetchMethodV2IntroVideo(brand)
19
- const introVideoProgressState = await getProgressState(introVideo.id)
19
+ const introVideoProgressState = await getProgressState(introVideo?.id)
20
20
  //resetAllLearningPaths()
21
21
  if (introVideoProgressState != 'completed') {
22
22
  //startLearningPath('drumeo', 422533)
23
23
  const timestamp = Math.floor(Date.now() / 1000)
24
24
  return {
25
- id: 0, // method card has no id
25
+ id: 1, // method card has no id
26
26
  type: 'method',
27
27
  header: 'Method',
28
+ progressType: 'method',
28
29
  body: {
29
30
  thumbnail: introVideo.thumbnail,
30
31
  title: introVideo.title,
31
- subtitle: `${introVideo.difficulty_string} • ${introVideo.artist_name}`,
32
+ subtitle: `${introVideo.difficulty_string} • ${introVideo.instructor?.[0]?.name}`,
32
33
  },
33
34
  cta: {
34
35
  text: 'Get Started',
@@ -85,9 +86,9 @@ export async function getMethodCard(brand) {
85
86
  }
86
87
 
87
88
  return {
88
- id: 0,
89
+ id: 1,
89
90
  type: 'learning-path-v2',
90
- progressType: 'content',
91
+ progressType: 'method',
91
92
  header: 'Method',
92
93
  body: learningPath,
93
94
  cta: {
@@ -2299,7 +2299,7 @@ export async function fetchShows(brand, type, sort = 'sort') {
2299
2299
  export async function fetchMethodV2IntroVideo(brand) {
2300
2300
  const type = "method-intro";
2301
2301
  const filter = `_type == '${type}' && brand == '${brand}'`;
2302
- const fields = getIntroVideoFields('method');
2302
+ const fields = getIntroVideoFields('method-v2');
2303
2303
 
2304
2304
  const query = `*[${filter}] { ${fields.join(", ")} }`;
2305
2305
  return fetchSanity(query, false);