musora-content-services 2.117.7 → 2.118.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.
Files changed (225) hide show
  1. package/.claude/settings.local.json +16 -0
  2. package/.coderabbit.yaml +0 -0
  3. package/.editorconfig +0 -0
  4. package/.github/pull_request_template.md +0 -0
  5. package/.github/workflows/conventional-commits.yaml +0 -0
  6. package/.github/workflows/docs.js.yml +0 -0
  7. package/.github/workflows/node.js.yml +0 -0
  8. package/.prettierignore +0 -0
  9. package/.prettierrc +0 -0
  10. package/.yarnrc.yml +1 -0
  11. package/CHANGELOG.md +52 -0
  12. package/CLAUDE.md +0 -0
  13. package/README.md +0 -0
  14. package/babel.config.cjs +0 -0
  15. package/check_content.js +30 -0
  16. package/check_content.mjs +32 -0
  17. package/jsdoc.json +0 -0
  18. package/package.json +1 -1
  19. package/src/constants/award-assets.js +0 -0
  20. package/src/constants/membership-permissions.ts +0 -0
  21. package/src/contentMetaData.js +9 -5
  22. package/src/filterBuilder.js +0 -0
  23. package/src/index.d.ts +2 -0
  24. package/src/index.js +2 -0
  25. package/src/infrastructure/http/HttpClient.ts +0 -0
  26. package/src/infrastructure/http/executors/FetchRequestExecutor.ts +0 -0
  27. package/src/infrastructure/http/index.ts +0 -0
  28. package/src/infrastructure/http/interfaces/HeaderProvider.ts +0 -0
  29. package/src/infrastructure/http/interfaces/HttpError.ts +0 -0
  30. package/src/infrastructure/http/interfaces/NetworkError.ts +0 -0
  31. package/src/infrastructure/http/interfaces/RequestExecutor.ts +0 -0
  32. package/src/infrastructure/http/providers/DefaultHeaderProvider.ts +0 -0
  33. package/src/lib/ads/monoid.ts +0 -0
  34. package/src/lib/ads/semigroup.ts +0 -0
  35. package/src/lib/brands.ts +0 -0
  36. package/src/lib/lastUpdated.js +0 -0
  37. package/src/lib/sanity/filter.ts +0 -0
  38. package/src/lib/sanity/query.ts +0 -0
  39. package/src/services/api/types.js +0 -0
  40. package/src/services/api/types.ts +0 -0
  41. package/src/services/awards/award-callbacks.js +0 -0
  42. package/src/services/awards/award-query.js +0 -0
  43. package/src/services/awards/internal/.indexignore +0 -0
  44. package/src/services/awards/internal/award-definitions.js +0 -0
  45. package/src/services/awards/internal/award-events.js +0 -0
  46. package/src/services/awards/internal/award-manager.js +0 -0
  47. package/src/services/awards/internal/certificate-builder.js +0 -0
  48. package/src/services/awards/internal/completion-data-generator.js +0 -0
  49. package/src/services/awards/internal/content-progress-observer.js +0 -0
  50. package/src/services/awards/internal/image-utils.js +0 -0
  51. package/src/services/awards/internal/message-generator.js +0 -0
  52. package/src/services/awards/internal/types.js +0 -0
  53. package/src/services/awards/types.d.ts +0 -0
  54. package/src/services/awards/types.js +0 -0
  55. package/src/services/content/artist.ts +0 -0
  56. package/src/services/content/content.ts +0 -0
  57. package/src/services/content/genre.ts +0 -0
  58. package/src/services/content/instructor.ts +0 -0
  59. package/src/services/content-org/content-org.js +0 -0
  60. package/src/services/content-org/guided-courses.ts +0 -0
  61. package/src/services/content-org/learning-paths.ts +0 -0
  62. package/src/services/content-org/playlists-types.js +0 -0
  63. package/src/services/content-org/playlists.js +0 -0
  64. package/src/services/content.js +54 -15
  65. package/src/services/contentAggregator.js +0 -0
  66. package/src/services/contentLikes.js +0 -0
  67. package/src/services/contentProgress.js +0 -0
  68. package/src/services/dataContext.js +41 -0
  69. package/src/services/dateUtils.js +0 -0
  70. package/src/services/eventsAPI.js +0 -0
  71. package/src/services/forums/categories.ts +0 -0
  72. package/src/services/forums/forums.ts +0 -0
  73. package/src/services/forums/posts.ts +0 -0
  74. package/src/services/forums/threads.ts +0 -0
  75. package/src/services/forums/types.ts +0 -0
  76. package/src/services/gamification/awards.ts +0 -0
  77. package/src/services/gamification/gamification.js +0 -0
  78. package/src/services/imageSRCBuilder.js +0 -0
  79. package/src/services/imageSRCVerify.js +0 -0
  80. package/src/services/liveTesting.ts +0 -0
  81. package/src/services/permissions/PermissionsAdapter.ts +0 -0
  82. package/src/services/permissions/PermissionsAdapterFactory.ts +0 -0
  83. package/src/services/permissions/PermissionsV1Adapter.ts +0 -0
  84. package/src/services/permissions/PermissionsV2Adapter.ts +0 -0
  85. package/src/services/permissions/README.md +0 -0
  86. package/src/services/permissions/index.ts +0 -0
  87. package/src/services/progress-events.js +0 -0
  88. package/src/services/progress-row/base.js +13 -3
  89. package/src/services/progress-row/rows/.indexignore +0 -0
  90. package/src/services/progress-row/rows/content-card.js +0 -0
  91. package/src/services/progress-row/rows/playlist-card.js +0 -0
  92. package/src/services/railcontent.js +0 -0
  93. package/src/services/recommendations.js +5 -2
  94. package/src/services/reporting/README.md +0 -0
  95. package/src/services/reporting/reporting.ts +0 -0
  96. package/src/services/reporting/types.ts +0 -0
  97. package/src/services/sentry/.indexignore +0 -0
  98. package/src/services/sentry/index.ts +0 -0
  99. package/src/services/sync/.indexignore +0 -0
  100. package/src/services/sync/adapters/factory.ts +0 -0
  101. package/src/services/sync/adapters/lokijs.ts +0 -0
  102. package/src/services/sync/adapters/sqlite.ts +0 -0
  103. package/src/services/sync/context/index.ts +0 -0
  104. package/src/services/sync/context/providers/base.ts +0 -0
  105. package/src/services/sync/context/providers/connectivity.ts +0 -0
  106. package/src/services/sync/context/providers/durability.ts +0 -0
  107. package/src/services/sync/context/providers/index.ts +0 -0
  108. package/src/services/sync/context/providers/session.ts +0 -0
  109. package/src/services/sync/context/providers/tabs.ts +0 -0
  110. package/src/services/sync/context/providers/visibility.ts +0 -0
  111. package/src/services/sync/database/factory.ts +0 -0
  112. package/src/services/sync/effects/index.ts +0 -0
  113. package/src/services/sync/effects/logout-warning.ts +0 -0
  114. package/src/services/sync/errors/boundary.ts +0 -0
  115. package/src/services/sync/errors/index.ts +0 -0
  116. package/src/services/sync/errors/validators.ts +0 -0
  117. package/src/services/sync/fetch.ts +0 -0
  118. package/src/services/sync/index.ts +0 -0
  119. package/src/services/sync/manager.ts +0 -0
  120. package/src/services/sync/models/Base.ts +0 -0
  121. package/src/services/sync/models/ContentLike.ts +0 -0
  122. package/src/services/sync/models/ContentProgress.ts +0 -0
  123. package/src/services/sync/models/Practice.ts +0 -0
  124. package/src/services/sync/models/PracticeDayNote.ts +0 -0
  125. package/src/services/sync/models/UserAwardProgress.ts +0 -0
  126. package/src/services/sync/models/index.ts +0 -0
  127. package/src/services/sync/repositories/base.ts +0 -0
  128. package/src/services/sync/repositories/content-likes.ts +0 -0
  129. package/src/services/sync/repositories/content-progress.ts +0 -0
  130. package/src/services/sync/repositories/index.ts +0 -0
  131. package/src/services/sync/repositories/practice-day-notes.ts +0 -0
  132. package/src/services/sync/repositories/practices.ts +0 -0
  133. package/src/services/sync/repositories/user-award-progress.ts +0 -0
  134. package/src/services/sync/repository-proxy.ts +0 -0
  135. package/src/services/sync/resolver.ts +0 -0
  136. package/src/services/sync/retry.ts +0 -0
  137. package/src/services/sync/run-scope.ts +0 -0
  138. package/src/services/sync/schema/index.ts +0 -0
  139. package/src/services/sync/serializers/index.ts +0 -0
  140. package/src/services/sync/serializers/model.ts +0 -0
  141. package/src/services/sync/serializers/raw.ts +0 -0
  142. package/src/services/sync/store/index.ts +0 -0
  143. package/src/services/sync/store/push-coalescer.ts +0 -0
  144. package/src/services/sync/store-configs.ts +0 -0
  145. package/src/services/sync/strategies/base.ts +0 -0
  146. package/src/services/sync/strategies/index.ts +0 -0
  147. package/src/services/sync/strategies/initial.ts +0 -0
  148. package/src/services/sync/strategies/polling.ts +0 -0
  149. package/src/services/sync/telemetry/flood-prevention.ts +0 -0
  150. package/src/services/sync/telemetry/index.ts +0 -0
  151. package/src/services/sync/telemetry/sampling.ts +0 -0
  152. package/src/services/sync/utils/event-emitter.ts +0 -0
  153. package/src/services/sync/utils/index.ts +0 -0
  154. package/src/services/sync/utils/throttle.ts +0 -0
  155. package/src/services/sync/utils/timers.ts +0 -0
  156. package/src/services/urlBuilder.ts +0 -0
  157. package/src/services/user/account.ts +0 -0
  158. package/src/services/user/chat.js +0 -0
  159. package/src/services/user/interests.js +0 -0
  160. package/src/services/user/management.js +0 -0
  161. package/src/services/user/memberships.ts +0 -0
  162. package/src/services/user/notifications.js +0 -0
  163. package/src/services/user/onboarding.ts +0 -0
  164. package/src/services/user/payments.ts +0 -0
  165. package/src/services/user/permissions.js +0 -0
  166. package/src/services/user/profile.js +0 -0
  167. package/src/services/user/sessions.js +10 -3
  168. package/src/services/user/types.d.ts +0 -0
  169. package/src/services/user/types.js +0 -0
  170. package/src/services/user/user-management-system.js +0 -0
  171. package/src/services/userActivity.js +0 -0
  172. package/test/HttpClient.test.js +0 -0
  173. package/test/awards/award-alacarte-observer.test.js +0 -0
  174. package/test/awards/award-auto-refresh.test.js +0 -0
  175. package/test/awards/award-calculations.test.js +0 -0
  176. package/test/awards/award-certificate-display.test.js +0 -0
  177. package/test/awards/award-collection-edge-cases.test.js +0 -0
  178. package/test/awards/award-collection-filtering.test.js +0 -0
  179. package/test/awards/award-completion-flow.test.js +0 -0
  180. package/test/awards/award-exclusion-handling.test.js +0 -0
  181. package/test/awards/award-multi-lesson.test.js +0 -0
  182. package/test/awards/award-observer-integration.test.js +0 -0
  183. package/test/awards/award-query-messages.test.js +0 -0
  184. package/test/awards/award-user-collection.test.js +0 -0
  185. package/test/awards/duplicate-prevention.test.js +0 -0
  186. package/test/awards/helpers/completion-mock.js +0 -0
  187. package/test/awards/helpers/index.js +0 -0
  188. package/test/awards/helpers/mock-setup.js +0 -0
  189. package/test/awards/helpers/progress-emitter.js +0 -0
  190. package/test/awards/message-generator.test.js +0 -0
  191. package/test/content.test.js +0 -0
  192. package/test/contentLikes.test.js +0 -0
  193. package/test/contentProgress.test.js +0 -0
  194. package/test/dataContext.test.js +0 -0
  195. package/test/forum.test.js +0 -0
  196. package/test/imageSRCBuilder.test.js +0 -0
  197. package/test/imageSRCVerify.test.js +0 -0
  198. package/test/initializeTests.js +0 -0
  199. package/test/learningPaths.test.js +0 -0
  200. package/test/lib/__snapshots__/filter.test.ts.snap +0 -0
  201. package/test/lib/filter.test.ts +0 -0
  202. package/test/lib/lastUpdated.test.js +0 -0
  203. package/test/lib/query.test.ts +0 -0
  204. package/test/live/contentProgressLive.test.js +0 -0
  205. package/test/live/railcontentLive.test.js +0 -0
  206. package/test/log.js +0 -0
  207. package/test/logout.test.js +199 -0
  208. package/test/mockData/award-definitions.js +0 -0
  209. package/test/mockData/mockData_fetchByRailContentIds_one_content.json +0 -0
  210. package/test/mockData/mockData_progress_content.json +0 -0
  211. package/test/mockData/mockData_sanity_progress_content.json +0 -0
  212. package/test/mockData/mockData_user_practices.json +0 -0
  213. package/test/notifications.test.js +0 -0
  214. package/test/progressRows.test.js +0 -0
  215. package/test/reporting.test.js +132 -0
  216. package/test/sanityQueryService.test.js +0 -0
  217. package/test/streakMessage.test.js +0 -0
  218. package/test/sync/adapter.ts +0 -0
  219. package/test/sync/initialize-sync-manager.js +0 -0
  220. package/test/sync/models/award-database-integration.test.js +0 -0
  221. package/test/user/permissions.test.js +0 -0
  222. package/test/userActivity.test.js +0 -0
  223. package/test_owned_navigate.js +74 -0
  224. package/tools/generate-index.cjs +0 -0
  225. package/tsconfig.json +17 -0
