@vibes.diy/base 14.3.113 → 14.3.115

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.
Files changed (63) hide show
  1. package/components/vibe-menu/VibeMenu.js +9 -3
  2. package/components/vibe-menu/VibeMenu.js.map +1 -1
  3. package/components/vibe-menu/cards/AccountCard.d.ts +4 -1
  4. package/components/vibe-menu/cards/AccountCard.js +25 -9
  5. package/components/vibe-menu/cards/AccountCard.js.map +1 -1
  6. package/components/vibe-menu/cards/CodeCard.d.ts +2 -1
  7. package/components/vibe-menu/cards/CodeCard.js +17 -6
  8. package/components/vibe-menu/cards/CodeCard.js.map +1 -1
  9. package/components/vibe-menu/cards/CodeModeWorkspace.d.ts +2 -1
  10. package/components/vibe-menu/cards/CodeModeWorkspace.js +8 -6
  11. package/components/vibe-menu/cards/CodeModeWorkspace.js.map +1 -1
  12. package/components/vibe-menu/geometry.d.ts +1 -0
  13. package/components/vibe-menu/geometry.js +5 -0
  14. package/components/vibe-menu/geometry.js.map +1 -1
  15. package/components/vibe-menu/index.d.ts +5 -0
  16. package/components/vibe-menu/index.js +5 -0
  17. package/components/vibe-menu/index.js.map +1 -1
  18. package/components/vibe-menu/parts/Chip.d.ts +2 -1
  19. package/components/vibe-menu/parts/Chip.js +26 -2
  20. package/components/vibe-menu/parts/Chip.js.map +1 -1
  21. package/components/vibe-menu/parts/Composer.d.ts +11 -0
  22. package/components/vibe-menu/parts/Composer.js +44 -1
  23. package/components/vibe-menu/parts/Composer.js.map +1 -1
  24. package/components/vibe-menu/parts/LookRestyleSection.d.ts +51 -0
  25. package/components/vibe-menu/parts/LookRestyleSection.js +290 -0
  26. package/components/vibe-menu/parts/LookRestyleSection.js.map +1 -0
  27. package/components/vibe-menu/parts/MomentLine.d.ts +1 -0
  28. package/components/vibe-menu/parts/MomentLine.js +4 -2
  29. package/components/vibe-menu/parts/MomentLine.js.map +1 -1
  30. package/components/vibe-menu/parts/SendCap.d.ts +8 -0
  31. package/components/vibe-menu/parts/SendCap.js +10 -0
  32. package/components/vibe-menu/parts/SendCap.js.map +1 -0
  33. package/components/vibe-menu/parts/StatusChipRow.d.ts +58 -0
  34. package/components/vibe-menu/parts/StatusChipRow.js +121 -0
  35. package/components/vibe-menu/parts/StatusChipRow.js.map +1 -0
  36. package/components/vibe-menu/parts/StatusLine.d.ts +21 -0
  37. package/components/vibe-menu/parts/StatusLine.js +25 -0
  38. package/components/vibe-menu/parts/StatusLine.js.map +1 -0
  39. package/components/vibe-menu/parts/SurveyStrip.d.ts +3 -1
  40. package/components/vibe-menu/parts/SurveyStrip.js +9 -1
  41. package/components/vibe-menu/parts/SurveyStrip.js.map +1 -1
  42. package/components/vibe-menu/parts/VibesSwitchGlass.d.ts +0 -9
  43. package/components/vibe-menu/parts/VibesSwitchGlass.js +2 -17
  44. package/components/vibe-menu/parts/VibesSwitchGlass.js.map +1 -1
  45. package/components/vibe-menu/parts/agent-log-frame.d.ts +9 -0
  46. package/components/vibe-menu/parts/agent-log-frame.js +10 -0
  47. package/components/vibe-menu/parts/agent-log-frame.js.map +1 -0
  48. package/components/vibe-menu/parts/use-composer-draft.js +30 -0
  49. package/components/vibe-menu/parts/use-composer-draft.js.map +1 -1
  50. package/components/vibe-menu/shell/VibeMenuShell.d.ts +5 -0
  51. package/components/vibe-menu/shell/VibeMenuShell.js +5 -1
  52. package/components/vibe-menu/shell/VibeMenuShell.js.map +1 -1
  53. package/components/vibe-menu/shell/shell.styles.js +270 -38
  54. package/components/vibe-menu/shell/shell.styles.js.map +1 -1
  55. package/components/vibe-menu/slices.d.ts +8 -2
  56. package/components/vibe-menu/slices.js.map +1 -1
  57. package/components/vibe-menu/vibe-menu.styles.d.ts +3 -3
  58. package/components/vibe-menu/vibe-menu.styles.js +99 -1
  59. package/components/vibe-menu/vibe-menu.styles.js.map +1 -1
  60. package/hooks/img-gen/use-img-gen.d.ts +1 -0
  61. package/hooks/img-gen/use-img-gen.js +374 -304
  62. package/hooks/img-gen/use-img-gen.js.map +1 -1
  63. package/package.json +5 -5
