musora-content-services 2.138.4 → 2.139.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
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
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.139.1](https://github.com/railroadmedia/musora-content-services/compare/v2.139.0...v2.139.1) (2026-03-04)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **BEH-1530:** cache 204 daily session response ([#852](https://github.com/railroadmedia/musora-content-services/issues/852)) ([9ce8013](https://github.com/railroadmedia/musora-content-services/commit/9ce80135799733e428bc7f7588615bbf80222b4f))
|
|
11
|
+
|
|
12
|
+
## [2.139.0](https://github.com/railroadmedia/musora-content-services/compare/v2.138.4...v2.139.0) (2026-03-04)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* adds SQLITE_FULL error simulation ([#854](https://github.com/railroadmedia/musora-content-services/issues/854)) ([fc1cf71](https://github.com/railroadmedia/musora-content-services/commit/fc1cf7185ff6a07b08f77eeee0fa5ec2f2fb4197))
|
|
18
|
+
|
|
5
19
|
### [2.138.4](https://github.com/railroadmedia/musora-content-services/compare/v2.138.3...v2.138.4) (2026-03-04)
|
|
6
20
|
|
|
7
21
|
|
package/package.json
CHANGED
|
@@ -102,9 +102,9 @@ export async function updateDailySession(
|
|
|
102
102
|
keepFirstLearningPath: keepFirstLearningPath,
|
|
103
103
|
}
|
|
104
104
|
try {
|
|
105
|
-
const response = (await POST(url, body)) as DailySessionResponse
|
|
105
|
+
const response = (await POST(url, body)) as DailySessionResponse|''
|
|
106
106
|
|
|
107
|
-
if (response) { // refresh cached value
|
|
107
|
+
if (response || response === '') { // refresh cached value
|
|
108
108
|
const urlGet: string = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${encodeURIComponent(dateWithTimezone)}`
|
|
109
109
|
dataPromiseGET(urlGet, true).then(() => {
|
|
110
110
|
dailySessionPromise = null
|
|
@@ -112,7 +112,7 @@ export async function updateDailySession(
|
|
|
112
112
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
return response
|
|
115
|
+
return (response !== '' ? response : null)
|
|
116
116
|
} catch (error: any) {
|
|
117
117
|
return null
|
|
118
118
|
}
|
|
@@ -497,23 +497,23 @@ interface completeLearningPathIntroVideo {
|
|
|
497
497
|
* @returns {Promise<Object|null>} response.intro_video_response - The intro video completion response or null if already completed.
|
|
498
498
|
* @returns {Promise<void>} response.learning_path_reset_response - The reset learning path response.
|
|
499
499
|
* @returns {Promise<Object[]>} response.lesson_import_response - The responses for completing each content_id within the learning path.
|
|
500
|
+
* @returns {Promise<Object|null>} response.update_dailies_response - The updated daily session if it was changed.
|
|
500
501
|
*/
|
|
501
502
|
export async function completeLearningPathIntroVideo(
|
|
502
503
|
introVideoId: number,
|
|
503
504
|
learningPathId: number,
|
|
504
505
|
lessonsToImport: number[] | null,
|
|
505
|
-
brand: string
|
|
506
|
+
brand: string
|
|
506
507
|
) {
|
|
507
508
|
let response = {} as completeLearningPathIntroVideo
|
|
508
|
-
|
|
509
509
|
const collection: CollectionObject = { id: learningPathId, type: COLLECTION_TYPE.LEARNING_PATH }
|
|
510
510
|
|
|
511
511
|
if (!lessonsToImport) {
|
|
512
512
|
response.learning_path_reset_response = await resetIfPossible(learningPathId, collection)
|
|
513
513
|
} else {
|
|
514
514
|
response.lesson_import_response = await contentStatusCompletedMany(lessonsToImport, collection)
|
|
515
|
-
const activePath = await getActivePath(brand)
|
|
516
515
|
|
|
516
|
+
const activePath = await getActivePath(brand)
|
|
517
517
|
if (activePath.active_learning_path_id === learningPathId) {
|
|
518
518
|
response.update_dailies_response = await updateDailySession(brand, new Date(), true)
|
|
519
519
|
}
|
|
@@ -2,8 +2,8 @@ import schema from '../schema'
|
|
|
2
2
|
import type { SyncUserScope } from '../index'
|
|
3
3
|
import { SyncError } from '../errors'
|
|
4
4
|
|
|
5
|
-
import type SQLiteAdapter from '
|
|
6
|
-
import type LokiJSAdapter from '
|
|
5
|
+
import type { default as SQLiteAdapter, SQLiteExtensions } from './sqlite'
|
|
6
|
+
import type LokiJSAdapter from './lokijs'
|
|
7
7
|
|
|
8
8
|
export type DatabaseAdapter = SQLiteAdapter | LokiJSAdapter
|
|
9
9
|
|
|
@@ -13,8 +13,9 @@ type LokiJSAdapterOptions = ConstructorParameters<typeof LokiJSAdapter>[0]
|
|
|
13
13
|
type DatabaseAdapterOptions = SQLiteAdapterOptions & LokiJSAdapterOptions
|
|
14
14
|
|
|
15
15
|
export default function syncAdapterFactory<T extends DatabaseAdapter>(
|
|
16
|
-
AdapterClass: new (options: DatabaseAdapterOptions) => T,
|
|
17
|
-
opts: Omit<DatabaseAdapterOptions, 'schema' | 'migrations'
|
|
16
|
+
AdapterClass: new (options: DatabaseAdapterOptions, extensions?: SQLiteExtensions) => T,
|
|
17
|
+
opts: Omit<DatabaseAdapterOptions, 'schema' | 'migrations'>,
|
|
18
|
+
extensions?: SQLiteExtensions
|
|
18
19
|
): (userScope: SyncUserScope) => T {
|
|
19
20
|
// IMPORTANT: we rely on namespaced databases to prevent data clobbering
|
|
20
21
|
// when localStorage.userId somehow changes outside of an explicit, app-managed logout
|
|
@@ -31,11 +32,13 @@ export default function syncAdapterFactory<T extends DatabaseAdapter>(
|
|
|
31
32
|
throw new SyncError('User ID is required to construct database adapter')
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
const adapter = new AdapterClass({
|
|
35
36
|
...opts,
|
|
36
37
|
dbName: `musora:sync:${userScope.initialId}`,
|
|
37
38
|
schema,
|
|
38
39
|
migrations: undefined
|
|
39
|
-
})
|
|
40
|
+
}, extensions)
|
|
41
|
+
|
|
42
|
+
return adapter
|
|
40
43
|
}
|
|
41
44
|
}
|
|
@@ -1 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite'
|
|
2
|
+
|
|
3
|
+
export default class SQLiteErrorAwareAdapter extends SQLiteAdapter {
|
|
4
|
+
private extensions: SQLiteExtensions;
|
|
5
|
+
|
|
6
|
+
constructor(options: any, extensions: SQLiteExtensions = {}) {
|
|
7
|
+
super(options);
|
|
8
|
+
this.extensions = extensions;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
batch(operations: any[], callback: any) {
|
|
12
|
+
const onFullError = this.extensions.onFullError;
|
|
13
|
+
super.batch(operations, (result: any) => {
|
|
14
|
+
if (result.error && isSQLiteFullError(result.error)) {
|
|
15
|
+
onFullError?.(result.error);
|
|
16
|
+
}
|
|
17
|
+
callback(result);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class FullFailingSQLiteAdapter extends SQLiteErrorAwareAdapter {
|
|
23
|
+
constructor(options: any, extensions?: { onFullError?: (error: Error) => void }) {
|
|
24
|
+
super(options, extensions);
|
|
25
|
+
|
|
26
|
+
// Wrap the dispatcher to intercept batch calls and simulate errors at dispatcher level
|
|
27
|
+
const originalDispatcher = (this as any)._dispatcher;
|
|
28
|
+
const originalCall = originalDispatcher.call.bind(originalDispatcher);
|
|
29
|
+
|
|
30
|
+
originalDispatcher.call = (methodName: string, args: any[], callback: any) => {
|
|
31
|
+
if (methodName === 'batch') {
|
|
32
|
+
// Simulate dispatcher-level error
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
callback({ error: new Error('sqlite error 13 (database or disk is full)') });
|
|
35
|
+
}, 0);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// For all other methods, use original dispatcher
|
|
39
|
+
return originalCall(methodName, args, callback);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isSQLiteFullError(error: Error) {
|
|
45
|
+
const message = error.message.toLowerCase();
|
|
46
|
+
return message.includes('sqlite error 13') || message.includes('database or disk is full');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type SQLiteExtensions = {
|
|
50
|
+
onFullError?: (err: Error) => void
|
|
51
|
+
}
|