From ee4d55027d22d9b1db9efb486e957c9cb55986cb Mon Sep 17 00:00:00 2001 From: Juan Fernando Castro Date: Tue, 29 Sep 2026 13:00:34 -0400 Subject: [PATCH] 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 --- src/docs/src/examples.js | 6 ++ .../examples/perms-ask-for-access-check.html | 32 +++++++ src/docs/src/recipe-tags.js | 1 + src/docs/src/recipes/perms-ask-for-access.md | 95 +++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 src/docs/src/playground/examples/perms-ask-for-access-check.html create mode 100644 src/docs/src/recipes/perms-ask-for-access.md diff --git a/src/docs/src/examples.js b/src/docs/src/examples.js index 4a9776700..112990cfe 100644 --- a/src/docs/src/examples.js +++ b/src/docs/src/examples.js @@ -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', + }, ], }, { diff --git a/src/docs/src/playground/examples/perms-ask-for-access-check.html b/src/docs/src/playground/examples/perms-ask-for-access-check.html new file mode 100644 index 000000000..89b23c23a --- /dev/null +++ b/src/docs/src/playground/examples/perms-ask-for-access-check.html @@ -0,0 +1,32 @@ + + + +

Notes app — settings

+ + + + + diff --git a/src/docs/src/recipe-tags.js b/src/docs/src/recipe-tags.js index 1597aa0c8..97b68e742 100644 --- a/src/docs/src/recipe-tags.js +++ b/src/docs/src/recipe-tags.js @@ -7,6 +7,7 @@ const recipeTags = { ai: 'AI', auth: 'Auth', + perms: 'Permissions', fs: 'File System', kv: 'Key-Value', hosting: 'Hosting', diff --git a/src/docs/src/recipes/perms-ask-for-access.md b/src/docs/src/recipes/perms-ask-for-access.md new file mode 100644 index 000000000..c1175c7e2 --- /dev/null +++ b/src/docs/src/recipes/perms-ask-for-access.md @@ -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.