@@ -149,6 +149,10 @@ let imgGenProbeDeadlineMs = IMG_GEN_PROBE_DEADLINE_MS;
149
149
  export function __setImgGenProbeDeadlineMsForTests(ms) {
150
150
  imgGenProbeDeadlineMs = ms ?? IMG_GEN_PROBE_DEADLINE_MS;
151
151
  }
152
+ const imgGenLeases = new Map();
153
+ export function __resetImgGenLeasesForTests() {
154
+ imgGenLeases.clear();
155
+ }
152
156
  const IMG_GEN_COMMIT_REPROBE_DELAYS_MS = [500, 1000, 2000, 4000, 8000, 15000];
153
157
  let imgGenCommitReprobeDelaysMs = IMG_GEN_COMMIT_REPROBE_DELAYS_MS;
154
158
  export function __setImgGenCommitReprobeDelaysMsForTests(ms) {
@@ -248,6 +252,8 @@ export function useImgGen(opts) {
248
252
  const playgroundSpentKeyRef = useRef(undefined);
249
253
  const currentGenRef = useRef(null);
250
254
  const probeInFlightRef = useRef(null);
255
+ const leaseWaitRef = useRef(null);
256
+ const ownedLeaseRef = useRef(null);
251
257
  const commitProbeInFlightRef = useRef(null);
252
258
  const displayReadBackRef = useRef(null);
253
259
  const committedGenRef = useRef(null);
@@ -310,13 +316,18 @@ export function useImgGen(opts) {
310
316
  };
311
317
  }, [skip, _id, mediaDb, db]);
