docs: easy fs sharing recipe (PUT-1958) (#3973)
Maintain Release Merge PR / update-release-pr (push) Canceled after 0s
Notify HeyPuter / notify (push) Canceled after 0s
release-please / release-please (push) Canceled after 0s

* docs: add the easy fs sharing recipe

share(), listShared(), getShares() and unshare() — the fs ground the
existing recipes do not already cover.

* docs: add a playground example per operation in the fs sharing recipe

One runnable example for each section of the recipe: share, mode,
listShared, getShares and unshare.

* docs: open the sharing recipe with what it lets an app build

* docs: ground the sharing examples in a document-editor flow

Each example now sits in the UI that would call it — a Share button, a
role picker, a shared-with-me inbox, an access list, ending a review.

* remove redundant examples and refine recipe

---------

Co-authored-by: Reynaldi Chernando <reynaldichernando@gmail.com>
This commit is contained in:
Juan Fernando CastroandReynaldi Chernando authored and GitHub committed 2026-09-29 23:47:23 +07:00
1 parent 8e31d9149a
commit 3b00cd2d14
3 files changed
+154

No files matched your search

+6
View File
@@ -450,6 +450,12 @@ const examples = [
slug: 'fs-getShareLink',
source: '/playground/examples/fs-getShareLink.html',
},
{
title: 'Choose how much access to give',
description: 'Grant read, write or manage access when sharing a file with Puter.js filesystem API. Run and modify this example instantly in your browser.',
slug: 'fs-share-a-file-mode',
source: '/playground/examples/fs-share-a-file-mode.html',
},
],
},
{
@@ -0,0 +1,32 @@
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<h3>Brand assets</h3>
<input id="who" placeholder="username or email">
<select id="mode">
<option value="read">Reviewer (read)</option>
<option value="write">Collaborator (write)</option>
<option value="manage">Lead (manage — can re-share)</option>
</select>
<button id="go">Set access</button>
<script>
// A design tool handing the same folder to different roles.
document.getElementById('go').addEventListener('click', async () => {
const recipient = document.getElementById('who').value.trim();
if (!recipient) return;
const mode = document.getElementById('mode').value;
await puter.fs.mkdir('assets', { createMissingParents: true }).catch(() => {});
try {
// Sharing again replaces their access, so changing a role is one call.
const [share] = await puter.fs.share('assets', recipient, mode);
puter.print(`${recipient} is now ${share.mode}<br>`);
puter.print(share.isNew ? 'newly added' : 'role changed');
} catch (e) {
puter.print(`Could not share: ${e.code ?? e.message}`);
}
});
</script>
</body>
</html>
+116
View File
@@ -0,0 +1,116 @@
---
title: Share a File
description: "Learn how to add file sharing to your app with Puter.js, so users can share files in their Puter account with other people."
tags: [fs, auth]
order: 45
---
Every file in Puter lives inside one user's Puter account, and only that user
can open it. When another Puter user needs the same file, share it with them
using the [filesystem API](/FS/). They can then open it from their own account,
without anyone copying the file or sending a link.
This lets you build sharing right inside your app, so people can work together
on a file.
## Share with someone
Pass the path and who to share it with:
```js
await puter.fs.share('report.txt', 'alice');
```
A string with an `@` in it is read as an email address, anything else as a
username. You can also be explicit, which is worth doing when the value comes
from user input:
```js
await puter.fs.share('report.txt', { username: 'alice' });
await puter.fs.share('report.txt', { email: 'alice@example.com' });
```
Sharing with an email address that has no Puter account yet sends an
invitation instead, which grants access once that address is confirmed.
## Choose how much access
The third argument is the mode, and it defaults to `'read'`:
```js
await puter.fs.share('budget.xlsx', 'alice', 'write');
```
- `'read'`: open it.
- `'write'`: open and change it. Does **not** allow sharing it onward.
- `'manage'`: everything `'write'` allows, plus re-sharing it.
- `'list'`, `'see'`: weaker than `read`, for making something discoverable
without exposing what is in it.
Sharing the same item with the same person again **replaces** their access
instead of adding a second share, so changing someone from read to write is one
more call:
```js
const [share] = await puter.fs.share('budget.xlsx', 'alice', 'write');
share.mode; // 'write'
share.isNew; // false, she already had access, at a different mode
```
The `isNew` field is `true` when the person did not have access before, and
`false` when they already had access. Use it to decide whether to show a
confirmation.
## See what has been shared with you
```js
const { items } = await puter.fs.listShared();
for (const item of items) {
console.log(item.name, item.mode, item.owner);
}
```
This resolves to an object with an `items` array, not to an
array. Your own files are never in it.
Shared items appear at a **masked path** of the form `/<owner>/<uid>/<name>`.
It works with any `puter.fs` method, so you can read one directly from the
listing:
```js
const [first] = items;
const blob = await puter.fs.read(first.path);
console.log(await blob.text());
```
The masked path hides *where* the item is stored in the owner's account, and
what other files are next to it. Label the item with `name`, since the masked
path has no meaningful folder to show.
## See who you shared something with
```js
const shares = await puter.fs.getShares('report.txt');
for (const share of shares) {
console.log(share.holder, share.mode);
}
```
This lists shares made by **anyone** holding `manage` on the item, not only
yours, so an owner can see who else it was shared with by the people they gave
`manage` to.
## Take access back
```js
const { revoked } = await puter.fs.unshare('report.txt', 'alice');
```
`revoked` counts the grants actually removed. `0` means there was nothing to
remove, which is not an error, so unsharing twice is safe.
To remove your own access to a file someone else shared with you, pass
**yourself** as the recipient.