@vue-skuilder/db 0.1.32-c → 0.1.32-e
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/dist/{dataLayerProvider-BAn-LRh5.d.ts → contentSource-BMlMwSiG.d.cts} +202 -626
- package/dist/{dataLayerProvider-BJqBlMIl.d.cts → contentSource-Ht3N2f-y.d.ts} +202 -626
- package/dist/core/index.d.cts +23 -84
- package/dist/core/index.d.ts +23 -84
- package/dist/core/index.js +476 -1819
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +456 -1803
- package/dist/core/index.mjs.map +1 -1
- package/dist/dataLayerProvider-BEqB8VBR.d.cts +67 -0
- package/dist/dataLayerProvider-DObSXjnf.d.ts +67 -0
- package/dist/impl/couch/index.d.cts +5 -5
- package/dist/impl/couch/index.d.ts +5 -5
- package/dist/impl/couch/index.js +484 -1827
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +460 -1807
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.d.cts +5 -4
- package/dist/impl/static/index.d.ts +5 -4
- package/dist/impl/static/index.js +458 -1801
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +437 -1784
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/{index-X6wHrURm.d.ts → index-BWvO-_rJ.d.ts} +1 -1
- package/dist/{index-m8MMGxxR.d.cts → index-Ba7hYbHj.d.cts} +1 -1
- package/dist/index.d.cts +461 -11
- package/dist/index.d.ts +461 -11
- package/dist/index.js +9239 -9159
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9129 -9049
- package/dist/index.mjs.map +1 -1
- package/dist/{types-DZ5dUqbL.d.ts → types-CJrLM1Ew.d.ts} +1 -1
- package/dist/{types-ZL8tOPQZ.d.cts → types-W8n-B6HG.d.cts} +1 -1
- package/dist/{types-legacy-C7r0T4OV.d.cts → types-legacy-JXDxinpU.d.cts} +1 -1
- package/dist/{types-legacy-C7r0T4OV.d.ts → types-legacy-JXDxinpU.d.ts} +1 -1
- package/dist/util/packer/index.d.cts +3 -3
- package/dist/util/packer/index.d.ts +3 -3
- package/package.json +2 -2
- package/src/core/interfaces/contentSource.ts +2 -3
- package/src/core/navigators/Pipeline.ts +60 -6
- package/src/core/navigators/PipelineDebugger.ts +103 -0
- package/src/core/navigators/filters/hierarchyDefinition.ts +2 -1
- package/src/core/navigators/filters/interferenceMitigator.ts +2 -1
- package/src/core/navigators/filters/relativePriority.ts +2 -1
- package/src/core/navigators/filters/userTagPreference.ts +2 -1
- package/src/core/navigators/generators/CompositeGenerator.ts +58 -5
- package/src/core/navigators/generators/elo.ts +7 -7
- package/src/core/navigators/generators/prescribed.ts +124 -35
- package/src/core/navigators/generators/srs.ts +3 -4
- package/src/core/navigators/generators/types.ts +48 -2
- package/src/core/navigators/index.ts +3 -3
- package/src/impl/couch/classroomDB.ts +4 -3
- package/src/impl/couch/courseDB.ts +3 -3
- package/src/impl/static/courseDB.ts +3 -3
- package/src/study/SessionController.ts +5 -27
- package/src/study/TagFilteredContentSource.ts +4 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CourseConfig, ClassroomConfig,
|
|
1
|
+
import { CourseConfig, ClassroomConfig, Status, SkuilderCourseData as SkuilderCourseData$1, CourseElo, DataShape, TagFilter } from '@vue-skuilder/common';
|
|
2
2
|
import { Moment } from 'moment';
|
|
3
|
-
import { S as SkuilderCourseData,
|
|
3
|
+
import { S as SkuilderCourseData, b as DocTypePrefixes, D as DocType, Q as QualifiedCardID, T as TagStub, a as Tag, C as CardHistory, c as CardRecord } from './types-legacy-JXDxinpU.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Admin functionality
|
|
@@ -85,114 +85,6 @@ interface ContentBase {
|
|
|
85
85
|
courseID: string;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
/**
|
|
89
|
-
* Service responsible for ELO rating calculations and updates.
|
|
90
|
-
*/
|
|
91
|
-
declare class EloService {
|
|
92
|
-
private dataLayer;
|
|
93
|
-
private user;
|
|
94
|
-
constructor(dataLayer: DataLayerProvider, user: UserDBInterface);
|
|
95
|
-
/**
|
|
96
|
-
* Updates both user and card ELO ratings based on user performance.
|
|
97
|
-
* @param userScore Score between 0-1 representing user performance
|
|
98
|
-
* @param course_id Course identifier
|
|
99
|
-
* @param card_id Card identifier
|
|
100
|
-
* @param userCourseRegDoc User's course registration document (will be mutated)
|
|
101
|
-
* @param currentCard Current card session record
|
|
102
|
-
* @param k Optional K-factor for ELO calculation
|
|
103
|
-
*/
|
|
104
|
-
updateUserAndCardElo(userScore: number, course_id: string, card_id: string, userCourseRegDoc: CourseRegistrationDoc, currentCard: StudySessionRecord, k?: number): Promise<void>;
|
|
105
|
-
/**
|
|
106
|
-
* Updates both user and card ELO ratings with per-tag granularity.
|
|
107
|
-
* Tags in taggedPerformance but not on card will be created dynamically.
|
|
108
|
-
*
|
|
109
|
-
* @param taggedPerformance Performance object with _global and per-tag scores
|
|
110
|
-
* @param course_id Course identifier
|
|
111
|
-
* @param card_id Card identifier
|
|
112
|
-
* @param userCourseRegDoc User's course registration document (will be mutated)
|
|
113
|
-
* @param currentCard Current card session record
|
|
114
|
-
*/
|
|
115
|
-
updateUserAndCardEloPerTag(taggedPerformance: TaggedPerformance, course_id: string, card_id: string, userCourseRegDoc: CourseRegistrationDoc, currentCard: StudySessionRecord): Promise<void>;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
interface SessionTrackingData {
|
|
119
|
-
peekSessionCount: number;
|
|
120
|
-
studySessionCount: number;
|
|
121
|
-
sessionCount: number;
|
|
122
|
-
firstSessionDate: string;
|
|
123
|
-
lastSessionDate: string;
|
|
124
|
-
signupPrompted: boolean;
|
|
125
|
-
promptDismissalCount: number;
|
|
126
|
-
studyModeAcknowledged: boolean;
|
|
127
|
-
}
|
|
128
|
-
interface UserConfig {
|
|
129
|
-
darkMode: boolean;
|
|
130
|
-
likesConfetti: boolean;
|
|
131
|
-
sessionTimeLimit: number;
|
|
132
|
-
email?: string;
|
|
133
|
-
sessionTracking?: Record<string, SessionTrackingData>;
|
|
134
|
-
}
|
|
135
|
-
interface ActivityRecord {
|
|
136
|
-
timeStamp: number | string;
|
|
137
|
-
[key: string]: any;
|
|
138
|
-
}
|
|
139
|
-
interface CourseRegistration {
|
|
140
|
-
status?: 'active' | 'dropped' | 'maintenance-mode' | 'preview';
|
|
141
|
-
courseID: string;
|
|
142
|
-
admin: boolean;
|
|
143
|
-
moderator: boolean;
|
|
144
|
-
user: boolean;
|
|
145
|
-
settings?: {
|
|
146
|
-
[setting: string]: string | number | boolean;
|
|
147
|
-
};
|
|
148
|
-
elo: number | CourseElo;
|
|
149
|
-
}
|
|
150
|
-
interface StudyWeights {
|
|
151
|
-
[courseID: string]: number;
|
|
152
|
-
}
|
|
153
|
-
interface CourseRegistrationDoc {
|
|
154
|
-
courses: CourseRegistration[];
|
|
155
|
-
studyWeight: StudyWeights;
|
|
156
|
-
}
|
|
157
|
-
interface ScheduledCard {
|
|
158
|
-
_id: PouchDB.Core.DocumentId;
|
|
159
|
-
/**
|
|
160
|
-
* The docID of the card to be reviewed
|
|
161
|
-
*/
|
|
162
|
-
cardId: PouchDB.Core.DocumentId;
|
|
163
|
-
/**
|
|
164
|
-
* The ID of the course
|
|
165
|
-
*/
|
|
166
|
-
courseId: string;
|
|
167
|
-
/**
|
|
168
|
-
* The time at which the card becomes eligible for review.
|
|
169
|
-
*
|
|
170
|
-
* (Should probably be UTC adjusted so that performance is
|
|
171
|
-
* not wonky across time zones)
|
|
172
|
-
*
|
|
173
|
-
* Note: Stored as ISO string for PouchDB serialization compatibility,
|
|
174
|
-
* but can be consumed as Moment objects via moment.utc(reviewTime)
|
|
175
|
-
*/
|
|
176
|
-
reviewTime: string | Moment;
|
|
177
|
-
/**
|
|
178
|
-
* The time at which this scheduled event was created.
|
|
179
|
-
*
|
|
180
|
-
* Note: Stored as ISO string for PouchDB serialization compatibility,
|
|
181
|
-
* but can be consumed as Moment objects via moment.utc(scheduledAt)
|
|
182
|
-
*/
|
|
183
|
-
scheduledAt: string | Moment;
|
|
184
|
-
/**
|
|
185
|
-
* Classifying whether this card is scheduled on behalf of a
|
|
186
|
-
* user-registered course or by as assigned content from a
|
|
187
|
-
* user-registered classroom
|
|
188
|
-
*/
|
|
189
|
-
scheduledFor: 'course' | 'classroom';
|
|
190
|
-
/**
|
|
191
|
-
* The ID of the course or classroom that requested this card
|
|
192
|
-
*/
|
|
193
|
-
schedulingAgentId: string;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
88
|
interface DataLayerResult {
|
|
197
89
|
status: Status;
|
|
198
90
|
message: string;
|
|
@@ -247,455 +139,6 @@ interface ContentNavigationStrategyData extends SkuilderCourseData {
|
|
|
247
139
|
staticWeight?: boolean;
|
|
248
140
|
}
|
|
249
141
|
|
|
250
|
-
/**
|
|
251
|
-
* Service responsible for Spaced Repetition System (SRS) scheduling logic.
|
|
252
|
-
*/
|
|
253
|
-
declare class SrsService {
|
|
254
|
-
private user;
|
|
255
|
-
constructor(user: UserDBInterface);
|
|
256
|
-
/**
|
|
257
|
-
* Remove a scheduled review from the user's database.
|
|
258
|
-
* Used to clean up orphaned reviews (e.g., card deleted from course DB).
|
|
259
|
-
*/
|
|
260
|
-
removeReview(reviewID: string): void;
|
|
261
|
-
/**
|
|
262
|
-
* Calculates the next review time for a card based on its history and
|
|
263
|
-
* schedules it in the user's database.
|
|
264
|
-
* @param history The full history of the card.
|
|
265
|
-
* @param item The study session item, used to determine if a previous review needs to be cleared.
|
|
266
|
-
*/
|
|
267
|
-
scheduleReview(history: CardHistory<CardRecord>, item: StudySessionItem): Promise<void>;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Service responsible for orchestrating the complete response processing workflow.
|
|
272
|
-
* Coordinates SRS scheduling and ELO updates for user card interactions.
|
|
273
|
-
*/
|
|
274
|
-
declare class ResponseProcessor {
|
|
275
|
-
private srsService;
|
|
276
|
-
private eloService;
|
|
277
|
-
constructor(srsService: SrsService, eloService: EloService);
|
|
278
|
-
/**
|
|
279
|
-
* Parses performance data into global score and optional per-tag scores.
|
|
280
|
-
*
|
|
281
|
-
* @param performance - Numeric or structured performance from QuestionRecord
|
|
282
|
-
* @returns Parsed performance with global score and optional tag scores
|
|
283
|
-
*/
|
|
284
|
-
private parsePerformance;
|
|
285
|
-
/**
|
|
286
|
-
* Processes a user's response to a card, handling SRS scheduling and ELO updates.
|
|
287
|
-
* @param cardRecord User's response record
|
|
288
|
-
* @param cardHistory Promise resolving to the card's history
|
|
289
|
-
* @param studySessionItem Current study session item
|
|
290
|
-
* @param courseRegistrationDoc User's course registration (for ELO updates)
|
|
291
|
-
* @param currentCard Current study session record
|
|
292
|
-
* @param courseId Course identifier
|
|
293
|
-
* @param cardId Card identifier
|
|
294
|
-
* @param maxAttemptsPerView Maximum attempts allowed per view
|
|
295
|
-
* @param maxSessionViews Maximum session views for this card
|
|
296
|
-
* @param sessionViews Current number of session views
|
|
297
|
-
* @returns ResponseResult with navigation and UI instructions
|
|
298
|
-
*/
|
|
299
|
-
processResponse(cardRecord: CardRecord, cardHistory: Promise<CardHistory<CardRecord>>, studySessionItem: StudySessionItem, courseRegistrationDoc: CourseRegistrationDoc, currentCard: StudySessionRecord, courseId: string, cardId: string, maxAttemptsPerView: number, maxSessionViews: number, sessionViews: number): Promise<ResponseResult>;
|
|
300
|
-
/**
|
|
301
|
-
* Handles processing for correct responses: SRS scheduling and ELO updates.
|
|
302
|
-
*/
|
|
303
|
-
private processCorrectResponse;
|
|
304
|
-
/**
|
|
305
|
-
* Handles processing for incorrect responses: ELO updates only.
|
|
306
|
-
*/
|
|
307
|
-
private processIncorrectResponse;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
interface HydratedCard<TView = unknown> {
|
|
311
|
-
item: StudySessionItem;
|
|
312
|
-
view: TView;
|
|
313
|
-
data: any[];
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
declare abstract class Loggable {
|
|
317
|
-
protected abstract readonly _className: string;
|
|
318
|
-
protected log(...args: unknown[]): void;
|
|
319
|
-
protected error(...args: unknown[]): void;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Represents a batch of content fetched from a single StudyContentSource.
|
|
324
|
-
*/
|
|
325
|
-
interface SourceBatch {
|
|
326
|
-
sourceIndex: number;
|
|
327
|
-
weighted: WeightedCard[];
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Strategy interface for mixing content from multiple sources into a unified
|
|
331
|
-
* set of weighted candidates.
|
|
332
|
-
*
|
|
333
|
-
* Different implementations can provide different balancing strategies:
|
|
334
|
-
* - QuotaRoundRobinMixer: Equal representation per source
|
|
335
|
-
* - MinMaxNormalizingMixer: Score normalization then global sort
|
|
336
|
-
* - PercentileBucketMixer: Bucketed round-robin
|
|
337
|
-
* etc.
|
|
338
|
-
*/
|
|
339
|
-
interface SourceMixer {
|
|
340
|
-
/**
|
|
341
|
-
* Mix weighted cards from multiple sources into a unified, ordered list.
|
|
342
|
-
*
|
|
343
|
-
* @param batches - Content batches from each source
|
|
344
|
-
* @param limit - Target number of cards to return
|
|
345
|
-
* @returns Mixed and ordered weighted cards
|
|
346
|
-
*/
|
|
347
|
-
mix(batches: SourceBatch[], limit: number): WeightedCard[];
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Quota-based mixer with interleaved output.
|
|
351
|
-
*
|
|
352
|
-
* Allocates equal representation to each source (top-N by score), then
|
|
353
|
-
* interleaves the results by dealing from a randomly-shuffled source order.
|
|
354
|
-
* Within each source, cards are dealt in score-descending order.
|
|
355
|
-
*
|
|
356
|
-
* This ensures that cards from different courses are spread throughout the
|
|
357
|
-
* queue rather than clustered by score bands, which matters because
|
|
358
|
-
* SessionController consumes queues front-to-back and sessions often end
|
|
359
|
-
* before reaching the tail.
|
|
360
|
-
*/
|
|
361
|
-
declare class QuotaRoundRobinMixer implements SourceMixer {
|
|
362
|
-
mix(batches: SourceBatch[], limit: number): WeightedCard[];
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Typed ephemeral pipeline hints for a single run.
|
|
367
|
-
* All fields are optional. Tag/card patterns support `*` wildcards.
|
|
368
|
-
*
|
|
369
|
-
* Previously defined in Pipeline.ts; moved here so it's co-exported
|
|
370
|
-
* with ReplanOptions from the public `@vue-skuilder/db` surface.
|
|
371
|
-
*/
|
|
372
|
-
interface ReplanHints {
|
|
373
|
-
/** Multiply scores for cards matching these tag patterns. */
|
|
374
|
-
boostTags?: Record<string, number>;
|
|
375
|
-
/** Multiply scores for these specific card IDs (glob patterns). */
|
|
376
|
-
boostCards?: Record<string, number>;
|
|
377
|
-
/** Cards matching these tag patterns MUST appear in results. */
|
|
378
|
-
requireTags?: string[];
|
|
379
|
-
/** These specific card IDs MUST appear in results. */
|
|
380
|
-
requireCards?: string[];
|
|
381
|
-
/** Remove cards matching these tag patterns from results. */
|
|
382
|
-
excludeTags?: string[];
|
|
383
|
-
/** Remove these specific card IDs from results. */
|
|
384
|
-
excludeCards?: string[];
|
|
385
|
-
/**
|
|
386
|
-
* Debugging label threaded from the replan requester.
|
|
387
|
-
* Prefixed with `_` to signal it's metadata, not a scoring hint.
|
|
388
|
-
*/
|
|
389
|
-
_label?: string;
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Options for requesting a mid-session replan.
|
|
393
|
-
*
|
|
394
|
-
* All fields are optional — callers can pass just the fields they need.
|
|
395
|
-
* When omitted, defaults match the existing behaviour (full 20-card
|
|
396
|
-
* replace with no hints).
|
|
397
|
-
*/
|
|
398
|
-
interface ReplanOptions {
|
|
399
|
-
/** Scoring hints forwarded to the pipeline (boost/exclude/require). */
|
|
400
|
-
hints?: ReplanHints;
|
|
401
|
-
/**
|
|
402
|
-
* Maximum number of new cards to return from the pipeline.
|
|
403
|
-
* Default: 20 (the standard session batch size).
|
|
404
|
-
*/
|
|
405
|
-
limit?: number;
|
|
406
|
-
/**
|
|
407
|
-
* How to integrate the new cards into the existing newQ.
|
|
408
|
-
* - `'replace'` (default): atomically swap the entire newQ.
|
|
409
|
-
* - `'merge'`: insert new cards at the front, keeping existing cards.
|
|
410
|
-
*/
|
|
411
|
-
mode?: 'replace' | 'merge';
|
|
412
|
-
/**
|
|
413
|
-
* Guarantee that at least this many cards will be served after the
|
|
414
|
-
* replan, even if the session timer has expired. Prevents intro cards
|
|
415
|
-
* from surfacing at the end of a session with zero follow-up exercise.
|
|
416
|
-
* Decremented on each card draw while active.
|
|
417
|
-
*/
|
|
418
|
-
minFollowUpCards?: number;
|
|
419
|
-
/**
|
|
420
|
-
* Human-readable label for debugging / provenance.
|
|
421
|
-
* Appears in console logs and in card provenance entries created
|
|
422
|
-
* by ephemeral hint application.
|
|
423
|
-
*/
|
|
424
|
-
label?: string;
|
|
425
|
-
}
|
|
426
|
-
interface StudySessionRecord {
|
|
427
|
-
card: {
|
|
428
|
-
course_id: string;
|
|
429
|
-
card_id: string;
|
|
430
|
-
card_elo: number;
|
|
431
|
-
};
|
|
432
|
-
item: StudySessionItem;
|
|
433
|
-
records: CardRecord[];
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
type SessionAction = 'dismiss-success' | 'dismiss-failed' | 'marked-failed' | 'dismiss-error';
|
|
437
|
-
interface ResponseResult {
|
|
438
|
-
nextCardAction: Exclude<SessionAction, 'dismiss-error'> | 'none';
|
|
439
|
-
shouldLoadNextCard: boolean;
|
|
440
|
-
/**
|
|
441
|
-
* When true, the card requested deferred advancement via `deferAdvance`.
|
|
442
|
-
* The record was logged and ELO updated, but navigation was suppressed.
|
|
443
|
-
* StudySession should stash `nextCardAction` and wait for a
|
|
444
|
-
* `ready-to-advance` event from the card before calling `nextCard()`.
|
|
445
|
-
*/
|
|
446
|
-
deferred?: boolean;
|
|
447
|
-
isCorrect: boolean;
|
|
448
|
-
performanceScore?: number;
|
|
449
|
-
shouldClearFeedbackShadow: boolean;
|
|
450
|
-
}
|
|
451
|
-
interface SessionServices {
|
|
452
|
-
response: ResponseProcessor;
|
|
453
|
-
}
|
|
454
|
-
declare class SessionController<TView = unknown> extends Loggable {
|
|
455
|
-
_className: string;
|
|
456
|
-
services: SessionServices;
|
|
457
|
-
private srsService;
|
|
458
|
-
private eloService;
|
|
459
|
-
private hydrationService;
|
|
460
|
-
private mixer;
|
|
461
|
-
private dataLayer;
|
|
462
|
-
private courseNameCache;
|
|
463
|
-
/**
|
|
464
|
-
* Default pipeline batch size for new-card planning.
|
|
465
|
-
* Set via constructor options; falls back to 20 when not specified.
|
|
466
|
-
* Individual replans can override via `ReplanOptions.limit`.
|
|
467
|
-
*/
|
|
468
|
-
private _defaultBatchLimit;
|
|
469
|
-
private sources;
|
|
470
|
-
private _sessionRecord;
|
|
471
|
-
set sessionRecord(r: StudySessionRecord[]);
|
|
472
|
-
private _currentCard;
|
|
473
|
-
private reviewQ;
|
|
474
|
-
private newQ;
|
|
475
|
-
private failedQ;
|
|
476
|
-
/**
|
|
477
|
-
* Promise tracking a currently in-progress replan, or null if idle.
|
|
478
|
-
* Used by nextCard() to await completion before drawing from queues.
|
|
479
|
-
*/
|
|
480
|
-
private _replanPromise;
|
|
481
|
-
/**
|
|
482
|
-
* Number of well-indicated new cards remaining before the queue
|
|
483
|
-
* degrades to poorly-indicated content. Decremented on each newQ
|
|
484
|
-
* draw; when it hits 0, a replan is triggered automatically
|
|
485
|
-
* (user state has changed from completing good cards).
|
|
486
|
-
*/
|
|
487
|
-
private _wellIndicatedRemaining;
|
|
488
|
-
/**
|
|
489
|
-
* When true, suppresses the quality-based auto-replan trigger in
|
|
490
|
-
* nextCard(). Set after a burst replan (small limit) to prevent the
|
|
491
|
-
* auto-replan from clobbering the burst cards before they're consumed.
|
|
492
|
-
* Cleared when the depletion-triggered replan fires (newQ exhausted).
|
|
493
|
-
*/
|
|
494
|
-
private _suppressQualityReplan;
|
|
495
|
-
/**
|
|
496
|
-
* Guards against infinite depletion-triggered replans. Set to true
|
|
497
|
-
* when a depletion replan fires; cleared when a replan produces
|
|
498
|
-
* content (newQ.length > 0 after replan) or when an explicit
|
|
499
|
-
* (non-auto) replan is requested.
|
|
500
|
-
*/
|
|
501
|
-
private _depletionReplanAttempted;
|
|
502
|
-
/**
|
|
503
|
-
* When > 0, the session timer cannot end the session. Decremented on
|
|
504
|
-
* each nextCard() draw. Set by replans that include `minFollowUpCards`.
|
|
505
|
-
*/
|
|
506
|
-
private _minCardsGuarantee;
|
|
507
|
-
private startTime;
|
|
508
|
-
private endTime;
|
|
509
|
-
private _secondsRemaining;
|
|
510
|
-
get secondsRemaining(): number;
|
|
511
|
-
/** True when a card guarantee is active, preventing timer-based session end. */
|
|
512
|
-
get hasCardGuarantee(): boolean;
|
|
513
|
-
get report(): string;
|
|
514
|
-
get detailedReport(): string;
|
|
515
|
-
private _intervalHandle;
|
|
516
|
-
/**
|
|
517
|
-
* @param sources - Array of content sources to mix for the session
|
|
518
|
-
* @param time - Session duration in seconds
|
|
519
|
-
* @param dataLayer - Data layer provider
|
|
520
|
-
* @param getViewComponent - Function to resolve view components
|
|
521
|
-
* @param mixer - Optional source mixer strategy (defaults to QuotaRoundRobinMixer)
|
|
522
|
-
* @param options - Optional session-level configuration
|
|
523
|
-
* @param options.defaultBatchLimit - Default pipeline batch size (default: 20).
|
|
524
|
-
* Smaller values for newer users cause more frequent replans, keeping plans
|
|
525
|
-
* aligned with rapidly-changing user state.
|
|
526
|
-
*/
|
|
527
|
-
constructor(sources: StudyContentSource[], time: number, dataLayer: DataLayerProvider, getViewComponent: (viewId: string) => TView, mixer?: SourceMixer, options?: {
|
|
528
|
-
defaultBatchLimit?: number;
|
|
529
|
-
});
|
|
530
|
-
private tick;
|
|
531
|
-
/**
|
|
532
|
-
* Returns a rough, erring toward conservative, guess at
|
|
533
|
-
* the amount of time the failed cards queue will require
|
|
534
|
-
* to clean up.
|
|
535
|
-
*
|
|
536
|
-
* (seconds)
|
|
537
|
-
*/
|
|
538
|
-
private estimateCleanupTime;
|
|
539
|
-
/**
|
|
540
|
-
* Extremely rough, conservative, estimate of amound of time to complete
|
|
541
|
-
* all scheduled reviews
|
|
542
|
-
*/
|
|
543
|
-
private estimateReviewTime;
|
|
544
|
-
prepareSession(): Promise<void>;
|
|
545
|
-
/**
|
|
546
|
-
* Request a mid-session replan. Re-runs the pipeline with current user state
|
|
547
|
-
* and atomically replaces the newQ contents. Safe to call at any time during
|
|
548
|
-
* a session — if called while a replan is already in progress, returns the
|
|
549
|
-
* existing replan promise (no duplicate work).
|
|
550
|
-
*
|
|
551
|
-
* Does NOT affect reviewQ or failedQ.
|
|
552
|
-
*
|
|
553
|
-
* If nextCard() is called while a replan is in flight, it will automatically
|
|
554
|
-
* await the replan before drawing from queues, ensuring the user always sees
|
|
555
|
-
* cards scored against their latest state.
|
|
556
|
-
*
|
|
557
|
-
* Typical trigger: application-level code (e.g. after a GPC intro completion)
|
|
558
|
-
* calls this to ensure newly-unlocked content appears in the session.
|
|
559
|
-
*/
|
|
560
|
-
requestReplan(options?: ReplanOptions | ReplanHints): Promise<void>;
|
|
561
|
-
/**
|
|
562
|
-
* Normalise the requestReplan argument. Accepts either a ReplanOptions
|
|
563
|
-
* object (new API) or a plain Record<string, unknown> (legacy callers
|
|
564
|
-
* that passed hints directly). Distinguishes the two by checking for
|
|
565
|
-
* the presence of ReplanOptions-specific keys.
|
|
566
|
-
*/
|
|
567
|
-
private normalizeReplanOptions;
|
|
568
|
-
/** Minimum well-indicated cards before an additive retry is attempted */
|
|
569
|
-
private static readonly MIN_WELL_INDICATED;
|
|
570
|
-
/**
|
|
571
|
-
* Score threshold for considering a card "well-indicated."
|
|
572
|
-
* Cards below this score are treated as fallback filler — present only
|
|
573
|
-
* because no strategy hard-removed them, but likely penalized by one
|
|
574
|
-
* or more filters. Strategy-agnostic: the SessionController doesn't
|
|
575
|
-
* know or care which strategy assigned the score.
|
|
576
|
-
*/
|
|
577
|
-
private static readonly WELL_INDICATED_SCORE;
|
|
578
|
-
/**
|
|
579
|
-
* Internal replan execution. Runs the pipeline, builds a new newQ,
|
|
580
|
-
* atomically swaps it in, and triggers hydration for the new contents.
|
|
581
|
-
*
|
|
582
|
-
* If the initial replan produces fewer than MIN_WELL_INDICATED cards that
|
|
583
|
-
* pass all hierarchy filters, one additive retry is attempted — merging
|
|
584
|
-
* any new high-quality candidates into the front of the queue.
|
|
585
|
-
*/
|
|
586
|
-
private _executeReplan;
|
|
587
|
-
addTime(seconds: number): void;
|
|
588
|
-
get failedCount(): number;
|
|
589
|
-
toString(): string;
|
|
590
|
-
reportString(): string;
|
|
591
|
-
/**
|
|
592
|
-
* Returns debug information about the current session state.
|
|
593
|
-
* Used by SessionControllerDebug component for runtime inspection.
|
|
594
|
-
*/
|
|
595
|
-
getDebugInfo(): {
|
|
596
|
-
api: {
|
|
597
|
-
mode: string;
|
|
598
|
-
description: string;
|
|
599
|
-
};
|
|
600
|
-
reviewQueue: {
|
|
601
|
-
length: number;
|
|
602
|
-
dequeueCount: number;
|
|
603
|
-
items: {
|
|
604
|
-
courseID: any;
|
|
605
|
-
cardID: any;
|
|
606
|
-
status: any;
|
|
607
|
-
}[];
|
|
608
|
-
};
|
|
609
|
-
newQueue: {
|
|
610
|
-
length: number;
|
|
611
|
-
dequeueCount: number;
|
|
612
|
-
items: {
|
|
613
|
-
courseID: any;
|
|
614
|
-
cardID: any;
|
|
615
|
-
status: any;
|
|
616
|
-
}[];
|
|
617
|
-
};
|
|
618
|
-
failedQueue: {
|
|
619
|
-
length: number;
|
|
620
|
-
dequeueCount: number;
|
|
621
|
-
items: {
|
|
622
|
-
courseID: any;
|
|
623
|
-
cardID: any;
|
|
624
|
-
status: any;
|
|
625
|
-
}[];
|
|
626
|
-
};
|
|
627
|
-
hydratedCache: {
|
|
628
|
-
count: number;
|
|
629
|
-
cardIds: string[];
|
|
630
|
-
};
|
|
631
|
-
replan: {
|
|
632
|
-
inProgress: boolean;
|
|
633
|
-
suppressQualityReplan: boolean;
|
|
634
|
-
defaultBatchLimit: number;
|
|
635
|
-
minCardsGuarantee: number;
|
|
636
|
-
};
|
|
637
|
-
};
|
|
638
|
-
/**
|
|
639
|
-
* Fetch content using the getWeightedCards API and mix across sources.
|
|
640
|
-
*
|
|
641
|
-
* This method:
|
|
642
|
-
* 1. Fetches weighted cards from each source
|
|
643
|
-
* 2. Fetches full review data (we need ScheduledCard fields for queue)
|
|
644
|
-
* 3. Uses SourceMixer to balance content across sources
|
|
645
|
-
* 4. Populates review and new card queues with mixed results
|
|
646
|
-
*/
|
|
647
|
-
/**
|
|
648
|
-
* Fetch weighted content from all sources and populate session queues.
|
|
649
|
-
*
|
|
650
|
-
* @param options.replan - If true, this is a mid-session replan rather than
|
|
651
|
-
* initial session setup. Skips review queue population (avoiding duplicates),
|
|
652
|
-
* atomically replaces newQ contents, and treats empty results as non-fatal.
|
|
653
|
-
* @param options.additive - If true (replan only), merge new high-quality
|
|
654
|
-
* candidates into the front of the existing newQ instead of replacing it.
|
|
655
|
-
* @returns Number of "well-indicated" cards (passed all hierarchy filters)
|
|
656
|
-
* in the new content. Returns -1 if no content was loaded.
|
|
657
|
-
*/
|
|
658
|
-
private getWeightedContent;
|
|
659
|
-
/**
|
|
660
|
-
* Returns items that should be pre-hydrated.
|
|
661
|
-
* Deterministic: top N items from each queue to ensure coverage.
|
|
662
|
-
* Failed queue items will typically already be hydrated (from initial render).
|
|
663
|
-
*/
|
|
664
|
-
private _getItemsToHydrate;
|
|
665
|
-
/**
|
|
666
|
-
* Selects the next item to present to the user.
|
|
667
|
-
* Nondeterministic: uses probability to balance between queues based on session state.
|
|
668
|
-
*/
|
|
669
|
-
private _selectNextItemToHydrate;
|
|
670
|
-
nextCard(action?: SessionAction): Promise<HydratedCard<TView> | null>;
|
|
671
|
-
/**
|
|
672
|
-
* Public API for processing user responses to cards.
|
|
673
|
-
* @param cardRecord User's response record
|
|
674
|
-
* @param cardHistory Promise resolving to the card's history
|
|
675
|
-
* @param courseRegistrationDoc User's course registration document
|
|
676
|
-
* @param currentCard Current study session record
|
|
677
|
-
* @param courseId Course identifier
|
|
678
|
-
* @param cardId Card identifier
|
|
679
|
-
* @param maxAttemptsPerView Maximum attempts allowed per view
|
|
680
|
-
* @param maxSessionViews Maximum session views for this card
|
|
681
|
-
* @param sessionViews Current number of session views
|
|
682
|
-
* @returns ResponseResult with navigation and UI instructions
|
|
683
|
-
*/
|
|
684
|
-
submitResponse(cardRecord: CardRecord, cardHistory: Promise<CardHistory<CardRecord>>, courseRegistrationDoc: CourseRegistrationDoc, currentCard: StudySessionRecord, courseId: string, cardId: string, maxAttemptsPerView: number, maxSessionViews: number, sessionViews: number): Promise<ResponseResult>;
|
|
685
|
-
private dismissCurrentCard;
|
|
686
|
-
/**
|
|
687
|
-
* Remove an item from its source queue after consumption by nextCard().
|
|
688
|
-
*/
|
|
689
|
-
private removeItemFromQueue;
|
|
690
|
-
/**
|
|
691
|
-
* End the session and record learning outcomes.
|
|
692
|
-
*
|
|
693
|
-
* This method aggregates all responses from the session and records a
|
|
694
|
-
* UserOutcomeRecord if evolutionary orchestration is enabled.
|
|
695
|
-
*/
|
|
696
|
-
endSession(): Promise<void>;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
142
|
/**
|
|
700
143
|
* A NavigationStrategyManager is an entity which may contain multiple strategies.
|
|
701
144
|
*
|
|
@@ -853,6 +296,84 @@ interface CourseDBInterface extends NavigationStrategyManager, StudyContentSourc
|
|
|
853
296
|
find(request: PouchDB.Find.FindRequest<any>): Promise<PouchDB.Find.FindResponse<any>>;
|
|
854
297
|
}
|
|
855
298
|
|
|
299
|
+
interface SessionTrackingData {
|
|
300
|
+
peekSessionCount: number;
|
|
301
|
+
studySessionCount: number;
|
|
302
|
+
sessionCount: number;
|
|
303
|
+
firstSessionDate: string;
|
|
304
|
+
lastSessionDate: string;
|
|
305
|
+
signupPrompted: boolean;
|
|
306
|
+
promptDismissalCount: number;
|
|
307
|
+
studyModeAcknowledged: boolean;
|
|
308
|
+
}
|
|
309
|
+
interface UserConfig {
|
|
310
|
+
darkMode: boolean;
|
|
311
|
+
likesConfetti: boolean;
|
|
312
|
+
sessionTimeLimit: number;
|
|
313
|
+
email?: string;
|
|
314
|
+
sessionTracking?: Record<string, SessionTrackingData>;
|
|
315
|
+
}
|
|
316
|
+
interface ActivityRecord {
|
|
317
|
+
timeStamp: number | string;
|
|
318
|
+
[key: string]: any;
|
|
319
|
+
}
|
|
320
|
+
interface CourseRegistration {
|
|
321
|
+
status?: 'active' | 'dropped' | 'maintenance-mode' | 'preview';
|
|
322
|
+
courseID: string;
|
|
323
|
+
admin: boolean;
|
|
324
|
+
moderator: boolean;
|
|
325
|
+
user: boolean;
|
|
326
|
+
settings?: {
|
|
327
|
+
[setting: string]: string | number | boolean;
|
|
328
|
+
};
|
|
329
|
+
elo: number | CourseElo;
|
|
330
|
+
}
|
|
331
|
+
interface StudyWeights {
|
|
332
|
+
[courseID: string]: number;
|
|
333
|
+
}
|
|
334
|
+
interface CourseRegistrationDoc {
|
|
335
|
+
courses: CourseRegistration[];
|
|
336
|
+
studyWeight: StudyWeights;
|
|
337
|
+
}
|
|
338
|
+
interface ScheduledCard {
|
|
339
|
+
_id: PouchDB.Core.DocumentId;
|
|
340
|
+
/**
|
|
341
|
+
* The docID of the card to be reviewed
|
|
342
|
+
*/
|
|
343
|
+
cardId: PouchDB.Core.DocumentId;
|
|
344
|
+
/**
|
|
345
|
+
* The ID of the course
|
|
346
|
+
*/
|
|
347
|
+
courseId: string;
|
|
348
|
+
/**
|
|
349
|
+
* The time at which the card becomes eligible for review.
|
|
350
|
+
*
|
|
351
|
+
* (Should probably be UTC adjusted so that performance is
|
|
352
|
+
* not wonky across time zones)
|
|
353
|
+
*
|
|
354
|
+
* Note: Stored as ISO string for PouchDB serialization compatibility,
|
|
355
|
+
* but can be consumed as Moment objects via moment.utc(reviewTime)
|
|
356
|
+
*/
|
|
357
|
+
reviewTime: string | Moment;
|
|
358
|
+
/**
|
|
359
|
+
* The time at which this scheduled event was created.
|
|
360
|
+
*
|
|
361
|
+
* Note: Stored as ISO string for PouchDB serialization compatibility,
|
|
362
|
+
* but can be consumed as Moment objects via moment.utc(scheduledAt)
|
|
363
|
+
*/
|
|
364
|
+
scheduledAt: string | Moment;
|
|
365
|
+
/**
|
|
366
|
+
* Classifying whether this card is scheduled on behalf of a
|
|
367
|
+
* user-registered course or by as assigned content from a
|
|
368
|
+
* user-registered classroom
|
|
369
|
+
*/
|
|
370
|
+
scheduledFor: 'course' | 'classroom';
|
|
371
|
+
/**
|
|
372
|
+
* The ID of the course or classroom that requested this card
|
|
373
|
+
*/
|
|
374
|
+
schedulingAgentId: string;
|
|
375
|
+
}
|
|
376
|
+
|
|
856
377
|
/**
|
|
857
378
|
* Record of a user's learning outcome over a specific period.
|
|
858
379
|
*
|
|
@@ -1522,7 +1043,7 @@ declare abstract class ContentNavigator implements StudyContentSource {
|
|
|
1522
1043
|
* @param limit - Maximum cards to return
|
|
1523
1044
|
* @returns Cards sorted by score descending, with provenance trails
|
|
1524
1045
|
*/
|
|
1525
|
-
getWeightedCards(_limit: number): Promise<
|
|
1046
|
+
getWeightedCards(_limit: number): Promise<GeneratorResult>;
|
|
1526
1047
|
/**
|
|
1527
1048
|
* Set ephemeral hints for the next pipeline run.
|
|
1528
1049
|
* No-op for non-Pipeline navigators. Pipeline overrides this.
|
|
@@ -1530,6 +1051,125 @@ declare abstract class ContentNavigator implements StudyContentSource {
|
|
|
1530
1051
|
setEphemeralHints(_hints: ReplanHints): void;
|
|
1531
1052
|
}
|
|
1532
1053
|
|
|
1054
|
+
/**
|
|
1055
|
+
* Typed ephemeral pipeline hints for a single run.
|
|
1056
|
+
* All fields are optional. Tag/card patterns support `*` wildcards.
|
|
1057
|
+
*/
|
|
1058
|
+
interface ReplanHints {
|
|
1059
|
+
/** Multiply scores for cards matching these tag patterns. */
|
|
1060
|
+
boostTags?: Record<string, number>;
|
|
1061
|
+
/** Multiply scores for these specific card IDs (glob patterns). */
|
|
1062
|
+
boostCards?: Record<string, number>;
|
|
1063
|
+
/** Cards matching these tag patterns MUST appear in results. */
|
|
1064
|
+
requireTags?: string[];
|
|
1065
|
+
/** These specific card IDs MUST appear in results. */
|
|
1066
|
+
requireCards?: string[];
|
|
1067
|
+
/** Remove cards matching these tag patterns from results. */
|
|
1068
|
+
excludeTags?: string[];
|
|
1069
|
+
/** Remove these specific card IDs from results. */
|
|
1070
|
+
excludeCards?: string[];
|
|
1071
|
+
/**
|
|
1072
|
+
* Debugging label threaded from the replan requester.
|
|
1073
|
+
* Prefixed with `_` to signal it's metadata, not a scoring hint.
|
|
1074
|
+
*/
|
|
1075
|
+
_label?: string;
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Context available to generators when producing candidates.
|
|
1079
|
+
*
|
|
1080
|
+
* Built once per getWeightedCards() call by the Pipeline.
|
|
1081
|
+
*/
|
|
1082
|
+
interface GeneratorContext {
|
|
1083
|
+
/** User database interface */
|
|
1084
|
+
user: UserDBInterface;
|
|
1085
|
+
/** Course database interface */
|
|
1086
|
+
course: CourseDBInterface;
|
|
1087
|
+
/** User's global ELO score for this course */
|
|
1088
|
+
userElo: number;
|
|
1089
|
+
/** Orchestration context for evolutionary weighting */
|
|
1090
|
+
orchestration?: OrchestrationContext;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Structured generator result.
|
|
1094
|
+
*
|
|
1095
|
+
* Generators may optionally emit one-shot replan hints alongside their
|
|
1096
|
+
* candidate cards. This allows a generator to shape the broader pipeline
|
|
1097
|
+
* without having to enumerate every affected support card directly.
|
|
1098
|
+
*/
|
|
1099
|
+
interface GeneratorResult {
|
|
1100
|
+
/** Candidate cards produced by the generator */
|
|
1101
|
+
cards: WeightedCard[];
|
|
1102
|
+
/** Optional one-shot hints to apply after the filter chain */
|
|
1103
|
+
hints?: ReplanHints;
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* A generator that produces candidate cards with initial scores.
|
|
1107
|
+
*
|
|
1108
|
+
* Generators are the "source" stage of a navigation pipeline.
|
|
1109
|
+
* They query the database for eligible cards and assign initial
|
|
1110
|
+
* suitability scores based on their strategy (ELO proximity,
|
|
1111
|
+
* review urgency, fixed order, etc.).
|
|
1112
|
+
*
|
|
1113
|
+
* ## Implementation Guidelines
|
|
1114
|
+
*
|
|
1115
|
+
* 1. **Create provenance**: Each card should have a provenance entry
|
|
1116
|
+
* with action='generated' documenting why it was selected.
|
|
1117
|
+
*
|
|
1118
|
+
* 2. **Score semantics**: Higher scores = more suitable for presentation.
|
|
1119
|
+
* Scores should be in [0, 1] range for composability.
|
|
1120
|
+
*
|
|
1121
|
+
* 3. **Limit handling**: Respect the limit parameter, but may over-fetch
|
|
1122
|
+
* internally if needed for scoring accuracy.
|
|
1123
|
+
*
|
|
1124
|
+
* 4. **Sort before returning**: Return cards sorted by score descending.
|
|
1125
|
+
*
|
|
1126
|
+
* 5. **Hints are optional**: Generators may return structured results with
|
|
1127
|
+
* `hints` when they need to apply pipeline-wide ephemeral pressure.
|
|
1128
|
+
*
|
|
1129
|
+
* ## Example Implementation
|
|
1130
|
+
*
|
|
1131
|
+
* ```typescript
|
|
1132
|
+
* const myGenerator: CardGenerator = {
|
|
1133
|
+
* name: 'My Generator',
|
|
1134
|
+
* async getWeightedCards(limit, context) {
|
|
1135
|
+
* const candidates = await fetchCandidates(context.course, limit);
|
|
1136
|
+
* return candidates.map(c => ({
|
|
1137
|
+
* cardId: c.id,
|
|
1138
|
+
* courseId: context.course.getCourseID(),
|
|
1139
|
+
* score: computeScore(c, context),
|
|
1140
|
+
* provenance: [{
|
|
1141
|
+
* strategy: 'myGenerator',
|
|
1142
|
+
* strategyName: 'My Generator',
|
|
1143
|
+
* strategyId: 'MY_GENERATOR',
|
|
1144
|
+
* action: 'generated',
|
|
1145
|
+
* score: computeScore(c, context),
|
|
1146
|
+
* reason: 'Explanation of selection'
|
|
1147
|
+
* }]
|
|
1148
|
+
* }));
|
|
1149
|
+
* }
|
|
1150
|
+
* };
|
|
1151
|
+
* ```
|
|
1152
|
+
*/
|
|
1153
|
+
interface CardGenerator {
|
|
1154
|
+
/** Human-readable name for this generator */
|
|
1155
|
+
name: string;
|
|
1156
|
+
/**
|
|
1157
|
+
* Produce candidate cards with initial scores.
|
|
1158
|
+
*
|
|
1159
|
+
* @param limit - Maximum number of cards to return
|
|
1160
|
+
* @param context - Shared context (user, course, userElo, etc.)
|
|
1161
|
+
* @returns Cards sorted by score descending, with provenance, optionally
|
|
1162
|
+
* accompanied by one-shot replan hints
|
|
1163
|
+
*/
|
|
1164
|
+
getWeightedCards(limit: number, context: GeneratorContext): Promise<GeneratorResult>;
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Factory function type for creating generators from configuration.
|
|
1168
|
+
*
|
|
1169
|
+
* Used by PipelineAssembler to instantiate generators from strategy documents.
|
|
1170
|
+
*/
|
|
1171
|
+
type CardGeneratorFactory<TConfig = unknown> = (config: TConfig) => CardGenerator;
|
|
1172
|
+
|
|
1533
1173
|
type StudySessionFailedItem = StudySessionFailedNewItem | StudySessionFailedReviewItem;
|
|
1534
1174
|
interface StudySessionFailedNewItem extends StudySessionItem {
|
|
1535
1175
|
status: 'failed-new';
|
|
@@ -1580,7 +1220,7 @@ interface StudyContentSource {
|
|
|
1580
1220
|
* @param limit - Maximum number of cards to return
|
|
1581
1221
|
* @returns Cards sorted by score descending
|
|
1582
1222
|
*/
|
|
1583
|
-
getWeightedCards(limit: number): Promise<
|
|
1223
|
+
getWeightedCards(limit: number): Promise<GeneratorResult>;
|
|
1584
1224
|
/**
|
|
1585
1225
|
* Get the orchestration context for this source.
|
|
1586
1226
|
* Used for recording learning outcomes.
|
|
@@ -1594,68 +1234,4 @@ interface StudyContentSource {
|
|
|
1594
1234
|
}
|
|
1595
1235
|
declare function getStudySource(source: ContentSourceID, user: UserDBInterface): Promise<StudyContentSource>;
|
|
1596
1236
|
|
|
1597
|
-
|
|
1598
|
-
* Main factory interface for data access
|
|
1599
|
-
*/
|
|
1600
|
-
interface DataLayerProvider {
|
|
1601
|
-
/**
|
|
1602
|
-
* Get the user database interface
|
|
1603
|
-
*/
|
|
1604
|
-
getUserDB(): UserDBInterface;
|
|
1605
|
-
/**
|
|
1606
|
-
* Create a UserDBReader for a specific user (admin access required)
|
|
1607
|
-
* Uses session authentication to verify requesting user is admin
|
|
1608
|
-
* @param targetUsername - The username to create a reader for
|
|
1609
|
-
* @throws Error if requesting user is not 'admin'
|
|
1610
|
-
*/
|
|
1611
|
-
createUserReaderForUser(targetUsername: string): Promise<UserDBReader>;
|
|
1612
|
-
/**
|
|
1613
|
-
* Get a course database interface
|
|
1614
|
-
*/
|
|
1615
|
-
getCourseDB(courseId: string): CourseDBInterface;
|
|
1616
|
-
/**
|
|
1617
|
-
* Get the courses-lookup interface
|
|
1618
|
-
*/
|
|
1619
|
-
getCoursesDB(): CoursesDBInterface;
|
|
1620
|
-
/**
|
|
1621
|
-
* Get a classroom database interface
|
|
1622
|
-
*/
|
|
1623
|
-
getClassroomDB(classId: string, type: 'student' | 'teacher'): Promise<ClassroomDBInterface>;
|
|
1624
|
-
/**
|
|
1625
|
-
* Get the admin database interface
|
|
1626
|
-
*/
|
|
1627
|
-
getAdminDB(): AdminDBInterface;
|
|
1628
|
-
/**
|
|
1629
|
-
* Initialize the data layer
|
|
1630
|
-
*/
|
|
1631
|
-
initialize(): Promise<void>;
|
|
1632
|
-
/**
|
|
1633
|
-
* Teardown the data layer
|
|
1634
|
-
*/
|
|
1635
|
-
teardown(): Promise<void>;
|
|
1636
|
-
/**
|
|
1637
|
-
* Check if this data layer is read-only
|
|
1638
|
-
*/
|
|
1639
|
-
isReadOnly(): boolean;
|
|
1640
|
-
/**
|
|
1641
|
-
* Trigger local replication of a course database.
|
|
1642
|
-
*
|
|
1643
|
-
* When a course opts in via `CourseConfig.localSync.enabled`, this method
|
|
1644
|
-
* replicates the remote course DB to a local PouchDB instance. Subsequent
|
|
1645
|
-
* `getCourseDB()` calls for that course will return a CourseDB that reads
|
|
1646
|
-
* from the local replica (fast, no network) and writes to the remote
|
|
1647
|
-
* (ELO updates, admin ops).
|
|
1648
|
-
*
|
|
1649
|
-
* Safe to call multiple times — concurrent calls coalesce. Returns when
|
|
1650
|
-
* sync is complete (or immediately if already synced / disabled).
|
|
1651
|
-
*
|
|
1652
|
-
* Implementations that don't support local sync may no-op.
|
|
1653
|
-
*
|
|
1654
|
-
* @param courseId - The course to sync locally
|
|
1655
|
-
* @param forceEnabled - Skip CourseConfig check and sync regardless.
|
|
1656
|
-
* Use when the caller already knows local sync is desired.
|
|
1657
|
-
*/
|
|
1658
|
-
ensureCourseSynced?(courseId: string, forceEnabled?: boolean): Promise<void>;
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
export { type StrategyContribution as $, type AdminDBInterface as A, type UserCourseSetting as B, type CourseDBInterface as C, type DataLayerProvider as D, type UsrCrsDataInterface as E, type ClassroomRegistrationDesignation as F, type ClassroomRegistration as G, type ClassroomRegistrationDoc as H, type SessionTrackingData as I, type UserConfig as J, type ActivityRecord as K, type CourseRegistration as L, type CourseRegistrationDoc as M, type UserOutcomeRecord as N, Loggable as O, type NavigatorConstructor as P, registerNavigator as Q, type ReplanHints as R, type StudySessionItem as S, type TeacherClassroomDBInterface as T, type UserDBInterface as U, getRegisteredNavigator as V, type WeightedCard as W, hasRegisteredNavigator as X, getRegisteredNavigatorRole as Y, getRegisteredNavigatorNames as Z, initializeNavigatorRegistry as _, type CoursesDBInterface as a, getCardOrigin as a0, Navigators as a1, NavigatorRole as a2, NavigatorRoles as a3, isGenerator as a4, isFilter as a5, type LearnableWeight as a6, type OrchestrationContext as a7, computeDeviation as a8, computeSpread as a9, computeEffectiveWeight as aa, createOrchestrationContext as ab, type ReplanOptions as ac, type StudySessionRecord as ad, type SessionAction as ae, type ResponseResult as af, SessionController as ag, type SourceMixer as ah, QuotaRoundRobinMixer as ai, type DocumentUpdater as aj, newInterval as ak, type ClassroomDBInterface as b, type UserDBReader as c, type CourseInfo as d, type DataLayerResult as e, type ContentNavigationStrategyData as f, ContentNavigator as g, type AssignedContent as h, type StudyContentSource as i, type StudentClassroomDBInterface as j, type ScheduledCard as k, type StudySessionFailedItem as l, type StudySessionFailedNewItem as m, type StudySessionFailedReviewItem as n, type StudySessionNewItem as o, type StudySessionReviewItem as p, isReview as q, type ContentSourceID as r, getStudySource as s, type SourceBatch as t, type AssignedTag as u, type AssignedCourse as v, type AssignedCard as w, type UserDBWriter as x, type UserDBAuthenticator as y, type UserCourseSettings as z };
|
|
1237
|
+
export { Navigators as $, type AdminDBInterface as A, type UsrCrsDataInterface as B, type CourseDBInterface as C, type DataLayerResult as D, type ClassroomRegistrationDesignation as E, type ClassroomRegistration as F, type GeneratorResult as G, type ClassroomRegistrationDoc as H, type SessionTrackingData as I, type UserConfig as J, type ActivityRecord as K, type CourseRegistration as L, type UserOutcomeRecord as M, type NavigatorConstructor as N, registerNavigator as O, getRegisteredNavigator as P, hasRegisteredNavigator as Q, type ReplanHints as R, type StudySessionItem as S, type TeacherClassroomDBInterface as T, type UserDBInterface as U, getRegisteredNavigatorRole as V, type WeightedCard as W, getRegisteredNavigatorNames as X, initializeNavigatorRegistry as Y, type StrategyContribution as Z, getCardOrigin as _, type UserDBReader as a, NavigatorRole as a0, NavigatorRoles as a1, isGenerator as a2, isFilter as a3, type CardGenerator as a4, type GeneratorContext as a5, type CardGeneratorFactory as a6, type LearnableWeight as a7, type OrchestrationContext as a8, computeDeviation as a9, computeSpread as aa, computeEffectiveWeight as ab, createOrchestrationContext as ac, type DocumentUpdater as ad, newInterval as ae, type CoursesDBInterface as b, type ClassroomDBInterface as c, type CourseInfo as d, type ContentNavigationStrategyData as e, ContentNavigator as f, type AssignedContent as g, type StudyContentSource as h, type StudentClassroomDBInterface as i, type ScheduledCard as j, type StudySessionFailedItem as k, type StudySessionFailedNewItem as l, type StudySessionFailedReviewItem as m, type StudySessionNewItem as n, type StudySessionReviewItem as o, isReview as p, type ContentSourceID as q, getStudySource as r, type CourseRegistrationDoc as s, type AssignedTag as t, type AssignedCourse as u, type AssignedCard as v, type UserDBWriter as w, type UserDBAuthenticator as x, type UserCourseSettings as y, type UserCourseSetting as z };
|