312
318
  useEffect(() => {
313
- if (skip || !_id)
319
+ if (skip || !_id) {
320
+ leaseWaitRef.current = null;
314
321
  return;
322
+ }
315
323
  const inputMeta = inputImage;
316
324
  const inputKey = inputMeta
317
325
  ? `${inputMeta.uploadId ?? ""}|${inputMeta.name ?? ""}|${inputMeta.lastModified ?? ""}|${inputMeta.size ?? ""}|${inputMeta.type ?? ""}`
318
326
  : "";
319
327
  const genKey = `${_id}-${generationId ?? ""}-${inputKey}-${model ?? ""}-${myHandle ?? ""}`;
328
+ const leaseWaitKey = `${mediaDbName(dbName)}\u0000${genKey}\u0000${prompt ?? ""}`;
329
+ if (leaseWaitRef.current !== leaseWaitKey)
330
+ leaseWaitRef.current = null;
320
331
  if (currentGenRef.current === genKey)
321
332
  return;
322
333
  currentGenRef.current = genKey;
@@ -496,14 +507,14 @@ export function useImgGen(opts) {
496
507
  }
497
508
  const promptForProbeKey = prompt ?? existingDoc?.prompt;
498
509
  const inputIsStoredRef = incomingSourceKey !== undefined;
499
- if (authoritative === false &&
500
- !isRegen &&
501
- (inputImage === undefined || inputIsStoredRef) &&
502
- (readStartedPending || readPending())) {
510
+ if (authoritative === false && !isRegen && (inputImage === undefined || inputIsStoredRef)) {
503
511
  if (existingDoc)
504
512
  setDocument(existingDoc);
505
513
  setPending(true);
506
514
  if (confirmedMediaProbe === undefined || confirmedMediaProbe === null) {
515
+ if (readStartedPending === false && readPending() === false) {
516
+ return decide(mediaDocs, legacyDoc, true);
517
+ }
507
518
  currentGenRef.current = null;
508
519
  if (readPending() === false)
509
520
  setDeferTick((t) => t + 1);
@@ -560,339 +571,398 @@ export function useImgGen(opts) {
560
571
  setDocument(existingDoc);
561
572
  return;
562
573
  }
563
- dropEarlyPreview();
564
- setPreviewUrl(undefined);
565
- setLoading(true);
566
- setProgress(10);
567
- setError(null);
568
- const target = {
569
- dbName,
570
- docId: hostDocId,
571
- regen: isRegen,
572
- ...(incomingSourceKey !== undefined ? { sourceKey: incomingSourceKey } : {}),
573
- };
574
- const tapRun = tapStarted && generationId !== undefined && tapSpentRef.current !== generationId;
575
- if (tapRun)
576
- tapSpentRef.current = generationId;
577
- const rFiles = await exception2Result(() => imgGen(promptText, {
578
- inputImage,
579
- model,
580
- target,
581
- ...(tapRun ? { userActivation: true } : {}),
582
- onPreview: (blob) => {
583
- if (currentGenRef.current !== genKey || unmountSignalRef.current.aborted)
584
- return;
585
- if (earlyPreviewRef.current !== null)
586
- return;
587
- const url = URL.createObjectURL(blob);
588
- earlyPreviewRef.current = { genKey, url, blob };
589
- setPreviewUrl(url);
590
- },
591
- }));
592
- if (rFiles.isErr()) {
593
- if (earlyPreviewRef.current?.genKey === genKey)
594
- dropEarlyPreview();
595
- const message = rFiles.Err().message;
596
- if (message === IMG_GEN_NEEDS_TAP || message === IMG_GEN_CANCELLED) {
597
- if (existingDoc)
598
- setDocument(existingDoc);
599
- playgroundSpentKeyRef.current = genKey;
600
- playgroundModeRef.current = true;
601
- currentGenRef.current = null;
602
- setNeedsTap(true);
574
+ const leaseKey = `${mediaDbName(dbName)}\u0000${hostDocId}\u0000${myHandle}`;
575
+ if (unmountSignalRef.current.aborted)
576
+ return;
577
+ const liveLease = imgGenLeases.get(leaseKey);
578
+ const previousLease = ownedLeaseRef.current;
579
+ const replacesOwnLease = previousLease !== null && previousLease.genKey !== genKey && previousLease.promise === liveLease;
580
+ const deliberateRequest = isRegen || (inputImage !== undefined && inputIsStoredRef === false);
581
+ if (liveLease !== undefined && replacesOwnLease === false && deliberateRequest === false) {
582
+ setPending(true);
583
+ const waitKey = leaseWaitKey;
584
+ currentGenRef.current = null;
585
+ if (leaseWaitRef.current === waitKey)
586
+ return;
587
+ leaseWaitRef.current = waitKey;
588
+ await liveLease;
589
+ if (unmountSignalRef.current.aborted || leaseWaitRef.current !== waitKey)
590
+ return;
591
+ if (currentGenRef.current !== null)
592
+ return;
593
+ const rRead = await exception2Result(loadMediaDocs);
594
+ if (unmountSignalRef.current.aborted || leaseWaitRef.current !== waitKey || currentGenRef.current !== null)
595
+ return;
596
+ leaseWaitRef.current = null;
597
+ currentGenRef.current = genKey;
598
+ if (rRead.isErr()) {
599
+ setError(rRead.Err());
600
+ setPending(false);
603
601
  setLoading(false);
602
+ currentGenRef.current = null;
604
603
  return;
605
604
  }
606
- if (message === IMG_GEN_SOURCE_UNUSABLE) {
607
- vibe.log("warn", IMG_GEN_SOURCE_UNUSABLE, { docId: hostDocId, dbName });
608
- }
609
- if (message === IMG_GEN_UNREACHABLE) {
610
- playgroundModeRef.current = true;
611
- setError(new Error(IMG_GEN_UNREACHABLE_MESSAGE));
612
- }
613
- else {
614
- setError(rFiles.Err());
615
- }
616
- setLoading(false);
617
- if (playgroundModeRef.current)
618
- setNeedsTap(true);
619
- currentGenRef.current = null;
620
- return;
621
- }
622
- const { files, docWritten } = rFiles.Ok();
623
- playgroundModeRef.current = false;
624
- const file = files[0];
625
- const early = earlyPreviewRef.current?.genKey === genKey ? earlyPreviewRef.current : null;
626
- if (early !== null) {
627
- earlyPreviewRef.current = null;
628
- if (previewUrlsRef.current.has(file.uploadId) === false)
629
- previewUrlsRef.current.set(file.uploadId, early.url);
630
- else
631
- URL.revokeObjectURL(early.url);
605
+ return decide(rRead.Ok(), legacyDoc, false);
632
606
  }
633
- else if (file.preview instanceof Blob && previewUrlsRef.current.has(file.uploadId) === false) {
634
- previewUrlsRef.current.set(file.uploadId, URL.createObjectURL(file.preview));
635
- }
636
- const ownBytes = early?.blob ?? (file.preview instanceof Blob ? file.preview : undefined);
637
- if (ownBytes !== undefined && pictures !== undefined) {
638
- void pictures.seed(file.uploadId, ownBytes);
639
- seededRef.current.add(file.uploadId);
607
+ let resolveLease = () => undefined;
608
+ const lease = new Promise((resolve) => {
609
+ resolveLease = resolve;
610
+ });
611
+ imgGenLeases.set(leaseKey, lease);
612
+ if (replacesOwnLease && previousLease !== null)
613
+ previousLease.release();
614
+ function releaseLease() {
615
+ if (imgGenLeases.get(leaseKey) === lease)
616
+ imgGenLeases.delete(leaseKey);
617
+ resolveLease();
618
+ if (ownedLeaseRef.current?.release === releaseLease)
619
+ ownedLeaseRef.current = null;
640
620
  }
641
- const rRun = await exception2Result(async () => {
642
- setProgress(90);
643
- const showCommitted = async (uploadId, clientWrite) => {
644
- if (currentGenRef.current !== genKey)
645
- return;
646
- committedGenRef.current = { genKey, uploadId };
647
- let after = await loadMediaDocs();
648
- const landedLocally = sortVersionDocs(after).some((vd) => Object.values(vd._files).some((f) => f.uploadId === uploadId && f.url !== undefined));
649
- const waitForSync = (rows) => {
650
- setDocument(composeDocument({
651
- hostDocId,
652
- versionDocs: sortVersionDocs(rows),
653
- pointer: findPointerDoc(rows, myHandle),
654
- legacyDoc,
655
- }));
656
- setPending(true);
657
- setLoading(false);
621
+ ownedLeaseRef.current = { genKey, promise: lease, release: releaseLease };
622
+ const generationHandle = myHandle;
623
+ const generationPrompt = promptText;
624
+ async function generate() {
625
+ dropEarlyPreview();
626
+ setPreviewUrl(undefined);
627
+ setLoading(true);
628
+ setProgress(10);
629
+ setError(null);
630
+ const target = {
631
+ dbName,
632
+ docId: hostDocId,
633
+ regen: isRegen,
634
+ ...(incomingSourceKey !== undefined ? { sourceKey: incomingSourceKey } : {}),
635
+ };
636
+ const tapRun = tapStarted && generationId !== undefined && tapSpentRef.current !== generationId;
637
+ if (tapRun)
638
+ tapSpentRef.current = generationId;
639
+ const rFiles = await exception2Result(() => imgGen(generationPrompt, {
640
+ inputImage,
641
+ model,
642
+ target,
643
+ ...(tapRun ? { userActivation: true } : {}),
644
+ onPreview: (blob) => {
645
+ if (currentGenRef.current !== genKey || unmountSignalRef.current.aborted)
646
+ return;
647
+ if (earlyPreviewRef.current !== null)
648
+ return;
649
+ const url = URL.createObjectURL(blob);
650
+ earlyPreviewRef.current = { genKey, url, blob };
651
+ setPreviewUrl(url);
652
+ },
653
+ }));
654
+ if (rFiles.isErr()) {
655
+ if (earlyPreviewRef.current?.genKey === genKey)
656
+ dropEarlyPreview();
657
+ const message = rFiles.Err().message;
658
+ if (message === IMG_GEN_NEEDS_TAP || message === IMG_GEN_CANCELLED) {
659
+ if (existingDoc)
660
+ setDocument(existingDoc);
661
+ playgroundSpentKeyRef.current = genKey;
662
+ playgroundModeRef.current = true;
658
663
  currentGenRef.current = null;
659
- };
660
- if (landedLocally) {
661
- setDocument(composeDocument({
662
- hostDocId,
663
- versionDocs: sortVersionDocs(after),
664
- pointer: findPointerDoc(after, myHandle),
665
- legacyDoc,
666
- }));
667
- setProgress(100);
664
+ setNeedsTap(true);
668
665
  setLoading(false);
669
666
  return;
670
667
  }
671
- if (confirmedMediaProbe === undefined || confirmedMediaProbe === null) {
672
- waitForSync(after);
673
- return;
668
+ if (message === IMG_GEN_SOURCE_UNUSABLE) {
669
+ vibe.log("warn", IMG_GEN_SOURCE_UNUSABLE, { docId: hostDocId, dbName });
674
670
  }
675
- const heldLocally = sortVersionDocs(after).some((vd) => Object.values(vd._files).some((f) => f.uploadId === uploadId));
676
- if (heldLocally) {
677
- setDocument(composeDocument({
678
- hostDocId,
679
- versionDocs: sortVersionDocs(after),
680
- pointer: findPointerDoc(after, myHandle),
681
- legacyDoc,
682
- }));
683
- setPending(true);
684
- setLoading(false);
685
- currentGenRef.current = null;
671
+ if (message === IMG_GEN_UNREACHABLE) {
672
+ playgroundModeRef.current = true;
673
+ setError(new Error(IMG_GEN_UNREACHABLE_MESSAGE));
686
674
  }
687
675
  else {
688
- setPending(true);
689
- currentGenRef.current = null;
676
+ setError(rFiles.Err());
690
677
  }
691
- const probeKey = `${genKey}\u0000${promptText}`;
692
- const stillOurs = () => unmountSignalRef.current.aborted === false &&
693
- commitProbeInFlightRef.current === probeKey &&
694
- (currentGenRef.current === null || currentGenRef.current === genKey);
695
- commitProbeInFlightRef.current = probeKey;
696
- let ourSeq = clientWrite?.seq;
697
- let rekeeps = 0;
698
- let collided = false;
699
- const readBack = () => readBackFromServer({
700
- probe: confirmedMediaProbe,
701
- dbName,
702
- hostDocId,
703
- signal: unmountSignalRef.current,
704
- stillOurs,
705
- logEvent: "imggen-commit-probe-failed",
706
- examine: async (probedDocs, probedLegacy) => {
707
- const probedVersions = sortVersionDocs(probedDocs);
708
- if (holdsUpload(probedVersions, uploadId, true)) {
709
- commitProbeInFlightRef.current = null;
710
- currentGenRef.current = genKey;
711
- setDocument(composeDocument({
712
- hostDocId,
713
- versionDocs: probedVersions,
714
- pointer: laterPointer(findPointerDoc(after, myHandle), findPointerDoc(probedDocs, myHandle)),
715
- legacyDoc: probedLegacy ?? legacyDoc,
716
- }));
717
- setPending(false);
718
- setProgress(100);
719
- setLoading(false);
720
- return { done: true, value: "shown" };
721
- }
722
- const taken = clientWrite !== undefined &&
723
- ourSeq !== undefined &&
724
- probedVersions.some((vd) => vd.seq === ourSeq && holdsUpload([vd], uploadId, false) === false);
725
- if (taken === false || clientWrite === undefined)
678
+ setLoading(false);
679
+ if (playgroundModeRef.current)
680
+ setNeedsTap(true);
681
+ currentGenRef.current = null;
682
+ return;
683
+ }
684
+ const { files, docWritten } = rFiles.Ok();
685
+ playgroundModeRef.current = false;
686
+ const file = files[0];
687
+ const early = earlyPreviewRef.current?.genKey === genKey ? earlyPreviewRef.current : null;
688
+ if (early !== null) {
689
+ earlyPreviewRef.current = null;
690
+ if (previewUrlsRef.current.has(file.uploadId) === false)
691
+ previewUrlsRef.current.set(file.uploadId, early.url);
692
+ else
693
+ URL.revokeObjectURL(early.url);
694
+ }
695
+ else if (file.preview instanceof Blob && previewUrlsRef.current.has(file.uploadId) === false) {
696
+ previewUrlsRef.current.set(file.uploadId, URL.createObjectURL(file.preview));
697
+ }
698
+ const ownBytes = early?.blob ?? (file.preview instanceof Blob ? file.preview : undefined);
699
+ if (ownBytes !== undefined && pictures !== undefined) {
700
+ void pictures.seed(file.uploadId, ownBytes);
701
+ seededRef.current.add(file.uploadId);
702
+ }
703
+ const rRun = await exception2Result(async () => {
704
+ setProgress(90);
705
+ const showCommitted = async (uploadId, clientWrite) => {
706
+ releaseLease();
707
+ if (currentGenRef.current !== genKey)
708
+ return;
709
+ committedGenRef.current = { genKey, uploadId };
710
+ let after = await loadMediaDocs();
711
+ const landedLocally = sortVersionDocs(after).some((vd) => Object.values(vd._files).some((f) => f.uploadId === uploadId && f.url !== undefined));
712
+ const waitForSync = (rows) => {
713
+ setDocument(composeDocument({
714
+ hostDocId,
715
+ versionDocs: sortVersionDocs(rows),
716
+ pointer: findPointerDoc(rows, myHandle),
717
+ legacyDoc,
718
+ }));
719
+ setPending(true);
720
+ setLoading(false);
721
+ currentGenRef.current = null;
722
+ };
723
+ if (landedLocally) {
724
+ setDocument(composeDocument({
725
+ hostDocId,
726
+ versionDocs: sortVersionDocs(after),
727
+ pointer: findPointerDoc(after, myHandle),
728
+ legacyDoc,
729
+ }));
730
+ setProgress(100);
731
+ setLoading(false);
732
+ return;
733
+ }
734
+ if (confirmedMediaProbe === undefined || confirmedMediaProbe === null) {
735
+ waitForSync(after);
736
+ return;
737
+ }
738
+ const heldLocally = sortVersionDocs(after).some((vd) => Object.values(vd._files).some((f) => f.uploadId === uploadId));
739
+ if (heldLocally) {
740
+ setDocument(composeDocument({
741
+ hostDocId,
742
+ versionDocs: sortVersionDocs(after),
743
+ pointer: findPointerDoc(after, myHandle),
744
+ legacyDoc,
745
+ }));
746
+ setPending(true);
747
+ setLoading(false);
748
+ currentGenRef.current = null;
749
+ }
750
+ else {
751
+ setPending(true);
752
+ currentGenRef.current = null;
753
+ }
754
+ const probeKey = `${genKey}\u0000${promptText}`;
755
+ const stillOurs = () => unmountSignalRef.current.aborted === false &&
756
+ commitProbeInFlightRef.current === probeKey &&
757
+ (currentGenRef.current === null || currentGenRef.current === genKey);
758
+ commitProbeInFlightRef.current = probeKey;
759
+ let ourSeq = clientWrite?.seq;
760
+ let rekeeps = 0;
761
+ let collided = false;
762
+ const readBack = () => readBackFromServer({
763
+ probe: confirmedMediaProbe,
764
+ dbName,
765
+ hostDocId,
766
+ signal: unmountSignalRef.current,
767
+ stillOurs,
768
+ logEvent: "imggen-commit-probe-failed",
769
+ examine: async (probedDocs, probedLegacy) => {
770
+ const probedVersions = sortVersionDocs(probedDocs);
771
+ if (holdsUpload(probedVersions, uploadId, true)) {
772
+ commitProbeInFlightRef.current = null;
773
+ currentGenRef.current = genKey;
774
+ setDocument(composeDocument({
775
+ hostDocId,
776
+ versionDocs: probedVersions,
777
+ pointer: laterPointer(findPointerDoc(after, myHandle), findPointerDoc(probedDocs, myHandle)),
778
+ legacyDoc: probedLegacy ?? legacyDoc,
779
+ }));
780
+ setPending(false);
781
+ setProgress(100);
782
+ setLoading(false);
783
+ return { done: true, value: "shown" };
784
+ }
785
+ const taken = clientWrite !== undefined &&
786
+ ourSeq !== undefined &&
787
+ probedVersions.some((vd) => vd.seq === ourSeq && holdsUpload([vd], uploadId, false) === false);
788
+ if (taken === false || clientWrite === undefined)
789
+ return { done: false };
790
+ collided = true;
791
+ if (rekeeps >= IMG_GEN_MAX_REKEEPS)
792
+ return { done: true, value: "unkept" };
793
+ rekeeps++;
794
+ vibe.log("warn", "imggen-version-seq-taken", { docId: hostDocId, dbName, seq: ourSeq ?? 0 });
795
+ const rekept = await clientWrite.rekeep(probedVersions);
796
+ if (rekept === undefined)
797
+ return { done: true, value: "unkept" };
798
+ ourSeq = rekept;
799
+ after = await loadMediaDocs();
726
800
  return { done: false };
801
+ },
802
+ });
803
+ let outcome = await readBack();
804
+ while (outcome.kind === "exhausted" &&
805
+ clientWrite !== undefined &&
806
+ ourSeq !== undefined &&
807
+ rekeeps < IMG_GEN_MAX_REKEEPS) {
808
+ const localVersions = sortVersionDocs(await loadMediaDocs());
809
+ if (stillOurs() === false)
810
+ return;
811
+ const lostLocally = localVersions.some((vd) => vd.seq === ourSeq && holdsUpload([vd], uploadId, false) === false);
812
+ if (lostLocally === false)
813
+ break;
727
814
  collided = true;
728
- if (rekeeps >= IMG_GEN_MAX_REKEEPS)
729
- return { done: true, value: "unkept" };
730
815
  rekeeps++;
731
- vibe.log("warn", "imggen-version-seq-taken", { docId: hostDocId, dbName, seq: ourSeq ?? 0 });
732
- const rekept = await clientWrite.rekeep(probedVersions);
733
- if (rekept === undefined)
734
- return { done: true, value: "unkept" };
816
+ vibe.log("warn", "imggen-version-seq-taken", { docId: hostDocId, dbName, seq: ourSeq });
817
+ const rekept = await clientWrite.rekeep(localVersions);
818
+ if (rekept === undefined) {
819
+ outcome = { kind: "done", value: "unkept" };
820
+ break;
821
+ }
735
822
  ourSeq = rekept;
736
823
  after = await loadMediaDocs();
737
- return { done: false };
738
- },
739
- });
740
- let outcome = await readBack();
741
- while (outcome.kind === "exhausted" &&
742
- clientWrite !== undefined &&
743
- ourSeq !== undefined &&
744
- rekeeps < IMG_GEN_MAX_REKEEPS) {
745
- const localVersions = sortVersionDocs(await loadMediaDocs());
824
+ outcome = await readBack();
825
+ }
826
+ if (outcome.kind === "lost" || (outcome.kind === "done" && outcome.value === "shown"))
827
+ return;
828
+ const latest = await loadMediaDocs();
746
829
  if (stillOurs() === false)
747
830
  return;
748
- const lostLocally = localVersions.some((vd) => vd.seq === ourSeq && holdsUpload([vd], uploadId, false) === false);
749
- if (lostLocally === false)
831
+ commitProbeInFlightRef.current = null;
832
+ const shownFiles = (documentRef.current?._files ?? {});
833
+ if (Object.values(shownFiles).some((f) => f.uploadId === uploadId && f.url !== undefined))
834
+ return;
835
+ const lostAtOurSeq = ourSeq !== undefined &&
836
+ sortVersionDocs(latest).some((vd) => vd.seq === ourSeq && holdsUpload([vd], uploadId, false) === false);
837
+ if ((outcome.kind === "done" && outcome.value === "unkept") || lostAtOurSeq) {
838
+ vibe.log("warn", "imggen-version-unkept", { docId: hostDocId, dbName, uploadId, rekeeps, collided });
839
+ setDocument(composeDocument({
840
+ hostDocId,
841
+ versionDocs: sortVersionDocs(latest),
842
+ pointer: findPointerDoc(latest, myHandle),
843
+ legacyDoc,
844
+ }));
845
+ setError(new Error(IMG_GEN_UNKEPT_MESSAGE));
846
+ setPending(false);
847
+ setLoading(false);
848
+ currentGenRef.current = null;
849
+ return;
850
+ }
851
+ waitForSync(latest);
852
+ };
853
+ if (docWritten === true) {
854
+ await showCommitted(file.uploadId);
855
+ return;
856
+ }
857
+ const fileMeta = {
858
+ uploadId: file.uploadId,
859
+ type: file.mimeType,
860
+ size: file.size,
861
+ lastModified: Date.now(),
862
+ ...(temporaryDraft && file.url !== undefined ? { url: file.url } : {}),
863
+ };
864
+ const putVersionAt = (seq) => {
865
+ const versionBody = buildMediaVersionDoc({
866
+ hostDocId,
867
+ promptKey: PROMPT_KEY,
868
+ seq,
869
+ authorHandle: generationHandle,
870
+ files: { [`m${seq}`]: fileMeta },
871
+ prompt: promptText,
872
+ model,
873
+ sourceKey: incomingSourceKey,
874
+ });
875
+ return exception2Result(() => mediaDb.put({ ...versionBody, _id: mediaVersionDocId(hostDocId, PROMPT_KEY, seq) }));
876
+ };
877
+ const movePointerTo = async (seq) => {
878
+ const freshPointerRead = await loadMediaDocs();
879
+ const freshCurrentSeq = findPointerDoc(freshPointerRead, myHandle)?.currentSeq ?? 0;
880
+ if (seq <= freshCurrentSeq)
881
+ return;
882
+ const pointerBody = buildMediaPointerDoc({
883
+ hostDocId,
884
+ promptKey: PROMPT_KEY,
885
+ authorHandle: generationHandle,
886
+ currentSeq: seq,
887
+ });
888
+ await mediaDb.put({ ...pointerBody, _id: mediaPointerDocId(hostDocId, generationHandle) });
889
+ };
890
+ const nextFreeSeq = (...lanes) => {
891
+ const seqs = lanes.flat().map((vd) => vd.seq);
892
+ return seqs.length > 0 ? Math.max(...seqs) + 1 : 1;
893
+ };
894
+ let latestRead = await loadMediaDocs();
895
+ let freshVersions = sortVersionDocs(latestRead);
896
+ let serverVersions = [];
897
+ if (confirmedMediaProbe !== undefined && confirmedMediaProbe !== null) {
898
+ const rServer = await probeWithDeadline(confirmedMediaProbe, dbName, hostDocId);
899
+ if (rServer.isOk())
900
+ serverVersions = sortVersionDocs(rServer.Ok().mediaDocs);
901
+ else
902
+ vibe.log("warn", "imggen-seq-probe-failed", {
903
+ docId: hostDocId,
904
+ dbName,
905
+ deadlineMs: imgGenProbeDeadlineMs,
906
+ message: rServer.Err().message,
907
+ });
908
+ }
909
+ if (holdsUpload([...freshVersions, ...serverVersions], fileMeta.uploadId, false)) {
910
+ await showCommitted(fileMeta.uploadId);
911
+ return;
912
+ }
913
+ let committedSeq;
914
+ let adopted = false;
915
+ let terminalError;
916
+ for (let attempt = 0; attempt < 3; attempt++) {
917
+ const nextSeq = nextFreeSeq(freshVersions, serverVersions);
918
+ const rPut = await putVersionAt(nextSeq);
919
+ if (rPut.isOk()) {
920
+ committedSeq = nextSeq;
921
+ break;
922
+ }
923
+ if (isConflictClassPutError(rPut.Err()) === false) {
924
+ terminalError = rPut.Err();
750
925
  break;
751
- collided = true;
752
- rekeeps++;
753
- vibe.log("warn", "imggen-version-seq-taken", { docId: hostDocId, dbName, seq: ourSeq });
754
- const rekept = await clientWrite.rekeep(localVersions);
755
- if (rekept === undefined) {
756
- outcome = { kind: "done", value: "unkept" };
926
+ }
927
+ latestRead = await loadMediaDocs();
928
+ freshVersions = sortVersionDocs(latestRead);
929
+ if (holdsUpload(freshVersions, fileMeta.uploadId, false)) {
930
+ adopted = true;
757
931
  break;
758
932
  }
759
- ourSeq = rekept;
760
- after = await loadMediaDocs();
761
- outcome = await readBack();
762
933
  }
763
- if (outcome.kind === "lost" || (outcome.kind === "done" && outcome.value === "shown"))
764
- return;
765
- const latest = await loadMediaDocs();
766
- if (stillOurs() === false)
767
- return;
768
- commitProbeInFlightRef.current = null;
769
- const shownFiles = (documentRef.current?._files ?? {});
770
- if (Object.values(shownFiles).some((f) => f.uploadId === uploadId && f.url !== undefined))
771
- return;
772
- const lostAtOurSeq = ourSeq !== undefined &&
773
- sortVersionDocs(latest).some((vd) => vd.seq === ourSeq && holdsUpload([vd], uploadId, false) === false);
774
- if ((outcome.kind === "done" && outcome.value === "unkept") || lostAtOurSeq) {
775
- vibe.log("warn", "imggen-version-unkept", { docId: hostDocId, dbName, uploadId, rekeeps, collided });
776
- setDocument(composeDocument({
777
- hostDocId,
778
- versionDocs: sortVersionDocs(latest),
779
- pointer: findPointerDoc(latest, myHandle),
780
- legacyDoc,
781
- }));
782
- setError(new Error(IMG_GEN_UNKEPT_MESSAGE));
783
- setPending(false);
934
+ if (committedSeq === undefined && adopted === false) {
935
+ setError(terminalError ?? new Error("Image generated but could not be saved after repeated write conflicts — please try again"));
784
936
  setLoading(false);
785
937
  currentGenRef.current = null;
786
938
  return;
787
939
  }
788
- waitForSync(latest);
789
- };
790
- if (docWritten === true) {
791
- await showCommitted(file.uploadId);
792
- return;
793
- }
794
- const fileMeta = {
795
- uploadId: file.uploadId,
796
- type: file.mimeType,
797
- size: file.size,
798
- lastModified: Date.now(),
799
- ...(temporaryDraft && file.url !== undefined ? { url: file.url } : {}),
800
- };
801
- const putVersionAt = (seq) => {
802
- const versionBody = buildMediaVersionDoc({
803
- hostDocId,
804
- promptKey: PROMPT_KEY,
805
- seq,
806
- authorHandle: myHandle,
807
- files: { [`m${seq}`]: fileMeta },
808
- prompt: promptText,
809
- model,
810
- sourceKey: incomingSourceKey,
811
- });
812
- return exception2Result(() => mediaDb.put({ ...versionBody, _id: mediaVersionDocId(hostDocId, PROMPT_KEY, seq) }));
813
- };
814
- const movePointerTo = async (seq) => {
815
- const freshPointerRead = await loadMediaDocs();
816
- const freshCurrentSeq = findPointerDoc(freshPointerRead, myHandle)?.currentSeq ?? 0;
817
- if (seq <= freshCurrentSeq)
940
+ if (committedSeq === undefined) {
941
+ await showCommitted(fileMeta.uploadId);
818
942
  return;
819
- const pointerBody = buildMediaPointerDoc({ hostDocId, promptKey: PROMPT_KEY, authorHandle: myHandle, currentSeq: seq });
820
- await mediaDb.put({ ...pointerBody, _id: mediaPointerDocId(hostDocId, myHandle) });
821
- };
822
- const nextFreeSeq = (...lanes) => {
823
- const seqs = lanes.flat().map((vd) => vd.seq);
824
- return seqs.length > 0 ? Math.max(...seqs) + 1 : 1;
825
- };
826
- let latestRead = await loadMediaDocs();
827
- let freshVersions = sortVersionDocs(latestRead);
828
- let serverVersions = [];
829
- if (confirmedMediaProbe !== undefined && confirmedMediaProbe !== null) {
830
- const rServer = await probeWithDeadline(confirmedMediaProbe, dbName, hostDocId);
831
- if (rServer.isOk())
832
- serverVersions = sortVersionDocs(rServer.Ok().mediaDocs);
833
- else
834
- vibe.log("warn", "imggen-seq-probe-failed", {
835
- docId: hostDocId,
836
- dbName,
837
- deadlineMs: imgGenProbeDeadlineMs,
838
- message: rServer.Err().message,
839
- });
840
- }
841
- if (holdsUpload([...freshVersions, ...serverVersions], fileMeta.uploadId, false)) {
842
- await showCommitted(fileMeta.uploadId);
843
- return;
844
- }
845
- let committedSeq;
846
- let adopted = false;
847
- let terminalError;
848
- for (let attempt = 0; attempt < 3; attempt++) {
849
- const nextSeq = nextFreeSeq(freshVersions, serverVersions);
850
- const rPut = await putVersionAt(nextSeq);
851
- if (rPut.isOk()) {
852
- committedSeq = nextSeq;
853
- break;
854
- }
855
- if (isConflictClassPutError(rPut.Err()) === false) {
856
- terminalError = rPut.Err();
857
- break;
858
943
  }
859
- latestRead = await loadMediaDocs();
860
- freshVersions = sortVersionDocs(latestRead);
861
- if (holdsUpload(freshVersions, fileMeta.uploadId, false)) {
862
- adopted = true;
863
- break;
864
- }
865
- }
866
- if (committedSeq === undefined && adopted === false) {
867
- setError(terminalError ?? new Error("Image generated but could not be saved after repeated write conflicts — please try again"));
944
+ await movePointerTo(committedSeq);
945
+ await showCommitted(fileMeta.uploadId, {
946
+ seq: committedSeq,
947
+ rekeep: async (probedVersions) => {
948
+ const seq = nextFreeSeq(sortVersionDocs(await loadMediaDocs()), probedVersions);
949
+ const rPut = await putVersionAt(seq);
950
+ if (rPut.isErr()) {
951
+ vibe.log("warn", "imggen-rekeep-failed", { docId: hostDocId, dbName, seq, message: rPut.Err().message });
952
+ return undefined;
953
+ }
954
+ await movePointerTo(seq);
955
+ return seq;
956
+ },
957
+ });
958
+ });
959
+ if (rRun.isErr()) {
960
+ setError(rRun.Err());
868
961
  setLoading(false);
869
962
  currentGenRef.current = null;
870
- return;
871
- }
872
- if (committedSeq === undefined) {
873
- await showCommitted(fileMeta.uploadId);
874
- return;
875
963
  }
876
- await movePointerTo(committedSeq);
877
- await showCommitted(fileMeta.uploadId, {
878
- seq: committedSeq,
879
- rekeep: async (probedVersions) => {
880
- const seq = nextFreeSeq(sortVersionDocs(await loadMediaDocs()), probedVersions);
881
- const rPut = await putVersionAt(seq);
882
- if (rPut.isErr()) {
883
- vibe.log("warn", "imggen-rekeep-failed", { docId: hostDocId, dbName, seq, message: rPut.Err().message });
884
- return undefined;
885
- }
886
- await movePointerTo(seq);
887
- return seq;
888
- },
889
- });
890
- });
891
- if (rRun.isErr()) {
892
- setError(rRun.Err());
893
- setLoading(false);
894
- currentGenRef.current = null;
895
964
  }
965
+ await generate().finally(releaseLease);
896
966
  }
897
967
  run();
898
968
  }, [