@@ -0,0 +1,16 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Read(//app/musora-platform-backend/**)",
5
+ "Read(//app/musora-platform-frontend/**)",
6
+ "Bash(find:*)",
7
+ "Bash(sed:*)",
8
+ "Read(//app/**)",
9
+ "Bash(cat:*)",
10
+ "Bash(docker exec:*)",
11
+ "Bash(npm config:*)"
12
+ ],
13
+ "deny": [],
14
+ "ask": []
15
+ }
16
+ }
package/.coderabbit.yaml CHANGED
File without changes
package/.editorconfig CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
package/.prettierignore CHANGED
File without changes
package/.prettierrc CHANGED
File without changes
package/.yarnrc.yml ADDED
@@ -0,0 +1 @@
1
+ nodeLinker: node-modules
package/CHANGELOG.md CHANGED
@@ -2,6 +2,58 @@
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.118.1](https://github.com/railroadmedia/musora-content-services/compare/v2.118.0...v2.118.1) (2026-01-14)
6
+
7
+ ## [2.118.0](https://github.com/railroadmedia/musora-content-services/compare/v2.107.4...v2.118.0) (2026-01-14)
8
+
9
+
10
+ ### Features
11
+
12
+ * adds column and implements for hiding cards ([#679](https://github.com/railroadmedia/musora-content-services/issues/679)) ([35ac42c](https://github.com/railroadmedia/musora-content-services/commit/35ac42cebe397c557d0b197d4fab38907ca08ab7))
13
+ * **BEH-1421:** lesson type migrations ([#660](https://github.com/railroadmedia/musora-content-services/issues/660)) ([7f5ab7e](https://github.com/railroadmedia/musora-content-services/commit/7f5ab7e64693b51aea754e0fb13f10edbd7a7958))
14
+ * **BEH-1442:** old method migration + course collection updates ([#673](https://github.com/railroadmedia/musora-content-services/issues/673)) ([24dd6bf](https://github.com/railroadmedia/musora-content-services/commit/24dd6bf6a1604ef3ee639979cf2ffab5abc05a24))
15
+ * **BEH-1491:** proper card ordering (and hiding) on progress row ([#686](https://github.com/railroadmedia/musora-content-services/issues/686)) ([e519c35](https://github.com/railroadmedia/musora-content-services/commit/e519c352ac5e8d09a910b89fa03baf31490da102))
16
+ * extra data for method card ([#691](https://github.com/railroadmedia/musora-content-services/issues/691)) ([36b034c](https://github.com/railroadmedia/musora-content-services/commit/36b034c83b86f0ff825dfc00af6a6b97b793c4c6))
17
+ * **MU2-1323:** Add dynamic filtering to lessons/songs excluding those without avaialable content ([072a471](https://github.com/railroadmedia/musora-content-services/commit/072a471a8b37bb31fc1421375563be0b2f124beb))
18
+ * **MU2-1323:** Remove redundant constant ([768befd](https://github.com/railroadmedia/musora-content-services/commit/768befdf393723cb0e091605f3c7e6ef4d523a92))
19
+ * **MU2-1323:** Use filterTypes for get all content types ([8065100](https://github.com/railroadmedia/musora-content-services/commit/80651009fcc9dae6661b3cbaecf55d5c3585d044))
20
+ * **T3Ps-1324:** Rename Tiered Courses filter to Course Collections ([97efe76](https://github.com/railroadmedia/musora-content-services/commit/97efe76fff3860d769593809bea2e59fb317b528))
21
+ * **T3PS-1413:** homepage progress row learning path lessons need need_access flag ([#688](https://github.com/railroadmedia/musora-content-services/issues/688)) ([cde7359](https://github.com/railroadmedia/musora-content-services/commit/cde73595c76c634b711e580497e291fa074b3d51))
22
+ * **TP-1046:** expose error hooks ([#655](https://github.com/railroadmedia/musora-content-services/issues/655)) ([233fa10](https://github.com/railroadmedia/musora-content-services/commit/233fa1009038448c763d130ec942b9de5a49a875))
23
+ * Use Get requests for Sanity if query under character limit ([#694](https://github.com/railroadmedia/musora-content-services/issues/694)) ([da5c384](https://github.com/railroadmedia/musora-content-services/commit/da5c384e7f538cf7c72a3d8f742787f24a4ed570))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * adds methods to set/remove http token ([0a460b6](https://github.com/railroadmedia/musora-content-services/commit/0a460b6d002fb7d85c340095d62c1e92ce253d64))
29
+ * **auth:** await for local storage ([69ee2ca](https://github.com/railroadmedia/musora-content-services/commit/69ee2ca780c71a707dfa452ede98240f0cfe8436))
30
+ * **auth:** client platform header on login ([52d5927](https://github.com/railroadmedia/musora-content-services/commit/52d5927fddd79db807440cccd541c09ae8ce770a))
31
+ * **auth:** login data ([a1b72d8](https://github.com/railroadmedia/musora-content-services/commit/a1b72d8145e230cfc850e208f147080c7ef8c6df))
32
+ * **BEH-878:** correct brand song type names ([#695](https://github.com/railroadmedia/musora-content-services/issues/695)) ([2b1cde9](https://github.com/railroadmedia/musora-content-services/commit/2b1cde9978dd744129bd906aff3a9bb03e01b04e))
33
+ * change js import to ts ([#683](https://github.com/railroadmedia/musora-content-services/issues/683)) ([1285cbe](https://github.com/railroadmedia/musora-content-services/commit/1285cbee851a3a2c68a0e36f37909e67173f82b8))
34
+ * changes lesson type mapping ([#690](https://github.com/railroadmedia/musora-content-services/issues/690)) ([af4dda9](https://github.com/railroadmedia/musora-content-services/commit/af4dda9e03eecfd49a341d2c1aea8afcf217e233))
35
+ * daniel merged bad ([#675](https://github.com/railroadmedia/musora-content-services/issues/675)) ([1c5863b](https://github.com/railroadmedia/musora-content-services/commit/1c5863bc921967fe16875367d9589c8dcf4e0ac3))
36
+ * establishes a positive progress validation ([#672](https://github.com/railroadmedia/musora-content-services/issues/672)) ([e9bc211](https://github.com/railroadmedia/musora-content-services/commit/e9bc211659262b282e1073c2746c3c8824371c35))
37
+ * fix explore all results ([#698](https://github.com/railroadmedia/musora-content-services/issues/698)) ([e9eb8a5](https://github.com/railroadmedia/musora-content-services/commit/e9eb8a5744b1d24c2b1b8e7ba5573cd128454463))
38
+ * fixes small bug with aggregator & adds safety for saveContentProgress ([#681](https://github.com/railroadmedia/musora-content-services/issues/681)) ([b3fd0a7](https://github.com/railroadmedia/musora-content-services/commit/b3fd0a7acf1fe01e2aff567148554fb291bac8a7))
39
+ * oops ([#693](https://github.com/railroadmedia/musora-content-services/issues/693)) ([0be66cb](https://github.com/railroadmedia/musora-content-services/commit/0be66cbaef0b33dad3074a22b9670cee4ddd0024))
40
+ * **pins:** user pins local storage ([#704](https://github.com/railroadmedia/musora-content-services/issues/704)) ([ca7c172](https://github.com/railroadmedia/musora-content-services/commit/ca7c1722b759c1a4711a1f6ee2213b7392d2632e))
41
+ * resolve foryou issue on mpf ([#703](https://github.com/railroadmedia/musora-content-services/issues/703)) ([3e8f0dd](https://github.com/railroadmedia/musora-content-services/commit/3e8f0ddc60eb51a5c510df6433e1cca1c5f5496a))
42
+ * Single lessons, Skill Packs and Entertainment tabs not display content and Courses display any content type ([9793443](https://github.com/railroadmedia/musora-content-services/commit/97934438bf8262fa27349eab562cecf1323c720a))
43
+ * some fixes from Rob ([#676](https://github.com/railroadmedia/musora-content-services/issues/676)) ([7e068ee](https://github.com/railroadmedia/musora-content-services/commit/7e068eee3cabc4de1d0620fe58eadf138532ab56))
44
+ * **T3PS-1187:** award progress optimizations ([#689](https://github.com/railroadmedia/musora-content-services/issues/689)) ([5d063b8](https://github.com/railroadmedia/musora-content-services/commit/5d063b8227e9ee5c70c30bc31263296bfcb4aa63))
45
+ * **T3PS-1289:** navigateTo calculation ([#677](https://github.com/railroadmedia/musora-content-services/issues/677)) ([12f4ca3](https://github.com/railroadmedia/musora-content-services/commit/12f4ca38b05a2175b33a9260e7c00f9aebfb8a87))
46
+ * **T3PS-1347:** Update getUserWeeklyStats to include query for past 60 days for streak calculation, retain original contract of the function ([d798acf](https://github.com/railroadmedia/musora-content-services/commit/d798acf2a01f25551746030722a41ccb81030ed9))
47
+ * **T3PS:** Cleanup ([07f057f](https://github.com/railroadmedia/musora-content-services/commit/07f057f867c8a3931ae6cbf5ecca9ae471f23d00))
48
+ * **TP-1051:** group contentProgress upsert pushes ([#665](https://github.com/railroadmedia/musora-content-services/issues/665)) ([27ff11f](https://github.com/railroadmedia/musora-content-services/commit/27ff11fb1b10075313e614cf895356a221f0c0d1))
49
+
50
+ ### [2.117.8](https://github.com/railroadmedia/musora-content-services/compare/v2.117.7...v2.117.8) (2026-01-13)
51
+
52
+
53
+ ### Bug Fixes
54
+
55
+ * **auth:** await for local storage ([69ee2ca](https://github.com/railroadmedia/musora-content-services/commit/69ee2ca780c71a707dfa452ede98240f0cfe8436))
56
+
5
57
  ### [2.117.7](https://github.com/railroadmedia/musora-content-services/compare/v2.117.6...v2.117.7) (2026-01-13)
6
58
 
7
59
 
package/CLAUDE.md CHANGED
File without changes
package/README.md CHANGED
File without changes
package/babel.config.cjs CHANGED
File without changes
@@ -0,0 +1,30 @@
1
+ const { initializeService } = require('./src/services/config.js');
2
+ const { fetchByRailContentIds } = require('./src/services/sanity.js');
3
+ require('dotenv/config');
4
+
5
+ async function checkContent() {
6
+ initializeService({
7
+ sanityConfig: {
8
+ token: process.env.SANITY_TOKEN,
9
+ projectId: process.env.SANITY_PROJECT_ID,
10
+ dataset: process.env.SANITY_DATASET,
11
+ version: process.env.SANITY_VERSION || '2021-06-07',
12
+ },
13
+ railcontentConfig: {
14
+ token: process.env.RAILCONTENT_TOKEN,
15
+ userId: process.env.RAILCONTENT_USER_ID,
16
+ baseUrl: process.env.RAILCONTENT_BASE_URL,
17
+ authToken: process.env.RAILCONTENT_AUTH_TOKEN,
18
+ },
19
+ baseUrl: process.env.RAILCONTENT_BASE_URL,
20
+ localStorage: null,
21
+ isMA: false,
22
+ });
23
+
24
+ console.log('Checking railcontent_id: 421814');
25
+ const contents = await fetchByRailContentIds([421814]);
26
+ console.log('Results:', JSON.stringify(contents, null, 2));
27
+ console.log('Found:', contents.length, 'items');
28
+ }
29
+
30
+ checkContent().catch(console.error);
@@ -0,0 +1,32 @@
1
+ import { initializeService } from './src/services/config.js';
2
+ import { fetchByRailContentIds } from './src/services/sanity.js';
3
+ import dotenv from 'dotenv';
4
+
5
+ dotenv.config();
6
+
7
+ async function checkContent() {
8
+ initializeService({
9
+ sanityConfig: {
10
+ token: process.env.SANITY_TOKEN,
11
+ projectId: process.env.SANITY_PROJECT_ID,
12
+ dataset: process.env.SANITY_DATASET,
13
+ version: process.env.SANITY_VERSION || '2021-06-07',
14
+ },
15
+ railcontentConfig: {
16
+ token: process.env.RAILCONTENT_TOKEN,
17
+ userId: process.env.RAILCONTENT_USER_ID,
18
+ baseUrl: process.env.RAILCONTENT_BASE_URL,
19
+ authToken: process.env.RAILCONTENT_AUTH_TOKEN,
20
+ },
21
+ baseUrl: process.env.RAILCONTENT_BASE_URL,
22
+ localStorage: null,
23
+ isMA: false,
24
+ });
25
+
26
+ console.log('Checking railcontent_id: 421814');
27
+ const contents = await fetchByRailContentIds([421814]);
28
+ console.log('Results:', JSON.stringify(contents, null, 2));
29
+ console.log('Found:', contents.length, 'items');
30
+ }
31
+
32
+ checkContent().catch(console.error);
package/jsdoc.json CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.117.7",
3
+ "version": "2.118.1",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
File without changes
File without changes
@@ -53,7 +53,7 @@ export class Tabs {
53
53
  static Collections = { name: 'Collections', short_name: 'Collections', value: 'type,collections', cardType: 'big' }
54
54
  static ExploreAll = { name: 'Explore All', short_name: 'Explore All', value: 'tab,explore all', icon: 'icon-filters', cardType: 'big'}
55
55
  static All = { name: 'All', short_name: 'All', value: '' }
56
- static Courses = { name: 'Courses', short_name: 'Courses', value: 'type,Courses' }
56
+ static Courses = { name: 'Courses', short_name: 'Courses', value: 'type,Courses', recSysSection: 'lesson', }
57
57
  static SkillLevel = { name: 'Skill Level', short_name: 'SKILL LEVEL', is_group_by: true, value: 'difficulty_string' }
58
58
  static Genres = { name: 'Genres', short_name: 'Genres', is_group_by: true, value: 'genre' }
59
59
  static Completed = {
@@ -82,12 +82,14 @@ export class Tabs {
82
82
  short_name: 'Tutorials',
83
83
  value: 'type,tutorials',
84
84
  cardType: 'big',
85
+ recSysSection: 'song',
85
86
  }
86
87
  static Transcriptions = {
87
88
  name: 'Transcriptions',
88
89
  short_name: 'Transcriptions',
89
90
  value: 'type,transcriptions',
90
91
  cardType: 'small',
92
+ recSysSection: 'song',
91
93
  }
92
94
  static SheetMusic = {
93
95
  name: 'Sheet Music',
@@ -100,12 +102,14 @@ export class Tabs {
100
102
  short_name: 'Tabs',
101
103
  value: 'type,transcriptions',
102
104
  cardType: 'small',
105
+ recSysSection: 'song',
103
106
  }
104
107
  static PlayAlongs = {
105
108
  name: 'Play-Alongs',
106
109
  short_name: 'Play-Alongs',
107
- value: 'type,play along',
110
+ value: 'type,play-along',
108
111
  cardType: 'small',
112
+ recSysSection: 'song',
109
113
  }
110
114
  static JamTracks = {
111
115
  name: 'Jam Tracks',
@@ -121,9 +125,9 @@ export class Tabs {
121
125
  static RecentActivityPosts = { name: 'Posts', short_name: 'Posts' }
122
126
  static RecentActivityComments = { name: 'Comments', short_name: 'Comments' }
123
127
  // new tabs - 29.10
124
- static SingleLessons = { name: 'Single Lessons', short_name: 'Single Lessons', value: 'type,Single Lessons' }
125
- static SkillPacks = { name: 'Skill Packs', short_name: 'Skill Packs', value: 'type,Skill Packs' }
126
- static Entertainment = { name: 'Entertainment', short_name: 'Entertainment', value: 'type,Entertainment' }
128
+ static SingleLessons = { name: 'Single Lessons', short_name: 'Single Lessons', value: 'type,Single Lessons', recSysSection: 'lesson', }
129
+ static SkillPacks = { name: 'Skill Packs', short_name: 'Skill Packs', value: 'type,Skill Packs', recSysSection: 'lesson', }
130
+ static Entertainment = { name: 'Entertainment', short_name: 'Entertainment', value: 'type,Entertainment', recSysSection: 'lesson', }
127
131
  }
128
132
 
129
133
  /**
File without changes
package/src/index.d.ts CHANGED
@@ -128,6 +128,7 @@ import {
128
128
  } from './services/contentProgress.js';
129
129
 
130
130
  import {
131
+ clearAllCachedData,
131
132
  verifyLocalDataContext
132
133
  } from './services/dataContext.js';
133
134
 
@@ -444,6 +445,7 @@ declare module 'musora-content-services' {
444
445
  buildEntityAndTotalQuery,
445
446
  buildImageSRC,
446
447
  calculateLongestStreaks,
448
+ clearAllCachedData,
447
449
  closeComment,
448
450
  completeLearningPathIntroVideo,
449
451
  completeMethodIntroVideo,
package/src/index.js CHANGED
@@ -132,6 +132,7 @@ import {
132
132
  } from './services/contentProgress.js';
133
133
 
134
134
  import {
135
+ clearAllCachedData,
135
136
  verifyLocalDataContext
136
137
  } from './services/dataContext.js';
137
138
 
@@ -443,6 +444,7 @@ export {
443
444
  buildEntityAndTotalQuery,
444
445
  buildImageSRC,
445
446
  calculateLongestStreaks,
447
+ clearAllCachedData,
446
448
  closeComment,
447
449
  completeLearningPathIntroVideo,
448
450
  completeMethodIntroVideo,
File without changes
File without changes
File without changes
File without changes
File without changes
package/src/lib/brands.ts 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
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
@@ -18,7 +18,10 @@ import {recommendations, rankCategories, rankItems} from "./recommendations";
18
18
  import {addContextToContent} from "./contentAggregator.js";
19
19
  import {globalConfig} from "./config";
20
20
  import {getUserData} from "./user/management";
21
- import {filterTypes, ownedContentTypes} from "../contentTypeConfig";
21
+ import {
22
+ lessonTypesMapping,
23
+ ownedContentTypes
24
+ } from "../contentTypeConfig";
22
25
  import {getPermissionsAdapter} from "./permissions/index.ts";
23
26
  import {MEMBERSHIP_PERMISSIONS} from "../constants/membership-permissions.ts";
24
27
 
@@ -100,6 +103,7 @@ export async function getTabResults(brand, pageName, tabName, {
100
103
  tabObj => tabObj.name.toLowerCase() === tabName.toLowerCase()
101
104
  )
102
105
  const tabValue = tabMatch?.value || ''
106
+ const tabRecSysSection = tabMatch?.recSysSection || ''
103
107
  const mergedIncludedFields = tabValue ? [...filteredSelectedFilters, tabValue] : filteredSelectedFilters;
104
108
 
105
109
  // Fetch data
@@ -112,23 +116,58 @@ export async function getTabResults(brand, pageName, tabName, {
112
116
  addProgressPercentage: true,
113
117
  addProgressStatus: true
114
118
  })
119
+ } else if (sort === 'recommended') {
120
+ const contentTypes = lessonTypesMapping[tabName.toLowerCase()] || []
121
+ const allRecommendations = await recommendations(brand, { contentTypes, section: tabRecSysSection })
122
+
123
+ let contentToDisplay
124
+ if (allRecommendations.length > 0) {
125
+ // Fetch and sort recommended content
126
+ let recommendedContent = await fetchByRailContentIds(allRecommendations, 'tab-data', brand, true)
127
+ recommendedContent.sort((a, b) => allRecommendations.indexOf(a.id) - allRecommendations.indexOf(b.id))
128
+
129
+ const start = (page - 1) * limit
130
+ const end = start + limit
131
+
132
+ // Need more content beyond recommendations?
133
+ if (recommendedContent.length < end) {
134
+ const additionalNeeded = end - recommendedContent.length;
135
+ const tabData = await fetchTabData(brand, pageName, {
136
+ page: Math.ceil(additionalNeeded / limit),
137
+ limit: additionalNeeded + limit,
138
+ sort: '-published_on',
139
+ includedFields: mergedIncludedFields,
140
+ progress: progressValue
141
+ })
142
+
143
+ // Filter out duplicates and combine
144
+ const recommendedIds = new Set(recommendedContent.map(c => c.id))
145
+ const additionalContent = tabData.entity.filter(c => !recommendedIds.has(c.id))
146
+
147
+ contentToDisplay = [...recommendedContent, ...additionalContent].slice(start, end)
148
+ } else {
149
+ contentToDisplay = recommendedContent.slice(start, end)
150
+ }
151
+ } else {
152
+ // No recommendations - use normal flow
153
+ const temp = await fetchTabData(brand, pageName, { page, limit, sort: '-published_on', includedFields: mergedIncludedFields, progress: progressValue })
154
+ contentToDisplay = temp.entity
155
+ }
156
+
157
+ results = await addContextToContent(() => contentToDisplay, {
158
+ addNextLesson: true,
159
+ addNavigateTo: true,
160
+ addProgressPercentage: true,
161
+ addProgressStatus: true
162
+ })
115
163
  } else {
116
164
  let temp = await fetchTabData(brand, pageName, { page, limit, sort, includedFields: mergedIncludedFields, progress: progressValue });
117
165
 
118
- const [ranking, contextResults] = await Promise.all([
119
- sort === 'recommended' ? rankItems(brand, temp.entity.map(e => e.id)) : [],
120
- addContextToContent(() => temp.entity, {
121
- addNextLesson: true,
122
- addNavigateTo: true,
123
- addProgressPercentage: true,
124
- addProgressStatus: true
125
- })
126
- ]);
127
-
128
- results = ranking.length === 0 ? contextResults : contextResults.sort((a, b) => {
129
- const indexA = ranking.indexOf(a.id);
130
- const indexB = ranking.indexOf(b.id);
131
- return (indexA === -1 ? Infinity : indexA) - (indexB === -1 ? Infinity : indexB);
166
+ results = await addContextToContent(() => temp.entity, {
167
+ addNextLesson: true,
168
+ addNavigateTo: true,
169
+ addProgressPercentage: true,
170
+ addProgressStatus: true
132
171
  })
133
172
  }
134
173
 
File without changes
File without changes
File without changes
@@ -147,3 +147,44 @@ export class DataContext {
147
147
  }
148
148
  }
149
149
  }
150
+
151
+ /**
152
+ * Clears all dataContext cached data from localStorage.
153
+ * Should be called on logout to prevent data leakage between users.
154
+ * Note: Does not clear user_pin_progress_row keys as they are user-specific.
155
+ */
156
+ export async function clearAllCachedData() {
157
+ const storage = globalConfig.localStorage
158
+
159
+ if (storage) {
160
+ const keysToRemove = []
161
+
162
+ // For React Native AsyncStorage
163
+ if (globalConfig.isMA && storage.getAllKeys) {
164
+ const allKeys = await storage.getAllKeys()
165
+ keysToRemove.push(...allKeys.filter(key =>
166
+ key.startsWith('dataContext_')
167
+ ))
168
+ }
169
+ // For web localStorage
170
+ else if (typeof storage.length !== 'undefined') {
171
+ const allKeys = []
172
+ for (let i = 0; i < storage.length; i++) {
173
+ const key = storage.key(i)
174
+ if (key) {
175
+ allKeys.push(key)
176
+ }
177
+ }
178
+ keysToRemove.push(...allKeys.filter(key =>
179
+ key.startsWith('dataContext_')
180
+ ))
181
+ }
182
+
183
+ // Use multiRemove for React Native AsyncStorage, removeItem for web localStorage
184
+ if (storage.multiRemove && typeof storage.multiRemove === 'function') {
185
+ await storage.multiRemove(keysToRemove)
186
+ } else {
187
+ keysToRemove.forEach(key => storage.removeItem(key))
188
+ }
189
+ }
190
+ }
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
@@ -18,6 +18,14 @@ import { PUT } from '../../infrastructure/http/HttpClient.ts'
18
18
 
19
19
  export const USER_PIN_PROGRESS_KEY = 'user_pin_progress_row'
20
20
 
21
+ /**
22
+ * Gets the localStorage key for user pinned progress, scoped by user ID
23
+ */
24
+ function getUserPinProgressKey() {
25
+ const userId = globalConfig.sessionConfig?.userId || globalConfig.railcontentConfig?.userId
26
+ return userId ? `user_pin_progress_row_${userId}` : USER_PIN_PROGRESS_KEY
27
+ }
28
+
21
29
  /**
22
30
  * Fetches and combines recent user progress rows and playlists, excluding certain types and parents.
23
31
  *
@@ -102,7 +110,8 @@ export async function unpinProgressRow(brand) {
102
110
  }
103
111
 
104
112
  async function getUserPinnedItem(brand) {
105
- const pinnedProgressRaw = await globalConfig.localStorage.getItem(USER_PIN_PROGRESS_KEY)
113
+ const key = getUserPinProgressKey()
114
+ const pinnedProgressRaw = await globalConfig.localStorage.getItem(key)
106
115
  let pinnedProgress = pinnedProgressRaw ? JSON.parse(pinnedProgressRaw) : {}
107
116
  pinnedProgress = pinnedProgress || {}
108
117
  return pinnedProgress[brand] ?? null
@@ -200,9 +209,10 @@ function mergeAndSortItems(items, limit) {
200
209
  }
201
210
 
202
211
  async function updateUserPinnedProgressRow(brand, pinnedData) {
203
- const pinnedProgressRaw = await globalConfig.localStorage.getItem(USER_PIN_PROGRESS_KEY)
212
+ const key = getUserPinProgressKey()
213
+ const pinnedProgressRaw = await globalConfig.localStorage.getItem(key)
204
214
  let pinnedProgress = pinnedProgressRaw ? JSON.parse(pinnedProgressRaw) : {}
205
215
  pinnedProgress = pinnedProgress || {}
206
216
  pinnedProgress[brand] = pinnedData
207
- await globalConfig.localStorage.setItem(USER_PIN_PROGRESS_KEY, JSON.stringify(pinnedProgress))
217
+ await globalConfig.localStorage.setItem(key, JSON.stringify(pinnedProgress))
208
218
  }
File without changes
File without changes
File without changes
File without changes