docs(perms): drop the app-root-dir raw string, wire the perms playground

`app-root-dir:` was listed among the raw permission strings, but it reads as
nothing during a permission check - the rewriter yields the sentinel outside a
grant, so `check()` reports it ungranted even once it is and `request()` prompts
every call. Both contradict what the same page promises. The `'appRootDir'`
resource is the supported path and asks the server instead; the list now says so
rather than implying the string behaves like its neighbours.

The playground listed no perms examples at all: six files existed but nothing
referenced them in examples.js, so a freshly-reshaped API shipped with nothing
runnable. Adds a Perms group after UI, matching the sidebar's order, and two
examples for the features that had none - one prompt covering several resources,
and check() deciding whether to prompt.
This commit is contained in:
Juan Castro
2026-08-21 10:20:05 -04:00
parent f0cd251626
commit 9bf49b7574
4 changed files with 98 additions and 1 deletions
+2 -1
View File
@@ -62,10 +62,11 @@ The array form resolves to an array of those values, in the order asked.
- File system: `fs:{path}:{read|write}`
- Apps: `apps-of-user:{uuid}:{read|write}`
- Subdomains: `subdomains-of-user:{uuid}:{read|write}`
- An app's root directory: `app-root-dir:{app_uid}:{read|write}`
Some permission strings are not supported and are denied silently.
An app's root directory has no raw form: `app-root-dir:` reads as nothing during a permission check, so asking for it this way would prompt on every call and [`check()`](/Perms/check/) would report it as not granted even once it is. Use the `'appRootDir'` resource, which asks the server directly.
A lone string that names no resource is treated as a permission string, so `puter.perms.request('fs:/user/Documents:read')` keeps working.
## Batching
+53
View File
@@ -715,6 +715,59 @@ const examples = [
},
],
},
{
title: 'Perms',
children: [
{
title: "Request the user's email",
description: "Request access to the user's email address with Puter.js permissions API. Run and experiment with this example directly in the playground.",
slug: 'perms-request-email',
source: '/playground/examples/perms-request-email.html',
},
{
title: 'Request folder access',
description: 'Request write access to a special folder with Puter.js permissions API. Run and modify this example instantly in your browser.',
slug: 'perms-request-folder',
source: '/playground/examples/perms-request-folder.html',
},
{
title: 'Request several at once',
description: 'Request everything your app needs under a single prompt with Puter.js permissions API. Run and experiment with this batch example in the playground.',
slug: 'perms-request-batch',
source: '/playground/examples/perms-request-batch.html',
},
{
title: 'Check without prompting',
description: 'Check whether access is already granted before asking for it with Puter.js permissions API. Run and modify this example in the playground.',
slug: 'perms-check',
source: '/playground/examples/perms-check.html',
},
{
title: "Request access to the user's apps",
description: "Request read access to the user's apps with Puter.js permissions API. Run and experiment with this example directly in the playground.",
slug: 'perms-request-apps',
source: '/playground/examples/perms-request-apps.html',
},
{
title: "Request access to the user's subdomains",
description: "Request write access to the user's subdomains with Puter.js permissions API. Run and modify this example instantly in your browser.",
slug: 'perms-request-subdomains',
source: '/playground/examples/perms-request-subdomains.html',
},
{
title: "Use another app's data",
description: "Request permission to use another app's key-value data with Puter.js permissions API. Run and experiment with this example in the playground.",
slug: 'perms-request-app-data',
source: '/playground/examples/perms-request-app-data.html',
},
{
title: 'Request a raw permission string',
description: 'Request a specific permission string with Puter.js permissions API. Run and modify this example directly in your browser.',
slug: 'perms-request-permission',
source: '/playground/examples/perms-request-permission.html',
},
],
},
{
title: 'Workers',
children: [
@@ -0,0 +1,23 @@
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<button id="save">Save to Documents</button>
<script>
document.getElementById('save').addEventListener('click', async () => {
const details = { name: 'Documents', access: 'write' };
// check() never prompts, so it can run before deciding whether to.
if (await puter.perms.check('folder', details)) {
puter.print('Already granted, no prompt needed');
} else if (!await puter.perms.request('folder', details)) {
puter.print('Documents write access denied');
return;
}
const user = await puter.auth.getUser();
await puter.fs.write(`/${user.username}/Documents/notes.txt`, 'Saved!');
puter.print('Saved to Documents');
});
</script>
</body>
</html>
@@ -0,0 +1,20 @@
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<button id="setup">Set Up</button>
<script>
document.getElementById('setup').addEventListener('click', async () => {
// One prompt for the set; the dialog lists only what is missing.
const [documents, apps, email] = await puter.perms.request([
{ resource: 'folder', name: 'Documents', access: 'write' },
{ resource: 'apps' },
{ resource: 'email' },
]);
puter.print(`Documents: ${documents ?? 'denied'}`);
puter.print(`Apps: ${apps ? 'granted' : 'denied'}`);
puter.print(`Email: ${email ?? 'denied'}`);
});
</script>
</body>
</html>