musora-content-services 2.161.2 → 2.161.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.
@@ -0,0 +1,25 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npx jest *)",
5
+ "Bash(npx tsc *)",
6
+ "Skill(counselors)",
7
+ "Bash(counselors ls *)",
8
+ "Bash(counselors groups *)",
9
+ "Bash(counselors run *)",
10
+ "Bash(npm test *)",
11
+ "Bash(gh pr *)",
12
+ "Bash(gh api *)",
13
+ "Bash(mkdir -p /tmp/pr-review-v2)",
14
+ "Read(//tmp/pr-review-v2/**)",
15
+ "Bash(cat /home/alesevero/railenvironment/applications/musora-content-services/AGENTS.md)",
16
+ "Bash(echo \"no AGENTS.md\")",
17
+ "Bash(echo \"exit=$?\")",
18
+ "Bash(git checkout *)",
19
+ "Skill(pr)",
20
+ "Skill(create-decision)"
21
+ ]
22
+ },
23
+ "effortLevel": "medium",
24
+ "model": "sonnet"
25
+ }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
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.161.3](https://github.com/railroadmedia/musora-content-services/compare/v2.161.2...v2.161.3) (2026-06-02)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **MU2-1487:** fetchAll to by pass permissions filter ([#991](https://github.com/railroadmedia/musora-content-services/issues/991)) ([39f38ca](https://github.com/railroadmedia/musora-content-services/commit/39f38cad21b97591eae113c32212b1fdc76be035))
11
+
5
12
  ### [2.161.2](https://github.com/railroadmedia/musora-content-services/compare/v2.161.1...v2.161.2) (2026-05-27)
6
13
 
7
14
  ### [2.161.1](https://github.com/railroadmedia/musora-content-services/compare/v2.161.0...v2.161.1) (2026-05-27)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.161.2",
3
+ "version": "2.161.3",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -34,14 +34,24 @@ import {
34
34
  tutorialsLessonTypes,
35
35
  } from '../contentTypeConfig.js'
36
36
  import { fetchSimilarItems } from './recommendations.js'
37
- import { ALWAYS_VISIBLE_TABS, CONTENT_STATUSES, getSongType, processMetadata } from '../contentMetaData.js'
37
+ import {
38
+ ALWAYS_VISIBLE_TABS,
39
+ CONTENT_STATUSES,
40
+ getSongType,
41
+ processMetadata,
42
+ } from '../contentMetaData.js'
38
43
  import { GET } from '../infrastructure/http/HttpClient.ts'
39
44
 
40
45
  import { globalConfig } from './config.js'
41
46
 
42
47
  import { arrayToStringRepresentation, FilterBuilder } from '../filterBuilder.js'
43
48
  import { getPermissionsAdapter } from './permissions/index.ts'
44
- import { getAllCompleted, getAllCompletedByIds, getAllStarted, getAllStartedOrCompleted } from './contentProgress.js'
49
+ import {
50
+ getAllCompleted,
51
+ getAllCompletedByIds,
52
+ getAllStarted,
53
+ getAllStartedOrCompleted,
54
+ } from './contentProgress.js'
45
55
  import { fetchRecentActivitiesActiveTabs } from './userActivity.js'
46
56
  import { query } from '../lib/sanity/query'
47
57
  import { Filters as f } from '../lib/sanity/filter'
@@ -101,7 +111,7 @@ export async function fetchSongById(documentId) {
101
111
  fields,
102
112
  {
103
113
  isSingle: true,
104
- },
114
+ }
105
115
  )
106
116
  return fetchSanity(query, false)
107
117
  }
@@ -128,7 +138,7 @@ export async function fetchLeaving(brand, { pageNumber = 1, contentPerPage = 20
128
138
  filterString,
129
139
  { pullFutureContent: false, availableContentStatuses: CONTENT_STATUSES.PUBLISHED_ONLY },
130
140
  getFieldsForContentType('leaving'),
131
- sortOrder,
141
+ sortOrder
132
142
  )
133
143
  return fetchSanity(query, true)
134
144
  }
