[Website] Serialize Blueprint snapshots and OPFS site lifecycle mutations - #4004
Closed
adamziel wants to merge 4 commits into
Closed
[Website] Serialize Blueprint snapshots and OPFS site lifecycle mutations#4004adamziel wants to merge 4 commits into
adamziel wants to merge 4 commits into
Conversation
adamziel
force-pushed
the
opfs-final-flush-contract
branch
from
July 10, 2026 20:35
d8ba5e8 to
0ba7a39
Compare
Collaborator
Author
|
Closing this draft instead of rebasing it onto the simplified stack. It depends on The branch is preserved. Useful lifecycle invariants can be extracted later as small standalone PRs with focused tests; this is no longer a valid next PR in the stack. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #4003.
What it does
Serializes Blueprint editor buffers, versioned bundle snapshots, saved-site metadata, and destructive OPFS lifecycle operations so one setup cannot persist into another setup's storage.
Before a bundle snapshot starts, the active editor flushes its in-memory buffer and drains older filesystem operations. The snapshot then occupies the same queue, so later edits wait until traversal finishes. Rapid file switches, panel unmounts, renames, exports, recreation, and persistence all use that boundary.
New Blueprint bundles are copied into inactive
blueprint-bundle-<uuid>directories. Site metadata continues selecting the previous complete version until the copy finishes and the site transaction commits the new directory. Failed and stale copies are deleted only after authoritative metadata proves they are not selected.Saved-site mutations now use per-site queues and browser locks. They re-read OPFS metadata while locked and verify the site ID and setup revision before writing. Slug allocation and autosave retention decisions are serialized separately because they operate on the whole collection.
A mounted OPFS runtime holds a shared browser lock. Reset, delete, and prune request the exclusive form before touching durable files. This tab can suspend and later restore its mount if another tab prevents exclusive access. Once destructive work starts, the old runtime is discarded rather than allowed to write stale MEMFS state back into the directory.
The save path now covers the active client check, storage selection, optional bundle copy, mount transition, metadata commit, and client-state commit in one site transaction. Failure cleanup retains a mount whose final flush failed, restores the previous mount when safe, removes inactive bundle versions, and forces a clean reboot when the old runtime can no longer be trusted.
Boot reconciles durable metadata after waiting for runtime access, finishes crash-interrupted resets, rejects incomplete initial saves, and ignores callbacks from replaced iframe boots.
This does not move any UI into the dock.
Rationale
A debounced Blueprint edit can exist only in CodeMirror when persistence starts walking the backend. Copying at that point saves an older Blueprint.
A reset or delete can also race an active OPFS journal in this tab or another tab. Deleting the directory is not enough if the old runtime is still able to recreate files afterward.
Redux is not authoritative across tabs. A stale tab can otherwise overwrite metadata for a reused slug or select a bundle copied for a setup that has already been replaced.
The code now has one order:
Compatibility
Existing sites whose
opfs-sitesource has nodirectorycontinue to load the legacyblueprint-bundledirectory. New writes use versioned directories.No existing public function is removed. Destructive operations can now reject when another tab keeps the same site mounted or when durable ownership changed. That rejection is intentional; proceeding would corrupt or delete another runtime's files.
Testing instructions