musora-content-services 2.179.0 → 2.180.0
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/.agent/decisions/2026-09-04-sanity-client-cloudflare-cache.md +37 -0
- package/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/infrastructure/http/HttpClient.ts +15 -1
- package/src/infrastructure/sanity/executors/FetchQueryExecutor.ts +1 -1
- package/src/services/config.js +5 -0
- package/src/services/content-org/learning-paths.ts +83 -63
- package/src/services/sanity.js +29 -15
- package/src/services/state.ts +2 -0
- package/src/services/user/management.js +8 -2
- package/src/version-info.js +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-09-04
|
|
3
|
+
branch: refactor/sanity-client-cloudflare-cache
|
|
4
|
+
pr: https://github.com/railroadmedia/musora-content-services/pull/1046
|
|
5
|
+
status: open
|
|
6
|
+
tags: [[chore]]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Route SanityClient through Cloudflare caching proxy
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
PR #900 added a Cloudflare caching layer for Sanity queries by pointing the legacy `fetchSanity()` function (`src/services/sanity.js`) at `sanity.musora.com` instead of hitting `*.sanity.io` directly. That change only touched the legacy path. The newer `SanityClient` class (`src/infrastructure/sanity/SanityClient.ts`) builds its request URL independently in `FetchQueryExecutor.buildUrl()`, which still hit `*.sanity.io` directly and bypassed the CF cache entirely.
|
|
14
|
+
|
|
15
|
+
## Decision
|
|
16
|
+
|
|
17
|
+
Mirrored the same host rewrite from PR #900 into `FetchQueryExecutor.buildUrl()` (`src/infrastructure/sanity/executors/FetchQueryExecutor.ts`):
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
return `https://sanity.musora.com/${config.projectId}/${api}/v${config.version}/${config.dataset}?perspective=${perspective}`
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
No other files needed to change — `DefaultConfigProvider`, `SanityConfig`, and `SanityClient` itself are all host-agnostic and pass through unaffected.
|
|
24
|
+
|
|
25
|
+
## Alternatives Considered
|
|
26
|
+
|
|
27
|
+
No alternatives considered — this is a direct parity fix to bring `SanityClient` in line with the URL rewrite already proven in `fetchSanity()`.
|
|
28
|
+
|
|
29
|
+
## Process Notes
|
|
30
|
+
|
|
31
|
+
Updated `test/unit/infrastructure/sanity/FetchQueryExecutor.test.ts` — 4 assertions were hardcoded against the old `*.sanity.io` URL format and needed updating to the new `sanity.musora.com` host/path shape.
|
|
32
|
+
|
|
33
|
+
The diff also shows unrelated prettier-driven reformatting in `src/services/sanity.js` (line wrapping, trailing commas) picked up from a main sync — not part of this change's intent.
|
|
34
|
+
|
|
35
|
+
## Consequences
|
|
36
|
+
|
|
37
|
+
Both Sanity query paths (`fetchSanity()` and `SanityClient`) now route through the Cloudflare caching proxy, so queries made via `SanityClient` benefit from the same CDN caching as the legacy path.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
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.180.0](https://github.com/railroadmedia/musora-content-services/compare/v2.179.0...v2.180.0) (2026-09-04)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **TP-1335:** consolidate duplicated user data fetches ([#1039](https://github.com/railroadmedia/musora-content-services/issues/1039)) ([bb2af2c](https://github.com/railroadmedia/musora-content-services/commit/bb2af2cddce8da519a414b24d7b86cc96639faaf))
|
|
11
|
+
* **TP-1354:** daily session / active path get optimisations ([#1041](https://github.com/railroadmedia/musora-content-services/issues/1041)) ([bca652c](https://github.com/railroadmedia/musora-content-services/commit/bca652ccf181b1ba943fe6e9b14b375bf4bebfc9))
|
|
12
|
+
|
|
5
13
|
## [2.179.0](https://github.com/railroadmedia/musora-content-services/compare/v2.178.1...v2.179.0) (2026-09-03)
|
|
6
14
|
|
|
7
15
|
|
package/package.json
CHANGED
|
@@ -18,6 +18,7 @@ export class HttpClient {
|
|
|
18
18
|
private headerProvider: HeaderProvider
|
|
19
19
|
private requestExecutor: RequestExecutor
|
|
20
20
|
private credentials: RequestCredentials
|
|
21
|
+
private inFlightGetRequests: Map<string, Promise<any>> = new Map()
|
|
21
22
|
|
|
22
23
|
constructor(
|
|
23
24
|
baseUrl: string = '',
|
|
@@ -42,7 +43,20 @@ export class HttpClient {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
public async get<T>(url: string, options: _RequestOptions = {}): Promise<T> {
|
|
45
|
-
|
|
46
|
+
const key = `GET:${this.resolveUrl(url)}:${options.dataVersion || ''}`
|
|
47
|
+
|
|
48
|
+
const inFlightRequest = this.inFlightGetRequests.get(key)
|
|
49
|
+
if (inFlightRequest) {
|
|
50
|
+
return inFlightRequest
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const request = this.request<T>(url, 'GET', options).finally(() => {
|
|
54
|
+
this.inFlightGetRequests.delete(key)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
this.inFlightGetRequests.set(key, request)
|
|
58
|
+
|
|
59
|
+
return request
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
public async post<T>(url: string, data: any, options: _RequestOptions = {}): Promise<T> {
|
|
@@ -46,7 +46,7 @@ export class FetchQueryExecutor implements QueryExecutor {
|
|
|
46
46
|
private buildUrl(config: SanityConfig): string {
|
|
47
47
|
const perspective = config.perspective ?? 'published'
|
|
48
48
|
const api = config.useCachedAPI ? 'apicdn' : 'api'
|
|
49
|
-
return `https
|
|
49
|
+
return `https://sanity.musora.com/${config.projectId}/${api}/v${config.version}/${config.dataset}?perspective=${perspective}`
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
private buildRequest(
|
package/src/services/config.js
CHANGED
|
@@ -9,6 +9,7 @@ export let globalConfig = {
|
|
|
9
9
|
sanityConfig: {},
|
|
10
10
|
railcontentConfig: {},
|
|
11
11
|
sessionConfig: {},
|
|
12
|
+
sessionUser: null,
|
|
12
13
|
localStorage: null,
|
|
13
14
|
isMA: false,
|
|
14
15
|
localTimezoneString: null, // In format: America/Vancouver
|
|
@@ -109,3 +110,7 @@ export function initializeService(config) {
|
|
|
109
110
|
export function initializeEnvVar(config) {
|
|
110
111
|
globalConfig.appEnv = config.appEnv
|
|
111
112
|
}
|
|
113
|
+
|
|
114
|
+
export function setSessionUserData(userData) {
|
|
115
|
+
globalConfig.sessionUser = userData || null
|
|
116
|
+
}
|
|
@@ -30,12 +30,38 @@ const excludeFromGeneratedIndex = [
|
|
|
30
30
|
'onLearningPathCompletedActions',
|
|
31
31
|
'mapContentsThatWereLastProgressedFromMethod',
|
|
32
32
|
'mapLearningPathParentsTo',
|
|
33
|
+
'resetLearningPathCachesForTests',
|
|
33
34
|
]
|
|
34
35
|
|
|
35
36
|
const BASE_PATH: string = `/api/content-org`
|
|
36
37
|
const LEARNING_PATHS_PATH = `${BASE_PATH}/v1/user/learning-paths`
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
const dailySessionPromises = new Map<string, Promise<DailySessionResponse | ''>>()
|
|
39
|
+
const activePathPromises = new Map<string, Promise<ActiveLearningPathResponse | ''>>()
|
|
40
|
+
|
|
41
|
+
function clearLearningPathCaches(): void {
|
|
42
|
+
dailySessionPromises.clear()
|
|
43
|
+
activePathPromises.clear()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function resetLearningPathCachesForTests(): void {
|
|
47
|
+
clearLearningPathCaches()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function rememberValue<T>(cache: Map<string, Promise<T>>, key: string, value: T | null): void {
|
|
51
|
+
if (value === null) {
|
|
52
|
+
cache.delete(key)
|
|
53
|
+
} else {
|
|
54
|
+
cache.set(key, Promise.resolve(value))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function activePathKey(brand: string): string {
|
|
59
|
+
return `active-path:${brand}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function dailySessionKey(brand: string, dateWithTimezone: string): string {
|
|
63
|
+
return `daily-session:${brand}:${dateWithTimezone}`
|
|
64
|
+
}
|
|
39
65
|
|
|
40
66
|
interface ActiveLearningPathResponse {
|
|
41
67
|
user_id: number
|
|
@@ -67,38 +93,25 @@ interface CollectionObject {
|
|
|
67
93
|
* If the daily session doesn't exist, it will be created.
|
|
68
94
|
* @param brand
|
|
69
95
|
* @param userDate - local datetime. must have date and time - format 2025-10-31T13:45:00
|
|
70
|
-
* @param forceRefresh - force cache refresh
|
|
71
96
|
*/
|
|
72
|
-
export async function getDailySession(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
forceRefresh: boolean = false,
|
|
76
|
-
) {
|
|
77
|
-
if (dailySessionPromise && !forceRefresh) {
|
|
78
|
-
return dailySessionPromise
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
dailySessionPromise = (async () => {
|
|
82
|
-
const dateWithTimezone = formatLocalDateTime(userDate)
|
|
83
|
-
const url = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${encodeURIComponent(dateWithTimezone)}`
|
|
97
|
+
export async function getDailySession(brand: string, userDate: Date) {
|
|
98
|
+
const dateWithTimezone = formatLocalDateTime(userDate)
|
|
99
|
+
const key = dailySessionKey(brand, dateWithTimezone)
|
|
84
100
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
101
|
+
try {
|
|
102
|
+
return await dataPromiseGET(dailySessionPromises, key, async () => {
|
|
103
|
+
const url = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${encodeURIComponent(dateWithTimezone)}`
|
|
88
104
|
|
|
89
|
-
|
|
90
|
-
return await updateDailySession(brand, userDate, false)
|
|
91
|
-
}
|
|
92
|
-
return response as DailySessionResponse
|
|
93
|
-
})()
|
|
105
|
+
const response = await GET(url) as DailySessionResponse | ''
|
|
94
106
|
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
if (!response) {
|
|
108
|
+
return await updateDailySession(brand, userDate, false)
|
|
109
|
+
}
|
|
110
|
+
return response as DailySessionResponse
|
|
111
|
+
})
|
|
97
112
|
} catch (error) {
|
|
98
113
|
console.error('Error fetching daily session:', (error as any).message)
|
|
99
114
|
return null
|
|
100
|
-
} finally {
|
|
101
|
-
dailySessionPromise = null
|
|
102
115
|
}
|
|
103
116
|
}
|
|
104
117
|
|
|
@@ -114,6 +127,7 @@ export async function updateDailySession(
|
|
|
114
127
|
keepFirstLearningPath: boolean = false,
|
|
115
128
|
) {
|
|
116
129
|
const dateWithTimezone = formatLocalDateTime(userDate)
|
|
130
|
+
const key = dailySessionKey(brand, dateWithTimezone)
|
|
117
131
|
const url: string = `${LEARNING_PATHS_PATH}/daily-session/create`
|
|
118
132
|
const body = {
|
|
119
133
|
brand: brand,
|
|
@@ -122,14 +136,10 @@ export async function updateDailySession(
|
|
|
122
136
|
}
|
|
123
137
|
try {
|
|
124
138
|
const response = (await POST(url, body)) as DailySessionResponse | ''
|
|
139
|
+
rememberValue(dailySessionPromises, key, response !== '' ? response : null)
|
|
125
140
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
dataPromiseGET(urlGet, true).then(() => {
|
|
129
|
-
dailySessionPromise = null
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
}
|
|
141
|
+
const urlGet: string = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${encodeURIComponent(dateWithTimezone)}`
|
|
142
|
+
GET(urlGet, { cache: 'reload' }).catch(() => {})
|
|
133
143
|
|
|
134
144
|
return (response !== '' ? response : null)
|
|
135
145
|
} catch (error: any) {
|
|
@@ -144,15 +154,13 @@ function formatLocalDateTime(date: Date): string {
|
|
|
144
154
|
/**
|
|
145
155
|
* Gets user's active learning path.
|
|
146
156
|
* @param brand
|
|
147
|
-
* @param forceRefresh - force cache refresh
|
|
148
157
|
*/
|
|
149
|
-
export async function getActivePath(brand: string
|
|
158
|
+
export async function getActivePath(brand: string) {
|
|
150
159
|
const url: string = `${LEARNING_PATHS_PATH}/active-path/get?brand=${brand}`
|
|
151
160
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return response
|
|
161
|
+
return (await dataPromiseGET(activePathPromises, activePathKey(brand), () =>
|
|
162
|
+
GET(url) as Promise<ActiveLearningPathResponse>,
|
|
163
|
+
)) as ActiveLearningPathResponse
|
|
156
164
|
}
|
|
157
165
|
|
|
158
166
|
/**
|
|
@@ -166,36 +174,36 @@ export async function startLearningPath(brand: string, learningPathId: number) {
|
|
|
166
174
|
|
|
167
175
|
const response = (await POST(url, body)) as ActiveLearningPathResponse
|
|
168
176
|
|
|
169
|
-
// manual BE call to avoid recursive POST<->GET calls
|
|
170
177
|
if (response) {
|
|
178
|
+
rememberValue(activePathPromises, activePathKey(brand), response)
|
|
179
|
+
dailySessionPromises.delete(dailySessionKey(brand, formatLocalDateTime(new Date())))
|
|
180
|
+
|
|
171
181
|
const urlGet: string = `${LEARNING_PATHS_PATH}/active-path/get?brand=${brand}`
|
|
172
|
-
|
|
173
|
-
activePathPromise = null
|
|
174
|
-
})
|
|
182
|
+
GET(urlGet, { cache: 'reload' }).catch(() => {})
|
|
175
183
|
}
|
|
176
184
|
|
|
177
185
|
return response
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
cache: forceRefresh ? 'reload' : 'default',
|
|
188
|
-
}) as Promise<DailySessionResponse>
|
|
189
|
-
}
|
|
190
|
-
return dailySessionPromise
|
|
191
|
-
} else if (url.includes('active-path')) {
|
|
192
|
-
if (!activePathPromise || forceRefresh) {
|
|
193
|
-
activePathPromise = GET(url, {
|
|
194
|
-
cache: forceRefresh ? 'reload' : 'default',
|
|
195
|
-
}) as Promise<ActiveLearningPathResponse>
|
|
196
|
-
}
|
|
197
|
-
return activePathPromise
|
|
188
|
+
function dataPromiseGET<T>(
|
|
189
|
+
cache: Map<string, Promise<T>>,
|
|
190
|
+
key: string,
|
|
191
|
+
fetcher: () => Promise<T>,
|
|
192
|
+
): Promise<T> {
|
|
193
|
+
if (cache.has(key)) {
|
|
194
|
+
return cache.get(key)!
|
|
198
195
|
}
|
|
196
|
+
|
|
197
|
+
const promise = fetcher()
|
|
198
|
+
cache.set(key, promise)
|
|
199
|
+
promise
|
|
200
|
+
.then((value) => {
|
|
201
|
+
if (!value && cache.get(key) === promise) cache.delete(key)
|
|
202
|
+
})
|
|
203
|
+
.catch(() => {
|
|
204
|
+
if (cache.get(key) === promise) cache.delete(key)
|
|
205
|
+
})
|
|
206
|
+
return promise
|
|
199
207
|
}
|
|
200
208
|
|
|
201
209
|
/**
|
|
@@ -204,6 +212,8 @@ async function dataPromiseGET(
|
|
|
204
212
|
export async function resetAllLearningPaths() {
|
|
205
213
|
const url: string = `${LEARNING_PATHS_PATH}/reset`
|
|
206
214
|
|
|
215
|
+
clearLearningPathCaches()
|
|
216
|
+
|
|
207
217
|
return await Promise.all([
|
|
208
218
|
devFetchAllLearningPathsAndIntroVideoIdsForDelete().then(async (all) => {
|
|
209
219
|
await Promise.all([
|
|
@@ -509,7 +519,16 @@ async function methodIntroVideoCompleteActions(brand: string, learningPathId: nu
|
|
|
509
519
|
const dateWithTimezone = formatLocalDateTime(userDate)
|
|
510
520
|
const url: string = `${LEARNING_PATHS_PATH}/method-intro-video-complete-actions`
|
|
511
521
|
const body = { brand: brand, learningPathId: learningPathId, userDate: dateWithTimezone }
|
|
512
|
-
|
|
522
|
+
const response = (await POST(url, body)) as DailySessionResponse
|
|
523
|
+
|
|
524
|
+
rememberValue(activePathPromises, activePathKey(brand), {
|
|
525
|
+
user_id: response.user_id,
|
|
526
|
+
brand: response.brand,
|
|
527
|
+
active_learning_path_id: response.active_learning_path_id,
|
|
528
|
+
})
|
|
529
|
+
rememberValue(dailySessionPromises, dailySessionKey(brand, dateWithTimezone), response)
|
|
530
|
+
|
|
531
|
+
return response
|
|
513
532
|
}
|
|
514
533
|
|
|
515
534
|
interface completeLearningPathIntroVideo {
|
|
@@ -557,6 +576,7 @@ export async function completeLearningPathIntroVideo(
|
|
|
557
576
|
} else {
|
|
558
577
|
response.lesson_import_response = await contentStatusCompletedMany(lessonsToImport, collection)
|
|
559
578
|
|
|
579
|
+
activePathPromises.delete(activePathKey(brand))
|
|
560
580
|
const activePath = await getActivePath(brand)
|
|
561
581
|
if (activePath.active_learning_path_id === learningPathId && !lateMethodSetup) { // don't update dailies if they were just set by completeMethodIntroVideoCompleteActions.
|
|
562
582
|
response.update_dailies_response = await updateDailySession(brand, new Date(), true)
|
package/src/services/sanity.js
CHANGED
|
@@ -46,7 +46,10 @@ import { globalConfig } from './config.js'
|
|
|
46
46
|
|
|
47
47
|
import { arrayToStringRepresentation, FilterBuilder } from '../filterBuilder.js'
|
|
48
48
|
import { getPermissionsAdapter } from './permissions/index.ts'
|
|
49
|
-
import {
|
|
49
|
+
import {
|
|
50
|
+
lifetimeUpgradeDecorator,
|
|
51
|
+
NEED_LIFETIME_UPGRADE_FIELD,
|
|
52
|
+
} from '../lib/sanity/decorators/need-lifetime-upgrade.ts'
|
|
50
53
|
import {
|
|
51
54
|
getAllCompleted,
|
|
52
55
|
getAllCompletedByIds,
|
|
@@ -906,7 +909,8 @@ export async function fetchAllFilterOptions(
|
|
|
906
909
|
? filtersToGroq(filters, excludeFilter)
|
|
907
910
|
: includedFieldsFilter
|
|
908
911
|
const statusFilter = ' && status == "published"'
|
|
909
|
-
const includeStatusFilter =
|
|
912
|
+
const includeStatusFilter =
|
|
913
|
+
!hasAllContentAccess && !['instructor', 'artist', 'genre'].includes(contentType)
|
|
910
914
|
|
|
911
915
|
return coachId
|
|
912
916
|
? `brand == '${brand}' && status == "published" && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${filterWithoutOption || ''} ${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}`
|
|
@@ -1197,8 +1201,12 @@ export async function fetchLiveEvent(brand, forcedContentId = null) {
|
|
|
1197
1201
|
|
|
1198
1202
|
const now = new Date()
|
|
1199
1203
|
|
|
1200
|
-
const startOfYesterday = new Date(
|
|
1201
|
-
|
|
1204
|
+
const startOfYesterday = new Date(
|
|
1205
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() - 1)
|
|
1206
|
+
).toISOString()
|
|
1207
|
+
const endOfTomorrow = new Date(
|
|
1208
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 2)
|
|
1209
|
+
).toISOString()
|
|
1202
1210
|
|
|
1203
1211
|
const liveEventFields = getLiveFields().concat(
|
|
1204
1212
|
`'event_coach_calendar_id': coalesce(calendar_id, '${defaultCalendarID}')`
|
|
@@ -1226,10 +1234,12 @@ export async function fetchLiveEvent(brand, forcedContentId = null) {
|
|
|
1226
1234
|
const windowStart = new Date(clientNow.getTime() - LIVE_EXTRA_MINUTES * 60000).toISOString()
|
|
1227
1235
|
const windowEnd = new Date(clientNow.getTime() + LIVE_EXTRA_MINUTES * 60000).toISOString()
|
|
1228
1236
|
|
|
1229
|
-
return
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1237
|
+
return (
|
|
1238
|
+
events?.find(
|
|
1239
|
+
(event) =>
|
|
1240
|
+
event.live_event_end_time >= windowStart && event.live_event_start_time <= windowEnd
|
|
1241
|
+
) ?? null
|
|
1242
|
+
)
|
|
1233
1243
|
}
|
|
1234
1244
|
|
|
1235
1245
|
/**
|
|
@@ -1571,6 +1581,7 @@ export async function fetchCommentModContentData(ids) {
|
|
|
1571
1581
|
}
|
|
1572
1582
|
|
|
1573
1583
|
/**
|
|
1584
|
+
* @deprecated Use SanityClient.ts or groq query runner instead. This function is a legacy wrapper for fetching data from the Sanity API using GROQ queries. It handles query construction, execution, and post-processing of results.
|
|
1574
1585
|
*
|
|
1575
1586
|
* @param {string} query - The GROQ query to execute against the Sanity API.
|
|
1576
1587
|
* @param {boolean} isList - Whether to return an array or a single result.
|
|
@@ -1586,7 +1597,6 @@ export async function fetchCommentModContentData(ids) {
|
|
|
1586
1597
|
* .then(data => console.log(data))
|
|
1587
1598
|
* .catch(error => console.error(error));
|
|
1588
1599
|
*/
|
|
1589
|
-
|
|
1590
1600
|
export async function fetchSanity(
|
|
1591
1601
|
query,
|
|
1592
1602
|
isList,
|
|
@@ -1640,7 +1650,9 @@ export async function fetchSanity(
|
|
|
1640
1650
|
return null
|
|
1641
1651
|
}
|
|
1642
1652
|
results = processNeedAccess ? await needsAccessDecorator(results, userPermissions) : results
|
|
1643
|
-
results = processNeedAccess
|
|
1653
|
+
results = processNeedAccess
|
|
1654
|
+
? needsLifetimeUpgradeDecorator(results, userPermissions)
|
|
1655
|
+
: results
|
|
1644
1656
|
results = processPageType ? pageTypeDecorator(results) : results
|
|
1645
1657
|
return customPostProcess ? customPostProcess(results) : results
|
|
1646
1658
|
} else {
|
|
@@ -2124,7 +2136,7 @@ export async function fetchTabData(
|
|
|
2124
2136
|
availableContentStatuses: hasAllContentAccess
|
|
2125
2137
|
? CONTENT_STATUSES.ADMIN_ALL
|
|
2126
2138
|
: CONTENT_STATUSES.PUBLISHED_ONLY,
|
|
2127
|
-
pullFutureContent: hasAllContentAccess
|
|
2139
|
+
pullFutureContent: hasAllContentAccess,
|
|
2128
2140
|
}).buildFilter()
|
|
2129
2141
|
query = buildEntityAndTotalQuery(filterWithRestrictions, entityFieldsString, {
|
|
2130
2142
|
sortOrder: sortOrder,
|
|
@@ -2242,11 +2254,13 @@ export async function fetchScheduledAndNewReleases(
|
|
|
2242
2254
|
|
|
2243
2255
|
const reordered = reorderScheduledAndNewReleases(r, limit)
|
|
2244
2256
|
const computedNow = new Date()
|
|
2245
|
-
return reordered.map(item => ({
|
|
2257
|
+
return reordered.map((item) => ({
|
|
2246
2258
|
...item,
|
|
2247
|
-
isLive:
|
|
2248
|
-
|
|
2249
|
-
|
|
2259
|
+
isLive:
|
|
2260
|
+
item.live_event_start_time && item.live_event_end_time
|
|
2261
|
+
? new Date(item.live_event_start_time) <= computedNow &&
|
|
2262
|
+
new Date(item.live_event_end_time) >= computedNow
|
|
2263
|
+
: false,
|
|
2250
2264
|
}))
|
|
2251
2265
|
}
|
|
2252
2266
|
|
package/src/services/state.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { streakCalculator } from './user/streakCalculator'
|
|
2
|
+
import { setSessionUserData } from './config.js'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Clears all client-side cached state in musora-content-services.
|
|
@@ -7,4 +8,5 @@ import { streakCalculator } from './user/streakCalculator'
|
|
|
7
8
|
*/
|
|
8
9
|
export function clearState(): void {
|
|
9
10
|
streakCalculator.invalidate()
|
|
11
|
+
setSessionUserData(null)
|
|
10
12
|
}
|
|
@@ -76,8 +76,14 @@ export async function deletePicture(pictureUrl) {
|
|
|
76
76
|
* @param {number} [userId=globalConfig.sessionConfig.userId]
|
|
77
77
|
* @returns {Promise<User|null>}
|
|
78
78
|
*/
|
|
79
|
-
export async function getUserData(userId
|
|
80
|
-
|
|
79
|
+
export async function getUserData(userId) {
|
|
80
|
+
if (!userId && globalConfig.sessionUser) {
|
|
81
|
+
return globalConfig.sessionUser
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let userIdToFetch = userId || globalConfig.sessionConfig.userId
|
|
85
|
+
|
|
86
|
+
const apiUrl = `${baseUrl}/v1/users/${userIdToFetch}`
|
|
81
87
|
return await GET(apiUrl)
|
|
82
88
|
}
|
|
83
89
|
|
package/src/version-info.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const MCS_VERSION = '2.
|
|
1
|
+
export const MCS_VERSION = '2.180.0'
|