* refactor(stores): one read-through RowCache for UserStore and AppStore UserStore and AppStore each carried the same multi-key row cache: key builder, cache read, tombstone-guarded backfill, broadcast refresh, invalidate and tombstone-on-delete. They now share RowCache on PuterStore, which also single-flights concurrent misses for one key and batches getByIds/getByUids: one pipelined tombstone check for the loaded rows and one pipelined backfill instead of per-row awaits. Cache keys and TTLs are unchanged. * perf(apps): invalidate cached app lists by generation, not by tracker scan Every app write SMEMBERS'd a global set of every cached list key, parsed each key back into its filters and deleted the matches. List pages are now keyed by their owner's generation token (or a shared one for unscoped lists), and a write replaces the tokens it affects: O(1) per write, and a page loaded before a write can no longer be cached after it. * refactor(stores): one keyset page helper for store listings Thirteen store listings each cut a LIMIT n+1 read to a page and sealed the last row's position, and each opened an id cursor its own way. They now use keysetPage() and openIdCursor() from util/pagination. Cursor payloads and sealing are unchanged; a cursor without a usable id still fails with 400 in ShareStore and still restarts the listing elsewhere (strict option). * refactor(stores): delete store methods nothing calls AppStore.existsByIndexUrl, OIDCStore.unlinkByUserId, TeamStore.listByOwner/listActiveSeatUuids, SubdomainStore.getByDomain/ listByDomain, FSEntryStore.ensureDirectoriesForUser, ShareStore.listByIssuer/listByRecipientEmail/deleteByRecipientEmail/ getDailyShareCount/listByHolderAndFsentries and PermissionStore.invalidateScanCache/deleteUserUserPermsByPermissionPrefix had no production callers. ShareStore.listByFsentries was a copy of listReaching; its callers use the latter. SubdomainStore SMEMBERS'd a per-user prefix-list tracker on every write and broadcast its deletion, but nothing ever wrote that set or cached a prefix listing. The reads are gone. * refactor(stores): shared escapeLike and bumpGeneration helpers escapeLike replaces the LIKE escaping copied into PermissionStore (twice), ShareStore and FSEntryStore, and now also guards SubdomainStore's prefix filters, which passed caller prefixes into LIKE unescaped. bumpGeneration sends INCR and EXPIRE in one pipeline instead of two awaited commands in PermissionStore, EventSubscriptionStore and PresenceStore. * refactor(stores): read affected rows off WriteResult Every database client returns affectedRows and anyRowsAffected, so the `affectedRows ?? changes ?? 0` fallbacks in ShareStore, NotificationStore, UserStore and UserBlockStore read those directly. * perf(stores): batch flat-permission KV deletes and durable cache drops PermissionStore deleted each flat KV entry with its own kv.del; one kv.batchDel now covers the set. DurableSubscriptionStore's suspend and reap dropped each row from the cache separately; EventSubscriptionStore gains dropDurables, which drops them per owner in one pass, and dropDurable calls it. suspend keeps one conditional UPDATE per row, which is how concurrent settles learn which rows each of them suspended. * refactor(fs): fold FSEntryStore's duplicate getters, sort maps and cache keys - getEntryByUuid and getEntryById share one by-column getter. - listChildren and listChildrenPage read one sort table; the offset listing now coalesces NULL modified/size like the cursor listing, so both order NULLs the same way on every engine. - Entry cache keys come from one builder instead of hand-built strings. - getEntriesByIds, getEntriesByPaths and the per-user path reader fetch their cache hits in one pipelined round trip instead of a GET per key, through readCacheValues, which RowCache.readMany now uses too. * fix(apps): cache the row a lost createFromOrigin race reads from the primary Keeps AppStore's private #writeCache as a RowCache write, so code that still calls it (#4166's read-back) loads in either merge order.
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

