mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-26 23:26:04 +00:00
feat: global outbound share listing (PUT-1664) (#3694)
* feat: global outbound share listing (PUT-1664) * fix: address review on outbound share listing - Check share-row liveness per (holder, entry, issuer) so a grant withdrawn outside unshare doesn't stay listed while another issuer still reaches the same holder; batch the permission reads across the whole page instead of per holder. - Retire a revoked issuer's unclaimed invites in the revoke cascade, and hide invites whose issuer lost their authority at read time. - Unify the pending/active app-attribution key on `issuedByApp` and dual-read the legacy `issuerAppUid` spelling. - Add the missing share issuer index (sqlite, postgres) and correct the listOutbound plan comment. - Refuse cursors that decode but name no id instead of silently restarting from page one. - Consolidate the five hand-built ResolvedShare literals and the two listing endpoints' parse/shape code. - Ship the SDK surface: puter.fs.listSharedByMe() with docs, types, suite coverage, and the rate-limit page entry.
This commit is contained in:
@@ -310,6 +310,7 @@ These cloud storage features are supported out of the box when using Puter.js:
|
||||
- **[`puter.fs.share()`](/FS/share/)** - Give another user access to a file or directory
|
||||
- **[`puter.fs.unshare()`](/FS/unshare/)** - Withdraw a user's access
|
||||
- **[`puter.fs.listShared()`](/FS/listShared/)** - List what others have shared with you
|
||||
- **[`puter.fs.listSharedByMe()`](/FS/listSharedByMe/)** - List everything you have shared out
|
||||
- **[`puter.fs.getShares()`](/FS/getShares/)** - List who has access to an item
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: puter.fs.listSharedByMe()
|
||||
description: List everything you have shared with other users, across all items.
|
||||
platforms: [websites, apps, nodejs, workers]
|
||||
---
|
||||
|
||||
This method lists everything you have shared out, a page at a time, without naming an item first. [`getShares()`](/FS/getShares/) answers the same question for one item you can already point at; this is what answers it when you can't. The listing includes invites to addresses that have no account yet (marked `pending`), and — for items you own — shares that a delegate with `manage` access issued on your behalf.
|
||||
|
||||
> **What an app sees.** An app never gets more reach than it was given: this
|
||||
> listing shows an app only the shares on items it can reach in its own right.
|
||||
> Shares an app creates are attributed to the user and carry `issuedByApp`, so
|
||||
> the owner can tell them apart.
|
||||
|
||||
## Syntax
|
||||
|
||||
```js
|
||||
puter.fs.listSharedByMe()
|
||||
puter.fs.listSharedByMe(options)
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
#### `options` (Object) (optional)
|
||||
|
||||
An object with the following properties:
|
||||
|
||||
- `limit` (Number) - Maximum shares per page.
|
||||
- `cursor` (String) - Continuation token from a previous page.
|
||||
- `includeTotal` (Boolean) - Include the total count in the response. Defaults to `false`.
|
||||
|
||||
## Return value
|
||||
|
||||
A `Promise` that resolves to an object with:
|
||||
|
||||
- `items` (Array) - The shares on this page. Each has `uid`, `mode`, `path`, `entryUid`, `isDir`, `name`, `type`, `thumbnail`, `owner`, `issuer`, `holder`, `issuedByApp`, `modified` and `size`. An unclaimed invite additionally carries `pending: true` and `recipientEmail`, with a `holder` of `null`.
|
||||
- `cursor` (String) - Pass to the next call to get the following page. **Present only while more pages remain.**
|
||||
- `total` (Number) - Present only when `includeTotal` was set. An approximation: it counts the shares recorded, before per-grant filtering, so it can be higher than the number of items paging actually yields.
|
||||
|
||||
Iterate until `cursor` is absent rather than comparing `items.length` to `limit`. A page can come back short — rows whose grant has since been withdrawn are filtered out after the page is read — while more pages still remain.
|
||||
|
||||
Items you own appear at their real path. An item you shared as a delegate (from someone else's folder you hold `manage` on) appears at the same masked path you reach it by.
|
||||
|
||||
## Examples
|
||||
|
||||
<strong class="example-title">See everything you have shared</strong>
|
||||
|
||||
```html;fs-listSharedByMe
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
const page = await puter.fs.listSharedByMe({ includeTotal: true });
|
||||
puter.print(`About ${page.total} share(s) you made<br>`);
|
||||
for (const share of page.items) {
|
||||
const who = share.pending
|
||||
? `${share.recipientEmail} (invited)`
|
||||
: share.holder;
|
||||
puter.print(`${share.path} — ${share.mode} to ${who}<br>`);
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
<strong class="example-title">Page through every share you made</strong>
|
||||
|
||||
```js
|
||||
let cursor;
|
||||
const all = [];
|
||||
do {
|
||||
const page = await puter.fs.listSharedByMe({ limit: 50, cursor });
|
||||
all.push(...page.items);
|
||||
cursor = page.cursor;
|
||||
} while (cursor);
|
||||
```
|
||||
|
||||
<strong class="example-title">Withdraw everything shared on one item</strong>
|
||||
|
||||
```js
|
||||
const page = await puter.fs.listSharedByMe();
|
||||
const target = page.items.find((share) => share.name === 'report.txt');
|
||||
if (target && !target.pending) {
|
||||
await puter.fs.unshare(target.path, target.holder);
|
||||
}
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [`puter.fs.share()`](/FS/share/) - Grant access
|
||||
- [`puter.fs.listShared()`](/FS/listShared/) - List what others shared with you
|
||||
- [`puter.fs.getShares()`](/FS/getShares/) - See who can reach one item you manage
|
||||
@@ -135,11 +135,13 @@ Sharing is bounded twice: on the calls, and on how many people one account can r
|
||||
| -------------------------------------------- | ------------ |
|
||||
| `share` / `revoke` calls per minute | 60 |
|
||||
| `share` / `revoke` calls per day | 500 |
|
||||
| Reads (`getShares`, `listShared`) per minute | 600 |
|
||||
| Reads (`getShares`, `listShared`, `listSharedByMe`) per minute | 600 |
|
||||
| New shares per day | 200 |
|
||||
| Recipients per request | 10 |
|
||||
| Items per request | 50 |
|
||||
|
||||
The read limit is one bucket shared by every share-listing call, so polling one of them spends budget the others need.
|
||||
|
||||
A "new share" is one that gives someone access they didn't already have. Changing the mode on an existing share, or re-sharing an item the recipient already has, costs nothing. Over the daily limit, `share` fails with `share_daily_limit_reached`.
|
||||
|
||||
Separately, the notification and email that tell a recipient about a share are budgeted — being told is not the same as being interrupted about it:
|
||||
|
||||
Reference in New Issue
Block a user