@wyxos/vibe 5.5.1 → 5.5.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/lib/index.js CHANGED
@@ -22,6 +22,7 @@ function L(e, t = [...e.items]) {
22
22
  activeReelPostId: e.activeReelPostId,
23
23
  autoScroll: { ...e.autoScroll },
24
24
  autofill: { ...e.autofill },
25
+ current: e.current,
25
26
  error: e.error,
26
27
  fill: {
27
28
  ...e.fill,
@@ -2384,6 +2385,7 @@ var Lt = 35, Rt = 420, zt = /* @__PURE__ */ d({
2384
2385
  //#region src/core/page.ts
2385
2386
  function Bt(e) {
2386
2387
  if (!e || typeof e != "object" || !Array.isArray(e.items)) throw TypeError("Vibe loadPage must resolve to a page with an items array.");
2388
+ if (e.current !== void 0 && e.current !== null && typeof e.current != "string" && typeof e.current != "number") throw TypeError("Vibe page current must be a string, number, null, or undefined.");
2387
2389
  if (e.next !== null && typeof e.next != "string" && typeof e.next != "number") throw TypeError("Vibe page next must be a string, number, or null.");
2388
2390
  if (e.total !== void 0 && (!Number.isFinite(e.total) || e.total < 0)) throw TypeError("Vibe page total must be a non-negative number when provided.");
2389
2391
  return e;
@@ -2662,13 +2664,13 @@ var on = class {
2662
2664
  }
2663
2665
  commitCollection() {
2664
2666
  let { onLastCursor: e, options: t, state: n } = this.context;
2665
- if (t?.strategy !== "frontend") return;
2667
+ if (t?.strategy !== "frontend") return !1;
2666
2668
  let r = this.collection;
2667
- this.collection = null, r && (n.items = Z(n.items, r.items), e(r.lastCursor), this.context.onPages(r.pages), n.next = r.next, r.total !== void 0 && (n.total = r.total), Object.assign(n.autofill, {
2669
+ return this.collection = null, r ? (n.items = Z(n.items, r.items), e(r.lastCursor), this.context.onPages(r.pages), n.next = r.next, r.total !== void 0 && (n.total = r.total), Object.assign(n.autofill, {
2668
2670
  missing: r.missing,
2669
2671
  received: r.received,
2670
2672
  requests: r.requests
2671
- }));
2673
+ }), !0) : !1;
2672
2674
  }
2673
2675
  }, sn = 100;
2674
2676
  function cn(e, t) {
@@ -3031,37 +3033,42 @@ var Mn = class {
3031
3033
  let t = jn(this.options.fill, this.options.state, e, this.options.onLastCursor);
3032
3034
  return t && this.syncBackendCountdown(), t;
3033
3035
  }
3034
- async start(e) {
3035
- let t = this.options.fill;
3036
- if (!t) throw Error("Vibe fill is not configured.");
3036
+ async start(e, t = {}) {
3037
+ let n = this.options.fill;
3038
+ if (!n) throw Error("Vibe fill is not configured.");
3037
3039
  if (this.isActive()) throw Error("Vibe fill is already active.");
3038
- let n = bn(e), r = `vibe-fill-${Date.now().toString(36)}-${++this.cycle}`;
3040
+ let r = bn(e), i = bn(t.target ?? r), a = t.progressOffset ?? {
3041
+ completedPages: 0,
3042
+ received: 0
3043
+ }, o = t.cycleId ?? `vibe-fill-${Date.now().toString(36)}-${++this.cycle}`;
3039
3044
  if (this.options.state.fill = {
3040
- ...Sn(t, void 0, !1),
3041
- cycleId: r,
3045
+ ...Sn(n, void 0, !1),
3046
+ completedPages: a.completedPages,
3047
+ cycleId: o,
3048
+ received: a.received,
3042
3049
  status: "filling",
3043
- target: n
3044
- }, this.options.state.next === null) {
3045
- this.options.state.fill.status = "pages" in n ? "exhausted" : "complete";
3050
+ target: i
3051
+ }, n.strategy === "backend" && this.options.state.next === null) {
3052
+ this.options.state.fill.status = "pages" in r ? "exhausted" : "complete";
3046
3053
  return;
3047
3054
  }
3048
- let i = ++this.requestVersion, a = new AbortController();
3049
- this.abortController = a;
3055
+ let s = ++this.requestVersion, c = new AbortController();
3056
+ this.abortController = c;
3050
3057
  try {
3051
- t.strategy === "frontend" ? await this.startFrontend(t, n, a, i) : (await Tn(t, this.options.state, {
3052
- cycleId: r,
3053
- feedKey: t.feedKey,
3058
+ n.strategy === "frontend" ? await this.startFrontend(n, r, c, s, t.prepareFrontend !== !1, a) : (await Tn(n, this.options.state, {
3059
+ cycleId: o,
3060
+ feedKey: n.feedKey,
3054
3061
  items: [...this.options.state.items],
3055
3062
  next: this.options.state.next,
3056
- signal: a.signal,
3057
- target: n,
3063
+ signal: c.signal,
3064
+ target: r,
3058
3065
  total: this.options.state.total
3059
- }, () => this.isCurrent(i)), this.syncBackendCountdown());
3066
+ }, () => this.isCurrent(s)), this.syncBackendCountdown());
3060
3067
  } catch (e) {
3061
- if (a.signal.aborted || !this.isCurrent(i)) return;
3068
+ if (c.signal.aborted || !this.isCurrent(s)) return;
3062
3069
  throw this.options.state.fill.error = e, this.options.state.fill.status = "error", e;
3063
3070
  } finally {
3064
- this.isCurrent(i) && (this.abortController = null, this.options.state.isLoadingMore = !1);
3071
+ this.isCurrent(s) && (this.abortController = null, this.options.state.isLoadingMore = !1);
3065
3072
  }
3066
3073
  }
3067
3074
  async cancel() {
@@ -3079,6 +3086,22 @@ var Mn = class {
3079
3086
  throw t.fill.error = e, t.fill.status = "error", e;
3080
3087
  }
3081
3088
  }
3089
+ resume(e) {
3090
+ let { fill: t } = this.options.state;
3091
+ if (t.status !== "paused" || !t.target) return Promise.resolve();
3092
+ let n = t.target, r = "pages" in n ? n.pages - t.completedPages : null;
3093
+ if (r !== null && r <= 0) return t.status = "complete", Promise.resolve();
3094
+ let i = r === null ? { until: "end" } : { pages: r };
3095
+ return t.strategy === "backend" ? this.start(i) : this.start(i, {
3096
+ cycleId: t.cycleId ?? void 0,
3097
+ prepareFrontend: e,
3098
+ progressOffset: {
3099
+ completedPages: t.completedPages,
3100
+ received: t.received
3101
+ },
3102
+ target: n
3103
+ });
3104
+ }
3082
3105
  reset() {
3083
3106
  this.abortLocalRequest(), this.delayCountdown.clear(), this.options.state.fill = Sn(this.options.fill, void 0, !1), this.collection = null;
3084
3107
  }
@@ -3091,33 +3114,60 @@ var Mn = class {
3091
3114
  isCurrent(e) {
3092
3115
  return e === this.requestVersion && !["cancelled", "cancelling"].includes(this.options.state.fill.status);
3093
3116
  }
3094
- async startFrontend(e, t, n, r) {
3095
- let i = this.options.loadPage;
3096
- if (!i) throw Error("Vibe frontend fill requires loadPage.");
3097
- let a = this.options.state;
3098
- a.isLoadingMore = !0;
3099
- let o = await wn({
3100
- existingItems: a.items,
3101
- initialCursor: a.next,
3102
- loadPage: i,
3117
+ async startFrontend(e, t, n, r, i, a) {
3118
+ let o = this.options.loadPage;
3119
+ if (!o) throw Error("Vibe frontend fill requires loadPage.");
3120
+ let s = this.options.state;
3121
+ if (s.isLoadingMore = !0, i && this.options.prepareFrontend && (this.options.needsFrontendPreparation?.() ?? !0)) {
3122
+ s.fill.status = "restoring";
3123
+ let e = await this.options.prepareFrontend({
3124
+ isCurrent: () => this.isCurrent(r),
3125
+ onDelayChange: (e) => {
3126
+ this.isCurrent(r) && Object.assign(s.fill, e);
3127
+ },
3128
+ signal: n.signal
3129
+ });
3130
+ if (!this.isCurrent(r)) return;
3131
+ if (e === "paused" || s.loadMoreLocked) {
3132
+ s.fill.status = "paused";
3133
+ return;
3134
+ }
3135
+ s.fill.status = "filling";
3136
+ }
3137
+ if (s.next === null) {
3138
+ s.fill.status = "pages" in t ? "exhausted" : "complete";
3139
+ return;
3140
+ }
3141
+ let c = await wn({
3142
+ existingItems: s.items,
3143
+ initialCursor: s.next,
3144
+ loadPage: o,
3103
3145
  onCollection: (e) => {
3104
- this.isCurrent(r) && (this.collection = e);
3146
+ this.isCurrent(r) && (this.collection = {
3147
+ ...e,
3148
+ completedPages: a.completedPages + e.completedPages,
3149
+ received: a.received + e.received
3150
+ });
3105
3151
  },
3106
3152
  onDelayChange: (e) => {
3107
- this.isCurrent(r) && Object.assign(a.fill, e);
3153
+ this.isCurrent(r) && Object.assign(s.fill, e);
3108
3154
  },
3109
3155
  onProgress: (e) => {
3110
- this.isCurrent(r) && Object.assign(a.fill, e);
3156
+ this.isCurrent(r) && Object.assign(s.fill, {
3157
+ ...e,
3158
+ completedPages: a.completedPages + e.completedPages,
3159
+ received: a.received + e.received
3160
+ });
3111
3161
  },
3112
3162
  options: e,
3113
- shouldPause: () => a.loadMoreLocked,
3163
+ shouldPause: () => s.loadMoreLocked,
3114
3164
  signal: n.signal,
3115
3165
  target: t
3116
3166
  });
3117
- this.isCurrent(r) && (a.items = Z(a.items, o.items), a.next = o.next, o.total !== void 0 && (a.total = o.total), this.options.onLastCursor(o.lastCursor), this.options.onPages(o.pages), Object.assign(a.fill, {
3118
- completedPages: o.completedPages,
3119
- received: o.received,
3120
- status: o.status
3167
+ this.isCurrent(r) && (s.items = Z(s.items, c.items), s.next = c.next, c.total !== void 0 && (s.total = c.total), this.options.onLastCursor(c.lastCursor), this.options.onPages(c.pages), Object.assign(s.fill, {
3168
+ completedPages: a.completedPages + c.completedPages,
3169
+ received: a.received + c.received,
3170
+ status: c.status
3121
3171
  }), this.collection = null);
3122
3172
  }
3123
3173
  commitCollection() {
@@ -3135,52 +3185,69 @@ var Mn = class {
3135
3185
  }
3136
3186
  };
3137
3187
  //#endregion
3188
+ //#region src/core/fillReconciliation.ts
3189
+ async function Nn({ controller: e, isCurrent: t, loadPage: n, onDelayChange: r, setLastCursor: i, signal: a, state: o }) {
3190
+ if (!e.needsReconciliation(o.items)) return "skipped";
3191
+ let s = await e.reconcile({
3192
+ existingItems: o.items,
3193
+ loadPage: n,
3194
+ onDelayChange: r,
3195
+ shouldPause: () => o.loadMoreLocked,
3196
+ signal: a
3197
+ });
3198
+ return t() ? (o.items = Z(o.items, s.items), o.next = s.next, i(s.lastCursor), s.total !== void 0 && (o.total = s.total), e.completeReconciliation(s), s.status) : s.status;
3199
+ }
3200
+ //#endregion
3138
3201
  //#region src/core/feedFooter.ts
3139
- function Nn(e) {
3202
+ function Pn(e) {
3140
3203
  return {
3141
3204
  cancelAutofill: () => e.cancelAutofill(),
3142
3205
  loadMore: () => e.loadNext(),
3143
- retry: () => e.reload(),
3206
+ retry: () => {
3207
+ let t = e.getState();
3208
+ return t.autofill.strategy === "frontend" && t.autofill.status === "error" && t.items.length > 0 && t.next !== null ? e.loadNext() : e.reload();
3209
+ },
3144
3210
  retryEnd: () => e.retryEnd()
3145
3211
  };
3146
3212
  }
3147
- function Pn(e) {
3148
- if (!Number.isFinite(e) || e <= 0) throw TypeError("Vibe reelAutoAdvance.intervalMs must be a positive number.");
3149
- }
3150
3213
  function Fn(e) {
3151
- e?.intervalMs !== void 0 && Pn(e.intervalMs);
3214
+ if (!Number.isFinite(e) || e <= 0) throw TypeError("Vibe reelAutoAdvance.intervalMs must be a positive number.");
3152
3215
  }
3153
3216
  function In(e) {
3217
+ e?.intervalMs !== void 0 && Fn(e.intervalMs);
3218
+ }
3219
+ function Ln(e) {
3154
3220
  return {
3155
3221
  enabled: e?.enabled ?? !1,
3156
3222
  includePostItems: e?.includePostItems ?? !1,
3157
3223
  intervalMs: e?.intervalMs ?? 5e3
3158
3224
  };
3159
3225
  }
3160
- function Ln(e, t) {
3226
+ function Rn(e, t) {
3161
3227
  if (typeof t == "boolean") {
3162
3228
  e.enabled = t;
3163
3229
  return;
3164
3230
  }
3165
- Fn(t), t.enabled !== void 0 && (e.enabled = t.enabled), t.includePostItems !== void 0 && (e.includePostItems = t.includePostItems), t.intervalMs !== void 0 && (e.intervalMs = t.intervalMs);
3231
+ In(t), t.enabled !== void 0 && (e.enabled = t.enabled), t.includePostItems !== void 0 && (e.includePostItems = t.includePostItems), t.intervalMs !== void 0 && (e.intervalMs = t.intervalMs);
3166
3232
  }
3167
3233
  //#endregion
3168
3234
  //#region src/core/reelInfoSheet.ts
3169
- function Rn(e) {
3235
+ function zn(e) {
3170
3236
  return { enabled: e?.enabled ?? !1 };
3171
3237
  }
3172
- function zn(e, t, n) {
3238
+ function Bn(e, t, n) {
3173
3239
  if (n && !t) throw Error("Vibe cannot enable reelInfoSheet without a configured component.");
3174
3240
  e.enabled = n;
3175
3241
  }
3176
3242
  //#endregion
3177
3243
  //#region src/core/initialRuntimeState.ts
3178
- function Bn(e, t) {
3244
+ function Vn(e, t) {
3179
3245
  let n = e.initialPage;
3180
3246
  return {
3181
3247
  activeReelPostId: null,
3182
3248
  autoScroll: dn(e.autoScroll),
3183
3249
  autofill: en(e.autofill),
3250
+ current: n?.current ?? null,
3184
3251
  error: null,
3185
3252
  fill: Sn(e.fill),
3186
3253
  infiniteScroll: e.infiniteScroll ?? !0,
@@ -3193,14 +3260,14 @@ function Bn(e, t) {
3193
3260
  next: n?.next ?? null,
3194
3261
  nextPageError: null,
3195
3262
  phoneMode: !1,
3196
- reelAutoAdvance: In(e.reelAutoAdvance),
3263
+ reelAutoAdvance: Ln(e.reelAutoAdvance),
3197
3264
  reelForward: {
3198
3265
  error: null,
3199
3266
  status: "idle"
3200
3267
  },
3201
3268
  reelForwardIndex: null,
3202
3269
  reelForwardItem: null,
3203
- reelInfoSheet: Rn(e.reelInfoSheet),
3270
+ reelInfoSheet: zn(e.reelInfoSheet),
3204
3271
  reelInfoSheetOverlay: !1,
3205
3272
  reelMediaSource: "original",
3206
3273
  reelOrigin: null,
@@ -3209,25 +3276,26 @@ function Bn(e, t) {
3209
3276
  }
3210
3277
  //#endregion
3211
3278
  //#region src/core/options.ts
3212
- function Vn(e, t) {
3279
+ function Hn(e, t) {
3213
3280
  if (t) {
3214
3281
  if (!Number.isFinite(t.height) || t.height <= 0) throw TypeError(`Vibe ${e} height must be a positive number.`);
3215
3282
  if (t.background !== void 0 && t.background !== "default" && t.background !== "transparent") throw TypeError(`Vibe ${e} background must be "default" or "transparent".`);
3216
3283
  }
3217
3284
  }
3218
- function Hn(e, t) {
3285
+ function Un(e, t) {
3219
3286
  if (t) {
3220
3287
  if (t.background !== void 0 && t.background !== "default" && t.background !== "transparent") throw TypeError(`Vibe mediaCard ${e} background must be "default" or "transparent".`);
3221
3288
  for (let [n, r] of [["paddingX", t.paddingX], ["paddingY", t.paddingY]]) if (r !== void 0 && (!Number.isFinite(r) || r < 0)) throw TypeError(`Vibe mediaCard ${e} ${n} must be a non-negative number.`);
3222
3289
  }
3223
3290
  }
3224
- function Un(e) {
3225
- if (un(e.autoScroll), Vn("cardHeader", e.cardHeader), Vn("cardFooter", e.cardFooter), Hn("header", e.mediaCard?.header), Hn("footer", e.mediaCard?.footer), $t(e.autofill), xn(e.fill), J(e.masonry), Fn(e.reelAutoAdvance), e.removalReconciliation) {
3291
+ function Wn(e) {
3292
+ if (un(e.autoScroll), Hn("cardHeader", e.cardHeader), Hn("cardFooter", e.cardFooter), Un("header", e.mediaCard?.header), Un("footer", e.mediaCard?.footer), $t(e.autofill), xn(e.fill), J(e.masonry), In(e.reelAutoAdvance), e.removalReconciliation) {
3226
3293
  if (!Number.isInteger(e.removalReconciliation.pageSize) || e.removalReconciliation.pageSize <= 0) throw TypeError("Vibe removalReconciliation pageSize must be a positive integer.");
3227
3294
  let t = e.removalReconciliation.maxReplayPages ?? 5;
3228
3295
  if (!Number.isInteger(t) || t <= 0) throw TypeError("Vibe removalReconciliation maxReplayPages must be a positive integer.");
3229
3296
  if (!e.loadPage) throw TypeError("Vibe removalReconciliation requires loadPage.");
3230
3297
  if (e.autofill?.strategy === "backend") throw TypeError("Vibe removalReconciliation does not support backend autofill.");
3298
+ if (e.autofill?.strategy === "frontend" && e.autofill.pageSize < e.removalReconciliation.pageSize) throw TypeError("Vibe autofill pageSize must be greater than or equal to removalReconciliation pageSize.");
3231
3299
  if (e.fill?.strategy === "backend") throw TypeError("Vibe removalReconciliation does not support backend fill.");
3232
3300
  }
3233
3301
  if (e.removalHistoryLimit !== void 0 && (!Number.isInteger(e.removalHistoryLimit) || e.removalHistoryLimit < 0)) throw TypeError("Vibe removalHistoryLimit must be a non-negative integer.");
@@ -3236,7 +3304,7 @@ function Un(e) {
3236
3304
  if (e.fill?.strategy === "frontend" && !e.loadPage) throw TypeError("Vibe frontend fill requires loadPage.");
3237
3305
  if (e.fill?.strategy === "backend" && e.fill.initialSession && !e.initialPage) throw TypeError("Vibe backend fill restoration requires initialPage.");
3238
3306
  }
3239
- function Wn(e) {
3307
+ function Gn(e) {
3240
3308
  if (typeof e != "string") return e;
3241
3309
  if (typeof document > "u") throw Error("Vibe cannot resolve a selector without a document.");
3242
3310
  let t = document.querySelector(e);
@@ -3245,8 +3313,8 @@ function Wn(e) {
3245
3313
  }
3246
3314
  //#endregion
3247
3315
  //#region src/core/pageRequest.ts
3248
- async function Gn({ append: e, autofillController: t, cursor: n, isCurrent: r, loadPage: i, onLastCursor: a, onPages: o, options: s, signal: c, state: l }) {
3249
- let u = s.autofill, d = e && u?.strategy === "frontend" && l.autofill.status === "paused", f = d ? {
3316
+ async function Kn({ append: e, autofillController: t, cursor: n, isCurrent: r, loadPage: i, onLastCursor: a, onPages: o, options: s, signal: c, state: l }) {
3317
+ let u = s.autofill, d = e && u?.strategy === "frontend" && (l.autofill.status === "paused" || l.autofill.status === "error"), f = d ? {
3250
3318
  received: l.autofill.received,
3251
3319
  requests: l.autofill.requests
3252
3320
  } : null, p = u ? d ? l.autofill.cycleId : t.beginCycle() : null;
@@ -3316,9 +3384,10 @@ async function Gn({ append: e, autofillController: t, cursor: n, isCurrent: r, l
3316
3384
  total: l.total
3317
3385
  }, r), t.syncCountdown();
3318
3386
  }
3319
- } catch (t) {
3387
+ } catch (n) {
3320
3388
  if (c.aborted || !r()) return;
3321
- u && (l.autofill.error = t, l.autofill.status = "error"), m || (e ? l.nextPageError = t : l.error = t);
3389
+ let i = u?.strategy === "frontend" ? t.commitCollection() : !1;
3390
+ u && (l.autofill.error = n, l.autofill.status = "error"), m || (e || i ? l.nextPageError = n : l.error = n);
3322
3391
  } finally {
3323
3392
  r() && (t.clearCollection(), l.isLoading = !1, l.isLoadingMore = !1);
3324
3393
  }
@@ -3328,13 +3397,13 @@ async function Gn({ append: e, autofillController: t, cursor: n, isCurrent: r, l
3328
3397
  function $(e) {
3329
3398
  return `${typeof e}:${String(e)}`;
3330
3399
  }
3331
- function Kn(e) {
3400
+ function qn(e) {
3332
3401
  return `${typeof e}:${String(e)}`;
3333
3402
  }
3334
- function qn(e) {
3403
+ function Jn(e) {
3335
3404
  return e.map(({ postId: e }) => e);
3336
3405
  }
3337
- var Jn = class {
3406
+ var Yn = class {
3338
3407
  delay;
3339
3408
  enabled;
3340
3409
  maxReplayPages;
@@ -3373,33 +3442,33 @@ var Jn = class {
3373
3442
  restore(e) {
3374
3443
  this.enabled && e.forEach((e) => this.tombstones.delete($(e)));
3375
3444
  }
3376
- async reconcile({ existingItems: e, loadPage: t, shouldPause: n = () => !1, signal: r }) {
3377
- let i = this.pending ?? this.createSession(e);
3378
- for (this.pending = i; i.remainingRequests > 0;) {
3379
- let e = Kn(i.cursor);
3380
- if (i.seenCursors.has(e)) throw Error("Vibe removal reconciliation received a repeated cursor.");
3445
+ async reconcile({ existingItems: e, loadPage: t, onDelayChange: n = () => void 0, shouldPause: r = () => !1, signal: i }) {
3446
+ let a = this.pending ?? this.createSession(e);
3447
+ for (this.pending = a; a.remainingRequests > 0;) {
3448
+ let e = qn(a.cursor);
3449
+ if (a.seenCursors.has(e)) throw Error("Vibe removal reconciliation received a repeated cursor.");
3381
3450
  if (await Jt({
3382
- delayMs: qt(i.pages.length, this.delay),
3383
- onChange: () => void 0,
3384
- signal: r
3385
- }), i.pages.length > 0 && n()) return this.result(i, "paused");
3386
- let a = Bt(await t({
3387
- cursor: i.cursor,
3388
- signal: r
3451
+ delayMs: qt(a.pages.length, this.delay),
3452
+ onChange: n,
3453
+ signal: i
3454
+ }), a.pages.length > 0 && r()) return this.result(a, "paused");
3455
+ let o = Bt(await t({
3456
+ cursor: a.cursor,
3457
+ signal: i
3389
3458
  }));
3390
- i.seenCursors.add(e);
3391
- let o = this.filterItems(a.items), s = [];
3392
- if (o.forEach((e) => {
3459
+ a.seenCursors.add(e);
3460
+ let s = this.filterItems(o.items), c = [];
3461
+ if (s.forEach((e) => {
3393
3462
  let t = $(e.postId);
3394
- i.attributed.has(t) || (i.attributed.add(t), s.push(e.postId)), i.appended.has(t) || (i.appended.add(t), i.items.push(e));
3395
- }), i.pages.push({
3396
- contributionIds: s,
3397
- cursor: i.cursor,
3398
- next: a.next,
3399
- returnedIds: qn(o)
3400
- }), i.lastCursor = i.cursor, i.next = a.next, --i.remainingRequests, a.total !== void 0 && (i.total = a.total), i.next === null ? i.remainingRequests = 0 : i.cursor = i.next, i.remainingRequests > 0 && n()) return this.result(i, "paused");
3463
+ a.attributed.has(t) || (a.attributed.add(t), c.push(e.postId)), a.appended.has(t) || (a.appended.add(t), a.items.push(e));
3464
+ }), a.pages.push({
3465
+ contributionIds: c,
3466
+ cursor: a.cursor,
3467
+ next: o.next,
3468
+ returnedIds: Jn(s)
3469
+ }), a.lastCursor = a.cursor, a.next = o.next, --a.remainingRequests, o.total !== void 0 && (a.total = o.total), a.next === null ? a.remainingRequests = 0 : a.cursor = a.next, a.remainingRequests > 0 && r()) return this.result(a, "paused");
3401
3470
  }
3402
- return this.result(i, "complete");
3471
+ return this.result(a, "complete");
3403
3472
  }
3404
3473
  createSession(e) {
3405
3474
  let t = this.findUnderfilledPage(e), n = t < 0 ? [] : this.pages.slice(t), r = n[0];
@@ -3435,7 +3504,7 @@ var Jn = class {
3435
3504
  return this.pages.findIndex(({ contributionIds: e }) => e.filter((e) => t.has($(e))).length < this.pageSize);
3436
3505
  }
3437
3506
  recordPage(e) {
3438
- let t = Kn(e.cursor), n = this.pages.findIndex(({ cursor: e }) => Kn(e) === t);
3507
+ let t = qn(e.cursor), n = this.pages.findIndex(({ cursor: e }) => qn(e) === t);
3439
3508
  n >= 0 && (this.pages = this.pages.slice(0, n)), this.pages.push({
3440
3509
  ...e,
3441
3510
  contributionIds: [...e.contributionIds],
@@ -3445,7 +3514,7 @@ var Jn = class {
3445
3514
  };
3446
3515
  //#endregion
3447
3516
  //#region src/core/activeItemRemoval.ts
3448
- function Yn(e, t, n, r, i) {
3517
+ function Xn(e, t, n, r, i) {
3449
3518
  let a = new Set(t.map(({ item: e }) => e.postId));
3450
3519
  if (e.activeReelPostId === null || !a.has(e.activeReelPostId)) return;
3451
3520
  let o = e.items[Math.max(n, 0)];
@@ -3458,7 +3527,7 @@ function Yn(e, t, n, r, i) {
3458
3527
  }
3459
3528
  //#endregion
3460
3529
  //#region src/core/exactMediaRemovalController.ts
3461
- function Xn(e, t) {
3530
+ function Zn(e, t) {
3462
3531
  let [n, ...r] = t;
3463
3532
  if (!n) throw Error("Vibe items must contain at least one media asset.");
3464
3533
  return {
@@ -3467,10 +3536,10 @@ function Xn(e, t) {
3467
3536
  items: r
3468
3537
  };
3469
3538
  }
3470
- function Zn(e) {
3539
+ function Qn(e) {
3471
3540
  if (!Number.isInteger(e.mediaIndex) || e.mediaIndex < 0) throw TypeError("Vibe mediaIndex must be a non-negative integer.");
3472
3541
  }
3473
- var Qn = class {
3542
+ var $n = class {
3474
3543
  generation = 0;
3475
3544
  metadata = /* @__PURE__ */ new WeakMap();
3476
3545
  state;
@@ -3478,7 +3547,7 @@ var Qn = class {
3478
3547
  this.options = e, this.state = e.state;
3479
3548
  }
3480
3549
  remove(e) {
3481
- Zn(e);
3550
+ Qn(e);
3482
3551
  let t = this.state.items.findIndex(({ postId: t }) => t === e.postId), n = this.state.items[t];
3483
3552
  if (!n) return null;
3484
3553
  let r = [...M(n)], i = r[e.mediaIndex];
@@ -3495,7 +3564,7 @@ var Qn = class {
3495
3564
  restored: !1
3496
3565
  });
3497
3566
  let o = this.state.mediaIndices.get(n.postId) ?? 0, s = this.isReelOpen() && this.state.activeReelPostId === n.postId, c = s && o === e.mediaIndex;
3498
- return r.splice(e.mediaIndex, 1), r.length > 0 ? (this.state.items[t] = Xn(n, r), this.updateMediaIndexAfterRemoval(n.postId, e.mediaIndex, c), a) : (this.state.items.splice(t, 1), this.options.onPostRemoved(n.postId), this.state.mediaIndices.delete(n.postId), s && this.advanceFromRemovedPost(a, n), a);
3567
+ return r.splice(e.mediaIndex, 1), r.length > 0 ? (this.state.items[t] = Zn(n, r), this.updateMediaIndexAfterRemoval(n.postId, e.mediaIndex, c), a) : (this.state.items.splice(t, 1), this.options.onPostRemoved(n.postId), this.state.mediaIndices.delete(n.postId), s && this.advanceFromRemovedPost(a, n), a);
3499
3568
  }
3500
3569
  reset() {
3501
3570
  this.generation += 1;
@@ -3521,7 +3590,7 @@ var Qn = class {
3521
3590
  }
3522
3591
  restoreIntoPost(e, t) {
3523
3592
  let n = this.state.items[e], r = [...M(n)], i = Math.min(t.mediaIndex, r.length);
3524
- if (r.splice(i, 0, t.media), this.state.items[e] = Xn(n, r), this.state.activeReelPostId !== t.postId) return;
3593
+ if (r.splice(i, 0, t.media), this.state.items[e] = Zn(n, r), this.state.activeReelPostId !== t.postId) return;
3525
3594
  let a = this.state.mediaIndices.get(t.postId) ?? 0;
3526
3595
  a >= i && this.state.mediaIndices.set(t.postId, a + 1);
3527
3596
  }
@@ -3534,18 +3603,18 @@ var Qn = class {
3534
3603
  };
3535
3604
  //#endregion
3536
3605
  //#region src/core/itemPlacement.ts
3537
- function $n(e, t) {
3606
+ function er(e, t) {
3538
3607
  let n = new Set(t);
3539
3608
  return e.flatMap((e, t) => n.has(e.postId) ? [{
3540
3609
  index: t,
3541
3610
  item: e
3542
3611
  }] : []);
3543
3612
  }
3544
- function er(e, t) {
3613
+ function tr(e, t) {
3545
3614
  let n = new Set(t.map(({ item: e }) => e.postId));
3546
3615
  return e.filter((e) => !n.has(e.postId));
3547
3616
  }
3548
- function tr(e, t) {
3617
+ function nr(e, t) {
3549
3618
  t.forEach(({ index: e }) => {
3550
3619
  if (!Number.isInteger(e) || e < 0) throw Error("Vibe item restore indexes must be non-negative integers.");
3551
3620
  });
@@ -3556,7 +3625,7 @@ function tr(e, t) {
3556
3625
  }
3557
3626
  //#endregion
3558
3627
  //#region src/core/itemRemovalController.ts
3559
- var nr = 20, rr = class {
3628
+ var rr = 20, ir = class {
3560
3629
  generation = 0;
3561
3630
  historyLimit;
3562
3631
  metadata = /* @__PURE__ */ new WeakMap();
@@ -3565,7 +3634,7 @@ var nr = 20, rr = class {
3565
3634
  itemOrder;
3566
3635
  stopItemsWatcher;
3567
3636
  constructor(e) {
3568
- this.options = e, this.historyLimit = e.historyLimit ?? nr, this.state = e.state, this.itemOrder = this.state.items.map(({ postId: e }) => e), this.stopItemsWatcher = O(() => this.state.items, (e) => this.appendUnknownItems(e), { flush: "sync" });
3637
+ this.options = e, this.historyLimit = e.historyLimit ?? rr, this.state = e.state, this.itemOrder = this.state.items.map(({ postId: e }) => e), this.stopItemsWatcher = O(() => this.state.items, (e) => this.appendUnknownItems(e), { flush: "sync" });
3569
3638
  }
3570
3639
  destroy() {
3571
3640
  this.reset(), this.stopItemsWatcher();
@@ -3579,7 +3648,7 @@ var nr = 20, rr = class {
3579
3648
  let a = this.options.startRemoval(i, t);
3580
3649
  if (a > 0 && await new Promise((e) => setTimeout(e, a)), this.metadata.get(r)?.generation !== this.generation) return r;
3581
3650
  let o = this.state.items.findIndex((e) => e.postId === this.state.activeReelPostId), s = new Set(n.map(({ item: e }) => e.postId)), c = o < 0 ? 0 : this.state.items.slice(0, o).filter(({ postId: e }) => s.has(e)).length, l = Math.max(o - c, 0);
3582
- return this.state.items = er(this.state.items, n), this.options.onItemsRemoved(r, n, l), this.record(r), r;
3651
+ return this.state.items = tr(this.state.items, n), this.options.onItemsRemoved(r, n, l), this.record(r), r;
3583
3652
  }
3584
3653
  reset() {
3585
3654
  this.generation += 1, this.history = [], this.itemOrder = [];
@@ -3590,7 +3659,7 @@ var nr = 20, rr = class {
3590
3659
  this.restoreRemoval(t);
3591
3660
  return;
3592
3661
  }
3593
- let n = new Set(this.state.items.map(({ postId: e }) => e)), r = e.filter(({ item: e }) => n.has(e.postId) ? !1 : (n.add(e.postId), !0)), i = tr(this.state.items, r);
3662
+ let n = new Set(this.state.items.map(({ postId: e }) => e)), r = e.filter(({ item: e }) => n.has(e.postId) ? !1 : (n.add(e.postId), !0)), i = nr(this.state.items, r);
3594
3663
  this.registerExternalPlacements(r), this.state.items = i, r.length > 0 && this.options.onRemovalRestored(r);
3595
3664
  }
3596
3665
  restoreRemoval(e) {
@@ -3616,7 +3685,7 @@ var nr = 20, rr = class {
3616
3685
  }
3617
3686
  collectOrderedPlacements(e) {
3618
3687
  let t = new Map(this.itemOrder.map((e, t) => [e, t]));
3619
- return $n(this.state.items, e).map((e) => ({
3688
+ return er(this.state.items, e).map((e) => ({
3620
3689
  index: t.get(e.item.postId) ?? e.index,
3621
3690
  item: e.item
3622
3691
  }));
@@ -3647,7 +3716,7 @@ var nr = 20, rr = class {
3647
3716
  let r = new Map(this.itemOrder.map((e, t) => [e, t]));
3648
3717
  return this.state.items = [...this.state.items, ...n].sort((e, t) => (r.get(e.postId) ?? 2 ** 53 - 1) - (r.get(t.postId) ?? 2 ** 53 - 1)), !0;
3649
3718
  }
3650
- }, ir = class {
3719
+ }, ar = class {
3651
3720
  forward = null;
3652
3721
  forwardPromise = null;
3653
3722
  forwardVersion = 0;
@@ -3664,7 +3733,7 @@ var nr = 20, rr = class {
3664
3733
  }, this.state.reelForward = {
3665
3734
  error: null,
3666
3735
  status: "loading"
3667
- }, this.state.reelForwardIndex = t, this.state.reelForwardItem = n, this.startForwardRequest(!1);
3736
+ }, this.state.reelForwardIndex = t, this.state.reelForwardItem = n, this.startForwardRequest();
3668
3737
  }
3669
3738
  cancel(e) {
3670
3739
  if (this.forward?.token !== e || this.state.reelForward.status === "idle") return null;
@@ -3678,7 +3747,7 @@ var nr = 20, rr = class {
3678
3747
  return !this.forward || this.state.reelForward.status === "idle" ? Promise.resolve() : (this.state.nextPageError = null, this.state.reelForward = {
3679
3748
  error: null,
3680
3749
  status: "loading"
3681
- }, this.startForwardRequest(this.state.next === null));
3750
+ }, this.startForwardRequest());
3682
3751
  }
3683
3752
  clearState() {
3684
3753
  this.state.reelForward = {
@@ -3686,19 +3755,19 @@ var nr = 20, rr = class {
3686
3755
  status: "idle"
3687
3756
  }, this.state.reelForwardIndex = null, this.state.reelForwardItem = null;
3688
3757
  }
3689
- startForwardRequest(e) {
3758
+ startForwardRequest() {
3690
3759
  if (this.forwardPromise) return this.forwardPromise;
3691
- let t = this.loadForward(e);
3692
- return this.forwardPromise = t, t.finally(() => {
3693
- this.forwardPromise === t && (this.forwardPromise = null, this.forward && this.state.reelForward.status === "loading" && this.startForwardRequest(!1));
3760
+ let e = this.loadForward();
3761
+ return this.forwardPromise = e, e.finally(() => {
3762
+ this.forwardPromise === e && (this.forwardPromise = null, this.forward && this.state.reelForward.status === "loading" && this.startForwardRequest());
3694
3763
  });
3695
3764
  }
3696
- async loadForward(e) {
3697
- let t = this.forward;
3698
- if (t) for (e && await this.options.retryEnd(); this.forward === t && t.version === this.forwardVersion;) {
3699
- let e = this.state.items[t.postIndex];
3700
- if (e) {
3701
- this.forward = null, this.clearState(), this.options.onActivate(e.postId);
3765
+ async loadForward() {
3766
+ let e = this.forward;
3767
+ if (e) for (; this.forward === e && e.version === this.forwardVersion;) {
3768
+ let t = this.state.items[e.postIndex];
3769
+ if (t) {
3770
+ this.forward = null, this.clearState(), this.options.onActivate(t.postId);
3702
3771
  return;
3703
3772
  }
3704
3773
  if (this.state.nextPageError) {
@@ -3708,24 +3777,33 @@ var nr = 20, rr = class {
3708
3777
  };
3709
3778
  return;
3710
3779
  }
3711
- if (this.state.next === null) {
3780
+ let n = this.state.next, r = this.state.items.length;
3781
+ if (await this.options.replenishAfterRemoval(), this.state.nextPageError) {
3712
3782
  this.state.reelForward = {
3713
- error: null,
3714
- status: "end"
3715
- };
3716
- return;
3717
- }
3718
- let n = this.state.next;
3719
- if (await this.options.loadNext(), this.state.next === n && !this.state.nextPageError && !this.state.items[t.postIndex]) {
3720
- this.state.reelForward = {
3721
- error: /* @__PURE__ */ Error("Vibe could not advance while page loading is unavailable."),
3783
+ error: this.state.nextPageError,
3722
3784
  status: "error"
3723
3785
  };
3724
3786
  return;
3725
3787
  }
3788
+ if (!this.state.items[e.postIndex]) {
3789
+ if (this.state.next === null) {
3790
+ this.state.reelForward = {
3791
+ error: null,
3792
+ status: "end"
3793
+ };
3794
+ return;
3795
+ }
3796
+ if (this.state.next === n && this.state.items.length === r) {
3797
+ this.state.reelForward = {
3798
+ error: /* @__PURE__ */ Error("Vibe could not advance while page loading is unavailable."),
3799
+ status: "error"
3800
+ };
3801
+ return;
3802
+ }
3803
+ }
3726
3804
  }
3727
3805
  }
3728
- }, ar = class {
3806
+ }, or = class {
3729
3807
  generation = 0;
3730
3808
  pending = Promise.resolve();
3731
3809
  constructor(e) {
@@ -3775,24 +3853,24 @@ var nr = 20, rr = class {
3775
3853
  };
3776
3854
  //#endregion
3777
3855
  //#region src/core/removalControllers.ts
3778
- function or(e) {
3779
- let t = new ir(e), n = new ar({
3856
+ function sr(e) {
3857
+ let t = new ar(e), n = new or({
3780
3858
  state: e.state,
3781
3859
  transitionMedia: (t) => e.surface()?.transitionActiveReelMedia(t) ?? Promise.resolve(!1),
3782
3860
  transitionPost: (t) => e.surface()?.transitionActiveReelPost(t) ?? Promise.resolve(!1)
3783
3861
  });
3784
3862
  return {
3785
- exactMediaRemoval: new Qn({
3863
+ exactMediaRemoval: new $n({
3786
3864
  onActivate: e.onActivate,
3787
3865
  onPostRemoved: (t) => e.onItemsRemoved([t]),
3788
3866
  onPostRestored: (t) => e.onItemsRestored([t]),
3789
3867
  reelForward: t,
3790
3868
  state: e.state
3791
3869
  }),
3792
- itemRemoval: new rr({
3870
+ itemRemoval: new ir({
3793
3871
  historyLimit: e.historyLimit,
3794
3872
  onItemsRemoved: (n, r, i) => {
3795
- e.onItemsRemoved(r.map(({ item: e }) => e.postId)), Yn(e.state, r, i, e.onActivate, (e, r) => t.start(n, e, r));
3873
+ e.onItemsRemoved(r.map(({ item: e }) => e.postId)), Xn(e.state, r, i, e.onActivate, (e, r) => t.start(n, e, r));
3796
3874
  },
3797
3875
  onRemovalRestored: (n) => {
3798
3876
  e.onItemsRestored(n.map(({ item: e }) => e.postId));
@@ -3807,17 +3885,17 @@ function or(e) {
3807
3885
  reelRemoval: n
3808
3886
  };
3809
3887
  }
3810
- var sr = 1.5;
3811
- function cr(e) {
3888
+ var cr = 1.5;
3889
+ function lr(e) {
3812
3890
  let t = Math.min(e.screenWidth, e.screenHeight);
3813
3891
  if (t > 0 && t < 600) return !0;
3814
- let n = Math.min(e.viewportWidth, e.viewportHeight), r = t >= n * sr;
3892
+ let n = Math.min(e.viewportWidth, e.viewportHeight), r = t >= n * cr;
3815
3893
  return !e.hasHover && n > 0 && n < 600 && r;
3816
3894
  }
3817
- function lr(e) {
3818
- return cr(e) ? "reel" : "masonry";
3819
- }
3820
3895
  function ur(e) {
3896
+ return lr(e) ? "reel" : "masonry";
3897
+ }
3898
+ function dr(e) {
3821
3899
  let t = e.ownerDocument.defaultView, n = e.ownerDocument.documentElement;
3822
3900
  return {
3823
3901
  hasHover: typeof t?.matchMedia == "function" && t.matchMedia("(hover: hover)").matches,
@@ -3827,15 +3905,15 @@ function ur(e) {
3827
3905
  viewportWidth: n.clientWidth
3828
3906
  };
3829
3907
  }
3830
- function dr(e) {
3831
- return cr(ur(e));
3832
- }
3833
3908
  function fr(e) {
3834
- return lr(ur(e));
3909
+ return lr(dr(e));
3910
+ }
3911
+ function pr(e) {
3912
+ return ur(dr(e));
3835
3913
  }
3836
3914
  //#endregion
3837
3915
  //#region src/core/responsiveLayoutController.ts
3838
- var pr = class {
3916
+ var mr = class {
3839
3917
  layoutMode;
3840
3918
  resizeObserver = null;
3841
3919
  target = null;
@@ -3860,10 +3938,10 @@ var pr = class {
3860
3938
  }
3861
3939
  handleResponsiveLayout = () => {
3862
3940
  if (!this.target) return;
3863
- let e = fr(this.target);
3864
- this.state.phoneMode = dr(this.target), this.state.reelInfoSheetOverlay = this.state.phoneMode, this.state.reelMediaSource = e === "reel" ? "preview" : "original", this.layoutMode === "responsive" && this.applyLayout(e);
3941
+ let e = pr(this.target);
3942
+ this.state.phoneMode = fr(this.target), this.state.reelInfoSheetOverlay = this.state.phoneMode, this.state.reelMediaSource = e === "reel" ? "preview" : "original", this.layoutMode === "responsive" && this.applyLayout(e);
3865
3943
  };
3866
- }, mr = class {
3944
+ }, hr = class {
3867
3945
  routedReelPostId = null;
3868
3946
  reelRouteIsActive = !1;
3869
3947
  constructor(e, t) {
@@ -3890,7 +3968,7 @@ var pr = class {
3890
3968
  let i = this.reelRouteIsActive ? "replace" : "push";
3891
3969
  this.reelRouteIsActive = !0, this.routedReelPostId = e, this.options.router[i](r);
3892
3970
  }
3893
- }, hr = class {
3971
+ }, gr = class {
3894
3972
  app = null;
3895
3973
  autoScroll;
3896
3974
  autofillController;
@@ -3911,52 +3989,57 @@ var pr = class {
3911
3989
  notificationItems;
3912
3990
  state;
3913
3991
  constructor(e) {
3914
- this.options = e, Un(e);
3992
+ this.options = e, Wn(e);
3915
3993
  let t = e.layout ?? "masonry";
3916
- this.state = x(Bn(e, t)), this.notificationItems = I(this.state), this.autoScroll = new fn({
3994
+ this.state = x(Vn(e, t)), this.lastLoadedCursor = e.initialPage?.current ?? e.initialPage?.next ?? null, this.notificationItems = I(this.state), this.autoScroll = new fn({
3917
3995
  getScrollElement: () => this.surface?.getAutoScrollElement() ?? null,
3918
3996
  state: this.state.autoScroll
3919
3997
  }), this.autofillController = new on({
3920
3998
  cancelRequest: () => this.cancelRequest(),
3921
- onLastCursor: (e) => {
3922
- this.lastLoadedCursor = e;
3923
- },
3999
+ onLastCursor: (e) => this.setCurrentCursor(e),
3924
4000
  onPages: (e) => this.removalReconciliation.recordPages(e),
3925
4001
  options: e.autofill,
3926
4002
  state: this.state
3927
- }), this.removalReconciliation = new Jn(e), this.fillController = new Mn({
4003
+ }), this.removalReconciliation = new Yn(e), this.fillController = new Mn({
3928
4004
  fill: e.fill,
3929
4005
  loadPage: e.loadPage ? (e) => this.loadFilteredPage(e) : void 0,
3930
- onLastCursor: (e) => {
3931
- this.lastLoadedCursor = e;
3932
- },
4006
+ needsFrontendPreparation: () => this.removalReconciliation.needsReconciliation(this.state.items),
4007
+ onLastCursor: (e) => this.setCurrentCursor(e),
3933
4008
  onPages: (e) => this.removalReconciliation.recordPages(e),
4009
+ prepareFrontend: ({ isCurrent: t, onDelayChange: n, signal: r }) => Nn({
4010
+ controller: this.removalReconciliation,
4011
+ isCurrent: t,
4012
+ loadPage: e.loadPage,
4013
+ onDelayChange: n,
4014
+ setLastCursor: (e) => this.setCurrentCursor(e),
4015
+ signal: r,
4016
+ state: this.state
4017
+ }),
3934
4018
  state: this.state
3935
- }), this.routing = new mr(e.routing, this.state);
3936
- let n = or({
4019
+ }), this.routing = new hr(e.routing, this.state);
4020
+ let n = sr({
3937
4021
  historyLimit: e.removalHistoryLimit,
3938
- loadNext: () => this.loadNext(),
3939
4022
  onActivate: (e) => this.setActiveReelPost(e),
3940
4023
  onItemsRemoved: (e) => this.removalReconciliation.remove(e),
3941
4024
  onItemsRestored: (e) => this.removalReconciliation.restore(e),
3942
- retryEnd: () => this.retryEnd(),
4025
+ replenishAfterRemoval: () => this.replenishAfterRemoval(),
3943
4026
  state: this.state,
3944
4027
  surface: () => this.surface
3945
4028
  });
3946
- this.exactMediaRemoval = n.exactMediaRemoval, this.itemRemoval = n.itemRemoval, this.reelForward = n.reelForward, this.reelRemoval = n.reelRemoval, this.responsiveLayout = new pr(t, this.state, () => {
4029
+ this.exactMediaRemoval = n.exactMediaRemoval, this.itemRemoval = n.itemRemoval, this.reelForward = n.reelForward, this.reelRemoval = n.reelRemoval, this.responsiveLayout = new mr(t, this.state, () => {
3947
4030
  this.routing.syncFeed();
3948
4031
  }), this.startStateNotifications();
3949
4032
  }
3950
4033
  async mount() {
3951
4034
  if (this.app) throw Error("Vibe is already mounted.");
3952
4035
  this.startStateNotifications();
3953
- let e = Wn(this.options.target);
4036
+ let e = Gn(this.options.target);
3954
4037
  this.responsiveLayout.mount(e), this.app = i(zt, {
3955
4038
  canRetryEnd: !!this.options.loadPage,
3956
4039
  cardFooter: this.options.cardFooter,
3957
4040
  cardHeader: this.options.cardHeader,
3958
4041
  feedFooter: this.options.feedFooter,
3959
- feedFooterActions: Nn(this),
4042
+ feedFooterActions: Pn(this),
3960
4043
  mediaCard: this.options.mediaCard,
3961
4044
  masonry: this.options.masonry,
3962
4045
  onMediaReady: this.options.onMediaReady,
@@ -4075,24 +4158,30 @@ var pr = class {
4075
4158
  restoreFillSession(e) {
4076
4159
  return this.fillController.restoreSession(e);
4077
4160
  }
4078
- async loadNext() {
4161
+ loadNext() {
4162
+ return this.startLoadMore(() => this.loadNextSequence());
4163
+ }
4164
+ replenishAfterRemoval() {
4165
+ return this.startLoadMore(() => this.replenishAfterRemovalSequence());
4166
+ }
4167
+ async startLoadMore(e) {
4079
4168
  if (this.pendingRequest) return this.pendingRequest;
4080
4169
  if (this.state.loadMoreLocked || tn(this.state.autofill) || this.fillController.isActive() || !this.options.loadPage || this.state.next === null && !this.removalReconciliation.needsReconciliation(this.state.items)) return;
4081
4170
  this.state.isLoadingMore = !0, this.state.nextPageError = null;
4082
- let e = this.loadNextSequence();
4083
- return this.pendingRequest = e, e.finally(() => {
4084
- this.pendingRequest === e && (this.pendingRequest = null), this.state.isLoadingMore = !1;
4171
+ let t = e();
4172
+ return this.pendingRequest = t, t.finally(() => {
4173
+ this.pendingRequest === t && (this.pendingRequest = null), this.state.isLoadingMore = !1;
4085
4174
  });
4086
4175
  }
4087
4176
  async refresh() {
4088
- return this.replaceFeed(this.state.next ?? this.lastLoadedCursor, "refresh");
4177
+ return this.replaceFeed(this.lastLoadedCursor, "refresh");
4089
4178
  }
4090
4179
  async reload() {
4091
4180
  return this.replaceFeed(null, "reload");
4092
4181
  }
4093
4182
  async replaceFeed(e, t) {
4094
4183
  if (!this.options.loadPage) throw Error(`Vibe cannot ${t} without loadPage.`);
4095
- return tn(this.state.autofill) && await this.cancelAutofill(), this.fillController.isActive() && await this.cancelFill(), this.cancelRequest(), this.state.autofill = en(this.options.autofill, void 0, !1), this.fillController.reset(), this.reelForward.reset(), this.reelRemoval.reset(), this.exactMediaRemoval.reset(), this.itemRemoval.reset(), this.removalReconciliation.reset(), this.state.error = null, this.state.isLoading = !0, this.state.items = [], this.state.next = null, this.state.nextPageError = null, this.state.total = null, this.startRequest(e, !1);
4184
+ return tn(this.state.autofill) && await this.cancelAutofill(), this.fillController.isActive() && await this.cancelFill(), this.cancelRequest(), this.state.autofill = en(this.options.autofill, void 0, !1), this.fillController.reset(), this.reelForward.reset(), this.reelRemoval.reset(), this.exactMediaRemoval.reset(), this.itemRemoval.reset(), this.removalReconciliation.reset(), this.state.error = null, this.state.current = null, this.state.isLoading = !0, this.state.items = [], this.state.next = null, this.state.nextPageError = null, this.state.total = null, this.startRequest(e, !1);
4096
4185
  }
4097
4186
  async loadFilteredPage(e) {
4098
4187
  let t = this.options.loadPage;
@@ -4106,19 +4195,26 @@ var pr = class {
4106
4195
  async loadNextSequence() {
4107
4196
  this.removalReconciliation.needsReconciliation(this.state.items) && !await this.reconcileBeforeNext() || this.state.loadMoreLocked || this.state.next !== null && await this.fetchPage(this.state.next, !0);
4108
4197
  }
4198
+ async replenishAfterRemovalSequence() {
4199
+ let e = this.state.items.length;
4200
+ this.removalReconciliation.needsReconciliation(this.state.items) && (!await this.reconcileBeforeNext() || this.state.items.length > e) || this.state.loadMoreLocked || this.state.next === null || await this.fetchPage(this.state.next, !0);
4201
+ }
4109
4202
  async reconcileBeforeNext() {
4110
4203
  let e = this.options.loadPage;
4111
4204
  if (!e) return !1;
4112
4205
  let t = ++this.requestVersion, n = new AbortController();
4113
4206
  this.abortController = n;
4114
4207
  try {
4115
- let r = await this.removalReconciliation.reconcile({
4116
- existingItems: this.state.items,
4208
+ let r = await Nn({
4209
+ controller: this.removalReconciliation,
4210
+ isCurrent: () => t === this.requestVersion,
4117
4211
  loadPage: e,
4118
- shouldPause: () => this.state.loadMoreLocked,
4119
- signal: n.signal
4212
+ onDelayChange: () => void 0,
4213
+ setLastCursor: (e) => this.setCurrentCursor(e),
4214
+ signal: n.signal,
4215
+ state: this.state
4120
4216
  });
4121
- return t === this.requestVersion ? (this.state.items = Z(this.state.items, r.items), this.state.next = r.next, this.lastLoadedCursor = r.lastCursor, r.total !== void 0 && (this.state.total = r.total), this.removalReconciliation.completeReconciliation(r), r.status === "complete") : !1;
4217
+ return t === this.requestVersion && r === "complete";
4122
4218
  } catch (e) {
4123
4219
  return !n.signal.aborted && t === this.requestVersion && (this.state.nextPageError = e), !1;
4124
4220
  } finally {
@@ -4134,13 +4230,9 @@ var pr = class {
4134
4230
  }
4135
4231
  setLoadMoreLocked(e) {
4136
4232
  if (this.state.loadMoreLocked !== e && (this.state.loadMoreLocked = e, !e)) {
4137
- let e = this.state.fill.status === "paused" ? this.state.fill.target : null;
4138
- if (e) {
4139
- let t = "pages" in e ? e.pages - this.state.fill.completedPages : null;
4140
- if (t === null || t > 0) {
4141
- this.fillController.start(t === null ? { until: "end" } : { pages: t });
4142
- return;
4143
- }
4233
+ if (this.state.fill.status === "paused" && this.state.fill.target) {
4234
+ this.fillController.resume(this.removalReconciliation.hasPendingSession());
4235
+ return;
4144
4236
  }
4145
4237
  if (this.state.autofill.status === "paused" || this.removalReconciliation.hasPendingSession()) {
4146
4238
  let e = this.pendingRequest;
@@ -4155,10 +4247,10 @@ var pr = class {
4155
4247
  this.state.total = e;
4156
4248
  }
4157
4249
  setReelAutoAdvance(e) {
4158
- Ln(this.state.reelAutoAdvance, e);
4250
+ Rn(this.state.reelAutoAdvance, e);
4159
4251
  }
4160
4252
  setReelInfoSheet(e) {
4161
- zn(this.state.reelInfoSheet, this.options.reelInfoSheet, e);
4253
+ Bn(this.state.reelInfoSheet, this.options.reelInfoSheet, e);
4162
4254
  }
4163
4255
  setLayout(e) {
4164
4256
  this.responsiveLayout.setLayout(e);
@@ -4178,15 +4270,13 @@ var pr = class {
4178
4270
  async fetchPage(e, t) {
4179
4271
  if (!this.options.loadPage) return;
4180
4272
  let n = ++this.requestVersion, r = new AbortController();
4181
- this.abortController = r, await Gn({
4273
+ this.abortController = r, await Kn({
4182
4274
  append: t,
4183
4275
  autofillController: this.autofillController,
4184
4276
  cursor: e,
4185
4277
  isCurrent: () => n === this.requestVersion,
4186
4278
  loadPage: (e) => this.loadFilteredPage(e),
4187
- onLastCursor: (e) => {
4188
- this.lastLoadedCursor = e;
4189
- },
4279
+ onLastCursor: (e) => this.setCurrentCursor(e),
4190
4280
  onPages: (e) => this.removalReconciliation.recordPages(e),
4191
4281
  options: this.options,
4192
4282
  signal: r.signal,
@@ -4206,15 +4296,13 @@ var pr = class {
4206
4296
  cycleId: n,
4207
4297
  isCurrent: () => e === this.requestVersion,
4208
4298
  onCollection: (t) => this.autofillController.captureCollection(t, e === this.requestVersion),
4209
- onLastCursor: (e) => {
4210
- this.lastLoadedCursor = e;
4211
- },
4299
+ onLastCursor: (e) => this.setCurrentCursor(e),
4212
4300
  onPages: (e) => this.removalReconciliation.recordPages(e),
4213
4301
  options: this.options,
4214
4302
  signal: t.signal,
4215
4303
  state: this.state
4216
4304
  }).catch((n) => {
4217
- t.signal.aborted || e !== this.requestVersion || (this.state.autofill.error = n, this.state.autofill.status = "error", this.state.nextPageError = n);
4305
+ t.signal.aborted || e !== this.requestVersion || (this.autofillController.commitCollection(), this.state.autofill.error = n, this.state.autofill.status = "error", this.state.nextPageError = n);
4218
4306
  }).finally(() => {
4219
4307
  e === this.requestVersion && (this.autofillController.clearCollection(), this.autofillController.syncCountdown(), this.abortController = null, this.state.isLoadingMore = !1, this.pendingRequest === r && (this.pendingRequest = null));
4220
4308
  });
@@ -4227,9 +4315,12 @@ var pr = class {
4227
4315
  flush: "post"
4228
4316
  }));
4229
4317
  }
4318
+ setCurrentCursor(e) {
4319
+ this.lastLoadedCursor = e, this.state.current = e;
4320
+ }
4230
4321
  };
4231
- function gr(e) {
4232
- return new hr(e);
4322
+ function _r(e) {
4323
+ return new gr(e);
4233
4324
  }
4234
4325
  //#endregion
4235
- export { gr as createVibe };
4326
+ export { _r as createVibe };