* fix(dashboard): size the Notifications sidebar row like its neighbors The bell button's font: inherit overrode the sidebar item's font-size (16px instead of 14px, 15px in the drawer), and its icon wrapper stayed 18px while the drawer grows nav icons to 20px. * test(dashboard): scope the directory-note assertion to the directory row The 2FA row reuses .teams-directory-note, so the unscoped selector read both notes and the test failed. * fix(dashboard): only treat a picked file as a new avatar while the avatar picker is open The Account tab listened for every file_opened on the dashboard window, so choosing an image for a web link's Change Icon in the Files tab opened the profile-picture crop modal, and saving it replaced the avatar. * fix(dashboard): let dialogs over the Files tab keep their keyboard The Files keydown handler ran under an open confirm, so pressing Enter on the focused Delete button of the permanent-delete prompt opened the trashed item instead (stacking a second alert), and arrows or Delete acted on the rows behind the dialog. * fix(dashboard): keep Apps grid keys away from an open context menu Choosing a tile's menu item with Enter (e.g. Open in new tab) also launched the focused app in place, and arrows moved tile focus while they walked the menu. * fix(dashboard): Escape on a menu or modal inside an app folder keeps the folder open The menu's and the uninstall modal's Escape handlers removed them before the folder's listener ran, so it saw nothing above it and closed the folder with the same keystroke. * fix(dashboard): a tap on the drawer or sheet scrim only dismisses it Outside-press handlers closed the mobile drawer and the notifications sheet on touchstart/pointerdown, which took away the scrim's hit area before the click, so the tap also landed on the app tile or file row underneath. * fix(dashboard): let the sidebar nav scroll on short viewports The nav clipped its overflow, so in a landscape phone's drawer (or a short desktop window) Usage, Account, and Security fell below the fold with no way to reach them. * fix(dashboard): keep the mobile drawer full width when the desktop sidebar is collapsed The remembered collapse outranked the drawer's width rule, so below the drawer breakpoint it opened as an unlabeled 50px icon strip, and the toggle that would undo it is hidden there. * perf(dashboard): stop refetching account data each time focus leaves an app Home's window focus listener fired whenever focus came back from an app's iframe, so every click from an app to the dashboard re-pulled whoami, subscription, storage, and usage (5 requests), on any tab. It now only refreshes after the page itself lost focus to another window. * fix(dashboard): show a seat's team name unescaped in the plan card i18n escapes its arguments for HTML, but the note is set with .text(), so a team called "Bob's & Co" read "Managed by Bob's & Co". * fix(dashboard): stop double-escaping app names in uninstall alerts UIAlert escapes its message, so an app titled "Tom & Jerry" read "Tom & Jerry" in the uninstall-failed and sessions-not-ended alerts. * fix(dashboard): roll back an uninstall whose revoke failed puter.perms.revokeApp resolves with error set instead of rejecting, so a failed revoke still removed the tile, marked the app removed for later sessions, and ended its sign-in, while the app kept its permissions and the rollback and error alert never ran. * fix(dashboard): read a team account's suspension when its name matches an Object member The per-account state map was a plain object, so a username such as constructor or toString was already "in" it, its audit entries were skipped, and a suspended account showed as active with no Delete. * fix(dashboard): update the profile card and sidebar name after a username change Neither carried the .username class that the rename refreshes, so both kept showing the old name until reload. * fix(dashboard): ask how to restore a trashed item whose name is taken Restore moved without overwrite or dedupe, so when the original location already had an item of that name the move 409'd and nothing happened: an uncaught error from the item menu, a console line from the others. All three restore entry points now share one path that offers the Replace / Keep Both prompt the paste flow uses, alerts on other errors, and updates the footer and empty notice once the rows are gone. * fix(dashboard): refresh a renamed row's name, icon, and position in the Files tab The Files tab passed rename_file a callback it never accepted, so a renamed row kept the desktop's 20-character truncation even in a wide column, kept its old type icon, and stayed out of sort order. rename_file now takes an optional onDone (carried through undo), which the Files tab uses to fit the name to its column, refresh the icon and type, and move the row into place. A cancelled rename no longer truncates the name either. * fix(dashboard): drop Publish and Properties from the Shared view's menu The Shared view is a query, not a folder, so both acted on the virtual shared path: Properties showed an unknown error and Publish opened a dialog for a path that doesn't exist. * fix(dashboard): close the Files image preview on Escape and when leaving the folder Escape cleared the selection but left the Space preview open with nothing selected, the preview stayed over a different folder after navigating, and a preview whose URL arrived after it was dismissed or replaced still opened. * fix(dashboard): don't move Files history for a navigation that's dropped renderDirectory ignores a navigation while another folder is loading, but every caller had already pushed or stepped history, so after a click during a load the listing and history disagreed and the next Back or Forward seemed to do nothing. History now only moves when the render will run; back/forward steps share one helper. * fix(dashboard): reopening the current folder adds no Files history entry Clicking the folder already on screen (e.g. Home in the sidebar) pushed a duplicate entry, so the next Back reloaded the same folder. * fix(dashboard): show installed apps when the recommended list fails to load get-launch-apps sat in the same Promise.all as the installed apps and its body was parsed without a status check, so a network error or a proxy's HTML error page replaced the whole grid with "Failed to load apps". A failed list now falls back to the last one that loaded. * fix(dashboard): fit the app uninstall dialog on narrow phones The card is mounted outside the dashboard's border-box rule, so its 320px min-width plus padding came to 370px and was clipped on 360px screens; a long unbroken app title also overflowed it. Desktop sizing is unchanged. * fix(dashboard): keep a new team account's one-time password on screen until dismissed The credential box lived only in the DOM inside the panel that every refresh repaints, so revisiting the Teams tab or any later action wiped a password that can't be retrieved again. It is now kept in state, for the team it belongs to, and drawn with the panel. * fix(dashboard): reload the Teams tab after a change made while it was loading refresh() handed back any load already in flight, so an action or team switch made during a revisit's background load awaited data read before the change: a toggled setting snapped back, and a team switch could paint one team's roster next to another's record. A change during a load now queues one more load, the stale one skips its paint, and revisiting the tab doesn't start a second load while init's is still running. * fix(dashboard): send one re-enable request for a double click in Teams Re-enable has no confirm dialog to absorb a second click, and nothing held the action while it ran, so a double click enabled the account twice (two audit entries). A suspend or re-enable already in flight for an account now ignores further clicks. * fix(dashboard): revert the avatar and say so when saving a new photo fails The crop's Save showed the new picture everywhere and revealed Remove without waiting for the upload, and update_profile swallows failures, so a failed save looked saved until reload. The save is now awaited: a failure puts the previous picture back with an error hint, and Remove waits for the upload so it can't race it. * fix(dashboard): hide the Usage tab's plan button for team seats A seat's plan belongs to its team, so Home already hides its upgrade link; the Usage tab still offered Upgrade, which only reaches a refusal. * fix(dashboard): don't drop Home's forced usage refresh during a running load loadUsageData handed any caller the load already in flight before looking at force, so a subscription change (or a return from the billing portal) during a routine load was answered with data read before the change, and the plan card stayed stale until the next refresh. A forced call now runs once more after the running load. * fix(dashboard): activate Apps when the URL names an unknown tab An unknown hash rendered Apps as the active tab but skipped its activation, so the grid kept the generic content padding and Apps' onActivate never ran. * fix(dashboard): make the sidebar user menu reachable from the keyboard The user button was a div with no tabindex, so Log Out, account switching, and Contact Us were out of reach without a pointer. It is now a button (rendering unchanged), with aria-haspopup. * fix(dashboard): name the sidebar's collapse and drawer buttons for assistive tech The collapse toggle held only two unlabeled images, so screen readers announced an unnamed button; it now carries a translated label and aria-expanded that follow its state. The drawer's open/close labels were hardcoded English and now go through i18n. * fix(dashboard): make Home's recent apps reachable from the keyboard Each recent app was a click-only div, so keyboard users couldn't open one. They are now buttons with a focus ring; the icon is decorative since the title names the button. * fix(dashboard): name the Security tab's 2FA switch for assistive tech The checkbox sat in a text-less label, so screen readers announced an unnamed checkbox. It now carries the translated Two Factor Authentication label, as the Teams switches do. * fix(dashboard): sort the Usage table from the keyboard The sortable headers were click-only th cells. Each now holds a button, carries aria-sort, and keeps focus across the re-render a sort causes. The Resource/Units/Cost headers go through i18n. * fix(dashboard): don't rebuild the Files listing under an open menu Returning to the browser tab re-rendered the folder even with a context menu or action sheet open, so its actions then targeted detached rows: Rename did nothing, Restore faded a row that was already gone. The refresh now waits while a menu is up, as it does for a rename. * fix(dashboard): point the Files sidebar's Documents at the current home The entry read window.documents_path, which globals.js sets once from the cached user and nothing updates; login and username changes keep window.docs_path current instead. After a username change, Documents pointed at the old home and showed "This folder couldn't be opened", even after reloading. * fix(dashboard): let only the newest share listing render in the share dialog Each action ends in a refresh, and refreshes from overlapping actions (or the opening load) could finish out of order, so an older listing landed last and undid what the user just did, e.g. the link control snapped back to restricted after turning the link on. Older refreshes now drop their result. * perf(dashboard): load a team's record, roster, and plan in parallel loadSelected awaited the audit log (every page of it), then the members, then the plan, on every visit to the Teams tab. They don't depend on each other, so they are now fetched together. * fix(dashboard): keep keyboard focus on the Teams control that was used Every Teams action repaints the whole panel, which dropped focus to <body>: a keyboard user toggling a switch or suspending an account was sent back to the top of the page. The repaint now refocuses the same control, or the same account's new action when the old one is gone. * fix(dashboard): give the app uninstall prompt dialog semantics and focus The prompt had no dialog role or label and never took focus, so keyboard and screen-reader users stayed on the inert grid behind it. It is now a labelled modal dialog that focuses Cancel on open and returns focus to the app's tile when dismissed. * fix(dashboard): keep the add-an-app tile when there are no apps With no apps at all, the empty state replaced the whole grid, add tile included, so a new user on an instance with no recommended apps had nothing to act on. The empty line now sits above a grid that keeps the tile, as a search with no matches already does. * fix(dashboard): don't rebuild the Apps grid under an active drag An uninstall finishing (or a failed one rolling back) re-rendered the grid even while another tile was being dragged, replacing the dragged tile with a fresh copy: the copy showed under the ghost and the drop was lost. Renders asked for mid-drag now wait for the one the drop does; the folder eject, which rebuilds the grid as part of the drag, still can. * fix(dashboard): return focus to the drawer toggle when the mobile drawer closes Closing the drawer (Escape, the close button, a tab pick) left focus on controls that had just become hidden, so it fell to <body>; closing the notifications sheet opened from the drawer tried to refocus the bell inside the closed drawer. Both now land on the drawer toggle. * fix(dashboard): truncate Files names between graphemes, with a binary search The middle truncation sliced UTF-16 code units, so at many widths a long name with emoji showed a half surrogate (rendered as a replacement character) or a broken joined emoji. It also measured one more character per step, a measureText call per character of every long name on each render and column resize. The cut now falls between graphemes and is found by binary search; output for other names is unchanged. * fix(dashboard): translate the Home tab's hardcoded English The tab label, the recent-apps empty state, card subtitles, the plan badge and trial wording, the upgrade/manage links, and the usage cards' "Used" / "of" lines were English literals. They now go through i18n, with placeholders where values are interpolated. * fix(dashboard): translate the sidebar's remaining English The Apps, Files, and Usage tab labels, the user button's fallback name, and the user menu's Developers item were English literals; they now use i18n keys like the other tabs. * fix(dashboard): translate the Usage tab's hardcoded English The subtitle, the "used of" meter lines (now the existing used_of key), Usage Details, the plan button, Show more/less, and the details error were English literals. * fix(dashboard): translate the Account and Security tabs' hardcoded English Both subtitles, the delete-account description, the sessions hint, the username fallback, and the avatar picker's window title were English literals. * fix(dashboard): translate the Apps tab's hardcoded English The uninstall prompt and its failure alert, empty and no-match notices, pager and folder-dot labels, the search placeholder, the edit toggle, and the tile menu's Open in New Tab / Quit / Uninstall were English literals. * fix(dashboard): translate the Files tab's hardcoded English The folder sidebar, footer counts (now the existing item-count keys), sort and view menus, upload status and errors, the empty and can't-open notices, the reserved-name alerts, the move error, and the loading text were English literals. * fix(dashboard): translate the action sheet's Back row and match delete in any language The touch action sheet styled an item red when its label contained the English word "delete", so Delete lost its danger styling in every other language; it now compares against the translated Delete labels. Its submenu Back row and the properties panel's Directory/disassociate labels were English literals. * fix(dashboard): make the Files sidebar, crumbs, and nav arrows keyboard-operable The folder sidebar, the breadcrumbs, and the back/forward/up arrows were click-only li/span/img elements, out of the tab order. They now take focus, carry button/link roles (the arrows with labels and aria-disabled), answer Enter and Space, and show a focus ring. The rows' Enter/Space shortcuts also no longer swallow those keys from a focused control: with rows selected, Enter on Upload opened the selection. * perf(dashboard): read grid name widths before writing any in the Files tab fitItemNames read each tile's name width right after writing the previous name, forcing a layout per row. Reading them all first, then writing, cuts switching 400 files into grid view from about 300ms to 170ms; the rendered names are identical.
The Open-Source Internet Computer!
« LIVE DEMO »
Puter.com
·
App Store
·
AI Builder
·
Developers
·
X
Puter
Puter is an advanced, open-source, self-hostable internet computer designed to be feature-rich, fast, and highly extensible.
For Users
Puter's goal is to provide you with every app and feature you need to work, create, and play under one roof. From a simple Notepad and Voice Recorder to Spreadsheet and Camera, Puter wants to be the all-in-one solution for your digital life.
For Developers
Puter provides everything you need to build and publish web apps and games. From AI to Cloud Storage and Database to Serverless Workers, Puter has you covered. Puter also helps you get users! Once you build your app, you can publish it on our App Store to reach and monetize users.
Getting Started
💻 Local Development
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
→ This should launch Puter at http://puter.localhost:4100
To run this checkout with Docker, follow Building from source. Create a local docker-compose.override.yml to select the local build; keeping these settings out of docker-compose.yml avoids conflicts when pulling updates and keeps local configuration out of pull requests.
🚀 Self-Hosting
Linux/macOS
curl -fsSL https://puter.com/selfhost | sh
Windows
irm https://puter.com/selfhost?os=windows | iex
→ For more details, see Self-Hosting Puter.
☁️ Puter.com
Puter is available as a hosted service at puter.com.
Support
Connect with the maintainers and community through these channels:
- Bug report or feature request? Please open an issue.
- X (Twitter): x.com/HeyPuter
- Security issues or abuse reports? security@puter.com
- Email maintainers at hi@puter.com
We are always happy to help you with any questions you may have. Don't hesitate to ask!
License
This repository, including all its contents, sub-projects, modules, and components, is licensed under AGPL-3.0 unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses.
Translations
- Arabic / العربية
- Armenian / Հայերեն
- Bengali / বাংলা
- Chinese / 中文
- Danish / Dansk
- English
- Farsi / فارسی
- Finnish / Suomi
- French / Français
- German / Deutsch
- Hebrew/ עברית
- Hindi / हिंदी
- Hungarian / Magyar
- Indonesian / Bahasa Indonesia
- Italian / Italiano
- Japanese / 日本語
- Korean / 한국어
- Malay / Bahasa Malaysia
- Malayalam / മലയാളം
- Dutch / Nederlands
- Polish / Polski
- Odia / ଓଡ଼ିଆ
- Portuguese / Português
- Punjabi / ਪੰਜਾਬੀ
- Romanian / Română
- Russian / Русский
- Spanish / Español
- Swedish / Svenska
- Tamil / தமிழ்
- Telugu / తెలుగు
- Thai / ไทย
- Turkish / Türkçe
- Ukrainian / Українська
- Urdu / اردو
- Vietnamese / Tiếng Việt

