Cloud: live cross-device and cross-tab sync
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 42/100
- Loại issue
- Tính năng
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- firebase, typescript
Hướng nghiên cứu
Start with dependency #793, then read src/hooks/useWorkspaceManager.ts:445-475 and the existing filesystem and version-counter paths. Check src/hooks/useTabEditorManager.ts, especially synchronous reads and mounted-tab handling, before mapping the Firestore manifest entry point. Done means the acceptance criteria pass, including in-place refresh, conflict copies, cleanup, deletes, and scoped mutation coverage of at least 80%.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
Propagate cloud drive changes between devices and browser tabs without a reload, using a Firestore
onSnapshot listener on the single manifest document.
This is essentially free given the chosen data model — and it is the main reason text lives in
Firestore rather than Cloud Storage, which has no change-notification mechanism at all.
Why one listener, not N
The listener subscribes to users/{uid}/drive/manifest only — one small document. A content
change bumps that file's hash and rev in the manifest, the listener fires with a tiny payload,
and the client fetches only the content documents that actually changed. Subscribing to the whole
content collection would re-deliver full file bodies on every keystroke-debounced save.
The in-place mutation constraint
src/hooks/useWorkspaceManager.ts:445-475 refreshes a workspace by mutating the filesystem object
in place and deliberately not calling setState. The comment at lines 470-473 explains why:
recreating the object would recreate compositeFileSystem, which resets the shell's current
working directory (issue #280). Sync-driven refresh must follow the same rule — mutate the
cache in place and signal the UI through the existing version counter on AdaptedFileSystem,
not by replacing the filesystem.
Conflict handling
Last-write-wins by rev, but never silently discard the loser. If a remote change would
overwrite unsaved or newer local content, write a conflict copy (e.g. main.lua alongside
main (conflict 2026-08-24).lua) and tell the user. Silent overwrite across devices is the
failure mode most likely to lose a student's work.
Acceptance criteria
- A change made on device A appears on device B without a reload
- A change in one browser tab appears in another tab
- The listener subscribes to the manifest document only, not the content collection
- Only changed content documents are re-fetched
- The filesystem is mutated in place; the shell's cwd is preserved across a sync event
- An open editor tab reflects remote changes without losing cursor position unnecessarily
- A conflicting concurrent edit produces a conflict copy, not a silent overwrite
- The listener is torn down on sign-out and on workspace unmount (no leaks, no orphaned reads)
- Deletes propagate as well as writes
- Scoped mutation coverage >= 80%
Implementation notes
- Firestore's
persistentLocalCachedelivers a cache-first snapshot then a server snapshot; make
sure the initial cached snapshot does not read as a spurious remote change. - Echo suppression: the client's own writes come back through the listener. Compare against the
pending write set /revso local saves do not round-trip as remote edits. src/hooks/useTabEditorManager.tsloads tab content synchronously via
filesystemRef.current.readFile(path)and mounts at most 5 editors (MRU virtualisation) —
check how a remote update to a mounted vs unmounted tab behaves.- Watch read costs: each snapshot delivering changed documents costs reads. One manifest document
plus only-changed content is the cheap shape; verify against the emulator's usage output.
Depends on
- #793
Related
- #280 - workspace refresh must not reset the shell cwd
Branching
This issue is part of the Cloud Accounts & Storage
milestone, which uses feat/cloud as its integration branch.
Branch from feat/cloud, and open the PR against feat/cloud. Never against main.
Create the branch (the --base flag also sets the default PR target for this branch):
gh issue develop <number> --base feat/cloud --checkout
Open the PR:
python3 scripts/issue-review.py <number> --base feat/cloud \
--summary "<summary>" --test-plan "<test-plan>"
feat/cloud merges to main in a single PR once the milestone is complete.
Why both flags are required: gh issue develop without --base branches from the repository
default branch (main), and scripts/issue-review.py falls back to main when --base is
omitted — both for the gh pr create target and for the changed-file list in the PR body.
- Ngôn ngữ chính
- TypeScript
- Star
- 1
- Fork
- 0
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của jcollard/LuaInTheWeb
-
tech-debt
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
jcollard/LuaInTheWeb#752 ·
-
tech-debt
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 68/100
jcollard/LuaInTheWeb#690 ·
-
tech-debt
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 75/100
jcollard/LuaInTheWeb#590 ·
-
tech-debt
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
jcollard/LuaInTheWeb#518 ·
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
jcollard/LuaInTheWeb#235 ·
Tất cả issue của jcollard/LuaInTheWeb
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
mobile-next/mobile-mcp#526 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
e2e-failure ready-to-code
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 73/100
redhat-developer/rhdh-plugin-export-overlays#4470 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
anthropics/anthropic-sdk-typescript#1273 ·
Maintainer thường phản hồi trong vòng 10 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
CopilotKit/OpenBot#815 ·
Maintainer thường phản hồi trong vòng 1 ngày