musora-content-services 2.96.0 → 2.96.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/services/content/artist.ts +6 -1
- package/src/services/content/genre.ts +6 -1
- package/src/services/content/instructor.ts +1 -1
- package/src/services/sync/fetch.ts +1 -6
- package/src/services/sync/models/ContentProgress.ts +9 -6
- package/src/services/sync/repositories/content-progress.ts +22 -26
- package/.claude/settings.local.json +0 -9
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.96.1](https://github.com/railroadmedia/musora-content-services/compare/v2.96.0...v2.96.1) (2025-12-09)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **agi:** interface return types ([cc0cfae](https://github.com/railroadmedia/musora-content-services/commit/cc0cfae1282266567ac46a6eb072f76ffde7032e))
|
|
11
|
+
|
|
5
12
|
## [2.96.0](https://github.com/railroadmedia/musora-content-services/compare/v2.95.5...v2.96.0) (2025-12-09)
|
|
6
13
|
|
|
7
14
|
|
package/package.json
CHANGED
|
@@ -15,6 +15,11 @@ export interface Artist {
|
|
|
15
15
|
lessonCount: number
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export interface Artists {
|
|
19
|
+
data: Artist[]
|
|
20
|
+
total: number
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
/**
|
|
19
24
|
* Fetch all artists with lessons available for a specific brand.
|
|
20
25
|
*
|
|
@@ -29,7 +34,7 @@ export interface Artist {
|
|
|
29
34
|
export async function fetchArtists(
|
|
30
35
|
brand: Brands | string,
|
|
31
36
|
options: BuildQueryOptions = { sort: 'lower(name) asc' }
|
|
32
|
-
): Promise<
|
|
37
|
+
): Promise<Artists> {
|
|
33
38
|
const lessonFilter = await new FilterBuilder(`brand == "${brand}" && references(^._id)`, {
|
|
34
39
|
bypassPermissions: true,
|
|
35
40
|
}).buildFilter()
|
|
@@ -15,6 +15,11 @@ export interface Genre {
|
|
|
15
15
|
thumbnail: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export interface Genres {
|
|
19
|
+
data: Genre[]
|
|
20
|
+
total: number
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
/**
|
|
19
24
|
* Fetch all genres with lessons available for a specific brand.
|
|
20
25
|
*
|
|
@@ -29,7 +34,7 @@ export interface Genre {
|
|
|
29
34
|
export async function fetchGenres(
|
|
30
35
|
brand: Brands | string,
|
|
31
36
|
options: BuildQueryOptions = { sort: 'lower(name) asc' }
|
|
32
|
-
): Promise<
|
|
37
|
+
): Promise<Genres> {
|
|
33
38
|
const lessonFilter = await new FilterBuilder(`brand == "${brand}" && references(^._id)`, {
|
|
34
39
|
bypassPermissions: true,
|
|
35
40
|
}).buildFilter()
|
|
@@ -35,7 +35,7 @@ export interface Instructors {
|
|
|
35
35
|
export async function fetchInstructors(
|
|
36
36
|
brand: Brands | string,
|
|
37
37
|
options: BuildQueryOptions
|
|
38
|
-
): Promise<
|
|
38
|
+
): Promise<Instructors> {
|
|
39
39
|
const lessonFilter = await new FilterBuilder(`brand == "${brand}" && references(^._id)`, {
|
|
40
40
|
bypassPermissions: true,
|
|
41
41
|
}).buildFilter()
|
|
@@ -308,12 +308,7 @@ function serializeIds(ids: { id: RecordId }): { client_record_id: RecordId } {
|
|
|
308
308
|
|
|
309
309
|
function deserializeRecord(record: SyncSyncable<BaseModel, 'client_record_id'> | null): SyncSyncable<BaseModel, 'id'> | null {
|
|
310
310
|
if (record) {
|
|
311
|
-
const { client_record_id: id, ...rest } = record
|
|
312
|
-
|
|
313
|
-
if ('collection_type' in rest && rest.collection_type === 'self') {
|
|
314
|
-
rest.collection_type = null
|
|
315
|
-
rest.collection_id = null
|
|
316
|
-
}
|
|
311
|
+
const { client_record_id: id, ...rest } = record
|
|
317
312
|
|
|
318
313
|
return {
|
|
319
314
|
...rest,
|
|
@@ -2,9 +2,12 @@ import BaseModel from './Base'
|
|
|
2
2
|
import { SYNC_TABLES } from '../schema'
|
|
3
3
|
|
|
4
4
|
export enum COLLECTION_TYPE {
|
|
5
|
+
SELF = 'self',
|
|
6
|
+
GUIDED_COURSE = 'guided-course',
|
|
5
7
|
LEARNING_PATH = 'learning-path-v2',
|
|
6
8
|
PLAYLIST = 'playlist',
|
|
7
9
|
}
|
|
10
|
+
export const COLLECTION_ID_SELF = 0
|
|
8
11
|
|
|
9
12
|
export enum STATE {
|
|
10
13
|
STARTED = 'started',
|
|
@@ -13,8 +16,8 @@ export enum STATE {
|
|
|
13
16
|
|
|
14
17
|
export default class ContentProgress extends BaseModel<{
|
|
15
18
|
content_id: number
|
|
16
|
-
collection_type: COLLECTION_TYPE
|
|
17
|
-
collection_id: number
|
|
19
|
+
collection_type: COLLECTION_TYPE
|
|
20
|
+
collection_id: number
|
|
18
21
|
state: STATE
|
|
19
22
|
progress_percent: number
|
|
20
23
|
resume_time_seconds: number | null
|
|
@@ -34,10 +37,10 @@ export default class ContentProgress extends BaseModel<{
|
|
|
34
37
|
return this._getRaw('progress_percent') as number
|
|
35
38
|
}
|
|
36
39
|
get collection_type() {
|
|
37
|
-
return
|
|
40
|
+
return this._getRaw('collection_type') as COLLECTION_TYPE
|
|
38
41
|
}
|
|
39
42
|
get collection_id() {
|
|
40
|
-
return
|
|
43
|
+
return this._getRaw('collection_id') as number
|
|
41
44
|
}
|
|
42
45
|
get resume_time_seconds() {
|
|
43
46
|
return (this._getRaw('resume_time_seconds') as number) || null
|
|
@@ -55,10 +58,10 @@ export default class ContentProgress extends BaseModel<{
|
|
|
55
58
|
set progress_percent(value: number) {
|
|
56
59
|
this._setRaw('progress_percent', Math.min(100, Math.max(0, value)))
|
|
57
60
|
}
|
|
58
|
-
set collection_type(value: COLLECTION_TYPE
|
|
61
|
+
set collection_type(value: COLLECTION_TYPE) {
|
|
59
62
|
this._setRaw('collection_type', value)
|
|
60
63
|
}
|
|
61
|
-
set collection_id(value: number
|
|
64
|
+
set collection_id(value: number) {
|
|
62
65
|
this._setRaw('collection_id', value)
|
|
63
66
|
}
|
|
64
67
|
set resume_time_seconds(value: number | null) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import SyncRepository, { Q } from './base'
|
|
2
|
-
import ContentProgress, { COLLECTION_TYPE, STATE } from '../models/ContentProgress'
|
|
2
|
+
import ContentProgress, { COLLECTION_TYPE, COLLECTION_ID_SELF, STATE } from '../models/ContentProgress'
|
|
3
3
|
|
|
4
4
|
export default class ProgressRepository extends SyncRepository<ContentProgress> {
|
|
5
5
|
// null collection only
|
|
6
6
|
async startedIds(limit?: number) {
|
|
7
7
|
return this.queryAllIds(...[
|
|
8
|
-
Q.where('collection_type',
|
|
9
|
-
Q.where('collection_id',
|
|
8
|
+
Q.where('collection_type', COLLECTION_TYPE.SELF),
|
|
9
|
+
Q.where('collection_id', COLLECTION_ID_SELF),
|
|
10
10
|
|
|
11
11
|
Q.where('state', STATE.STARTED),
|
|
12
12
|
Q.sortBy('updated_at', 'desc'),
|
|
@@ -18,8 +18,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
18
18
|
// null collection only
|
|
19
19
|
async completedIds(limit?: number) {
|
|
20
20
|
return this.queryAllIds(...[
|
|
21
|
-
Q.where('collection_type',
|
|
22
|
-
Q.where('collection_id',
|
|
21
|
+
Q.where('collection_type', COLLECTION_TYPE.SELF),
|
|
22
|
+
Q.where('collection_id', COLLECTION_ID_SELF),
|
|
23
23
|
|
|
24
24
|
Q.where('state', STATE.COMPLETED),
|
|
25
25
|
Q.sortBy('updated_at', 'desc'),
|
|
@@ -55,8 +55,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
55
55
|
} = {}
|
|
56
56
|
) {
|
|
57
57
|
const clauses: Q.Clause[] = [
|
|
58
|
-
Q.where('collection_type',
|
|
59
|
-
Q.where('collection_id',
|
|
58
|
+
Q.where('collection_type', COLLECTION_TYPE.SELF),
|
|
59
|
+
Q.where('collection_id', COLLECTION_ID_SELF),
|
|
60
60
|
|
|
61
61
|
Q.or(Q.where('state', STATE.STARTED), Q.where('state', STATE.COMPLETED)),
|
|
62
62
|
Q.sortBy('updated_at', 'desc'),
|
|
@@ -80,8 +80,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
80
80
|
async mostRecentlyUpdatedId(contentIds: number[], collection: { type: COLLECTION_TYPE; id: number } | null = null) {
|
|
81
81
|
return this.queryOneId(
|
|
82
82
|
Q.where('content_id', Q.oneOf(contentIds)),
|
|
83
|
-
Q.where('collection_type', collection?.type ??
|
|
84
|
-
Q.where('collection_id', collection?.id ??
|
|
83
|
+
Q.where('collection_type', collection?.type ?? COLLECTION_TYPE.SELF),
|
|
84
|
+
Q.where('collection_id', collection?.id ?? COLLECTION_ID_SELF),
|
|
85
85
|
|
|
86
86
|
Q.sortBy('updated_at', 'desc')
|
|
87
87
|
)
|
|
@@ -93,8 +93,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
93
93
|
) {
|
|
94
94
|
const clauses = [
|
|
95
95
|
Q.where('content_id', contentId),
|
|
96
|
-
Q.where('collection_type', collection?.type ??
|
|
97
|
-
Q.where('collection_id', collection?.id ??
|
|
96
|
+
Q.where('collection_type', collection?.type ?? COLLECTION_TYPE.SELF),
|
|
97
|
+
Q.where('collection_id', collection?.id ?? COLLECTION_ID_SELF),
|
|
98
98
|
]
|
|
99
99
|
|
|
100
100
|
return await this.queryOne(...clauses)
|
|
@@ -106,8 +106,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
106
106
|
) {
|
|
107
107
|
const clauses = [
|
|
108
108
|
Q.where('content_id', Q.oneOf(contentIds)),
|
|
109
|
-
Q.where('collection_type', collection?.type ??
|
|
110
|
-
Q.where('collection_id', collection?.id ??
|
|
109
|
+
Q.where('collection_type', collection?.type ?? COLLECTION_TYPE.SELF),
|
|
110
|
+
Q.where('collection_id', collection?.id ?? COLLECTION_ID_SELF),
|
|
111
111
|
]
|
|
112
112
|
|
|
113
113
|
return await this.queryAll(...clauses)
|
|
@@ -118,8 +118,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
118
118
|
|
|
119
119
|
const result = this.upsertOne(id, (r) => {
|
|
120
120
|
r.content_id = contentId
|
|
121
|
-
r.collection_type = collection?.type ??
|
|
122
|
-
r.collection_id = collection?.id ??
|
|
121
|
+
r.collection_type = collection?.type ?? COLLECTION_TYPE.SELF
|
|
122
|
+
r.collection_id = collection?.id ?? COLLECTION_ID_SELF
|
|
123
123
|
|
|
124
124
|
r.state = progressPct === 100 ? STATE.COMPLETED : STATE.STARTED
|
|
125
125
|
r.progress_percent = progressPct
|
|
@@ -142,8 +142,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
142
142
|
progressPercent: progressPct,
|
|
143
143
|
progressStatus: progressPct === 100 ? STATE.COMPLETED : STATE.STARTED,
|
|
144
144
|
bubble: true,
|
|
145
|
-
collectionType: collection?.type ??
|
|
146
|
-
collectionId: collection?.id ??
|
|
145
|
+
collectionType: collection?.type ?? COLLECTION_TYPE.SELF,
|
|
146
|
+
collectionId: collection?.id ?? COLLECTION_ID_SELF,
|
|
147
147
|
resumeTimeSeconds: resumeTime ?? null,
|
|
148
148
|
timestamp: Date.now()
|
|
149
149
|
})
|
|
@@ -165,8 +165,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
165
165
|
ProgressRepository.generateId(contentId, collection),
|
|
166
166
|
(r: ContentProgress) => {
|
|
167
167
|
r.content_id = contentId
|
|
168
|
-
r.collection_type = collection?.type ??
|
|
169
|
-
r.collection_id = collection?.id ??
|
|
168
|
+
r.collection_type = collection?.type ?? COLLECTION_TYPE.SELF
|
|
169
|
+
r.collection_id = collection?.id ?? COLLECTION_ID_SELF
|
|
170
170
|
|
|
171
171
|
r.state = progressPct === 100 ? STATE.COMPLETED : STATE.STARTED
|
|
172
172
|
r.progress_percent = progressPct
|
|
@@ -185,8 +185,8 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
185
185
|
ProgressRepository.generateId(+contentId, collection),
|
|
186
186
|
(r: ContentProgress) => {
|
|
187
187
|
r.content_id = +contentId
|
|
188
|
-
r.collection_type = collection?.type ??
|
|
189
|
-
r.collection_id = collection?.id ??
|
|
188
|
+
r.collection_type = collection?.type ?? COLLECTION_TYPE.SELF
|
|
189
|
+
r.collection_id = collection?.id ?? COLLECTION_ID_SELF
|
|
190
190
|
|
|
191
191
|
r.state = progressPct === 100 ? STATE.COMPLETED : STATE.STARTED
|
|
192
192
|
r.progress_percent = progressPct
|
|
@@ -204,10 +204,6 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
|
|
|
204
204
|
contentId: number,
|
|
205
205
|
collection: { type: COLLECTION_TYPE; id: number } | null
|
|
206
206
|
) {
|
|
207
|
-
|
|
208
|
-
return `${contentId}:${collection.type}:${collection.id}`
|
|
209
|
-
} else {
|
|
210
|
-
return `${contentId}`
|
|
211
|
-
}
|
|
207
|
+
return `${contentId}:${collection?.type || COLLECTION_TYPE.SELF}:${collection?.id || COLLECTION_ID_SELF}`
|
|
212
208
|
}
|
|
213
209
|
}
|