musora-content-services 2.167.1 → 2.167.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.
- package/.agent/decisions/2026-07-17-onboarding-statuses.md +21 -0
- package/.agent/decisions/2026-07-20-mu2-1724-songs-lessons-counts.md +33 -0
- package/.agent/decisions/2026-07-20-query-builder-tostring.md +37 -0
- package/CHANGELOG.md +15 -0
- package/package.json +2 -1
- package/src/contentTypeConfig.js +2 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
- package/src/lib/sanity/query.ts +5 -0
- package/src/services/config.js +15 -0
- package/src/services/content/artist.ts +1 -3
- package/src/services/content/counts.ts +47 -0
- package/src/services/content/genre.ts +1 -3
- package/src/services/content/instructor.ts +1 -3
- package/src/services/contentProgress.js +1 -1
- package/src/services/eventsAPI.js +49 -7
- package/src/services/user/onboarding.ts +22 -0
- package/src/services/userActivity.js +2 -0
- package/src/version-info.js +1 -0
- package/.claude/settings.local.json +0 -52
- package/test/initializeTests.js +0 -60
- package/test/integration/awards/award-exclusion-handling.test.ts +0 -275
- package/test/integration/awards/internal/image-utils.test.ts +0 -86
- package/test/integration/content-progress/__mocks__/mocks.ts +0 -104
- package/test/integration/content-progress/contentProgress.test.ts +0 -335
- package/test/integration/content-progress/e2eOfflineProgress.test.ts +0 -352
- package/test/integration/content-progress/e2eProgress.test.ts +0 -612
- package/test/integration/content-progress/getters.test.ts +0 -334
- package/test/integration/content-progress/helpers.test.ts +0 -263
- package/test/integration/content-progress/offlineContentProgress.test.ts +0 -226
- package/test/integration/forums.test.ts +0 -209
- package/test/integration/infrastructure/FetchRequestExecutor.test.ts +0 -88
- package/test/integration/initializeTestDB.ts +0 -80
- package/test/integration/learning-paths.test.ts +0 -854
- package/test/integration/notifications.test.ts +0 -178
- package/test/integration/progress-row/content-card.test.ts +0 -283
- package/test/integration/sync/adapters/idb-errors.test.ts +0 -144
- package/test/integration/sync/adapters/sqlite-errors.test.ts +0 -173
- package/test/integration/sync/fetch.test.ts +0 -224
- package/test/integration/sync/repositories/content-likes.test.ts +0 -99
- package/test/integration/sync/repositories/practices.test.ts +0 -179
- package/test/integration/sync/repositories/progress.test.ts +0 -245
- package/test/integration/sync/repositories/user-award-progress.static.test.ts +0 -68
- package/test/integration/sync/repositories/user-award-progress.test.ts +0 -387
- package/test/integration/sync/store/cross-user-protection.test.ts +0 -217
- package/test/integration/sync/store/store-idb.test.ts +0 -180
- package/test/integration/sync/store/store.test.ts +0 -361
- package/test/integration/user/permissions.test.js +0 -20
- package/test/integration/userActivity.test.ts +0 -102
- package/test/live/README.md +0 -29
- package/test/live/content.test.js +0 -116
- package/test/localStorageMock.js +0 -21
- package/test/log.js +0 -5
- package/test/mockData/award-definitions.js +0 -171
- package/test/mockData/mockData_fetchByRailContentIds_one_content.json +0 -35
- package/test/mockData/mockData_progress_content.json +0 -182
- package/test/mockData/mockData_sanity_progress_content.json +0 -1451
- package/test/mockData/mockData_user_practices.json +0 -9
- package/test/setupConsole.js +0 -6
- package/test/setupNetworkGuard.js +0 -3
- package/test/setupTimers.js +0 -13
- package/test/unit/HttpClient.test.ts +0 -267
- package/test/unit/awards/award-alacarte-observer.test.ts +0 -199
- package/test/unit/awards/award-auto-refresh.test.ts +0 -84
- package/test/unit/awards/award-calculations.test.ts +0 -34
- package/test/unit/awards/award-callbacks.test.ts +0 -144
- package/test/unit/awards/award-certificate-display.test.ts +0 -330
- package/test/unit/awards/award-collection-edge-cases.test.ts +0 -212
- package/test/unit/awards/award-collection-filtering.test.ts +0 -287
- package/test/unit/awards/award-completion-flow.test.ts +0 -306
- package/test/unit/awards/award-multi-lesson.test.ts +0 -243
- package/test/unit/awards/award-observer-integration.test.ts +0 -327
- package/test/unit/awards/award-query-messages.test.ts +0 -448
- package/test/unit/awards/award-user-collection.test.ts +0 -416
- package/test/unit/awards/duplicate-prevention.test.ts +0 -120
- package/test/unit/awards/helpers/completion-mock.ts +0 -56
- package/test/unit/awards/helpers/index.ts +0 -3
- package/test/unit/awards/helpers/mock-setup.ts +0 -79
- package/test/unit/awards/helpers/progress-emitter.ts +0 -45
- package/test/unit/awards/message-generator.test.ts +0 -162
- package/test/unit/content-progress/bubbleTrickle.test.ts +0 -322
- package/test/unit/content-progress/helpers.test.ts +0 -329
- package/test/unit/content-progress/navigateTo.test.ts +0 -381
- package/test/unit/contentLikes.test.ts +0 -62
- package/test/unit/contentMetaData.test.ts +0 -58
- package/test/unit/dataContext.test.ts +0 -38
- package/test/unit/dateUtils.test.ts +0 -188
- package/test/unit/endScreen.test.js +0 -712
- package/test/unit/imageSRCBuilder.test.ts +0 -37
- package/test/unit/imageSRCVerify.test.ts +0 -155
- package/test/unit/infrastructure/DefaultHeaderProvider.test.ts +0 -39
- package/test/unit/infrastructure/sanity/ContentClient.test.ts +0 -168
- package/test/unit/infrastructure/sanity/DefaultConfigProvider.test.ts +0 -93
- package/test/unit/infrastructure/sanity/FetchQueryExecutor.test.ts +0 -174
- package/test/unit/infrastructure/sanity/SanityClient.test.ts +0 -140
- package/test/unit/lib/__snapshots__/filter.test.ts.snap +0 -5
- package/test/unit/lib/filter.test.ts +0 -1154
- package/test/unit/lib/lastUpdated.test.ts +0 -21
- package/test/unit/lib/query.test.ts +0 -1469
- package/test/unit/lib/sanity/decorators/base.test.ts +0 -368
- package/test/unit/lib/sanity/decorators/navigate-to.test.ts +0 -361
- package/test/unit/lib/sanity/decorators/need-access.test.ts +0 -89
- package/test/unit/lib/sanity/decorators/need-lifetime-upgrade.test.ts +0 -85
- package/test/unit/lib/sanity/decorators/page-type.test.ts +0 -81
- package/test/unit/playerSettings.test.ts +0 -73
- package/test/unit/progress-row/content-card.test.ts +0 -314
- package/test/unit/progress-row/playlist-card.test.ts +0 -104
- package/test/unit/progressRows.test.ts +0 -243
- package/test/unit/recommendations.test.js +0 -47
- package/test/unit/sanityQueryService.test.ts +0 -200
- package/test/unit/search.test.ts +0 -44
- package/test/unit/sentry.test.ts +0 -62
- package/test/unit/services/progress-internal/bubble.test.ts +0 -279
- package/test/unit/services/progress.test.ts +0 -396
- package/test/unit/streakMessage.test.ts +0 -251
- package/test/unit/sync/context.test.ts +0 -51
- package/test/unit/sync/effects/logout-warning.test.ts +0 -158
- package/test/unit/sync/effects/push-failure-notification.test.ts +0 -196
- package/test/unit/sync/errors/sync-errors.test.ts +0 -106
- package/test/unit/sync/errors/validators.test.ts +0 -61
- package/test/unit/sync/helpers/TestModel.ts +0 -44
- package/test/unit/sync/helpers/index.ts +0 -172
- package/test/unit/sync/manager.test.ts +0 -303
- package/test/unit/sync/models/user-award-progress.test.ts +0 -82
- package/test/unit/sync/resolver.test.ts +0 -229
- package/test/unit/sync/retry.test.ts +0 -314
- package/test/unit/sync/run-scope.test.ts +0 -23
- package/test/unit/sync/stale-record-cleanup.test.ts +0 -107
- package/test/unit/sync/store/push-coalescer.test.ts +0 -156
- package/test/unit/sync/store-configs.test.ts +0 -37
- package/test/unit/sync/telemetry/sync-telemetry.test.ts +0 -118
- package/test/unit/sync/utils/event-emitter.test.ts +0 -64
- package/test/unit/sync/utils/throttle.test.ts +0 -245
- package/test/unit/url-builder.test.ts +0 -72
- package/test/unit/user/account.test.ts +0 -66
- package/test/unit/user/permissions.test.js +0 -191
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { SanityClient } from '../../../../src/infrastructure/sanity/SanityClient'
|
|
2
|
-
import { ConfigProvider } from '../../../../src/infrastructure/sanity/interfaces/ConfigProvider'
|
|
3
|
-
import { QueryExecutor } from '../../../../src/infrastructure/sanity/interfaces/QueryExecutor'
|
|
4
|
-
import { SanityConfig } from '../../../../src/infrastructure/sanity/interfaces/SanityConfig'
|
|
5
|
-
|
|
6
|
-
describe('SanityClient', () => {
|
|
7
|
-
const config: SanityConfig = {
|
|
8
|
-
projectId: 'p',
|
|
9
|
-
dataset: 'd',
|
|
10
|
-
version: '2021-06-07',
|
|
11
|
-
token: 't',
|
|
12
|
-
}
|
|
13
|
-
let mockConfigProvider: jest.Mocked<ConfigProvider>
|
|
14
|
-
let mockExecutor: jest.Mocked<QueryExecutor>
|
|
15
|
-
let client: SanityClient
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
mockConfigProvider = {
|
|
19
|
-
getConfig: jest.fn().mockReturnValue(config),
|
|
20
|
-
}
|
|
21
|
-
mockExecutor = {
|
|
22
|
-
execute: jest.fn(),
|
|
23
|
-
}
|
|
24
|
-
client = new SanityClient(mockConfigProvider, mockExecutor)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('fetchSingle', () => {
|
|
28
|
-
test('returns first item from result array', async () => {
|
|
29
|
-
mockExecutor.execute.mockResolvedValue({
|
|
30
|
-
result: [{ id: 1 }, { id: 2 }],
|
|
31
|
-
ms: 5,
|
|
32
|
-
query: 'q',
|
|
33
|
-
})
|
|
34
|
-
const result = await client.fetchSingle<{ id: number }>('*[_type=="x"]', { a: 1 })
|
|
35
|
-
expect(result).toEqual({ id: 1 })
|
|
36
|
-
expect(mockExecutor.execute).toHaveBeenCalledWith(
|
|
37
|
-
{ query: '*[_type=="x"]', params: { a: 1 } },
|
|
38
|
-
config
|
|
39
|
-
)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
test('returns null when result array is empty', async () => {
|
|
43
|
-
mockExecutor.execute.mockResolvedValue({ result: [], ms: 1, query: 'q' })
|
|
44
|
-
expect(await client.fetchSingle('q')).toBeNull()
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('returns null when result is not an array', async () => {
|
|
48
|
-
mockExecutor.execute.mockResolvedValue({ result: { id: 1 } as any, ms: 1, query: 'q' })
|
|
49
|
-
expect(await client.fetchSingle('q')).toBeNull()
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('rethrows SanityError unchanged and returns nothing useful', async () => {
|
|
53
|
-
const sanityError = { message: 'boom', query: 'q' }
|
|
54
|
-
mockExecutor.execute.mockRejectedValue(sanityError)
|
|
55
|
-
await expect(client.fetchSingle('q')).rejects.toEqual(sanityError)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('wraps non-SanityError as SanityError including query and originalError', async () => {
|
|
59
|
-
const raw = new Error('network down')
|
|
60
|
-
mockExecutor.execute.mockRejectedValue(raw)
|
|
61
|
-
await expect(client.fetchSingle('myquery')).rejects.toMatchObject({
|
|
62
|
-
message: 'network down',
|
|
63
|
-
query: 'myquery',
|
|
64
|
-
originalError: raw,
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
describe('fetchList', () => {
|
|
70
|
-
test('returns result array', async () => {
|
|
71
|
-
const data = [{ id: 1 }, { id: 2 }]
|
|
72
|
-
mockExecutor.execute.mockResolvedValue({ result: data, ms: 1, query: 'q' })
|
|
73
|
-
const result = await client.fetchList('q')
|
|
74
|
-
expect(result).toEqual(data)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
test('returns empty array when result is null/undefined', async () => {
|
|
78
|
-
mockExecutor.execute.mockResolvedValue({ result: null as any, ms: 1, query: 'q' })
|
|
79
|
-
expect(await client.fetchList('q')).toEqual([])
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('rethrows existing SanityError', async () => {
|
|
83
|
-
const sanityError = { message: 'boom', query: 'q' }
|
|
84
|
-
mockExecutor.execute.mockRejectedValue(sanityError)
|
|
85
|
-
await expect(client.fetchList('q')).rejects.toEqual(sanityError)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
test('wraps non-SanityError as SanityError', async () => {
|
|
89
|
-
mockExecutor.execute.mockRejectedValue(new Error('fail'))
|
|
90
|
-
await expect(client.fetchList('q')).rejects.toMatchObject({
|
|
91
|
-
message: 'fail',
|
|
92
|
-
query: 'q',
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
describe('executeQuery', () => {
|
|
98
|
-
test('returns the raw result', async () => {
|
|
99
|
-
mockExecutor.execute.mockResolvedValue({ result: { count: 7 }, ms: 1, query: 'q' })
|
|
100
|
-
const result = await client.executeQuery<{ count: number }>('q')
|
|
101
|
-
expect(result).toEqual({ count: 7 })
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
test('returns null when result is missing', async () => {
|
|
105
|
-
mockExecutor.execute.mockResolvedValue({ result: null as any, ms: 1, query: 'q' })
|
|
106
|
-
expect(await client.executeQuery('q')).toBeNull()
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
test('rethrows wrapped error on failure', async () => {
|
|
110
|
-
mockExecutor.execute.mockRejectedValue(new Error('explode'))
|
|
111
|
-
await expect(client.executeQuery('q')).rejects.toMatchObject({
|
|
112
|
-
message: 'explode',
|
|
113
|
-
query: 'q',
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
describe('config caching', () => {
|
|
119
|
-
test('loads config once across multiple calls', async () => {
|
|
120
|
-
mockExecutor.execute.mockResolvedValue({ result: [], ms: 1, query: 'q' })
|
|
121
|
-
await client.fetchList('q1')
|
|
122
|
-
await client.fetchList('q2')
|
|
123
|
-
await client.fetchSingle('q3')
|
|
124
|
-
expect(mockConfigProvider.getConfig).toHaveBeenCalledTimes(1)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
test('refreshConfig forces a reload on the next call', async () => {
|
|
128
|
-
mockExecutor.execute.mockResolvedValue({ result: [], ms: 1, query: 'q' })
|
|
129
|
-
await client.fetchList('q1')
|
|
130
|
-
client.refreshConfig()
|
|
131
|
-
await client.fetchList('q2')
|
|
132
|
-
expect(mockConfigProvider.getConfig).toHaveBeenCalledTimes(2)
|
|
133
|
-
})
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
test('falls back to default providers when none are supplied', () => {
|
|
137
|
-
const defaultClient = new SanityClient()
|
|
138
|
-
expect(defaultClient).toBeInstanceOf(SanityClient)
|
|
139
|
-
})
|
|
140
|
-
})
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`Filters - Async Methods (Integration) Integration & Edge Cases snapshot: admin complete filter 1`] = `"status in ['draft','scheduled','published','archived','unlisted'] && published_on <= "2024-01-15T14:01:00.000Z" && !defined(deprecated_railcontent_id)"`;
|
|
4
|
-
|
|
5
|
-
exports[`Filters - Async Methods (Integration) Integration & Edge Cases snapshot: free user complete filter 1`] = `"status in ['scheduled','published'] && ((!defined(permission_v2) || count(permission_v2) == 0)) && published_on <= "2024-01-15T14:01:00.000Z" && !defined(deprecated_railcontent_id)"`;
|