Repository navigation
Tasks: collaborate on lists through KV shares - #80
Merged
Merged
Conversation
Collaborative lists were built on public read-URL files: every member published a replica, the owner kept a manifest, and joining took a two-link handshake. Anyone holding a replica or manifest URL could read the list for up to a year, and removing a member did not cut their access. New collaborations now keep the list under its own prefix in the owner's KV store (meta, one key per task and per deletion) and share it at write level with each invited username via puter.kv.share, after asking for kvShare consent (the permission-string form on older SDKs). Members discover shares with listShared() and on the kv.share.received notification, read and write through the handle, and merge with the existing id/updatedAt/tombstone rules. Changes arrive through kv event subscriptions, with polling for lists without one. Removing a member, stopping, and leaving are unshare calls, retried until they land; a member whose handle stops working keeps a private copy. Lists already on linked replicas keep working. SDKs without kv.share, pages that can't ask for consent, and deployments with shares turned off fall back to linked replicas. The test mock gains KV shares, handle-scoped kv ops, events and consent.
The share sheet asked owners to pass an invite link and approve a confirmation link. For lists shared over KV shares it now has a username field, lists who has access from listSharedByMe, and says that removing someone cuts access right away; there is no link step for members, whose app adopts the list and toasts who shared it. If the deployment refuses KV shares, the sheet switches to the invite link. The app starts the share watch after boot, looks for new shares on focus, and polls collab lists every minute while visible. The dev mock gains ?kvshare to try the owner flow, and the README describes the new storage layout and the fallback.
The poll skips KV lists whose live subscription delivers their changes, but revoking a share only stops its deliveries: the subscription stays open, so a removed member's list never turned into a private copy until the next focus. A watched list is now still synced by the poll once it has gone five minutes without a sync.
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.
Collaborative lists in Tasks were built on the assumption that Puter storage is strictly per-account and that there is no inbox:
Puter's KV shares (HeyPuter/puter#4331) make that unnecessary, and they fix three problems with it:
How it works now
tasks:collab:<id>:. That prefix holdsmeta(name, icon, colour, owner username), onet:<taskId>key per task, and oned:<taskId>tombstone per deletion. Each collaboration gets a fresh id, so restarting one never picks up keys or shares an earlier one left behind.perms.request('kvShare', { prefix: 'tasks:collab:', access: 'write' }), or the permission string on older SDKs. The list is then shared atwrite, with its cleaned name as the label.listShared()at startup, on thekv.share.receivednotice, and on focus or poll. No link is involved.updatedAt, tombstones). Shared data can't touch other lists.kv:<appID>:<prefix>*and members watchkv:<handle>:*. Polling stays as a fallback.unshare. A member whose handle stops working gets a private copy, the same as today's ended collaborations.Compatibility
kv.share.metais writable by any member, so a former member could use it to take over someone's list.Worth a look from reviewers
writeshares are adopted;readandwatchshares are ignored.meta.Testing
tests/kvshare.test.js(24 tests) covers:metaand tampered keyscreateMockPuter({ kvShares: true }). Holders are usernames, and errors are{ message, code }withoutstatus, as the real API returns them.npm run buildsucceeds. The owner flow was tried in Chrome with the dev mock (?kvshare); the member flow is covered by tests only.