@@ -155,7 +165,7 @@ export async function fetchReturning(brand, { pageNumber = 1, contentPerPage = 2
155
165
  filterString,
156
166
  { pullFutureContent: true, availableContentStatuses: CONTENT_STATUSES.DRAFT_ONLY },
157
167
  getFieldsForContentType('returning'),
158
- sortOrder,
168
+ sortOrder
159
169
  )
160
170
 
161
171
  return fetchSanity(query, true)
@@ -181,7 +191,7 @@ export async function fetchComingSoon(brand, { pageNumber = 1, contentPerPage =
181
191
  filterString,
182
192
  { getFutureContentOnly: true },
183
193
  getFieldsForContentType(),
184
- sortOrder,
194
+ sortOrder
185
195
  )
186
196
  return fetchSanity(query, true)
187
197
  }
@@ -208,7 +218,7 @@ function getQueryFromPage(pageNumber, contentPerPage) {
208
218
  export async function fetchSongArtistCount(brand) {
209
219
  const filter = await new FilterBuilder(
210
220
  `_type == "song" && brand == "${brand}" && references(^._id)`,
211
- { bypassPermissions: true },
221
+ { bypassPermissions: true }
212
222
  ).buildFilter()
213
223
  const query = `
214
224
  count(*[_type == "artist"]{
@@ -220,7 +230,7 @@ export async function fetchSongArtistCount(brand) {
220
230
 
221
231
  export async function fetchPlayAlongsCount(
222
232
  brand,
223
- { searchTerm, includedFields, progressIds, progress },
233
+ { searchTerm, includedFields, progressIds, progress }
224
234
  ) {
225
235
  const searchFilter = searchTerm
226
236
  ? `&& (artist->name match "${searchTerm}*" || instructor[]->name match "${searchTerm}*" || title match "${searchTerm}*" || name match "${searchTerm}*")`
@@ -325,7 +335,7 @@ export async function fetchRelatedSongs(brand, songId) {
325
335
  */
326
336
  export async function fetchNewReleases(
327
337
  brand,
328
- { page = 1, limit = 20, sort = '-published_on' } = {},
338
+ { page = 1, limit = 20, sort = '-published_on' } = {}
329
339
  ) {
330
340
  const newTypes = getNewReleasesTypes(brand)
331
341
  const typesString = arrayToStringRepresentation(newTypes)
@@ -402,7 +412,7 @@ export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {})
402
412
  sortOrder: 'published_on asc',
403
413
  start: start,
404
414
  end: end,
405
- },
415
+ }
406
416
  )
407
417
  return fetchSanity(query, true, { processNeedAccess: true })
408
418
  }
@@ -481,7 +491,7 @@ export async function fetchByRailContentId(id, contentType) {
481
491
  entityFieldsString,
482
492
  {
483
493
  isSingle: true,
484
- },
494
+ }
485
495
  )
486
496
 
487
497
  return fetchSanity(query, false)
@@ -504,7 +514,7 @@ export async function fetchByRailContentIds(
504
514
  contentType = undefined,
505
515
  brand = undefined,
506
516
  includePermissionsAndStatusFilter = false,
507
- filterOptions = {},
517
+ filterOptions = {}
508
518
  ) {
509
519
  if (!ids?.length) {
510
520
  return []
@@ -652,7 +662,7 @@ export async function fetchAll(
652
662
  customFields = [],
653
663
  progress = 'all',
654
664
  onlyPublished = true,
655
- } = {},
665
+ } = {}
656
666
  ) {
657
667
  let config = contentTypeConfig[type] ?? {}
658
668
  let additionalFields = config?.fields ?? []
@@ -662,7 +672,6 @@ export async function fetchAll(
662
672
  const end = start + limit
663
673
  let bypassStatusAndPublishedValidation =
664
674
  type == 'instructor' || groupBy == 'artist' || groupBy == 'genre' || groupBy == 'instructor'
665
- let bypassPermissions = bypassStatusAndPublishedValidation
666
675
  // Construct the type filter
667
676
  let typeFilter
668
677
 
@@ -761,7 +770,7 @@ export async function fetchAll(
761
770
 
762
771
  const filterWithRestrictions = await new FilterBuilder(filter, {
763
772
  bypassStatuses: bypassStatusAndPublishedValidation,
764
- bypassPermissions: bypassPermissions,
773
+ bypassPermissions: true,
765
774
  bypassPublishedDateRestriction: bypassStatusAndPublishedValidation,
766
775
  }).buildFilter()
767
776
  query = buildEntityAndTotalQuery(filterWithRestrictions, entityFieldsString, {
@@ -770,7 +779,7 @@ export async function fetchAll(
770
779
  end: end,
771
780
  })
772
781
 
773
- return fetchSanity(query, true)
782
+ return fetchSanity(query, true, { processNeedAccess: true })
774
783
  }
775
784
 
776
785
  async function getProgressFilter(progress, progressIds) {
@@ -870,7 +879,7 @@ export async function fetchAllFilterOptions(
870
879
  term,
871
880
  progressIds,
872
881
  coachId,
873
- includeTabs = false,
882
+ includeTabs = false
874
883
  ) {
875
884
  if (contentType == 'lessons' || contentType == 'songs') {
876
885
  const metaData = processMetadata(brand, contentType, true)
@@ -881,7 +890,7 @@ export async function fetchAllFilterOptions(
881
890
 
882
891
  if (coachId && contentType !== 'coach-lessons') {
883
892
  throw new Error(
884
- `Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`,
893
+ `Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`
885
894
  )
886
895
  }
887
896
 
@@ -1016,7 +1025,7 @@ export async function fetchRelatedRecommendedContent(railContentId, brand, count
1016
1025
  }
1017
1026
 
1018
1027
  return await fetchRelatedLessons(railContentId, brand).then((result) =>
1019
- result.related_lessons?.splice(0, count),
1028
+ result.related_lessons?.splice(0, count)
1020
1029
  )
1021
1030
  }
1022
1031
 
@@ -1141,15 +1150,15 @@ export async function fetchRelatedLessons(railContentId) {
1141
1150
  }
1142
1151
  const filterSameArtist = await new FilterBuilder(
1143
1152
  `${defaultFilterFields} && references(^.artist->_id)`,
1144
- params,
1153
+ params
1145
1154
  ).buildFilter()
1146
1155
  const filterSameGenre = await new FilterBuilder(
1147
1156
  `${defaultFilterFields} && references(^.genre[]->_id)`,
1148
- params,
1157
+ params
1149
1158
  ).buildFilter()
1150
1159
  const filterSameDifficulty = await new FilterBuilder(
1151
1160
  `${defaultFilterFields} && difficulty == ^.difficulty`,
1152
- params,
1161
+ params
1153
1162
  ).buildFilter()
1154
1163
  const queryFields = getFieldsForContentType()
1155
1164
 
@@ -1188,12 +1197,12 @@ export async function fetchLiveEvent(brand, forcedContentId = null) {
1188
1197
  let endDateTemp = new Date()
1189
1198
 
1190
1199
  startDateTemp = new Date(
1191
- startDateTemp.setMinutes(startDateTemp.getMinutes() + LIVE_EXTRA_MINUTES),
1200
+ startDateTemp.setMinutes(startDateTemp.getMinutes() + LIVE_EXTRA_MINUTES)
1192
1201
  )
1193
1202
  endDateTemp = new Date(endDateTemp.setMinutes(endDateTemp.getMinutes() - LIVE_EXTRA_MINUTES))
1194
1203
 
1195
1204
  const liveEventFields = getLiveFields().concat(
1196
- `'event_coach_calendar_id': coalesce(calendar_id, '${defaultCalendarID}')`,
1205
+ `'event_coach_calendar_id': coalesce(calendar_id, '${defaultCalendarID}')`
1197
1206
  )
1198
1207
  const fieldsString = liveEventFields.join(',')
1199
1208
 
@@ -1260,7 +1269,7 @@ export async function fetchPackData(id) {
1260
1269
  */
1261
1270
  export async function fetchByReference(
1262
1271
  brand,
1263
- { sortOrder = '-published_on', searchTerm = '', page = 1, limit = 20, includedFields = [] } = {},
1272
+ { sortOrder = '-published_on', searchTerm = '', page = 1, limit = 20, includedFields = [] } = {}
1264
1273
  ) {
1265
1274
  const fieldsString = getFieldsForContentType()
1266
1275
  const start = (page - 1) * limit
@@ -1536,11 +1545,11 @@ export async function fetchCommentModContentData(ids) {
1536
1545
  `railcontent_id in [${idsString}]`,
1537
1546
  { bypassPermissions: true },
1538
1547
  fields,
1539
- { end: 50 },
1548
+ { end: 50 }
1540
1549
  )
1541
1550
  let data = await fetchSanity(query, true)
1542
1551
  let mapped = {}
1543
- data.forEach(function(content) {
1552
+ data.forEach(function (content) {
1544
1553
  mapped[content.id] = {
1545
1554
  id: content.id,
1546
1555
  type: content.type,
@@ -1572,7 +1581,7 @@ export async function fetchCommentModContentData(ids) {
1572
1581
  export async function fetchSanity(
1573
1582
  query,
1574
1583
  isList,
1575
- { customPostProcess = null, processNeedAccess = true, processPageType = true } = {},
1584
+ { customPostProcess = null, processNeedAccess = true, processPageType = true } = {}
1576
1585
  ) {
1577
1586
  // Check the config object before proceeding
1578
1587
  if (!checkSanityConfig(globalConfig)) {
@@ -1704,7 +1713,7 @@ function contentResultsDecorator(results, fieldName, callback) {
1704
1713
  }
1705
1714
 
1706
1715
  function pageTypeDecorator(results) {
1707
- return contentResultsDecorator(results, 'page_type', function(content) {
1716
+ return contentResultsDecorator(results, 'page_type', function (content) {
1708
1717
  return SONG_TYPES_WITH_CHILDREN.includes(content['type']) ? 'song' : 'lesson'
1709
1718
  })
1710
1719
  }
@@ -1712,7 +1721,7 @@ function pageTypeDecorator(results) {
1712
1721
  function needsAccessDecorator(results, userPermissions) {
1713
1722
  if (globalConfig.sanityConfig.useDummyRailContentMethods) return results
1714
1723
  const adapter = getPermissionsAdapter()
1715
- return contentResultsDecorator(results, 'need_access', function(content) {
1724
+ return contentResultsDecorator(results, 'need_access', function (content) {
1716
1725
  return adapter.doesUserNeedAccess(content, userPermissions)
1717
1726
  })
1718
1727
  }
@@ -1789,7 +1798,7 @@ export async function fetchMetadata(brand, type, options = {}) {
1789
1798
  if (processedData.filters) {
1790
1799
  processedData.filters = filterTypeOptionsByContentCounts(
1791
1800
  processedData.filters,
1792
- contentTypeCounts,
1801
+ contentTypeCounts
1793
1802
  )
1794
1803
  }
1795
1804
  } catch (error) {
@@ -1829,7 +1838,7 @@ export function getSanityDate(date, roundToHourForCaching = true) {
1829
1838
  date.getFullYear(),
1830
1839
  date.getMonth(),
1831
1840
  date.getDate(),
1832
- date.getHours(),
1841
+ date.getHours()
1833
1842
  )
1834
1843
 
1835
1844
  return roundedDate.toISOString()
@@ -1872,7 +1881,7 @@ function checkSanityConfig(config) {
1872
1881
  function buildRawQuery(
1873
1882
  filter = '',
1874
1883
  fields = '...',
1875
- { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false },
1884
+ { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false }
1876
1885
  ) {
1877
1886
  const sortString = sortOrder ? `order(${sortOrder})` : ''
1878
1887
  const countString = isSingle ? '[0...1]' : `[${start}...${end}]`
@@ -1886,7 +1895,7 @@ async function buildQuery(
1886
1895
  baseFilter = '',
1887
1896
  filterParams = { pullFutureContent: false },
1888
1897
  fields = '...',
1889
- { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false },
1898
+ { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false }
1890
1899
  ) {
1891
1900
  const filter = await new FilterBuilder(baseFilter, filterParams).buildFilter()
1892
1901
  return buildRawQuery(filter, fields, { sortOrder, start, end, isSingle })
@@ -1901,7 +1910,7 @@ export function buildEntityAndTotalQuery(
1901
1910
  end = 10,
1902
1911
  isSingle = false,
1903
1912
  withoutPagination = false,
1904
- },
1913
+ }
1905
1914
  ) {
1906
1915
  const sortString = sortOrder ? ` | order(${sortOrder})` : ''
1907
1916
  const countString = isSingle ? '[0...1]' : withoutPagination ? `` : `[${start}...${end}]`
@@ -2023,7 +2032,7 @@ export async function fetchTabData(
2023
2032
  progressIds = undefined,
2024
2033
  progress = 'all',
2025
2034
  excludeIds = [],
2026
- } = {},
2035
+ } = {}
2027
2036
  ) {
2028
2037
  const start = (page - 1) * limit
2029
2038
  const end = start + limit
@@ -2126,7 +2135,7 @@ export async function fetchTabData(
2126
2135
  export async function fetchRecent(
2127
2136
  brand,
2128
2137
  pageName,
2129
- { page = 1, limit = 10, sort = '-published_on', includedFields = [], progress = 'recent' } = {},
2138
+ { page = 1, limit = 10, sort = '-published_on', includedFields = [], progress = 'recent' } = {}
2130
2139
  ) {
2131
2140
  const mergedIncludedFields = [...includedFields, `tab,all`]
2132
2141
  const results = await fetchTabData(brand, pageName, {
@@ -2143,7 +2152,7 @@ export async function fetchScheduledAndNewReleases(
2143
2152
  brand,
2144
2153
  // page param deprecated, doesnt have 1-1 affect on this functionality
2145
2154
  // if we want to allow pagination, this requires a revisit
2146
- { limit = 10 } = {},
2155
+ { limit = 10 } = {}
2147
2156
  ) {
2148
2157
  const maxLessons = 3
2149
2158
  const maxSongs = 5
@@ -2163,7 +2172,7 @@ export async function fetchScheduledAndNewReleases(
2163
2172
  f.typeIn(parentsWithoutSong),
2164
2173
  f.statusIn(['published']),
2165
2174
  f.publishedBefore(now),
2166
- f.publishedAfter(fifteenDaysAgo),
2175
+ f.publishedAfter(fifteenDaysAgo)
2167
2176
  )
2168
2177
 
2169
2178
  const songFilter = f.combine(
@@ -2172,14 +2181,14 @@ export async function fetchScheduledAndNewReleases(
2172
2181
  f.type('song'),
2173
2182
  f.statusIn(['published']),
2174
2183
  f.publishedBefore(now),
2175
- f.publishedAfter(fifteenDaysAgo),
2184
+ f.publishedAfter(fifteenDaysAgo)
2176
2185
  )
2177
2186
 
2178
2187
  const livestreamFilter = f.combine(
2179
2188
  'show_in_new_feed == true',
2180
2189
  f.combineOr(f.brand(brand), 'live_global_event == true'),
2181
2190
  f.statusIn(['scheduled']),
2182
- `live_event_start_time >= '${now}'`,
2191
+ `live_event_start_time >= '${now}'`
2183
2192
  )
2184
2193
 
2185
2194
  const lessonQuery = query()
@@ -2340,7 +2349,7 @@ export async function fetchMethodV2StructureFromId(contentId) {
2340
2349
  */
2341
2350
  export async function fetchOwnedContent(
2342
2351
  brand,
2343
- { type = [], page = 1, limit = 10, sort = '-published_on' } = {},
2352
+ { type = [], page = 1, limit = 10, sort = '-published_on' } = {}
2344
2353
  ) {
2345
2354
  const start = (page - 1) * limit
2346
2355
  const end = start + limit
@@ -50,6 +50,7 @@ export interface UpgradeProduct {
50
50
  price: number
51
51
  monthly_price: number
52
52
  includes_trial: boolean
53
+ tier: 'plus' | 'basic' | ''
53
54
  }
54
55
 
55
56
  export interface UpgradeOption {