@vue-skuilder/db 0.2.1 → 0.2.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/dist/{contentSource-Ht3N2f-y.d.ts → contentSource-Cplhv3bJ.d.ts} +1 -1
- package/dist/{contentSource-BMlMwSiG.d.cts → contentSource-kI9_jwTu.d.cts} +1 -1
- package/dist/core/index.d.cts +5 -5
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +76 -21
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +76 -21
- package/dist/core/index.mjs.map +1 -1
- package/dist/{dataLayerProvider-BEqB8VBR.d.cts → dataLayerProvider-CiA2Rr0v.d.cts} +1 -1
- package/dist/{dataLayerProvider-DObSXjnf.d.ts → dataLayerProvider-DrBqOUa3.d.ts} +1 -1
- package/dist/impl/couch/index.d.cts +35 -3
- package/dist/impl/couch/index.d.ts +35 -3
- package/dist/impl/couch/index.js +76 -21
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +76 -21
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.d.cts +4 -4
- package/dist/impl/static/index.d.ts +4 -4
- package/dist/impl/static/index.js +4 -5
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +4 -5
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/{index-BWvO-_rJ.d.ts → index-BLLT5BYE.d.ts} +1 -1
- package/dist/{index-Ba7hYbHj.d.cts → index-k9NFHpS1.d.cts} +1 -1
- package/dist/index.d.cts +164 -10
- package/dist/index.d.ts +164 -10
- package/dist/index.js +215 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +215 -28
- package/dist/index.mjs.map +1 -1
- package/dist/{types-W8n-B6HG.d.cts → types-BFUa1pa3.d.cts} +1 -1
- package/dist/{types-CJrLM1Ew.d.ts → types-CHgpWQAY.d.ts} +1 -1
- package/dist/{types-legacy-JXDxinpU.d.cts → types-legacy-4tlwHnXo.d.cts} +1 -1
- package/dist/{types-legacy-JXDxinpU.d.ts → types-legacy-4tlwHnXo.d.ts} +1 -1
- package/dist/util/packer/index.d.cts +3 -3
- package/dist/util/packer/index.d.ts +3 -3
- package/docs/session-lifecycle-and-replan.md +418 -0
- package/package.json +3 -3
- package/src/core/navigators/Pipeline.ts +5 -1
- package/src/core/navigators/generators/elo.ts +19 -6
- package/src/core/navigators/generators/srs.ts +10 -0
- package/src/impl/couch/courseDB.ts +146 -17
- package/src/study/SessionController.ts +295 -13
- package/src/study/services/CardHydrationService.ts +24 -0
package/dist/index.js
CHANGED
|
@@ -1982,10 +1982,8 @@ var init_elo = __esm({
|
|
|
1982
1982
|
{ limit, elo: "user" },
|
|
1983
1983
|
(c) => !activeCards.some((ac) => c.cardID === ac.cardID)
|
|
1984
1984
|
)).map((c) => ({ ...c, status: "new" }));
|
|
1985
|
-
const
|
|
1986
|
-
|
|
1987
|
-
const scored = newCards.map((c, i) => {
|
|
1988
|
-
const cardElo = cardEloData[i]?.global?.score ?? 1e3;
|
|
1985
|
+
const scored = newCards.map((c) => {
|
|
1986
|
+
const cardElo = c.elo ?? 1e3;
|
|
1989
1987
|
const distance = Math.abs(cardElo - userGlobalElo);
|
|
1990
1988
|
const rawScore = Math.max(0, 1 - distance / 500);
|
|
1991
1989
|
const samplingKey = rawScore > 0 ? Math.random() ** (1 / rawScore) : 0;
|
|
@@ -4209,7 +4207,8 @@ var init_orchestration = __esm({
|
|
|
4209
4207
|
// src/core/navigators/Pipeline.ts
|
|
4210
4208
|
var Pipeline_exports = {};
|
|
4211
4209
|
__export(Pipeline_exports, {
|
|
4212
|
-
Pipeline: () => Pipeline
|
|
4210
|
+
Pipeline: () => Pipeline,
|
|
4211
|
+
mergeHints: () => mergeHints2
|
|
4213
4212
|
});
|
|
4214
4213
|
function globToRegex(pattern) {
|
|
4215
4214
|
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -5901,6 +5900,7 @@ ${above.rows.map((r) => ` ${r.id}-${r.key}
|
|
|
5901
5900
|
}
|
|
5902
5901
|
async addNavigationStrategy(data) {
|
|
5903
5902
|
logger.debug(`[courseDB] Adding navigation strategy: ${data._id}`);
|
|
5903
|
+
this.invalidateNavigatorCache();
|
|
5904
5904
|
return this.remoteDB.put(data).then(() => {
|
|
5905
5905
|
});
|
|
5906
5906
|
}
|
|
@@ -5967,23 +5967,67 @@ ${e.stack}` : JSON.stringify(e);
|
|
|
5967
5967
|
* @returns Cards sorted by score descending
|
|
5968
5968
|
*/
|
|
5969
5969
|
_pendingHints = null;
|
|
5970
|
+
/**
|
|
5971
|
+
* Session-scoped cache of the broad ELO-neighbor pool used by
|
|
5972
|
+
* getCardsCenteredAtELO. The `elo` view query re-indexes on first touch per
|
|
5973
|
+
* call (PouchDB 9 ignores `stale`), so without this each plan/replan pays
|
|
5974
|
+
* ~1.5-2s. The pool is fetched once and re-ranked against the live (roaming)
|
|
5975
|
+
* ELO in memory on subsequent calls.
|
|
5976
|
+
*/
|
|
5977
|
+
_eloPoolCache = null;
|
|
5978
|
+
_eloPoolTtlMs = 5 * 60 * 1e3;
|
|
5979
|
+
/**
|
|
5980
|
+
* Cached assembled navigator (Pipeline). createNavigator() reads strategy
|
|
5981
|
+
* docs and builds a fresh Pipeline every call — whose internal `_tagCache`
|
|
5982
|
+
* and `_cachedOrchestration` are designed to make replans cheap but never
|
|
5983
|
+
* survive, because the instance is discarded each run. Caching it lets those
|
|
5984
|
+
* caches persist across plan/replan within a session (SessionController holds
|
|
5985
|
+
* one CourseDB instance for the session's lifetime). Rebuilt on user change,
|
|
5986
|
+
* TTL expiry, or explicit invalidation after a strategy-doc write.
|
|
5987
|
+
*/
|
|
5988
|
+
_cachedNavigator = null;
|
|
5989
|
+
_navigatorTtlMs = 5 * 60 * 1e3;
|
|
5970
5990
|
setEphemeralHints(hints) {
|
|
5971
5991
|
this._pendingHints = hints;
|
|
5972
5992
|
}
|
|
5973
5993
|
async getWeightedCards(limit) {
|
|
5974
5994
|
const u = await this._getCurrentUser();
|
|
5975
5995
|
try {
|
|
5976
|
-
const navigator2 = await this.
|
|
5996
|
+
const { navigator: navigator2 } = await this._getCachedNavigator(u);
|
|
5977
5997
|
if (this._pendingHints) {
|
|
5978
5998
|
navigator2.setEphemeralHints(this._pendingHints);
|
|
5979
5999
|
this._pendingHints = null;
|
|
5980
6000
|
}
|
|
5981
|
-
|
|
6001
|
+
const result = await navigator2.getWeightedCards(limit);
|
|
6002
|
+
return result;
|
|
5982
6003
|
} catch (e) {
|
|
5983
6004
|
logger.error(`[courseDB] Error getting weighted cards: ${e}`);
|
|
5984
6005
|
throw e;
|
|
5985
6006
|
}
|
|
5986
6007
|
}
|
|
6008
|
+
/**
|
|
6009
|
+
* Return the assembled navigator, reusing the cached instance when possible.
|
|
6010
|
+
* Reuse preserves the Pipeline's per-session caches (tags, orchestration
|
|
6011
|
+
* context) across replans, which is the dominant per-replan cost once the
|
|
6012
|
+
* ELO-pool cost is removed. Rebuilds on user change or TTL expiry.
|
|
6013
|
+
*/
|
|
6014
|
+
async _getCachedNavigator(user) {
|
|
6015
|
+
const userId = user.getUsername();
|
|
6016
|
+
const now = Date.now();
|
|
6017
|
+
if (this._cachedNavigator && this._cachedNavigator.userId === userId && now - this._cachedNavigator.builtAt < this._navigatorTtlMs) {
|
|
6018
|
+
return { navigator: this._cachedNavigator.navigator, cacheStatus: "hit" };
|
|
6019
|
+
}
|
|
6020
|
+
const navigator2 = await this.createNavigator(user);
|
|
6021
|
+
this._cachedNavigator = { navigator: navigator2, userId, builtAt: now };
|
|
6022
|
+
return { navigator: navigator2, cacheStatus: "miss" };
|
|
6023
|
+
}
|
|
6024
|
+
/**
|
|
6025
|
+
* Drop the cached navigator so the next getWeightedCards() rebuilds it.
|
|
6026
|
+
* Call after mutating this course's navigation strategy documents.
|
|
6027
|
+
*/
|
|
6028
|
+
invalidateNavigatorCache() {
|
|
6029
|
+
this._cachedNavigator = null;
|
|
6030
|
+
}
|
|
5987
6031
|
async getCardsCenteredAtELO(options = {
|
|
5988
6032
|
limit: 99,
|
|
5989
6033
|
elo: "user"
|
|
@@ -6006,20 +6050,31 @@ ${e.stack}` : JSON.stringify(e);
|
|
|
6006
6050
|
} else {
|
|
6007
6051
|
targetElo = options.elo;
|
|
6008
6052
|
}
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
let
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6053
|
+
const POOL_SIZE = Math.max(2e3, options.limit * 4);
|
|
6054
|
+
const nowMs = Date.now();
|
|
6055
|
+
let cacheStatus = "hit";
|
|
6056
|
+
if (!this._eloPoolCache || nowMs - this._eloPoolCache.fetchedAt > this._eloPoolTtlMs) {
|
|
6057
|
+
const fetched = await this.getCardsByELO(targetElo, POOL_SIZE);
|
|
6058
|
+
if (fetched.length > 0) {
|
|
6059
|
+
this._eloPoolCache = { rows: fetched, fetchedAt: nowMs };
|
|
6060
|
+
}
|
|
6061
|
+
cacheStatus = "miss";
|
|
6062
|
+
}
|
|
6063
|
+
const rankAgainstCurrentElo = () => {
|
|
6064
|
+
const raw = this._eloPoolCache?.rows ?? [];
|
|
6065
|
+
const survivors = filter ? raw.filter((c) => filter(c)) : raw;
|
|
6066
|
+
return survivors.map((c) => ({ ...c })).sort(
|
|
6067
|
+
(a, b) => Math.abs((a.elo ?? targetElo) - targetElo) - Math.abs((b.elo ?? targetElo) - targetElo)
|
|
6068
|
+
);
|
|
6069
|
+
};
|
|
6070
|
+
let cards = rankAgainstCurrentElo();
|
|
6071
|
+
if (cards.length < options.limit && (cacheStatus === "hit" || !this._eloPoolCache)) {
|
|
6072
|
+
const fetched = await this.getCardsByELO(targetElo, POOL_SIZE);
|
|
6073
|
+
if (fetched.length > 0) {
|
|
6074
|
+
this._eloPoolCache = { rows: fetched, fetchedAt: nowMs };
|
|
6075
|
+
}
|
|
6076
|
+
cards = rankAgainstCurrentElo();
|
|
6077
|
+
cacheStatus = "refresh";
|
|
6023
6078
|
}
|
|
6024
6079
|
const selectedCards = [];
|
|
6025
6080
|
while (selectedCards.length < options.limit && cards.length > 0) {
|
|
@@ -11290,6 +11345,7 @@ var ItemQueue = class {
|
|
|
11290
11345
|
|
|
11291
11346
|
// src/study/SessionController.ts
|
|
11292
11347
|
init_couch();
|
|
11348
|
+
init_core();
|
|
11293
11349
|
init_recording();
|
|
11294
11350
|
|
|
11295
11351
|
// src/util/index.ts
|
|
@@ -12716,6 +12772,7 @@ init_dataDirectory();
|
|
|
12716
12772
|
|
|
12717
12773
|
// src/study/SessionController.ts
|
|
12718
12774
|
init_navigators();
|
|
12775
|
+
init_Pipeline();
|
|
12719
12776
|
|
|
12720
12777
|
// src/study/SourceMixer.ts
|
|
12721
12778
|
var QuotaRoundRobinMixer = class {
|
|
@@ -13427,6 +13484,32 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
13427
13484
|
* each nextCard() draw. Set by replans that include `minFollowUpCards`.
|
|
13428
13485
|
*/
|
|
13429
13486
|
_minCardsGuarantee = 0;
|
|
13487
|
+
/**
|
|
13488
|
+
* Session-durable scoring hints. Re-merged into every pipeline run for
|
|
13489
|
+
* the rest of the session (initial plan + every replan, including bare
|
|
13490
|
+
* auto-replans and the wedge-breaker), via `_applyHintsToSources`.
|
|
13491
|
+
*
|
|
13492
|
+
* Set by `setSessionHints()` (e.g. session-start post-lesson boost) or by
|
|
13493
|
+
* any replan carrying `ReplanOptions.sessionHints` (e.g. a just-failed
|
|
13494
|
+
* concept boost). Replace semantics, no decay — lives until overwritten
|
|
13495
|
+
* or session end. See `ReplanOptions.sessionHints` for rationale.
|
|
13496
|
+
*
|
|
13497
|
+
* Note: the controller-managed auto-excludes (current card, session
|
|
13498
|
+
* record, imminent draw) are intentionally NOT folded in here — those are
|
|
13499
|
+
* recomputed per-run in `_runReplan` and would otherwise go stale.
|
|
13500
|
+
*/
|
|
13501
|
+
_sessionHints = null;
|
|
13502
|
+
/**
|
|
13503
|
+
* Consumer-supplied hooks invoked after each question response is processed.
|
|
13504
|
+
* Seeded from constructor options (threaded from
|
|
13505
|
+
* `StudySessionConfig.outcomeObservers`). See {@link OutcomeObserver}.
|
|
13506
|
+
*/
|
|
13507
|
+
_outcomeObservers = [];
|
|
13508
|
+
/**
|
|
13509
|
+
* Lazily-built, stable capability object handed to observers. Bound to
|
|
13510
|
+
* `this`; constructed once so observers can rely on referential identity.
|
|
13511
|
+
*/
|
|
13512
|
+
_sessionControls = null;
|
|
13430
13513
|
startTime;
|
|
13431
13514
|
endTime;
|
|
13432
13515
|
_secondsRemaining;
|
|
@@ -13486,6 +13569,9 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
13486
13569
|
if (options?.initialReviewCap !== void 0) {
|
|
13487
13570
|
this._initialReviewCap = options.initialReviewCap;
|
|
13488
13571
|
}
|
|
13572
|
+
if (options?.outcomeObservers?.length) {
|
|
13573
|
+
this._outcomeObservers = [...options.outcomeObservers];
|
|
13574
|
+
}
|
|
13489
13575
|
this.log(`Session constructed:
|
|
13490
13576
|
startTime: ${this.startTime}
|
|
13491
13577
|
endTime: ${this.endTime}
|
|
@@ -13613,6 +13699,7 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
13613
13699
|
if (opts.minFollowUpCards !== void 0) return true;
|
|
13614
13700
|
if (opts.mode && opts.mode !== "replace") return true;
|
|
13615
13701
|
if (opts.hints && Object.keys(opts.hints).length > 0) return true;
|
|
13702
|
+
if (opts.sessionHints !== void 0) return true;
|
|
13616
13703
|
return false;
|
|
13617
13704
|
}
|
|
13618
13705
|
/**
|
|
@@ -13641,12 +13728,13 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
13641
13728
|
excludeSet.add(this.newQ.peek(0).cardID);
|
|
13642
13729
|
}
|
|
13643
13730
|
hints.excludeCards = [...excludeSet];
|
|
13644
|
-
if (opts.
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13731
|
+
if (opts.sessionHints !== void 0) {
|
|
13732
|
+
this._sessionHints = opts.sessionHints;
|
|
13733
|
+
this.log(
|
|
13734
|
+
`[Replan] Session hints ${opts.sessionHints ? "set" : "cleared"}: ${JSON.stringify(opts.sessionHints)}`
|
|
13735
|
+
);
|
|
13649
13736
|
}
|
|
13737
|
+
this._applyHintsToSources(opts.hints, opts.label);
|
|
13650
13738
|
const labelTag = opts.label ? ` [${opts.label}]` : "";
|
|
13651
13739
|
this.log(
|
|
13652
13740
|
`Mid-session replan requested${labelTag} (limit: ${opts.limit ?? "default"}, mode: ${opts.mode ?? "replace"}${opts.hints ? ", with hints" : ""})`
|
|
@@ -13657,6 +13745,100 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
13657
13745
|
}
|
|
13658
13746
|
await this._executeReplan(opts);
|
|
13659
13747
|
}
|
|
13748
|
+
/**
|
|
13749
|
+
* Set the session-durable scoring hints (replace semantics, no decay).
|
|
13750
|
+
*
|
|
13751
|
+
* Unlike a one-shot replan hint, these are re-merged into every pipeline
|
|
13752
|
+
* run for the rest of the session — including the initial plan when set
|
|
13753
|
+
* before `prepareSession()`, every replan, the bare auto-replans, and the
|
|
13754
|
+
* wedge-breaker. Pass `null` to clear.
|
|
13755
|
+
*
|
|
13756
|
+
* Typical callers:
|
|
13757
|
+
* - `StudySession` at session start, threading `StudySessionConfig.initHints`
|
|
13758
|
+
* (e.g. a post-lesson concept boost) — so the boost outlives the first
|
|
13759
|
+
* queue rebuild instead of being clobbered by the first auto-replan.
|
|
13760
|
+
* - A consumer view on a failure, boosting the just-failed concept tag.
|
|
13761
|
+
*
|
|
13762
|
+
* Does not itself trigger a replan; the next plan/replan picks it up.
|
|
13763
|
+
*/
|
|
13764
|
+
setSessionHints(hints) {
|
|
13765
|
+
this._sessionHints = hints;
|
|
13766
|
+
this.log(`Session hints ${hints ? "set" : "cleared"}: ${JSON.stringify(hints)}`);
|
|
13767
|
+
}
|
|
13768
|
+
/**
|
|
13769
|
+
* Read the current session-durable hints (for read-modify-write callers,
|
|
13770
|
+
* e.g. an outcome observer that clamps a compounding boost).
|
|
13771
|
+
*/
|
|
13772
|
+
getSessionHints() {
|
|
13773
|
+
return this._sessionHints;
|
|
13774
|
+
}
|
|
13775
|
+
/**
|
|
13776
|
+
* Merge `hints` into the durable session hints via the pipeline's
|
|
13777
|
+
* `mergeHints` (boosts multiply, require/exclude lists concat-dedup).
|
|
13778
|
+
* Convenience over get-then-set for the common additive case. Note the
|
|
13779
|
+
* multiplicative, no-decay semantics — clamp boost factors at the call
|
|
13780
|
+
* site if a repeatedly-emphasised tag could compound unboundedly.
|
|
13781
|
+
*/
|
|
13782
|
+
mergeSessionHints(hints) {
|
|
13783
|
+
this._sessionHints = mergeHints2([this._sessionHints, hints]) ?? null;
|
|
13784
|
+
this.log(`Session hints merged: ${JSON.stringify(this._sessionHints)}`);
|
|
13785
|
+
}
|
|
13786
|
+
/**
|
|
13787
|
+
* Merge the durable `_sessionHints` with this run's one-shot hints and
|
|
13788
|
+
* push the result to every source for consumption on the next pipeline
|
|
13789
|
+
* run. Centralised so the initial plan and all replan paths apply session
|
|
13790
|
+
* emphasis identically. No-op when there are no hints of either kind.
|
|
13791
|
+
*/
|
|
13792
|
+
_applyHintsToSources(oneShot, label) {
|
|
13793
|
+
const oneShotWithLabel = oneShot && label ? { ...oneShot, _label: label } : oneShot;
|
|
13794
|
+
const merged = mergeHints2([this._sessionHints, oneShotWithLabel]);
|
|
13795
|
+
if (!merged) return;
|
|
13796
|
+
for (const source of this.sources) {
|
|
13797
|
+
source.setEphemeralHints?.(merged);
|
|
13798
|
+
}
|
|
13799
|
+
}
|
|
13800
|
+
/**
|
|
13801
|
+
* Build (once) the stable capability object handed to outcome observers.
|
|
13802
|
+
* Methods are bound to `this`; the object identity is stable across calls
|
|
13803
|
+
* so observers may key off it.
|
|
13804
|
+
*/
|
|
13805
|
+
_getSessionControls() {
|
|
13806
|
+
if (!this._sessionControls) {
|
|
13807
|
+
this._sessionControls = {
|
|
13808
|
+
getSessionHints: () => this.getSessionHints(),
|
|
13809
|
+
setSessionHints: (h) => this.setSessionHints(h),
|
|
13810
|
+
mergeSessionHints: (h) => this.mergeSessionHints(h),
|
|
13811
|
+
requestReplan: (opts) => this.requestReplan(opts)
|
|
13812
|
+
};
|
|
13813
|
+
}
|
|
13814
|
+
return this._sessionControls;
|
|
13815
|
+
}
|
|
13816
|
+
/**
|
|
13817
|
+
* Notify registered outcome observers about a processed response.
|
|
13818
|
+
*
|
|
13819
|
+
* Only question records are surfaced (non-question dismisses are skipped).
|
|
13820
|
+
* Observers run after ELO/SRS are recorded and before navigation. Each is
|
|
13821
|
+
* awaited but isolated in try/catch — a throwing observer is logged and
|
|
13822
|
+
* skipped, never wedging the session. Keep observers cheap and `void` any
|
|
13823
|
+
* long work (e.g. a triggered replan) to avoid stalling the draw.
|
|
13824
|
+
*/
|
|
13825
|
+
async _notifyOutcomeObservers(record, currentCard, result) {
|
|
13826
|
+
if (this._outcomeObservers.length === 0) return;
|
|
13827
|
+
if (!isQuestionRecord(record)) return;
|
|
13828
|
+
const outcome = {
|
|
13829
|
+
record,
|
|
13830
|
+
card: currentCard.card,
|
|
13831
|
+
result
|
|
13832
|
+
};
|
|
13833
|
+
const controls = this._getSessionControls();
|
|
13834
|
+
for (const observer of this._outcomeObservers) {
|
|
13835
|
+
try {
|
|
13836
|
+
await observer(outcome, controls);
|
|
13837
|
+
} catch (e) {
|
|
13838
|
+
this.error("[OutcomeObserver] observer threw; ignoring", e);
|
|
13839
|
+
}
|
|
13840
|
+
}
|
|
13841
|
+
}
|
|
13660
13842
|
/**
|
|
13661
13843
|
* Run a replan, bypassing requestReplan()'s coalesce logic.
|
|
13662
13844
|
*
|
|
@@ -13684,7 +13866,7 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
13684
13866
|
*/
|
|
13685
13867
|
normalizeReplanOptions(input) {
|
|
13686
13868
|
if (!input) return {};
|
|
13687
|
-
const replanKeys = ["hints", "limit", "mode", "label", "minFollowUpCards"];
|
|
13869
|
+
const replanKeys = ["hints", "sessionHints", "limit", "mode", "label", "minFollowUpCards"];
|
|
13688
13870
|
const inputKeys = Object.keys(input);
|
|
13689
13871
|
if (inputKeys.some((k) => replanKeys.includes(k))) {
|
|
13690
13872
|
return input;
|
|
@@ -13836,6 +14018,9 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
13836
14018
|
const additive = options?.additive ?? false;
|
|
13837
14019
|
const newLimit = options?.limit ?? this._defaultBatchLimit;
|
|
13838
14020
|
const fetchLimit = replan ? newLimit : newLimit + this._initialReviewCap;
|
|
14021
|
+
if (!replan) {
|
|
14022
|
+
this._applyHintsToSources();
|
|
14023
|
+
}
|
|
13839
14024
|
const batches = [];
|
|
13840
14025
|
for (let i = 0; i < this.sources.length; i++) {
|
|
13841
14026
|
const source = this.sources[i];
|
|
@@ -14116,7 +14301,7 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
14116
14301
|
const studySessionItem = {
|
|
14117
14302
|
...currentCard.item
|
|
14118
14303
|
};
|
|
14119
|
-
|
|
14304
|
+
const result = await this.services.response.processResponse(
|
|
14120
14305
|
cardRecord,
|
|
14121
14306
|
cardHistory,
|
|
14122
14307
|
studySessionItem,
|
|
@@ -14128,6 +14313,8 @@ var SessionController = class _SessionController extends Loggable {
|
|
|
14128
14313
|
maxSessionViews,
|
|
14129
14314
|
sessionViews
|
|
14130
14315
|
);
|
|
14316
|
+
await this._notifyOutcomeObservers(cardRecord, currentCard, result);
|
|
14317
|
+
return result;
|
|
14131
14318
|
}
|
|
14132
14319
|
dismissCurrentCard(action = "dismiss-success") {
|
|
14133
14320
|
if (this._currentCard) {
|