docs: easy perms recipe (PUT-1965) (#3972)

* docs: add the easy perms recipe

Covers the supported surface: request() and check(). Adds the perms
recipe tag the build validates against.

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

One runnable example for each section: request a folder, request the
email address, request apps or subdomains, and check before prompting.

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

* docs: ground the perms examples in the UI that would ask

A photo editor exporting to Pictures, a checkout emailing a receipt, a
launcher listing apps, and a settings toggle that reads its own state
without raising a prompt.

* refine

---------

Co-authored-by: Reynaldi Chernando <reynaldichernando@gmail.com>
This commit is contained in:
Juan Fernando CastroandReynaldi Chernando authored and GitHub committed 2026-09-30 00:00:34 +07:00
1 parent 7eb9ace733
commit ee4d55027d
4 files changed
+134

No files matched your search

+6
View File
@@ -945,6 +945,12 @@ const examples = [
slug: 'perms-request-permission',
source: '/playground/examples/perms-request-permission.html',
},
{
title: 'Check before you prompt',
description: 'Check whether access is already held before showing an opt-in with Puter.js permissions API. Run and modify this example directly in your browser.',
slug: 'perms-ask-for-access-check',
source: '/playground/examples/perms-ask-for-access-check.html',
},
],
},
{
@@ -0,0 +1,32 @@
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<h3>Notes app — settings</h3>
<label><input type="checkbox" id="toggle"> Autosave to Documents</label>
<button id="save">Save a note</button>
<script>
const details = { name: 'Documents', access: 'write' };
const toggle = document.getElementById('toggle');
(async () => {
// check() never prompts, so a settings screen can render the real
// state without a dialog appearing the moment it opens.
toggle.checked = await puter.perms.check('folder', details);
})();
toggle.addEventListener('change', async () => {
if (!toggle.checked) return;
const path = await puter.perms.request('folder', details);
// Snap back if they declined, so the switch never lies.
toggle.checked = Boolean(path);
});
document.getElementById('save').addEventListener('click', async () => {
const path = await puter.perms.request('folder', details);
if (!path) return puter.print('Autosave is off');
await puter.fs.write(`${path}/note.txt`, 'Saved!');
puter.print(`Saved to ${path}/note.txt`);
});
</script>
</body>
</html>
+1
View File
@@ -7,6 +7,7 @@
const recipeTags = {
ai: 'AI',
auth: 'Auth',
perms: 'Permissions',
fs: 'File System',
kv: 'Key-Value',
hosting: 'Hosting',
@@ -0,0 +1,95 @@
---
title: Ask for Access
description: "Learn how to request permissions with Puter.js to let your app use the user's folders, apps, subdomains and email address."
tags: [perms, auth]
order: 15
---
A Puter app runs in a sandbox. By default it can only use the files and
resources it created itself. When your app needs something outside that sandbox,
such as the user's Documents folder or their email address, it asks the user
with the [permissions API](/Perms/). The user sees a prompt and approves or
declines it. Puter remembers the answer, so the user is asked only once.
## Ask for a Folder
To use one of the user's folders, call
[`puter.perms.request()`](/Perms/request/) with `'folder'`, the folder name and
the access you need. It resolves to the folder's path, which you then use with
the [filesystem API](/FS/):
```js
const path = await puter.perms.request('folder', {
name: 'Documents',
access: 'write',
});
if (path) {
await puter.fs.write(`${path}/notes.txt`, 'Saved!');
}
```
The folder can be `Desktop`, `Documents`, `Pictures` or `Videos`. Access is
`'read'` by default. Write access includes read access, so one `'write'` request
covers both.
## Ask for Apps or Subdomains
To read the list of the user's apps, call
[`puter.perms.request()`](/Perms/request/) with `'apps'`. It resolves to `true`
when granted, and then [`puter.apps.list()`](/Apps/list/) returns the user's
apps:
```js
if (await puter.perms.request('apps')) {
const apps = await puter.apps.list();
console.log(apps.length);
}
```
To publish to the user's subdomains, ask for `'subdomains'` with write access:
```js
const canPublish = await puter.perms.request('subdomains', { access: 'write' });
```
## Ask for the Email Address
To get the user's email address, call [`puter.perms.request()`](/Perms/request/)
with `'email'`. It resolves to the address itself:
```js
const email = await puter.perms.request('email');
if (email) {
console.log(email);
}
```
When the user declines, [`puter.perms.request()`](/Perms/request/) resolves to a
falsy value for every resource. That is why a single `if` handles both outcomes
in each example on this page.
## Check Before You Ask
To find out whether access is already granted, call
[`puter.perms.check()`](/Perms/check/). It takes the same arguments as
[`puter.perms.request()`](/Perms/request/), resolves to `true` or `false`, and
never shows a prompt. Use it when your own UI needs to show the current state,
such as a settings toggle for saving to Documents:
```js
const details = { name: 'Documents', access: 'write' };
toggle.checked = await puter.perms.check('folder', details);
toggle.addEventListener('change', async () => {
if (toggle.checked) {
toggle.checked = Boolean(await puter.perms.request('folder', details));
}
});
```
When you only need the access itself, call
[`puter.perms.request()`](/Perms/request/) directly. It skips the prompt for
anything the user has already granted.