Include 'builder' in the RECOMMENDED_APP_NAMES array in src/backend/services/apps/RecommendedAppsService.ts so the RecommendedAppsService treats the builder app as a recommended application and surfaces it accordingly.
* Alpha: compaction support for OpenAI and Anthropic
* update lock
* fix billing for anthropic compactions
* Fix max_tokens bug in together provider
* Fix responses compaction
* feat: meter Gemini thinking tokens and grounding requests
- Thinking tokens: Extracted from standard completion tokens to ensure they are billed accurately at the correct model-specific rate.
- Grounding requests: Added flat-fee metering for Google Search by tracking grounding_metadata across both streaming and non-streaming responses.
- Pricing updates: Corrected stale rates for Gemini 2.5 Flash output, cached tokens, thinking tokens, and grounding requests.
* fix: correct Gemini 2.x metering rates and harden grounding capture
Pricing corrections (verified against ai.google.dev/gemini-api/docs/pricing):
- gemini-2.5-flash output is $2.50/M, not $1.00/M: restore
completion_tokens to 250 and bill thinking_tokens at the same output
rate (250). The previous 100 under-billed output ~60%, and this is the
provider's default model.
- gemini-2.5-flash cache read is $0.03/M: restore cached_tokens to 3
(the 7.5 value over-billed).
- Grounding with Google Search is $35 / 1,000 requests for Gemini 2.x
models and $14 / 1,000 for 3.x. Set grounding_requests to 3_500_000
for gemini-2.0-flash, gemini-2.5-flash, gemini-2.5-flash-lite and
gemini-2.5-pro; 3.x models keep 1_400_000.
Streaming robustness:
- In create_chat_stream_handler, don't let a later extra_content chunk
without grounding_metadata overwrite an earlier one that carried it,
so grounding requests are still metered.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---------
Co-authored-by: Daniel Salazar <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Include 'butler' in the RECOMMENDED_APP_NAMES array in RecommendedAppsService so it appears in the recommended apps list. Updates src/backend/services/apps/RecommendedAppsService.ts.
Revamps the phone verification dialog and adds reusable phone helper modules.
- Heavily refactors UIWindowPhoneVerificationRequired.js to add a searchable inline country picker, national-number live formatting, country autodetect for "+" input, WebOTP auto-fill support, resend cooldown timer, accessibility improvements, proper teardown/cleanup, and last-used country persistence.
- Introduces helpers/src/helpers/country_codes.js (get_country_list, flag emoji) which builds a localized list of dialable countries from libphonenumber-js and Intl.DisplayNames.
- Introduces helpers/src/helpers/phone.js with thin wrappers around libphonenumber-js: format_phone_as_you_type, inspect_phone, phone_example_for, detect_country_from_input.
- Adds English i18n strings for the new UI in src/gui/src/i18n/translations/en.js.
These changes keep submission canonicalization using libphonenumber-js (E.164), improve UX for selecting/formatting numbers, and make the country list and phone utilities reusable across the app.
The healthcheck was using 'puter.localhost:4100/test' which fails for
two reasons:
- 'puter.localhost' does not resolve inside the container; the service
listens on all interfaces at port 4100, so 'localhost' works
- '/test' endpoint does not exist; use '/' which serves the shell
This caused the container to be perpetually marked as unhealthy.
Fixes#3191
* ci: add docs build workflow
Add CI workflow that runs npm ci and npm run build in src/docs
whenever files under src/docs change in a pull request.
Closes#3225
* ci: also trigger docs build when workflow file changes
* ci: address docs build workflow review
* fix: coerce Mistral image_url parts from object to string
Mistral's API expects image_url content parts to be a plain string URL,
not the OpenAI-style { url: string } object that process_input_messages
produces. Without this coercion, sending an image to any Mistral model
that supports vision (mistral-small, mistral-medium, mistral-large,
ministral-*) results in a request error from the Mistral SDK.
Add #coerceImageUrls() as a private method on MistralAIProvider that
maps { type: 'image_url', image_url: { url } } -> { type: 'image_url',
image_url: url } for every content part in every message. Messages with
plain string content are left untouched, as are parts whose image_url is
already a string.
Add four unit tests covering: object-to-string coercion, already-flat
strings, plain string message content, and mixed text+image content.
* style: use plain ASCII dashes in comment section divider
* Add docs fixes for deployment and workers pages
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* handle router edge case
* explicit info about wildcard requiring name
---------
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* Minor fix deployment docs
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
---------
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
* fix(docs/search): show loading state and replay query when index isn't ready
Previously performSearch rendered "No results found" while the
MiniSearch index was still loading, which is misleading on slow
networks. Track the last query as pendingQuery and replay it from
fetchSearchIndex once the index is ready; render a distinct
"Failed to load search index" message on fetch error so the
loading message doesn't persist indefinitely.
Fixes#3180.
* fix(docs/search): close stale-replay race and consolidate status messages
Drop pendingQuery synchronously in the input handler when the query
falls below the minimum length, so a fetchSearchIndex that resolves
within the 300ms debounce window after the user clears the field can
no longer replay the cleared query into an empty input.
Move the idle, loading, and failed copy into a single
renderSearchStatus(kind) helper so the four .search-no-results
renderings can only drift in one place.
* feat(database): add postgres database client
Adds the PostgreSQL database client, native bootstrap migration, SQL preparation helpers, and database config/factory wiring.\n\nRefs #3165.
* feat(database): make backend queries postgres-aware
Updates runtime SQL call sites for database-specific booleans, identifiers, insert-ignore, upserts, JSON extraction, intervals, and Postgres insert ids.\n\nRefs #3165.
* test(database): cover postgres client behavior
Adds unit coverage for SQL preparation, factory selection, write-result mapping, and transaction rollback/commit ordering, plus an env-gated PostgreSQL integration flow.\n\nRefs #3165.
* docs(self-hosting): document postgres database setup
Adds PostgreSQL configuration examples and migration path guidance for self-hosted deployments.\n\nRefs #3165.
* fix: harden postgres oidc tests
* fix(postgres): normalize query results and SQL prep
* fix(user): preserve normalized cache booleans
* test(postgres): run integration coverage with pgmock
* tests: add way to run all tests with postgres though slow
Also adding note that postgres is not in active use so might not work out the box
---------
Co-authored-by: Daniel Salazar <[email protected]>
* feat: worker sessions get their own kind + per-(user, app, worker_name) row
Schema
------
- mysql_mig_11.sql + sqlite 0054: add idx_sessions_user_worker_active,
a partial unique index over (user_id, app_uid, meta.worker_name) for
kind='worker' rows. Active worker sessions are deduped by that triple
so each named worker gets its own session row and they don't fight
the existing idx_sessions_user_app_active (which still constrains
kind='app' only). app_uid is allowed NULL for user-scoped workers
with no app binding.
SessionStore
------------
- getOrCreateWorker(userId, { appUid, workerName, ... }): mirrors the
getOrCreateApp pattern — cache lookup, partial-unique re-SELECT on
insert-ignore, all keyed on the worker triple. expires_at lands at
WORKER_WINDOW_SECONDS (~99y) so the worker doesn't have to re-mint
on any cadence.
- #cacheKeyWorker + #allCacheKeysForRow worker branch so revoke /
update invalidates the worker cache view alongside the by-uuid one.
AuthService
-----------
- createWorkerSessionToken(user, workerName, meta?) now takes the
workerName explicitly and routes through getOrCreateWorker. Emits
the same { session, token, gui_token } shape but both JWTs carry
{ worker: true, worker_name }.
- createWorkerAppToken(actor, appUid, workerName) likewise — JWT
carries the worker_name claim so a verifier can tell two workers
under the same app apart without a DB round-trip.
- Both methods 400 on empty workerName.
WorkerDriver
------------
- Five auth-mint call sites swapped over: app-bound deploy (3x:
appId branch, actor.app fallback, hot-reload redeploy), user-bound
fallback (2x: cold deploy, hot-reload). All pass `workerName` so
the worker's session row is naturally idempotent across redeploys.
GUI manage-sessions
-------------------
- sessionTitle adds a kind='worker' branch ("name (app)" for
app-scoped workers, just "name" for user-scoped), pulling worker_name
from the meta-spread that listSessions already surfaces.
- en.js adds ui_session_kind_worker.
* fix(workers): MySQL JSON_EXTRACT quoting + revoke cache invalidation +
SQLite NULL-distinct in worker index
Three real bugs in the worker session plumbing from the prior commit,
plus a misleading comment. Schema design kept (worker_name lives in
`meta` rather than a dedicated column) per offline review:
1. `#selectWorkerRow` compared `JSON_EXTRACT(meta, '$.worker_name')`
directly to a bind parameter. MySQL's `JSON_EXTRACT` returns a
JSON-typed value with embedded quotes (`"name"`, not `name`), so
the comparison never matched. After the first INSERT, every
follow-up getOrCreateWorker call missed the existing row in the
SELECT, hit INSERT-IGNORE, then missed again in the re-SELECT —
the caller would receive whatever the INSERT-IGNORE returned (a
no-op row in conflict cases). Wrap with `JSON_UNQUOTE` on MySQL
via `db.case`; SQLite's `json_extract` already returns the
unwrapped scalar so it keeps the literal form.
2. mig_11's generated `worker_unique_key` had the same JSON-quoting
bug. Mirror the fix: `IFNULL(JSON_UNQUOTE(JSON_EXTRACT(...)), '')`
so the concatenated unique key is a plain string that lines up
with what `#selectWorkerRow` now binds against.
3. SQLite UNIQUE indexes treat NULL columns as distinct (per the SQL
standard), so two user-scoped workers (app_uid NULL) with the same
worker_name would both insert. Wrap the index expression with
`IFNULL(app_uid, '')` so they correctly conflict — matches the
MySQL side's `IFNULL` in the generated column.
4. `removeByUuid` / `revokeCascade` SELECTed only the identity
columns (no `meta`), so `#allCacheKeysForRow`'s worker branch
couldn't read `meta.worker_name` and the composite
`sessions:v2:worker:<user>:<app>:<name>` cache key survived
revocation. Up to CACHE_TTL_SECONDS (15min) afterwards,
getOrCreateWorker would short-circuit to the cached (revoked) row.
Add `meta` to both SELECTs; the existing meta-parsing logic in
`#allCacheKeysForRow` handles the rest.
* feat (put-1019 put-1021): v2 auth revoke endpoints + silent v1->v2 token migration
PUT-1019 (AUTH-5): full revoke-endpoint coverage
- /logout: soft-revoke web session + its asset cookies via revokeCascade
(app sessions and access tokens survive)
- POST /auth/revoke-session: cascade per row kind (web/app/access_token/asset)
- POST /auth/revoke-all-sessions: revoke all web rows for user; optional
include_apps=true nuclear option; gated by userProtected (cookie-only)
- revokeAccessToken: soft-revoke matching access_token row in addition to
removing access_token_permissions
- All revokes are UPDATE revoked_at = now(); no DELETE statements remain
PUT-1021 (SDK-1): backend POST /auth/migrate-token
- v1 access_token/app -> mint matching-kind v2 token, idempotent on
(auth_id, kind, token_uid)
- v1 web/session -> 409 { code: "reauth_required" } (interactive relogin only)
- Same-origin / signed-referer hardening; rate-limited per IP and auth_id
- Gated by auth.allow_v1_tokens; emits puter_token_v2 cookie for app-in-browser
DB migrations: mysql_mig_10, sqlite 0053 (sessions.access_token_uid column)
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* fix(put-1019): reject self-revoke; enrich list-sessions response
- handleRevokeSession refuses uuid === req.actor.session.uid (use /logout
instead). The cookie that authenticated the call should never be the
target of a self-revoke — the response can't write fresh auth state
and the client ends up with an ambiguous identity. revoke-all-sessions
still has the explicit include_current opt-in for the nuclear case.
- AuthService.listSessions now joins the apps table for kind='app' rows
(returning { uid, name, title, icon } so the manage-sessions UI can
render the authorizing app without a second round trip), surfaces
kind / expires_at / label / last_ip / created_via, and filters out
asset rows (per-cookie children of web rows, revoked transitively via
cascade — surfacing them as standalone entries would be confusing).
- Sort order: current session first, then most-recently-active. UI
relies on this to anchor "you are here" at the top.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* fix(put-1019 put-1021): review nits — origin normalization, cookie fallback, types, migration order
B1: createAccessToken.options.expiresIn widened to string | number.
The impl (#hardExpiryFromExpiresIn) and existing callers/tests use
jsonwebtoken-style strings ('1h', '30d'); narrowing to number forced
unsafe casts at every call site. Cast at the single sign() boundary
where jsonwebtoken's typed template-literal SignOptions clashes
with the wider runtime contract.
B2: Inline comment on the DELETE in access_token_permissions. The
AUTH-5 "no DELETE on revoke" rule scoped to the `sessions` table
(where the cascade graph + audit trail matter). Permissions rows
are the grant manifest for an active token — once its session is
soft-revoked they're dead-weight cache entries. A future audit
requirement would land as a `revoked_at` column on this table,
not a behavior change in this PR.
B3: handleMigrateToken now sets the puter_token_v2 cookie (with the
shared sessionCookieFlags + httpOnly) when the migration result
is kind='app'. The endpoint is already gated on Origin so the
caller is by definition in a browser; access tokens deliberately
skip the cookie since they're programmatic.
B4: #isMigrateTokenOriginAllowed normalizes both incoming origin and
config.origin / allowlist entries (trim + strip trailing slash +
lowercase) before equality. A misconfigured `config.origin =
"https://puter.com/"` would otherwise reject every same-origin
browser call.
B5: Replaced 4x `this.config.cookie_name!` non-null assertions in
AuthController with `(this.config.cookie_name ?? 'puter_token')`.
IConfig is `Partial<IConfigOptional>` so cookie_name is undefined
at runtime in some deployments / test setups; the fallback matches
the pattern in userProtected / OIDCController / puterSite.
B6: MySQLDatabaseClient sorts migrations numerically by trailing
integer instead of lexically. Existing files use unpadded names
(`mysql_mig_<N>.sql`), so plain `.sort()` ran mysql_mig_10 before
mysql_mig_2 — a future migration that depended on _2..9 running
first would break. Non-numeric filenames fall through to
localeCompare for determinism.
B7: Restored the docstring for SessionStore.getOrCreateApp's
`opts.auth_id` ("Stable per-user identity (survives re-login);
carried on every v2 JWT so manage-sessions can group by identity")
— the previous edit truncated it to a fragment.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* test + feat: backend test coverage for PUT-1019/1021 review fixes + worker session methods
Tests
-----
- compareMigrationFilenames (new) covering B6 numeric-sort: confirms
mysql_mig_10.sql lands after mysql_mig_9.sql; non-numeric files sort
after numbered ones; stable for already-ordered input.
- listSessions (AuthService.test.ts): excludes kind="asset" rows;
enriches with kind/expires_at/last_ip/created_via; joins kind="app"
rows with the apps table; sorts current first then by last_activity
desc.
- handleRevokeSession (AuthController.test.ts): refuses self-revoke
with 400; still allows revoking a sibling session.
- handleMigrateToken (AuthController.test.ts): rejects missing/
disallowed Origin; tolerates trailing slash and uppercase Origin
(B4 normalization); returns 409 reauth_required for v1 web tokens;
does NOT set the cookie for access-token migration; DOES set the
puter_token_v2 cookie (httpOnly + sessionCookieFlags) for
app-under-user migration.
- SessionStore tests updated to import APP_WINDOW_SECONDS /
WEB_WINDOW_SECONDS rather than hardcoded 30/90 day values — the
windows just got bumped to 1y and the assertions need to follow
the constant.
Refactor
--------
- MySQLDatabaseClient exports compareMigrationFilenames so the sort
logic is unit-testable in isolation.
Worker tokens
-------------
- AuthService.createWorkerSessionToken(user, meta?): mints a new
kind="web" row tagged meta.worker=true, expires_at =
WORKER_WINDOW_SECONDS, returns { session, token, gui_token }
with worker: true on each JWT.
- AuthService.createWorkerAppToken(actor, appUid): mints a new
kind="app" row tagged meta.worker=true, expires_at =
WORKER_WINDOW_SECONDS, returns an app-under-user JWT with
worker: true. Note the existing idx_sessions_user_app_active
unique index will collide with an existing non-worker app
session for the same (user, app) — future schema work can
carve workers out of that uniqueness.
SessionStore.js: WEB/APP_WINDOW_SECONDS now 1y;
WORKER_WINDOW_SECONDS = 99y added for the worker path.
Full backend suite: 2172 passed / 16 skipped / 0 failed.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
* feat (put-1022 put-1023 put-1024): puter.js reauth handling + GUI v2 modal + silent v1 migration
PUT-1022 (PJS-1): puter.js handles 401 reauth_required
- Single apiCall wrapper intercepts 401 { code: "reauth_required" }
- Clears local token, emits puter.auth.reauth_required { reason, auth_id }
- Queues in-flight requests, re-issues after re-auth completes
- web/app: opens puter.com login popup forwarding auth_id
- gui: no-op (handled by GUI-1 modal)
- workers: surfaces as structured exception
- All token writes go through setAuthToken() (future-proofed for PJS-2)
PUT-1023 (GUI-1): web GUI reauth modal + v2 token storage
- Detects 401 reauth_required across http + websocket connect paths
- Soft modal preserves URL/window state; auth_id forwarded into login form
- Storage key migrated: auth_token -> auth_token_v2
- Cookie cleared on logout: puter_token (legacy) cleared, backend writes puter_token_v2
- Cross-tab propagation via localStorage storage events
- WebSocket revocation surfaces as same modal (no silent failure)
PUT-1024 (PJS-2): puter.js storage versioning + silent v1->v2 migration
- New storage key puter.auth.token.v2
- On SDK init: prefer v2 key; else legacy v1 -> silent POST /auth/migrate-token (SDK-1)
- On success: store v2, clear v1. On failure: fall back to PJS-1 reauth flow
- URL-param tokens (?puter.auth.token=, ?auth_token=) also run through silent migration
- Logout clears both keys; setAuthToken writes v2 only
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* fix(put-1023): manage-sessions polish — hide self-revoke, fix modal stack, richer rows
Three issues surfaced during local testing of the manage-sessions UI:
1. The session row representing the caller's own cookie had a Revoke
button that, if used, left the client in an ambiguous identity state
(backend now rejects it too — see put-1019 backend fix). The button
is now omitted entirely when session.current=true; /logout remains
the right path for ending the active session.
2. The confirm-revoke prompt rendered behind the manage-sessions
window because both share the dominant z-index pool. UIAlert calls
now pass parent_uuid (the manage-sessions window's data-element_uuid)
plus stay_on_top, so the prompt stacks above its parent.
3. Each row only showed the bare uuid. Now renders: title (app
title for app sessions, label / "Browser session" / "Access token"
otherwise), app icon when applicable, kind / current badges,
created / last-active / expires (timeago, with absolute on hover),
and last_ip. App metadata is joined server-side per the backend
listSessions change.
Adds en.js strings for the new labels (ui_session_*).
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* fix(put-1022): tighten reauth replay + iframe postMessage hygiene
driverCall_ replay (G1): on 401 reauth_required, re-enter driverCall_
instead of calling replayXhrAfterReauth. The generic helper wires the
retried XHR through setupXhrEventHandlers which resolves with the
parsed response and silently skips driverCall_'s streaming detection,
usage-limit / email-confirmation handling, settings.transform, and
resp.result unwrapping — i.e. it would change the driver call API
contract on retry. One-shot via settings._reauthReplayed so a
fresh-token rejection bubbles up instead of looping.
responseType drift (G2): driverCall_ sets xhr.responseType from
settings AFTER initXhr (which captured the stale value into
xhr._puterReq). Mirror the mutation onto _puterReq so any replay path
builds the retry with the live config rather than the snapshot.
targetOrigin lockdown (G3): triggerReauth's parent.postMessage now
targets this.defaultGUIOrigin instead of '*'. The payload carries
reauth metadata + auth_id and is only meaningful to the GUI; '*'
would leak the signal to whatever frame happened to be embedding us.
event.source pinning (G4): the reauth wait listener also matches
event.source against globalThis.parent, not just event.origin —
origin alone admits any same-origin frame on the GUI domain.
event name alignment (G5): the SDK now emits and listens for
'puter.auth.reauth_required' (matches the documented name in the
PR / commit description). The old 'auth.reauth_required' key isn't
yet consumed externally so this is a safe rename.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Record the 2.4.2 release in the repo. The version was published to npm
(via prepublishOnly's `npm version patch`) but the bump was never
committed, leaving package.json stuck at 2.4.1 on GitHub.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- decrease ai related alerts and make errors not 500
- decreased bad fs controller checks to be 404s instead of 500s
- force bucket regions for now
- validate webdav perms for locking/unlocking
Delete the large TabFiles.js file (file browser tab) and update dashboard, styles, helpers, and init logic accordingly. Related changes in UIDashboard.js, dashboard.css, style.css, helpers.js and initgui.js remove or adapt references to the removed component and adjust UI/initialization and styling to account for the file-tab extraction. This reduces duplicate/legacy code and centralizes file browser functionality; review UIDashboard and helper updates to ensure file management features (navigation, upload, context menus, previews) are migrated or re-implemented as needed.
- When hovering main menu items, it must clear hover effects
- Two submenus under each other and diagonal moving
- separator hovering removes highlight but disabled item should do the same
- better way to remove focus
- when mouse leaves context menu highlight should be removed
* Restrict cross-origin cookie auth
Block the auth probe from using ambient session cookies when a browser Origin does not match the request Host. Explicit bearer, body, and x-api-key tokens continue to work for cross-origin SDK calls.
Co-authored-by: Codex <[email protected]>
* Normalize origin checks for cookie auth
Compare normalized origins for browser cookie authentication so default ports and protocol mismatches are handled consistently. Add coverage for default-port and protocol-mismatch cases.
Co-authored-by: Codex <[email protected]>
---------
Co-authored-by: Codex <[email protected]>
xAI's Voice pricing table lists Text to Speech at $15.00 / 1M characters,
but we were charging $4.20 / 1M characters (420 microcents/char), undercharging
by ~72%. Update the cost constant, listEngines pricing, and test expectation
to 1500 microcents/char.
Adds offline XAITTSProvider.test.ts covering voice/format selection,
request shape, error paths, and cost reporting. Spies on global fetch
(the provider's egress point) against a real PuterServer + live
MeteringService.
Closes#2998
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Adds offline ElevenLabsTTSProvider.test.ts covering voice/format
selection, request shape, error paths, and cost reporting. Spies on
global fetch (the provider's egress point) against a real PuterServer
+ live MeteringService. The companion integration test stays untouched.
Closes#2999
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Adds offline OpenAITTSProvider.test.ts covering voice/format selection,
request shape, error paths, and cost reporting. Mocks the OpenAI SDK at
the module boundary against a real PuterServer + live MeteringService.
The companion integration test stays untouched.
Closes#3000
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Adds offline OpenAIVideoProvider.test.ts covering parameter mapping
(size and seconds snapping to allowed values, input_reference
forwarding), polling for queued/in_progress jobs (under fake timers),
sora-2-pro size tiers (xl/xxl per-second pricing), per-second metering
on default tier, failure handling, and error paths. Mocks the OpenAI
SDK at the module boundary against a real PuterServer + live
MeteringService.
Closes#2993
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Adds offline GeminiTTSProvider.test.ts covering voice/format selection,
request shape (transcript framing + speechConfig), error paths, and
cost reporting (token-priced input + output:audio batching, including
the PCM-to-WAV wrapping path). Mocks @google/genai at the module
boundary against a real PuterServer + live MeteringService.
Closes#2997
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Adds offline TTSDriver.test.ts covering provider selection/dispatch
(args.provider, legacy driverAlias via Context.driverName, registered
fallback), voice/format param validation, error mapping, and metering
propagation (provider failures must not bill). Mocks each provider's
SDK / fetch boundary against a real PuterServer wired with credentials
for every TTS provider.
Closes#2995
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Adds offline AWSPollyTTSProvider.test.ts covering voice/format
selection (caller-supplied, language-derived, default-per-engine
fallback), SSML handling (TextType=ssml routing), request shape to the
AWS SDK SynthesizeSpeechCommand, engine validation, error paths, and
cost reporting. Mocks @aws-sdk/client-polly at the module boundary
against a real PuterServer + live MeteringService.
Closes#2996
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Adds offline VideoGenerationDriver.test.ts covering provider
selection/dispatch (args.provider, model-id resolution across the
unified catalog, Context.driverName fallback), parameter validation
(seconds + dimension snapping to model.durationSeconds /
model.dimensions, string coercion), error mapping (provider
HttpErrors pass through, SDK errors don't bill), and metering
propagation (driver-level dispatch reaches the provider's
incrementUsage). Mocks each provider's SDK boundary against a real
PuterServer wired with credentials for every video provider.
Closes#2991
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Mocks the OpenAI SDK at the module boundary, boots a real PuterServer
for the wired MeteringService, and exercises construction (xAI base
URL, missing-key throw), model catalog (default + verbatim list),
test_mode bypass, prompt validation, the credit gate (402 before SDK),
model resolution (alias and unknown-id fallback), and the success
path covering URL/b64_json branches plus per-image metering with the
expected microcent override.
closes#2988
Mocks the OpenAI SDK at the module boundary, boots a real PuterServer
for the wired MeteringService, and covers the three model families
the provider treats differently. Exercises construction, model catalog
(dall-e-2 default + verbatim list), test_mode bypass, prompt
validation, the credit gate (402 before SDK), DALL-E request shape
(allowedRatio snap, hd-only-on-DALL-E-3, per-size metering, url and
b64_json output), gpt-image-* token-priced metering (input + output
batched line items at the model rates), and the gpt-image-2 size
normalizer (pixel-budget snap to multiples of 16, 3:1 ratio clamp,
3840 edge cap).
closes#2990
Mocks the together-ai SDK at the module boundary, boots a real
PuterServer for the wired MeteringService, and exercises construction
(missing-key throw), model catalog (default + verbatim list), test_mode
bypass, prompt validation, the credit gate (402 before SDK), all three
pricing branches (per-MP × ratio, per-image, per-tier with resolution
map rewrite), request shape (togetherai: prefix stripping, dimension
snap to multiples of 8 with min 64, optional knob clamping/forwarding,
input_image → image_base64 aliasing), and output handling for both
url/b64_json branches plus the wrapped error message.
closes#2987
Mocks @google/genai at the module boundary, boots a real PuterServer
for the wired MeteringService, and covers both the generateContent
(Flash) and generateImages (Imagen) code paths. Exercises
construction (missing-key throw), model catalog (default + verbatim
list), test_mode bypass, prompt validation, the credit gate (402
before SDK), Flash request shape (aspect ratio, allowedRatio fallback,
inlineData → base64 data URL extraction), Flash 3-line metering
(input + output:text + output:image with the IMAGE-modality token
count), Imagen routing (generateImages, per-image metering,
empty-response and rai-filtered failure modes).
closes#2989
Boots a real PuterServer with API keys for every image provider
configured (so the driver indexes them all), drives
server.drivers.aiImage directly, and mocks each provider SDK at the
module boundary so the driver's routing is exercised without real
network egress. Covers 401 without actor, 400 on unknown model,
catalog dedup + sort, list() and getReportedCosts shape, provider
routing (id-based, lowercased lookups, args.provider override,
Context.driverName fallback), ratio normalization (width/height and
aspect_ratio "w:h" forms), and the ai.log.image audit event firing
both before the upstream call and even when it fails.
closes#2984
Boots a real PuterServer for the wired MeteringService, stubs global
fetch (the provider talks to the Cloudflare REST API directly with no
SDK). Covers construction, model catalog, test_mode bypass, prompt
validation, the credit gate (402 before fetch), request shape (JSON
body, account-scoped /ai/run/<model> endpoint, apiBaseUrl override,
multipart routing for requiresMultipart models, steps clamping
[1,50]), output extraction (binary image/* → base64 data URL, JSON
envelope image with output_format → MIME, http(s) URL passthrough,
success:false 400, non-2xx 400, missing image 400), and per-scheme
cost components (tile-plus-step and flux2-klein-9b-mp split).
closes#2985
Mocks the groq-sdk at the module boundary, boots a real PuterServer
for the wired MeteringService, and exercises construction, model
catalog/resolution, request shape (max_completion_tokens rename, tools
passthrough, content blanking when paired with tool_calls), non-stream
+ streaming output (including Groq's x_groq.usage envelope deviation),
error mapping, and moderation.
closes#2977
Mocks @anthropic-ai/sdk at the module boundary, boots a real
PuterServer for the wired MeteringService/stores/FSService, and
exercises construction (long timeout for Opus 4.7 thinking), model
catalog/resolution, request shape (tool_choice locking, system message
extraction, OpenAI-shape tool_calls → Claude tool_use blocks, tool
role → user tool_result, opus-4.7 temperature drop, adaptive thinking
config, enabled budget thinking + temperature=1 for older Sonnet),
non-stream output (input/output/cache token metering), streaming via
the message_start/content_block_*/message_delta/message_stop event
graph for both text_delta and input_json_delta tool_use, and the
moderation throw.
closes#2958
Mocks the OpenAI SDK at the module boundary, boots a real PuterServer
for the wired MeteringService/stores/FSService, and exercises
construction, model catalog (responses_api_only filtering), argument
validation (messages-array gate, web_search routing — error when no
sibling, delegation when one is set), request shape (max_completion_
tokens rename, gpt-5 vs non-gpt-5 reasoning_effort/verbosity gating,
stream_options gating), non-stream + streaming output (cached-token
splitting), the moderations.create flagging branch (above and at the
0.8 threshold), and error mapping.
closes#2959
Boots a real PuterServer with an ElevenLabs apiKey configured, drives
server.drivers.aiSpeech2Speech, and stubs global fetch (the real
network egress for ElevenLabs). Covers getReportedCosts mirroring
costs.ts, argument validation (test_mode bypass, missing actor 401,
missing audio 400), the credit gate (402 before fetch), the success
path (POST URL with voice id, default + override voice/model, optional
knobs forwarded via FormData and search params, audio stream return
shape), per-second metering math, and error mapping when ElevenLabs
returns a non-2xx body.
closes#2963
Mocks the OpenAI SDK at the module boundary, boots a real PuterServer
for the wired MeteringService, and exercises construction, model
catalog/resolution, request shape (max_tokens, tools, stream_options,
DeepSeek's content-blanking and tool-result system-message workarounds),
non-stream + streaming output paths, error mapping, and moderation.
closes#2976
Mocks the together-ai SDK at the module boundary, boots a real
PuterServer for the wired MeteringService, and clears the kv-cached
model list between tests. Covers construction, model catalog (kv
caching, embedding-type filtering, alias flattening, synthetic
model-fallback-test-1), request shape (togetherai: prefix stripping,
max_tokens omission, tools/stream_options gating), model resolution,
non-stream + streaming output (with input/output cost-key remap),
error mapping, and moderation.
closes#2981
Mocks both the OpenAI SDK and axios at the module boundary, boots a
real PuterServer for the wired MeteringService, and clears the
kv-cached model list between tests. Covers construction (default and
custom apiBaseUrl), model catalog (axios fetch + kv caching, openrouter:
prefix on ids, openrouter/auto filtering), the openrouter/auto disallow
gate, request shape (prefix stripping, usage:{include:true}, stream
options, retry-without-max_tokens on context-length errors, rethrow on
unrelated errors), both cost-calculator branches (cost-bearing vs
per-token fallback) for non-stream and streaming, and moderation.
closes#2980
Mocks the OpenAI SDK at the module boundary (Gemini speaks the
OpenAI-compat dialect at the v1beta/openai endpoint), boots a real
PuterServer for the wired MeteringService, and exercises construction,
model catalog/resolution, request shape (max_completion_tokens rename,
cache_control stripping, stream_options gating), non-stream + streaming
output (cached-token splitting in the metered usage shape), error
mapping, and moderation.
closes#2961
Drops the local makeMeteringStub in favour of a live PuterServer-wired
MeteringService. The OpenAI SDK is still mocked at the module boundary
(the real network egress point); the mock now also exposes a default
export so the test server can boot every chat provider (some import
the default and read .OpenAI off it). Aligns with AGENTS.md: "Prefer
test server over mocking deps."
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
* tests: add tests for OCRDriver: [#2964]
Adds offline OCRDriver.test.ts covering both providers:
• test_mode short-circuit; argument validation (missing actor, missing
source, unknown provider, AWS/Mistral not configured)
• aws-textract: raw-bytes vs S3Object source selection (regional
client when fsEntry has a bucket), block normalisation (PAGE/WORD/
TABLE filtered, LINE/LAYOUT_TITLE → text/textract:* blocks),
402 on insufficient credits, per-page metering
• mistral: image vs PDF chunk packaging (image_url with base64 data
URL vs document_url with documentName), pass-through of pages /
annotation / image-limit options, markdown → LINE-block
normalisation with page indices, per-page metering, additional
annotations metering when bbox/document annotation formats are set
• default-provider selection (AWS preferred → Mistral fallback →
500 when neither is configured)
• getReportedCosts mirrors costs.ts
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* tests: OCRDriver uses setupTestServer + real fs/metering
Drops the manual config/clients/stores/services stub apparatus and
the loadFileInput mock in favour of the live wired driver from
server.drivers.aiOcr. The Textract and Mistral SDKs are still mocked
at the module boundary (the real network egress points); inputs go
through the real loadFileInput against real fs/store wiring (data
URLs for most cases; FSService.write produces a real fsEntry for the
PDF documentName test). Aligns with AGENTS.md: "Prefer test server
over mocking deps."
The S3Object-source/regional-client assertion was dropped because it
isn't deterministic against the in-memory S3 store and the driver's
per-region TextractClient cache leaks across tests. That branch is
better exercised by a real-cloud integration test.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
* tests: add unit tests for MoonshotProvider with mocked client: [#2979]
Adds offline MoonshotProvider.test.ts covering construction, model
resolution and aliasing, request shape (hardcoded max_tokens=1000,
stream_options gating, tool_use → tool_calls hoisting), vision-model
image-inlining hook, non-stream and streaming output, error logging
and rethrow, and metering. Existing integration test is left
untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* tests: MoonshotProvider uses setupTestServer + real metering
Drops the local makeMeteringStub in favour of a live PuterServer-wired
MeteringService. The OpenAI SDK is still mocked at the module boundary
(the real network egress point); inlineHttpImageUrls is mocked because
verifying the provider invokes it for vision-capable models is the
unit's concern. Aligns with AGENTS.md: "Prefer test server over
mocking deps."
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
* tests: add unit tests for MistralAiProvider with mocked client: [#2978]
Adds offline MistralAiProvider.test.ts covering construction, model
resolution and aliasing, request shape (camelCase maxTokens, tool_calls
→ toolCalls and tool_call_id → toolCallId rewrite, complete-vs-stream
routing), non-stream output with the camelCase usage coercion,
streaming with the chunk.data unwrap and toolCalls deviation, error
mapping, and metering. Existing integration test is left untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* tests: MistralAiProvider uses setupTestServer + real metering
Drops the local makeMeteringStub in favour of a live PuterServer-wired
MeteringService. The Mistral SDK is still mocked at the module
boundary (the real network egress point); everything else runs through
the real wired graph. Aligns with AGENTS.md: "Prefer test server over
mocking deps."
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
* tests: add unit tests for PuterAIController: [#2965]
Adds offline PuterAIController.test.ts with stubbed drivers covering:
route registration (paths and per-route auth options), app-actor
gating across all four chat-proxy routes, body validation (messages
must be an array; openaiCompletions prompt must be a string;
openaiResponses provider must be openai-responses), driver delegation
and request shaping (model + messages + provider defaults), response
shaping for OpenAI chat-completion / text-completion / Responses
envelopes and Anthropic message envelope (text + tool_use blocks),
SSE streaming with [DONE] terminator, model-listing endpoints with
hidden-id filtering and 501 when list() is unavailable, and the
HMAC-gated video proxy's input/expiry/secret guards.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* tests: PuterAIController uses setupTestServer + spy on aiChat.complete
Drops the manual driver/controller stub apparatus (makeStubDriver,
makeController, custom dep builders) in favour of the live wired
controller from server.controllers.puterAi. Each test that needs a
canned chat completion result spies on server.drivers.aiChat.complete,
which keeps the unit-of-test focused on the controller (validation,
response shape, SSE streaming) without dragging in chat-driver model
resolution and credit checks. Aligns with AGENTS.md: "Prefer test
server over mocking deps."
The "500 when URL signature secret missing" assertion was dropped —
the default config wires a secret, so the branch is unreachable in
the live test server. Replaced with the equivalent 403-on-invalid-
signature assertion which actually exercises the HMAC gate.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
* tests: add unit tests for ZAIProvider with mocked client: [#2983]
Adds offline ZAIProvider.test.ts covering construction, model
resolution and aliasing, GLM-specific request shape (custom params,
cache_control stripping, user_id derivation, stream_options gating),
non-stream output with reasoning_content normalisation, streaming
deltas (text and tool_use), error mapping, and metering. Existing
integration test is left untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* tests: ZAIProvider uses setupTestServer + real metering
Drops the local makeMeteringStub in favour of a live PuterServer-wired
MeteringService. The OpenAI SDK is still mocked at the module boundary
(the real network egress point); everything else — config, Context,
metering recording — runs through the real wired graph. Aligns with
AGENTS.md: "Prefer test server over mocking deps."
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Covers `Messages` (normalize_single_message / normalize_messages /
extract_and_remove_system_messages / extract_text), `FunctionCalling`
(normalize_json_schema / normalize_tools_object /
make_openai_tools / make_claude_tools), and `Streaming`
(AIChatStream / AIChatMessageStream / AIChatTextStream /
AIChatToolUseStream). All three are pure data transforms — Streaming
is exercised against a real `AIChatStream` wired to a buffering
Writable, so no method-level spies are needed.
Closes#2956
Covers the Puter↔OpenAI shape conversion (`process_input_messages`,
`process_input_messages_responses_api`), usage extraction
(`extractMeteredUsage`, `create_usage_calculator`), the streaming
handlers (`create_chat_stream_handler` and the responses-API variant),
and the non-stream `handle_completion_output[_responses_api]` paths
including moderation, missing-content, and per-provider deviations.
Streaming is exercised via a real `AIChatStream` wired to a buffering
Writable so no method-level spies are needed.
Closes#2955
Covers the early-return guard when the homepage service is unwired,
shell rendering at /, /settings, /dashboard, /action, /@:username,
canonical_url + meta inheritance from gui_params, /app/:name (404 +
shell, embedded app metadata, JSON / object metadata, malformed JSON),
and /show/* launching the explorer with the trimmed path.
Closes#2973
Covers the provider listing route, the auth-start redirect (404 / 400 /
500 / 302), all three callback flows (login / signup / revalidate)
including state validation, suspended accounts, unconfirmed-email
linking refusal, redirect_uri origin clamping, and the
revalidate-done landing page. Routes are collected via PuterRouter and
invoked with stubbed services that return prefab data.
Closes#2966
Covers `loadFileInput` (validation, data-URL decoding, FS-path resolution,
maxBytes enforcement, ACL gating) and `inferFilenameFromUrlOrPath`. Stubs
stores/fsService with prefab data so tests don't require a real server.
Closes#2957
Covers each config-gated branch (client_libs_root, puterjs_root,
gui_assets_root, builtin_apps) using real temp directories so the
existsSync checks see real files instead of mocked module behavior.
Asserts both registration outcomes (which routes appear, on which
subdomains) and the file resolution rules for the puter.js / puter.dev.js
fallback.
Closes#2974
Extensions listening on the `puter.signup.validate` event can now set a
`code` field (in addition to `message`) when blocking signups. The code
is forwarded through HttpError and appears in the JSON error response,
giving clients a stable, machine-readable signal to act on.
Covers both the AuthController (password signup) and OIDCService paths.
Adds tests for the new field.
In the app environment, the prompt input was initialized using `options.value`, so `defaultValue` was not reflected.
This change ensures that `defaultValue` is used when provided, while keeping backward compatibility with `options.value`.
Add a default-on email confirmation gate that rejects users with
`requires_email_confirmation && !email_confirmed` on all authenticated
routes, returning 403 with `email_confirmation_required`.
Previously this was only enforced client-side via a GUI modal, meaning
direct API calls could bypass the check entirely.
Essential routes are exempted via `allowUnconfirmed: true`:
`/whoami`, `/logout`, `/send-confirm-email`, `/confirm-email`,
`/save_account`, `/get-anticsrf-token`, `/get-gui-token`,
`/session/sync-cookie`, `/auth/revoke-session`,
`/user-protected/delete-own-user`
No impact on temp users (`requires_email_confirmation` is false),
self-hosted deployments without email (flag is never set), or
unauthenticated routes (login, signup, password recovery, OIDC).
Co-authored-by: Claude Opus 4.6 <[email protected]>
- Add XAITTSProvider calling POST /v1/tts with 5 voices (eve, ara, rex,
sal, leo), speech tags, and configurable output format
- Add XAISpeechToTextDriver calling POST /v1/stt with support for
diarization, multichannel, text formatting, and xAI's native URL
param for remote audio files
- Register both providers in TTSDriver and driver index using existing
xAI API key from config
- Update puter.js client to route provider:'xai' for both txt2speech
and speech2txt, including listVoices/listEngines
- Add TypeScript types for new STT options (provider, format, diarize,
multichannel, etc.)
- Update txt2speech.md and speech2txt.md with xAI options and examples
- Add playground examples for both TTS and STT
Cost metering:
TTS: 420 microcents/char ($4.20/1M chars)
STT: 2778 microcents/sec ($0.10/hr)
Introduce a new Gemini TTS provider and wire it through the driver, client, docs, and examples. Adds src/backend/drivers/ai-tts/providers/gemini/GeminiTTSProvider.ts (Google GenAI client usage, PCM->WAV wrapping, metering, model/voice validation) and a costs table in providers/gemini/costs.ts. Registers the provider in TTSDriver, exposes the alias gemini-tts, and prefers it in provider selection. Updates puter-js client to recognize "gemini" provider/engine and route driver calls to gemini-tts. Documentation updated with Gemini options, a usage example, and a playground example HTML file.
* Remove gross retarded legacy tools and docs
* Remove tools scripts
* nuke the bs
* Remove contributor/self-hosting docs, update license
* Remove src/useapi package and update configs
* remove source map files
* Remove wiki submodule
* ok not everything is retarded, for example this one (v86) is cool but has to go for now
* Remove puter-wisp module
* Remove install.md
* Remove twisp submodule
* Remove epoxy-tls submodule
Remove the epoxy-tls submodule and its configuration: delete the gitlink at submodules/epoxy-tls and remove the corresponding entry from .gitmodules.
* Fixing issues with mobile contextMenu in puter env app where user couldn't tap on menu items and there was checkmark in wrong place
* context menu mobile version - handle submenus
* context menu mobile icon placement tweak
* Web Components for Puter SDK UI API
* Rest of the components
* component docs
* Revert file and directory picker changes
* style matching with puter.com and support for custom styling
* item divider style tweak
* Puter JS - Web Components tweaking
* alert default image fix
* context menu mobile style fix
* Fix app iframe height when app is in fullpage mode and has puter-js menubar
* menubar web component tweak
* Action sheet behavior for contextmenu on mobile also in env app
* replace alert icons
* context menu and menubar keyboard navigation, submenu mouse navigation improvements
* package-lock
* Improve submenu mouse hovering
Make the DB update in AppES awaitable so the write completes before proceeding (avoids race conditions). Also add invalidation of the Redis object key for the app UID in AppInformationService to ensure cached entries keyed by uid are cleared after updates.
When the Start button is clicked while the popover is already open,
close it instead of doing nothing. This fixes the toggle behavior
on Android Chrome where the menu stays open on repeated taps.
The `.popover-launcher` removal triggers the UIPopover remove event
handler which automatically cleans up the `has-open-popover` class.
Fixes#1681
* Consistent header with files
* custom order with draggable app icons
* mobile style tweak
* Drag apps to sidebar
* uninstall
* Add desktop switch button to home tab
Drag sidebar apps order
* Display app storage use in Usage tab
* Add context menu options to apps: open in new tab, open in window
* Sidebar apps section with taskbar/dock behavior
* add close button to sidebar app item
* prevent dashboard files items from being selected when dragging
* File contextmenu shows filename
Keep dashboard URL when opening items
* Fixed issue with mobile selecting
* sidebar toggling
* sidebar tooltips
* done!
* Files tab statusbar width fix
* Consistent header with files
* custom order with draggable app icons
* mobile style tweak
* Drag apps to sidebar
* uninstall
* Add desktop switch button to home tab
Drag sidebar apps order
* Display app storage use in Usage tab
* Add context menu options to apps: open in new tab, open in window
* Sidebar apps section with taskbar/dock behavior
* add close button to sidebar app item
* prevent dashboard files items from being selected when dragging
* File contextmenu shows filename
Keep dashboard URL when opening items
* Fixed issue with mobile selecting
* sidebar toggling
* sidebar tooltips
* done!
* Files tab statusbar width fix
* Remove desktop switch button from Home tab
* App uninstall fix
* mobile style tweaks for dashboard sidebar
* Usage tab header fixes
* style tweaks
* Disable Uninstall for certain system apps
* Use app title in uninstall modal
* Remove delete-data option from uninstall modal
* Update dashboard.css
* Update TabApps.js
---------
Co-authored-by: jelveh <[email protected]>
Remove the alpha notice banner and spacer from Peer documentation pages (Peer.md, connect.md, ensureTurnRelays.md, connect.md, serve.md). This updates the docs to stop advertising the Peer API as alpha and cleans up redundant banner markup.
When reload_on_success is set, use '/' as the fallback redirect URL instead of the current page (window.location.href). This prevents redirecting back to the signup page after a successful signup while preserving any explicit options.redirect_url value.
Move @esbuild/linux-x64 from dependencies to optionalDependencies in src/docs/package.json so the platform-specific esbuild binary is treated as optional. Update package-lock.json to reflect that change (adds platform-specific @esbuild entries, marks various packages as peer/optional, bumps @emnapi/wasi-threads to 1.2.1 and removes obsolete @emnapi core/runtime entries).
Do not unconditionally overwrite window.disable_temp_users during GUI init. If window.disable_temp_users is already set, keep it; otherwise fall back to options.disable_temp_users (or false). Added a clarifying comment explaining the behavior.
* Add kv.list() pagination playground example
Create an interactive playground example for kv.list() that
demonstrates cursor-based pagination with sample data (6 items,
2 per page). Also wire the pagination docs example to the playground
by changing the code fence from plain html to html;kv-list.
Fixes#2755
* fix: address review feedback - restore code example, create new pagination playground
* minor refactor
---------
Co-authored-by: Reynaldi Chernando <[email protected]>
* docs(kv): add sorting section with examples to list() API reference
Added sorting section with examples for lexicographic order and zero-padding for numbers.
* docs(kv): add sorting note to list() description
* feat(playground): add kv-list-sort example
* feat(playground): add kv-list-padding.html
* add Sorting examples to kv list on doc/src/examples.js
* docs(kv): add sorting examples to list.md examples section
* Refine copy and code example
* remove extra newline
---------
Co-authored-by: Reynaldi Chernando <[email protected]>
* Map context_length for OpenRouter models
OpenRouter's API returns context_length for each model, but it was not
being mapped to the context field in the model list response. This
caused the context window size to be missing for all OpenRouter models.
Closes#2347
* Add context field to MistralAI and OpenAI model definitions
Addresses reviewer feedback to support the context field in more
providers. All 9 providers now consistently expose context window
sizes via the context field.
- MistralAI: 16 models (context matches known window sizes)
- OpenAI: 27 models (128k for GPT series, 200k for o-series,
1M+ for GPT-4.1 and GPT-5.4)
Bump the .dashboard-sidebar width from 200px to 250px to provide more room for navigation items and improve layout spacing. min-width, background, and border styles remain unchanged.
* Display logged-in banner on homepage
Pass auth_user from the router into PuterHomepageService and show a logged-in banner when a user is present. _default.js now includes auth_user in the svc_puterHomepage.send call. PuterHomepageService.send signature was updated to accept auth_user; the service stores logged_in_user, forwards it to generate_puter_page_html, and injects a styled "Logged in as <username>" banner into the top of the page when available. This surfaces the current user on the GUI and exposes logged_in_user to page generation and addons.
* Include request path and logged in user in GUI params; remove banner
* fix: bad auth_user check for homepage
---------
Co-authored-by: Daniel Salazar <[email protected]>
Prevent a visual flash by hiding the apps grid until all app icons have loaded. Adds revealWhenLoaded($container) which removes the myapps-grid-loading class when images finish (or error). TabApps now caches the .myapps-container lookup and calls revealWhenLoaded after initial render, after search results, and after loading installed apps. CSS changes: add .myapps-grid-loading (opacity:0 + transition) and a small padding-right tweak for the search input.
Fetch both the installedApps and get-launch-apps endpoints in parallel, normalize recommended + recent launch items, and merge them with installed apps while deduplicating by name (launch items are prioritized). Update this._apps and render the combined list. Also simplify the app tile icon styling by removing border-radius and box-shadow for a flatter icon appearance. Error handling for failed loads is preserved.
Add /css/dashboard.css to the GUI asset lists so dashboard styles are served and bundled. Updated src/gui/puter-gui.json and src/gui/src/static-assets.js to include the new stylesheet.
* feat: add Anthropic Messages API compatibility layer
Add a new endpoint at /puterai/anthropic/v1/messages that implements the
Anthropic Messages API wire format, allowing clients using the Anthropic
SDK to point directly at Puter.
- New router translates between Anthropic format and Puter's internal
svcAiChat.complete() pipeline
- Supports non-streaming, SSE streaming (proper Anthropic event sequence),
and tool use round-trips
- Translates system field, tool definitions (input_schema -> parameters),
and tool_result content blocks
- Integration tests covering non-streaming, streaming, tool use,
Anthropic SDK compatibility, and system parameter
Closes#2554
* Fix authentication middleware
---------
Co-authored-by: ProgrammerIn-wonderland <[email protected]>
Prevent creating temporary users on unauthenticated first visits when the current action is the login or signup flow. The initgui else-if was expanded to include explicit checks for action !== 'login' and action !== 'signup', avoiding interference with explicit authentication routes and Turnstile challenges.
Use a single expression to derive the plan key (offering.name or 'free') and pass it to i18n when updating .bento-plan-name. This removes the previous ternary and duplicates, allowing dynamic offering names to be localized consistently.
Add missing English translations for plan tiers (free, basic, professional, business) to src/gui/src/i18n/translations/en.js and perform a minor formatting cleanup near billing messages to ensure keys are available for UI display.
Update TabHome to read the plan name from subscription.offering.name instead of subscription.plan_name. This adapts to the updated subscription object shape while keeping the fallback to the 'pro' translation and the 'free' label when no active subscription exists.
The taskbar uses position:fixed with bottom:5px, which gets hidden
behind the iOS Safari bottom toolbar on devices with home indicators.
Use env(safe-area-inset-bottom) to push the dock above the safe area.
The viewport-fit=cover meta tag is already present in initgui.js.
Fixes#2517
* fix: tighten up cors for socket io
* fix: allow socket io to push to rooms in redis
* fix: various socket io issues to improve cross session stability
Update check for suspended users on change_emeail and user-protected
endpoints. The `change_email` endpoint isn't using the auth middleware
because it infers from the token that was passed - this means it needs
explicit logic to check suspended users; before suspended users were
able to complete a a flow for changing their username if they already
started it before being suspended.
Update user-protected endpoints and configurable_auth so endpoints that
make sensitive account changes do not rely on cached information about a
user.
Introduce a new i18n key `add_to_desktop` with value 'Add to Desktop' to the English translations file. This provides a label for UI actions that add items or apps to the desktop.
* chore: upgrade git-date (used for release notes generator)
* chore: update vitest, vitest plugins, and svgo
* chore: run `npm audit fix`
* chore: run `npm audit --force`
* meta: empty commit to run git tests
* fix: tests gone because of a... syntax error?
I question GitHub's judgement of handling a syntax error in the file
that defines tests to run on PRs by pretending everything is fine and
passing all PRs. That to me seems like the worst possible way to handle
that. I think they should have done it not like that.
When a global ClickHouse client is available, run two parallel ClickHouse queries (JSONEachRow) to fetch per-app open_count and distinct user_count, parse results into Maps (parsing counts as integers). If ClickHouse is not present, fall back to the original MySQL aggregate queries. Apps list still comes from MySQL as before. This enables using ClickHouse for analytics performance while preserving the existing behavior as a fallback.
* fix: only set authToken if present for apps
* fix: keep bootstrap in url for app to do whatever
* fix: tests
* fix: app merging
just cleaning up how merging subdomain and canon apps work, namely, persisting data better and making sure its temp alias are deleted when appropriate
* fix: tests oom
Usage example:
const b = new puter.fs.Batch();
b.move('file_1.txt', '~/Trash');
b.move('file_2.txt', '~/Trash');
await b.end();
Chaining is also supported:
await new puter.fs.Batch()
.move('file_1.txt', '~/Trash')
.move('file_2.txt', '~/Trash')
.end();
This commit provides `move` and `delete` methods for Batch.
* feat: scope index_url uniqueness to hosted domains
Allows duplicate non-hosted origins while enforcing hosted-origin uniqueness and joining new app creation into an existing owner-matching hosted app UUID.
Restricts hosted index_url joins to unowned conflict apps, persists old-to-canonical app UID aliases in kvstore via sudo, and resolves aliases on read with parallel lookup to minimize latency.
* fix: allow merge for owned origin bootstrap apps
Restores hosted update/create merge when the conflicting app is the same-user auto-created origin bootstrap app while still blocking merges into normal same-owner apps to avoid multi-join behavior.
Adds non-blocking public hosted actor cookie mint/verify flow for non-private apps, sets actor context when available, and includes focused middleware/auth tests for security and performance-sensitive paths.
Adds an extension that presents an unauthenticated page for testing
various actions of Puter when it's under development. This action is
only meant to be used in development and is not loaded by default.
* feat: phase 2 enforce index url ownership and uniqueness
Adds write-time index URL uniqueness checks, expands hosted subdomain ownership enforcement to private hosting domains, and updates AppService tests for duplicate-index behavior.
* test: align app service comp fixtures with index url uniqueness
Updates regression test fixtures that intentionally exercise name conflicts and selection paths to use unique index_url values under the new one-index-per-app constraint.
* fix: exempt placeholder index url from uniqueness checks
Skips index_url uniqueness enforcement for the shared dev-center coming-soon URL in both AppService and AppES, and adds unit/comp regressions to keep one-index-per-app behavior for all other URLs.
Set reload_on_success explicitly when invoking UIWindowLogin so the UI does not trigger a page reload if the GUI is embedded in a popup. Previously the call forwarded a reload_on_success variable; now it uses !window.embedded_in_popup to prevent unwanted reloads in popup embeds.
* Revert "dev(oidc): hide unnecessary div"
This reverts commit 468558f8dc.
* fix(oidc): remove the "You will be asked to..." box properly
Earlier this was removed with a simple `display: none` in CSS to avoid
changing any logic, and the reason for that was OIDC had already gone
through significant testing, re-testing, and bug fixes; it became clear
that changes to the auth flow are fragile and the test surface is very
large. Now unfortunately what seemed like a smart decision to fix a
cosmetic issue with CSS instead of updating logic actually wound up
breaking the change username/password flow for non-OIDC users. This
commit removes this box properly and hopefully does not introduce a
subsequent terrible bug. Why would it? There's absolutely no reason I
can see that it would, but it would seem that nothing is safe, not even
CSS.
* temp: disable LRU cache of homepage for now
This is working fine but we're disabling it temporarily so we can test
specific future changes in isolation without managing two separate
branches.
* fix: put verify password text in the box
There's always something...
LRU cache the output of PuterHomepageService with a cache key based on
metadata that affects the output of the homepage (if an app was
specified, and if so what app was specified).
With this change in place we can afford more time processing this
output, for example to minify the output and reduce outbound bandwidth.
* add configurable GUI bundle
* also support CSS and puterjs custom location
* simplify ternary
* used bundled instead of use_bundled_gui
* Quote the string
* close script tag
* feat: phase 1 canonical app origin resolution
Adds cache-first canonical app uid resolution for origin-based auth flows with oldest-app selection and deterministic fallback, plus regression tests for hosted/non-hosted canonicalization behavior.
* refactor: use kv singleton for origin local cache
Replaces AuthService app-origin local canonicalization Map cache with kvjs singleton keys, applies TTL via EX on writes, and rotates local cache namespace on version bumps to avoid broad clears.
* refactor: target origin cache invalidation
Removes global app-origin cache version bumps and invalidates canonical origin cache entries by affected app index URLs from app.changed payloads. Also emits app and old_app data on update events for targeted invalidation.
* fix: avoid invalid old_app owner field in app change event
Removes owner_user_id access from AppES old_entity event payload because the entity model does not expose that property, fixing AppService comp upsert regression tests.
Convert newline characters in email reason text to <br /> tags and ensure proper escaping. Replaced {{reason}} with {{{nl2br reason}}} in the rejection template and registered an nl2br Handlebars helper that escapes HTML entities, transforms newlines to <br /> and returns a SafeString so line breaks render correctly in emails.
Each of these methods is only being called by get_app_icon_url. By
changing that ternary operator into an `if` block with an early return
we can move the bodies of these functions here. If one of the former
functions ever needs to be used in more than one place, it's easy to
extract it out of here agian - for now though let's not pay the cost of
jumping to another function definition while trying to understand this
code if we're not gaining anything from it.
* style(puterfs): update adherence to linter rules
* fix(puterfs): await queue items for fsentry actions
This will ensure some operations always function as expected in a
sequence, although it may incur some performance costs.
* dev(apps): add configuration to not use app icon subdomain
For some local configurations of Puter, such as using ngrok or a hosting
service that has limited subdomains or limited subdomain depth, the
static hosting subdomain for app icons is difficult to configure and may
not be viable. Since this is only done so an external geo-replicated
cache can be used, and it's always possible for Puter's backend to
generate an app icon, it should be possible to configure Puter's backend
to use icons from a URL hosted on the default subdomain.
Add a configuration parameter to the service "app-icon" called
"no_subdomain" which prevents Puter's backend from sending puter-icons
subdomain URLs or redirecting to them.
Also perform some small cleanup changes to make the existing code easier
to understand, including:
- rename `buildAppIconUrl` to `buildAppIconSubdomainUrl` to make it
clear which of the two types of icon URLs are being generated.
- replace `withAppIconUrl` with `get_app_icon_url` so it is possible to
get an icon URL without mutating an app object.
- make the `get_taskbar_items` helper use the same code for getting app
icons as the `get_apps` helper.
* fix(apps): test initializes a service with no config
The request object was not being passed to OIDC signup because it is
called by createUserFromOIDC which doesn't take a request object as a
parameter. It was decided to have `create_user` take the request object
from context if it's not specified rather than change the signature of
createUserFromOIDC.
I decided not to remove it because I really don't want to introduce a
bug right now while everything is finally working smoothly... I'm making
a note to properly clean this up later when it can be more easily tested
in isolation from everything else.
It turns out there are nuances between `puter.ui.authenticateWithPuter`
vs `puter.auth.signIn` - these don't do the same thing. The primary
difference is that `puter.ui.authenticateWithPuter` will display an
override if it's not triggered by a user action, whereas
`puter.auth.signIn` will not. This definitely suggests
`puter.ui.authenticateWithPuter` should be a caller of
`puter.auth.signIn` instead of implementing its own logic for handling
the popup - that makes this part of the code more fagile - but that
refactor is out-of-scope for this bug fix.
* feat: resolve private app hosts by index_url fallback
Adds a private-app lookup fallback for hosted subdomains without associated_app_id by matching owner-scoped index_url candidates built from request host and configured protocol.
* fix: redirect path
* fix: add new domains too
* fix, bootstrap url
* fix: bootstrap url
* fix: auto sign in puter pirvate app
* Fix: When a maximized window gets resized, Puter apps should be resized as well
* Fix maximixed selector to match any window with data-is_maximized (not just apps)
For convenience, switch flow if the user's action doesn't match the
system state when signing up or logging in with Google:
- If the user chooses "signup" but they already have an account, log
them into that account.
- If the user chooses "login" but they do not have an account yet,
create an account where their authenticated email address.
Adds a config flag to disable private app gate enforcement, structured middleware audit logs for private access decisions, and regression coverage for the disabled-gate path.
When a rate-limit scope is not configured, use a default configuration
instead of throwing an error. Display a warning about the unconfigured
rate-limit scope when the default is used.
* fix: disable broadcast for cache invalidation
* fix: remove broadcast for redis events for now
* fix: don't await cache invalidation for grant app permission
Fixes an error introduced in 4b8c46e where the page load is attempted to
be triggered by dispatching the login event, however the listener which
handles loading the page has not yet been registered.
* fix(oidc): OIDC login with puter.js popup auth
Bring login through OpenID Connect to a working state in the puter.js
popup authentication flow. This allows OIDC login to work with
third-party websites and apps.
* fix(oidc): error handling, use const (initgui)
Remove a condition that can be handled by the control flow logic
already implied by a try...catch, which also allows a variable to become
const, and log errors in this catch block.
* doc(oidc): make this comment a little more helpful
* clean(oidc): remove out-of-scope puter.js change
Remove a change that gives explicit overrides of the `defaultGUIOrigin`
paramter precedence over other sources of this value. This was necessary
when testing but might not be the correct fix for this issue.
Await the window.update_auth_data call in initgui.js so subsequent logic (such as popup spinner hiding and timing) runs after authentication data has been updated. This prevents race conditions where later UI code executes before auth state is fully applied.
Read user preference keys (show_hidden_files, language, clock_visible) into local variables with try/catch and sensible defaults, instead of fetching/parsing them inline. This prevents exceptions from missing or malformed KV entries and centralizes parsing for show_hidden_files. Also remove an extra blank line in initgui.js's AJAX complete callback.
Redirect to the login or signup page when there is an error signing in
or creating an account using OIDC, instead of displaying the error on a
new page. Alter the flow in cases where the suggested action is not the
same as the initial action taken by the user (based on the error case).
* fix nano banana pro pricing and resolutions
* move gemini resolution map into models.ts
* require gemini 3 model for specific resolution and price logic
* fix usageamount for mp models
UIItem makes a recursive call when there are multiple matching elements
in the `options.appendTo` argument. When calling recursively, the
`appendTo` property of the `options` object is mutated to a specific
element before the call, which expects that each call to UIItem occurs
synchronously. UIItem was made asynchronous by
9d598f7965
which resulted in a bug causing duplicate item icons in one directory
window instead of one item icon in each directory window after a file
upload when multiple instances of a window at the same directory
location exist.
Resolves#2514
we saw some errors with icons not allowed when being objects, this likely user error, but this adds some validation to at least avoid nulls being flagged wrong
* fix: allow healthcheck from other hosts
* fix: don't await for cache writes
we think some awaiting on redis writes was causing issues, we shouldn't need to await really, so removing now. will have optimistic caching for these
some style changes from a recently changed rule that seems to clash with prior one
Fixed: The gradient and progress bar on the usage details page is not very pleasant and looks inverted
Fixed: The billing card on the billing tab is still light mode
This code was previously lost because I edited `outcomeutil.js` instead
of `outcomeutil.ts`. We're not building into a `dist/` directory and
`tsc` has a most peculiar lack of generating a comment at the top of
output files stating something like "// GENERATED - DO NOT EDIT" as I've
seen from every other code generator or transpiler I've worked with.
This caused the bug with duplicate confirmed emails and "account not
found" during testing on the staging server.
I forgot that our transpile tooling requires manually gitignoring
individual javascript files because we don't actually create a full
generated build of backend.
During development a property named `success` was inverted to a property
named `failed` which resulted in an incorrect accessor reference with a
referring piece of code that wasn't updated. This is type error.
In lieu of knowing exactly what happened (probably more than one thing),
the "Disable 2FA" window was very broken. It was blank, but then after
fixing that all the actions were broken. There wasn't much value in
keeping the implementation though, because it was already inconsistent
with other flows - instead of fixing what was there it made more sense
to re-use the pattern of UIWindowChangeUsername and UIWindowChangeEmail,
creating UIWindowDisable2FA. After testing this, it works much better
(it actaully works), but there is a caching issue unrelated to the UI
implementation.
A component was removed and an html property was passed to
UIComponentWindow. This makes sense because UIWindow accepts an html
property, so rather than update the calling code it made more sense to
update UIComponentWindow to be more intuitive.
This button was useful during manual testing, but the re-authentication
flow for protected endpoints with OIDC users reliably invokes the popup,
so this is no longer necessary. Removing this button reduces clutter on
these screens and might make the flow easier for users to understand.
In implementing OIDC it became necessary to introduce the separation of
"GUI Tokens" and "Session Tokens". This breaks QR login because Puter
does not set the HTTP-only session cookie when logging in with this
flow.
Add a middelware to WebServerService to detect QR Code logins and set
the appropriate HTTP-only session cookie.
Use the openRevalidatePopup function in util/openid.js within
UIWindowChangePassword instead of re-implementing that functionality.
Additionally, normalize some of the code so it is more similar to
UIWindowChangeUsername and UIWindowChangePassword.
There is common functionality between all of the GUI code for actions on
protected endpoints. Update UIWindowChangeEmail and
UIWindowChangeUsername to both use a new utility function called
openRevalidatePopup in util/openid.js.
This file is called `openid.js` instead of `oidc.js` so that it's more
easily recognized by contributors who might be more familiar with the
name of the organization than the name of the standard itself.
After these changes, UIWindowChangePassword and the "disable 2FA" button
in UITabSecurity still need to be updated to use `util/openid.js`
instead of duplicating this functionality.
The justification for following DRY here instead of leaving the
implementation as-is is because these flows are particularly error
prone and will be difficult to maintain without this consistency. Some
subtle bugs I previously wasn't aware of got fixed in the process.
The OIDC re-authentication flow, which replaces password confirmation
for accounts that were created with OIDC and do not have a password, was
previously added to "change username" for manual testing of the
backend-side implementation. Add the re-authentication flow to the
remaining user-protected endpoints, which are:
- change password
- change email
- disable two-factor authentication
When using "change password" on a new account created via OIDC, the
account changes state to a passworded account which causes these flows
to use password confirmation as before instead of re-authentication.
The monthly number of username changes was hardcoded as `2`. Being able
to configure this value makes it easier to test the username change
flow. Hosters of OSS Puter may also find this configuration beneficial.
When users make sensitive changes to their account they are asked to
re-enter their password. This prevents a hijacked session from causing
futher damage.
Users created with the new OIDC flow do not necessarily have a password
set on their account, and they need to also be able to make these
changes. While removal of the password entry requirement for these users
would solve this problem, it would also make their accounts more
vulnerable. To solve this problem while maintaining the same security
standard for OIDC users, we need them to confirm via either 2FA or
re-authentication via OIDC. Since users aren't required to have 2FA, the
re-authentication via OIDC approach is also the minimum viable solution.
This commit adds OIDC re-authentication support for all endpoints under
UserProtectedEndpointsService, and makes updates to the
UIWindowChangeUsername dialog for manual testing.
Currently this implementation fails at the final submission to change
the username because of a separate issue with the correct authentication
token not being set; this is related to the separation of GUI tokens vs
http-only tokens.
This commit is rather monolithic. An attempt to split it up into smaller
changes proved too difficult (as well as frustrating) and I realized it
would absolutely increase the chance of having a broken commit (making
bisects more difficult) unless a lot of testing effort between commits
was performed, which would have very little benefit.
The changes in this commit include:
- Outcome utility used by SignupService for error handling
- SignupService, whichs implements re-usable create_user function
- Signup method in OIDCService
- flow-specific callbacks in OIDC (separates login from signup)
- **SEPARATE SESSION COOKIE AND GUI COOKIE**
- this change "rocks the boat" the most and has the highest likelihood
of causing problems
* Fixed issues where file list wasn't scrollable on mobile device, and tap'n'hold on file opened wrong context menu.
* Fixes text color of selected row
- [x] Fixes path navigation button transitions
- [x] Fixes path navigation button colors
- [x] Hide AppData folder
- [x] Hide hidden files
Fix ESM/CJS interop issue in unit tests with a hack that checks the
class name as a string instead of just doing an `instanceof` check. This
is assuming that the "rewriter must be a PermissionRewriter" error I'm
seeing on GitHub is because there are two different "copies" of
PermissionWriter due to ESM/CJS interop issues. If this is not the case,
then you're not reading this commit message on `main`; if this commit is
on `main` then that's exactly what went down.
Add the ability to request an app's root directory. A permission
rewriter is provided so that apps may refer to a permission when
requesting this access without knowing the path of the app's root
directory.
* Dashboard - Added files tab with basic folder and files listing.
* clearing out some linter errors
* Removed Public folder for now
* Added "modified" column
Subfolder are listed before the files
* Dashboard - files tab: context menu basics
* Dashboard - Files tab: subfolders can be opened. Items can be opened from more-menu or by double clicking on them
* Dashboard - Files tab: use UIContentMenu instead of custom menu for "more menu"
* Dashboard - Files tab: Delete implemented, Trash folder added
* refactored context menu rendering
* Implemented UIItem context menu functionalities
Added path
* Rename files and folders
* Rename fix
* tweaks and fixes
* WIP: Multiple selection, drag and drop, trash folder improvements
* clean
* Files handling improvements
* empty trash fix
* grid view
* grid view improvements
* update icons
context menu for multiple items shows file counts such as: Delete (9)
* Path navifation buttons
* better way to get user's directories
* Added icons for various file types
* Use puter.kv instead of window.user_preferences
* sorting and column resizing
* documentation of the functions
* Style update. Dashboard colors now as CSS variables
* refactored restoring from trash and emptying trash with proper callbacks & refreshing
* select documents folder by default
style tweaking
* Drag to select files and folders
* dark mode
* style tweaks
* removed some dead code..
* Keyboard shortcuts (copied from UIWindow - untested & in progress)
* Add drag-and-drop file upload support to Dashboard
Implement native file drag-and-drop from local filesystem to Dashboard:
- Add dragster handlers for main content area, sidebar folders, and folder rows
- Create uploadFiles() method with progress modal and directory refresh
- Add visual feedback CSS for drop zones (highlight on hover)
- Fix subfolder drop detection to prevent duplicate uploads
- Add callback support to unzipItem/untarItem for directory refresh
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* style tweaks
* Fix cut/paste functionality in Dashboard
The cut operation was storing clipboard items as plain path strings, but
window.move_clipboard_items() looks for .item DOM elements which don't
exist in Dashboard (it uses .row elements). Added a Dashboard-specific
moveClipboardItems() method that calls puter.fs.move() directly with UIDs,
and updated cut to store objects with path and uid like copy does.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Add mobile phone layout optimizations for Dashboard
- Add responsive CSS for screens ≤480px with two-row file list layout
- Wrap item-size and item-modified in item-metadata div for mobile grid
- Hide directories sidebar on mobile (use breadcrumbs for navigation)
- Reorganize header with breadcrumbs on top row, nav buttons below
- Add single-tap to open folders on touch devices
- Fix context menu "Open" action in Dashboard by adding onOpen callback
- Hide column headers on mobile since metadata is shown per-item
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Add CSS variables to Dashboard bento elements for dark mode support
Replace hardcoded color values with CSS custom properties throughout
the bento card components to enable proper dark mode theming. Adds new
variables for icon shadows, fancy headers, gradients, and usage bars
with appropriate values for both light and dark color schemes.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Add spacebar image preview feature to Dashboard Files
Pressing spacebar on a selected image file now shows a full-size preview
popover centered over the files container. Features include:
- Toggle behavior: press spacebar again to close
- Auto-switch: selecting another file updates the preview
- Click outside to dismiss
- Works in both grid and list view
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Add floating action bar for multi-file selection in Dashboard Files
When 2+ files are selected, a floating action bar appears above the footer
with quick access buttons for common operations:
- Download, Cut, Copy, Delete for normal files
- Restore and Delete Permanently for items in Trash
The bar slides up with a smooth animation and disappears when clicking
the background to deselect. Includes mobile-responsive styling with
icon-only buttons on smaller screens.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Add mobile select mode for multi-file selection in Dashboard Files
On mobile devices, users can now tap a select button in the path actions
to enter select mode. In this mode, tapping files toggles their selection
instead of opening them, with checkboxes appearing next to each item.
The floating action bar appears with 1+ selected items (vs 2+ on desktop)
and includes a Done button to exit select mode.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Center empty directory message in Dashboard Files
Replace row-based layout with centered flex positioning for the
"No files in this directory" message, improving visual presentation.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Fixed issue where clicking on files background created blue dot (drag rectangle selection bug)
* Image preview size tweak
* Add URL-based routing to Dashboard with hash fragments
Enable shareable/bookmarkable URLs for Dashboard tabs and file paths.
The URL hash reflects current location (e.g., #files/username/Documents,
#usage, #account). Browser back/forward navigation now works for folder
navigation, and direct URL entry loads the correct tab and path.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* fixing draggable styles
* drag clone fixes
* Add smart column resizing and filename truncation to Dashboard Files
- Add middle-truncation for filenames preserving extensions (e.g., "longfile…name.txt")
- Double-click column resize handles to auto-fit content width
- Reset saved column widths to defaults if they don't fit smaller screens
- Apply truncation to both list and grid views
Co-Authored-By: Claude Opus 4.5 <[email protected]>
* Separated dashboard styles into dashboard.css and loading it dynamically only when navigating to /dashboard
* Files and folders can be dropped over path items in order to move them. This is useful when you want to move items into parent folders.
* Use custom context menu component for item-more menu on mobile devices
* Created callback system to undo_last_action so that dashboard file list would always refresh after undo operation
* gray update
* hovering folder while dragging items opens the folder
* Fixed issue with hover-dropping
* Fixed chained drag-over-folder-and-hover system
* dark mode tweak
* - [x] Right clicking on background of an empty folder doesn't trigger context menu
- [x] Right clicking on path should keep path item active
- [x] Sidebar folder don't have context menu
- [x] Drag item should be opaque so I can see through it
- [x] Transition animation issue when hovering path action buttons
- [x] Double clicking on column resizer: add padding
- [x] Load dashboard.css before loading the page content
- [x] Mobile: opening menu, clicking outside menu should close it
- [x] Mobile: on smaller screen there should be still two columns
- [x] Mobile: file name truncation in grid view doesn't work
* Added missing badges
* WIP has_worker
* display worker icon on the .js files which are workers
* Display worker badge on worker files, hovering badge shows worker URL.
Worker URL added to file properties modal.
* disable "publish as website" from context menu for folders that are already published
* Loading spinner for Files
* tweaks and fixes
* Files clean loading spinner
* Files: worker URL in the properties modal is clickable link
* use custom tooltip to display worker URL
* refactored renderDirectory
* Fix Sidebar folder highlighting
* add Beta badge on Files tab
* Implemeting socket based item updating
* Put newly added items into the position where they would land when list is sorted
* restore from trash refresh fix
* Revert "Revert "Adds worker badge to .js files which have been registered as workers. Hovering badge shows popover with worker URL. File properties modal also shows clickable worker URL. (#2462)""
This reverts commit c2750f2ca1.
* worker in stat
* update puterjs and frontend code to support returnWorkers in stat
* Better way of handling worker info
* Fixed issue where right clicking on background opened two instances of a context menu
* Fixes issue where while renaming a file, double clicking on word opened the file
* fixes issue where while dragging multiple items the top-most item was transparent resulting blurry mess
* when opening a folder, update view instantly
* Improved drag-to-select items
* Added feature where typing selects matching file items
Fixed issue where keyboard listener for file list was active when context menu was open
* Fixed issues with File -> New in context menu
Fixes issue where files-selection-actions menu didn't disappear after deleting items
* Improved drag to select behavior
Improved drag items
Improved worker badge handling
* Cancel zone for dragging items (when spring-loading subfolders)
* context menu's submenu tweak
* Fixed issue where resizing window didn't work (when using "Open in New Window" from context menu)
* Disabled buttons on .files-selection-actions while drag-to-select is happening
* Fixes issue where creating new items using right-clicking re-rendered the directory view
---------
Co-authored-by: Claude Opus 4.5 <[email protected]>
Co-authored-by: ProgrammerIn-wonderland <[email protected]>
Handle upgrade flow when running in the app environment by calling await puter.ui.requestUpgrade() in driverCall_. Added app-specific branches in two places where usage/insufficient-funds were previously handled only for web (which showed a web dialog). This ensures the in-app UI is used for upgrade requests and awaits the result.
Temporarily comment out code in UIWindowPublishWorker that updates item UI after publishing: hiding the lines that show the item website badge, show per-item website-url badges, and set the data-website_url attribute. This prevents the publish worker from automatically modifying those DOM elements/attributes (kept commented for potential rollback or debugging).
* add sandboxing by default in god mode workers
* closes#2481
* Update UIWindowPublishWorker.js
* Add sandbox option to worker publish UI
Add a collapsible 'Advanced' section with a 'Sandboxed' checkbox (checked by default) to UIWindowPublishWorker. On publish the code reads the checkbox state and builds createOptions ({ sandbox: true } or { sandbox: false }) and passes it to puter.workers.create as an argument so workers can be created in sandboxed or non-sandboxed mode. Small UI styling and markup for the details/summary block included.
---------
Co-authored-by: jelveh <[email protected]>
* [PUT-471] feat: estimate and bill input for gemini imgaes :dev:
* [PUT-472] add input/output costs to openai image models too
* npm version bump
* remove second url log
* fix gemini pro image
---------
Co-authored-by: ProgrammerIn-wonderland <[email protected]>
For reasons still unknown, there are circumstances where the permission
scanner denies permission to access tokens that should have been granted
permission. This change de-abstracts/flattens the logic for checking
access tokens so that it is easier to understand and maintain. The newly
implemented code does not suffer from the same issue.
Change default behavior for email confirmation by initializing email_confirmation_required to 0 (not required) instead of 1. Remove the duplicate declaration and clarify the comment; existing logic still overrides this default (sets to 0 for matching pseudo_user/uuid_user and to 1 when event.requires_email_confirmation). Minor whitespace cleanup.
After a successful flow, fetch the user app token for the opener origin, cache the returned app_uid on window.host_app_uid, and post a 'puter.token' message to the opener containing success, msg_id, token, username, and app_uid. If the action is absent or equals 'sign-in', close the popup window. This enables parent windows to receive credentials in popup/embedded auth flows.
It is possible this broke after redis caching was employed because it
broke the expectation that assignments to attributes on cached objects
would remain for future accesses on said objects. This has not been
confirmed as the cause.
This also causes the filename to have the extension `.mjs` instead of
`.js`, as well as an await added in FilesystemAPIService. Luckily
lifecycle events are async so this didn't cause any problems.
I add this change somewhat reluctantly because this _should_ be a
non-functional change. Technically adding the `await` in
FilesystemAPIService makes it possible (albiet incredibly unlikely) for
some subtle bug or change in behavior to be introduced.
This change makes GUI invoke readdir without fetching subdomains, and
then fetch subdomains after. This allows displaying the directory items
sooner and then later populating the icons with glyphs to indicate if
there is an associated subdomain.
This was AI-assisted with manual modifications and bug fixes as
necessary.
This endpoint can be called to get subdomain information after
performing a readdir without fetching subdomains.
This was AI-assisted with modifications and bug fixes as necessary.
This parameter will allow readdir requests to not include subdomain
fetching, which will allow for the later effort of fetching subdomains
for directory listings in the gui with a separate request.
This extensions brings back the dev-socket functionality, which is
really important when testing things like broadcast, alarms, events, etc
; it saves a lot of time if you can invoke a command directly to the
backend.
This is an optional extension that will not be included in production
deployments. This is for development purposes only.
This still needs to be tested. I was going to test this using the `test`
command registered by BroadcastService that exists for this purpose but
`dev.sock` doesn't seem to be working anymore.
Why wasn't `dev.sock` working? Well... we deleted all the code that
makes it work. Why did we delete it? That question isn't a setup for my
next statement; I genuinely do not know. The whole point of dev.sock was
so we could remove the dev console but still maintain support for this
commandline interface that's absolutely needed for testing things that
aren't accesible directly from Puter's GUI.
This tool makes it possible to manually test webhook support in
BroadcastService without running multiple Puter instances. This helps to
verify the functionality without setting up multiple Puter peers
locally.
This commit adds the "receive" side of webhook support for
BroadcastService, which will eventually make broadcasting stateless and
not requiring of persistent connections.
Some specific considerations taken into account include:
- incremental nonce to prevent replay attacks
- request timestamp to prevent nonce-reuse after restarting
- HMAC signature to ensure authorized peer
Known limitations:
- if instances run indefinitely, eventually the nonce value would wrap
around to zero and broadcasts would stop working. It is assumed that
9 quintillion requests in the lifetime of an instance is reasonably
impossible.
It turns out this part of `35461a0` was not necessary to fix this issue,
and the code is still more correct if it falls true when the token's
authorizor has a permission granted.
Range header support was mostly incorrect, which brought to surface
undefined behavior in OnlyOffice which resulted in a request hanging.
This was the cause of the `pdf-editor` app hanging for a while when
opening it with a new file.
When the user clicks Cancel in the authorization window, the code now disables action buttons and replaces the window body with a cancellation UI (header with icon, title, description and a message). Added corresponding English i18n keys (authorization_cancelled, authorization_cancelled_desc, authorization_cancelled_message) to provide localized text for the new cancelled state.
Introduce a new UIWindowAuthMe component that displays a security-focused consent dialog for redirecting to third-party URLs with the user's auth token. Adds related i18n strings and integrates the dialog into initgui, replacing the previous UIAlert confirm flows; when approved (resolves true) the token is appended to the redirect URL and navigation proceeds. Changes: adds src/gui/src/UI/UIWindowAuthMe.js, updates src/gui/src/i18n/translations/en.js, and imports/uses the new dialog in src/gui/src/initgui.js.
Introduce a new UIWindowCopyToken component to display the user's auth token with a copy-to-clipboard button and confirmation message. Integrate the token UI into the account dashboard (TabAccount) by adding an auth token card and click handler to open the window. Add corresponding i18n keys (auth_token, token_copied, copy_token_message, copy_token_description) and import the new window in initgui. Also wire the global action 'copyauth' to show the token dialog and adjust session/login flow so the session list/login windows respect the action (avoid auto-reload when showing the token dialog). Minor UI string cleanup to use i18n('approve') directly.
Replace the plain text response with a styled HTML confirmation page for the local authentication callback. The handler now sets Content-Type to text/html and returns a responsive, animated "Authentication Successful" page (with checkmark graphic and Puter branding) while preserving the existing token extraction from the callback URL's search params.
Read the 'action' value from URL query params and handle a new 'authme' action. When 'authme' is present, prompt the user to approve redirecting to the provided redirectURL; if approved, append the current auth token as a 'token' query parameter and navigate to that URL. The prompt is shown in two places (after auth data is updated and before loading the desktop) to cover different entry flows. Also removed a stray blank line.
There were a couple issues with ACL where access would be denied to app
tokens within access tokens, caused by:
- incorrect recursion: only `false` was considered when in fact the
result from the recursive call is appropriate
- files without a known path are incorrectly handled, which can happen
when iterating over parent directories
* docs: add example for streaming with function calling
* Minor fix and add example to playground
---------
Co-authored-by: Reynaldi Chernando <[email protected]>
WebDAVService catches `/*`, which shouldn't be a problem because it is
on the `dav.` subdomain - however, other middlewares were being invoked
before the subdomain check. Thanks to the `'route'` parameter for the
`next` function we can handle subdomain checks in a more reliable way
* Add ststem info to user options extensions - Add UIWindowSystemInfo, add ui sections for client and server, add basic getClientinfo function
* Fix typo
* Replace accidentally deleted es.js file
* Refactor client information to be consistant with project standard
* Complete Client information in ststem information window
* Remove console logs
* Add basic api functionality for getting server system information
* Structure return data from system server information endpoint | Add copyright to UIWindowSystemInfo
* Add function to format server system api data | Add loading element to server container while waiting for data | Complete System Information
* fix: disallow non admin for backend + move to extensions
---------
Co-authored-by: Daniel Salazar <[email protected]>
This is the effort remaining to bring back URL parameters to drivers
which support them. This fixes the implementation for DNS resolution
resulting in errors for undefined IP addresses when DNS resolution is
successful.
Introduced a resize_window_to_aspect_ratio function and added 'Advanced' menu items to allow resizing the window to 16:9, 4:3, or 9:16 aspect ratios. This enhances user control over window dimensions for specific use cases.
This reverts commit 2139551abf.
It looks like this breaks dev-center because the file associations
aren't properly sent. I will need to investigate this.
This is the first functional migration from ths `es:app` driver to the
`app` driver. Any call to `puter.apps.get` will go through `es:app`
after this change.
* wip: batch fetch get apps for launch apps and recommended apps
* fix: boot issues
* fix: bad refresh app cache
* tmp: remove test for now since can't mock db call
This is the first functional migration from ths `es:app` driver to the
`app` driver. Any call to `puter.apps.get` will go through `es:app`
after this change.
It turned out this error was not coming from `app`, but it was coming
from `app:es` due to a pre-existing issue. Since these tests are meant
to compare the resulting behavior and `app` can handle this case while
`app:es` cannot, the best course of action is to avoid invoking the
issue and only test the intended behavior.
Add tests for all the CRUD operations and related edge cases in `app` to
ensure the behavior is the same as `es:app`. These tests detect 3 issues
across 4 failing tests.
This is comitted separately from the commit for AppService.comp.test.js
that will follow because it interacts with all other test cases. It did
not cause any issue based on what I observed, but I'm still wrapping it
in a separate commit in case we need to revert or change it later.
An "anti-test" (test that should fail) was created to verify that a test
fails when apps are different. This revealed a problem in the original
logic of comparing the database state (UUIDs don't need to be, and will
not be, identical; they need to be excluded from comparison). This
commit contains the new test and fixes the existing test case, which was
passing because this problem caused a false-negative.
The file `context.js` causes problems in unit tests because vitest does
not play nice with CJS, especially when both CJS and ESM are in use such
as in our repository.
Given that it is not feasible to solve the underlying interoperability
issue, I have elected to make `context.js` a singleton in `Symbol.for`.
This worked very well with `helpers.js`.
The `helpers.js` file has two instances when testing with vitest.
Usually this can be solved by creating an "import bridge" file - another
CJS file that imports the desired CJS file and re-exports it so that the
`require` mechanism for caching modules is used instead of the `import`
mechanism for caching modules. Unfortunately in my most recent test
cases this does not work. I do not know why this does not work. However,
without doing a deep-dive into the internals of vitest I can at least
see that the only state in helpers is for providing `services` as a
pseudo-global, so a hack with `Symbol.for` solves everything.
This test was very difficult to get working because of issues
initializing the context under vitest. After a lot of effort and trying
to narrow down the issue in many ways that didn't work, I eventually
found that manually setting the storage and calling run on the
AsyncLocalStorage object got it working. I'm currently unsure if this is
specific to vitest or not. We don't seem to do this in Puter's kernel
but everything works fine in the typical runtime. Maybe this is
side-effect of otel's own use of AsyncLocalStorage.
This is a naive implementation of the `.upsert()` method that simply
calls `.create()` or `.update()` depending on whether or not the app
already exists.
Primarily these tests were AI generated an then checked over for sanity.
These tests are good unit tests to avoid regressions as a result of
changes to this code but are not sufficient to test for regressions
introduced by this new implementation that will replace `es:app`.
Fixes are also included for a couple issues that were found:
- `null` being included in extensions list
- property called `user_owner` instead of `owner`
Most of this implementation matched `.select()` which saved time. The
common behavior can be factored out, but since the purpose of this
refactor is to flatten everything as much as possible I'm going to leave
the duplicated code and make a note to do this later.
The challenging part was `#build_complex_id_where()`, which is the
equivalent to the `fetch_based_on_complex_id_()` method in
EntityStoreService. This allows `uid: app-UUID-OF-APP` and `id: { name:
'editor' }` to both work.
Adds the `icon_size` parameter to the `.select()` method on the new
non-ES/OM implementation.
When adding the necessary `params` parameter to the `.select()`
method, it was noticed that the `predicate` parameter did not have a
default value - potentially causing a regression; a default value was
set for both `params` and `predicate`.
It turns out self-referencing tables add some nuances to what is and
what isn't ambiguous in SQL queries, so getting this right took a little
longer than expected. Following the entire chain doesn't seem to be
possible so a compromise is made by only traversing one level of depth.
(you can the uid of the owner of the app, but not the uid of the owner
app's own owner)
The "flat" implementation of permissions was broken because
revokePermission tried to delete entries by calling `.set` with an
option called "delete". I'm not sure if this has ever existed on the
puter-kvstore interface, so it's weird that it was called like that.
The permission implicator for protected apps was written before changes
to the permission system that affect the conditions under which a user
is allowed to grant and revoke permissions; specifically this is the
`manage:` set of permissions, which now needs to be granted to the owner
of a protected app.
Additionally, the "level" component of the permission is ignored because
the owner of a protected all is implied to have all the permissions
pertaining to that protected app.
Make the home directory (AKA "~") the default CWD for puter.js, making
relative paths work in environments other than app environments (i.e.
gui or worker environments).
Handle a race condition affecting mkdir operations with the
`createMissingParents` option enabled. When creating a directory because
this option was specified, errors because the directory already exists
are likely due to a race condition and should not be propagated to the
client but instead handled by using the directory that's already there.
* Improve UI for App Deployment Options in Dev Center
- Added CSS styling for deployment option cards
- Implemented active state switching between deployment methods with guardrails
- Abstracted saveEditApp for reuse across Deploy and Edit tabs
- Added error handling for invalid URLs in the Deploy tab
* updated mode's description and fixed function's error
* updated by npm install
* Revert "updated by npm install"
This reverts commit 82cd962f62.
* in url mode the deploy button is enabled by default
* Add README for Puter localization and setup
This README provides an overview of Puter, including installation instructions, system requirements, and support information.
* Update README.od.md
---------
Co-authored-by: Nariman Jelveh <[email protected]>
Introduces thumbnail generation for image files during upload operations. Thumbnails are generated client-side if enabled via the `generateThumbnails` option, and are included in file metadata and operation payloads. This enhances file previews and user experience in the file system.
Based on a stack trace from production and manual static analysis, it
appears that a race condition occurs within hashing_stream
intermittently. The conditions that cause this issue might be heavy
backpressure. The source stream emits the 'end' event before
stream.Transform's transform callback has had a chance to process all of
the chunks, which results in an incorrect order in calling methods on
the `typeof crypto.createHash()` object.
It would appear that `source.pipe(stream)` is not able to propagate
errors from Transform because the chain was simply broken and upload
would get stuck (if this was indeed the cause of upload getting stuck,
which seems likely but not conclusive)
There was a configuration parameter for this but it isn't being used and
has the incorrect name in `config.js`. I decided to keep the old check
here anyway because having support to configure a lower size limit could
come in handy.
I set the limit to 2MiB through the following logic:
- largest icon size I've ever heard of is 512px
- 512*512*4 (4 color channels) is 1048576 (1MiB)
- increase to next MiB just to be safe
Deleted the ComplainAboutVersionsService and its registration in SelfHostedModule, as well as cleaned up related service mappings in DriverService. This streamlines the codebase by removing the version complaint feature.
Fixes#2218
The DEV Center was unable to open worker files in the text editor because
it lacked godmode permissions. The file_paths parameter in puter.ui.launchApp
requires the calling app to have godmode=1 in order to work.
Changes:
- Added database migration 0044_dev-center-godmode.sql to set godmode=1
for the dev-center app (uid: app-0b37f054-07d4-4627-8765-11bd23e889d4)
- Updated SqliteDatabaseAccessService.js to include the new migration
This allows DEV Center to successfully pass file paths when launching the
editor app, fixing the issue where clicking on a worker file path resulted
in an empty editor window.
There were two different things here:
- invalid requests have an ambiguous error message
- migration of PuterFSProvider to an extension caused an issue
for shortcut creation in some flows
Closes#2200
Remove a method in hl_mkdir which was determined to not be referred to
anywhere. hl_mkdir was re-tested to verify that this did not cause a
regression.
This error message was ambiguous for mkdir operations where a shortcut
target is specified for hl_mkdir. The message looks like it's referring
to the shortcut target but really it is referring to the parent
directory for the new directory that will be created.
This merits a test because changes to how `puter.site` works in the
future could easily break this redirection, and maintaining this
redirect is important to us.
Redirect the subdomains `""` and `"www"` to a configurable URL, which is
by default `https://developer.puter.com/static-hosting/`.
This is potentially a breaking change for local instances that have a
subdomain called "www". Users hosting their own Puter may want to be
aware of this.
Closes#2214
Removed unnecessary console.log statements from PuterFSProvider.js and WebServerService.js. Increased PENDING_QUERY_TTL to 3 seconds and added a timeout mechanism for coalesced queries in get_app to prevent indefinite waiting.
* Update first-run-issues.md with dnf5 instructions
Add installation instructions for Development Tools on dnf5.
* Fixing the command to install it on Fedora 41+
Introduces a TTL-based pending query cache to the get_app function to prevent duplicate database queries for the same app lookup. This change improves efficiency by coalescing concurrent requests for the same app and ensures only one database query is performed per unique lookup within the TTL window.
This commit adds the DataAccessModule, which is where replacement
"flatter" implementations for what is currently implemented via
EntityStorage/OM will be developed.
This commit also adds AppService, which is where the `crud-q`
implementor for apps will be implemented.
This commit adds the `select()` implementation for AppService. Currently
it is missing many behaviors for parity with the current ES/OM
implementation including:
- coercion of boolean values
- nested objects and their properties
- `icon_size` parameter support
The EntityStorage/OM mechanism for data access is being replaced.
Specifying 'es:app' in puter.js calls will allow the ES/OM mechanism and
its replacement to be tested together to check for regressions. When the
replacement is done, we can change 'es:app' to the new service name.
This is comitted separately because it should not have any functional
changes. Do not skip this in a `git bisect`, but do not revert this when
testing commits for functional changes.
Eliminated the spinner shown when creating a temporary user in popup mode and removed the corresponding hideSpinner call. This streamlines the user experience during account setup.
Adds the necessary configuration and the `npm run bench` script, as well
as the first benchmark to verify everything is working. The first
benchmark is permissionUtils. This is important to benchmark because
permission strings are used often and there is some non-trivial logic
such as escaping of full-colon characters. Other overheads like database
access will be much more significant, but it may be useful to know how
much more significant in quantifiable terms.
It took a long time to figure out why this was happening, but
user-to-app permissions and dev-to-app permissions were being checked in
sequence instead of concurrently. It turns out it was a recursive call
in user-to-app permissions that was blocking. This recursive call was
not actually a dependency of the query for user-to-app permissions; it
was only needed for determining if default user-to-app permissions are
held by the user. This was fixed by simply splitting up these
non-dependent queries into two separate scanners.
* Remove smol utility library and update usage
Deleted the smol utility library from putility, removed its documentation, and refactored code in linux.js to use native string methods instead of smol.split. This simplifies the codebase by eliminating a redundant utility.
* Remove `putility.libs.time` and inline time utilities
* Update imports and time constant usage in core modules
Replaced usage of time.SECOND with a local SECOND constant in ServerHealthService for clarity and removed unused import. Updated all service imports in TestCoreModule to explicitly include the .js extension for compatibility with ES module resolution.
* Remove unused `wrap_text` and `ansi_visible_length` functions
Deleted the wrap_text and ansi_visible_length utility functions from string.js, as they are no longer needed or used in the codebase.
* Remove `format_as_usd` utility and related docs
The format_as_usd function and its documentation have been removed from the codebase and README files. This cleans up unused or deprecated currency formatting utilities.
* Remove osclink utility and update references
The osclink function and its documentation have been removed from putility. All usages in backend modules have been updated to use plain URLs instead of OSC 8 hyperlinks. This simplifies string utilities and avoids terminal-specific formatting.
* Remove PosixError utility module
* Remove NariMethodsFeature and related references
Deleted the NariMethodsFeature module and removed its usage from AdvancedBase and PuterJSFileSystemModule. This simplifies the codebase by eliminating unused or deprecated NARI method support.
* Remove DevConsoleService and related dev console widgets
Eliminates `DevConsoleService` and `NullDevConsoleService`, along with all code that registers or manages dev console widgets across the backend. Developer messages and notifications are now logged directly to the console. Removes related commands and test mocks, simplifying the developer experience and reducing code complexity.
* Remove MinLogService and related registration code
Deleted MinLogService.js and removed its registration from SelfHostedModule.js. This cleans up unused or deprecated logging functionality.
* Remove `DevSocketService` and related registration
* Increase test job timeouts in CI workflow
* Remove dev environment widget ops counter
Eliminated increment and decrement of the dev_batch-widget ops counter in BatchExecutor. This simplifies the code and removes dev-only UI tracking logic from the batch operation flow.
* Remove console Puter logo feature and related code
Deleted the src/fun/logos.js file and removed all references to the Puter logo display in WebServerService and documentation. This streamlines the server startup output and eliminates unused or unnecessary code.
* Update WebServerService.js
* Standardize console banner formatting in services
* Remove tag cache refresh logic from AppInformationService
Eliminated the _refresh_tags method and its scheduled interval from AppInformationService. This change removes the tag cache refresh functionality, likely due to refactoring or deprecation of tag-based app discovery.
* Remove AI usage testing contributor docs
* Remove dev-console-ui-utils and update related services
* Remove debug console.log statements from backend code
Eliminated various leftover console.log and debug print statements across multiple backend modules and services to clean up the codebase and reduce unnecessary logging in production.
* Remove unnecessary console.log statements
Deleted the CommentService implementation and its test file, and unregistered the service from CoreModule. This removes all comment-related backend functionality.
* Refactor puter-js to remove putility and service layer
* Add fallback for IPC listener registration
* Remove TeePromise in favor of `createDeferred` pattern
* Update utils.js
* Bump version to 2.2.0 in package.json
* Remove model name normalization and driver mapping logic
Eliminated the code responsible for normalizing model names and mapping models to specific AI drivers. The default driver is now set to 'ai-chat', simplifying the model selection and driver assignment process.
* Simplify AIService selection logic in image generation
* Remove unused Together image model constants
* Remove terminal and phoenix built-in apps and emulator
This commit removes the terminal and phoenix built-in apps from the backend, database migrations, and permissions. It also deletes the entire emulator and phoenix/terminal app source directories, assets, and related configuration files. References to these apps in the backend module loader and router are removed, and related SQL migrations are updated to reflect their removal.
* Remove emulator references from SelfHostedModule
* Remove emulator integration and related references
* Remove parsers and pty modules
* Update package-lock.json
Deleted ThirdPartyDriversModule.js, html_footer.js, and html_head.js from the backend source directory. These files are no longer needed and have been removed to clean up the codebase.
Deleted the src/backend-core-0 package and moved its validation helpers directly into src/backend/src/validation.js. Updated references in CoreModule.js and helpers.js to use the new local validation module. Adjusted ESLint configs to remove backend-core-0 references.
* Revert "fix: together ai image prices (#2130)"
This reverts commit 04c8b06616.
* Revert "feat: single image ai endpoint (#2129)"
This reverts commit 161ca74aa3.
* Revert "fix: prevent loot qp if failing ai models? (#2122)"
This reverts commit 8d52cefe47.
* Revert "feat: rename ai models to match norm (#2121)"
This reverts commit 9da8aa0849.
* feat: refactor ai to have single entry point and follow defined model structure
* fix: missing openrouter registration
* fix: dedupe models
* feat: provide usage in stream mode 🚀
We weren't able to see any custom spans, only the builtin
instrumentations for node.js. This commit downgrades opentelemetry so
that we can see custom spans in tools like jaeger as before.
Previously a new ConsoleSpanExporter was passed to the constructor of
NodeSDK. This was possibly unintentional but it did not cause any
issues. After the recent update to opentelemetry, or perhaps the changes
introduced in 3c579dcc0d, this no longer
works as it prevents tools like Jaeger from getting any spans from
Puter's backend.
* Add dashboard UI and routing support
Introduces a new Dashboard UI component with sidebar navigation and user options. Updates backend routing to redirect /dashboard to the root path. Integrates dashboard mode detection and initialization in the GUI, including responsive styles and logic to open the dashboard or desktop as appropriate.
* Improve dashboard user menu and UI behavior
Added support for multiple logged-in users, session saving for temporary users, and improved context menu options in the dashboard. Updated CSS for user button state and adjusted font size for signup terms. Changed dashboard initialization to use UIDashboard instead of UIWindow.
* Add dynamic apps section to dashboard UI
* Add specific class for dashboard apps section
* Refactor dashboard tabs into modular components
* Update style.css
* Add Developers menu and improve signup window behavior
Added a 'Developers' menu item to the dashboard linking to developer.puter.com. Updated login and signup window logic to ensure the signup window opens centered and dominant, improving user experience when transitioning from login to signup.
* Update UIWindowLogin.js
* Refactor apps tab UI and improve app card interaction
It calls requestPermission on the UI module. The method on the UI model
needs to still exist because the UI module is tightly-coupled with IPC.
A refactor of the IPC mechanism on the puter.js side could solve this.
This commit adds methods to request standard directories like the
Desktop, Documents, Pictures, or Videos directory. Additionally, the
message displayed when permission for these directories is requested is
easier to read.
This bug took a long time to diagnose, so I also made an async/await
wrapper around #postMessageWithCallback called #postMessageAsync so that
similar promise resolving errors are less likely here in the future.
The vitest test suite can import different states of the same module, so
this value was very helpful in determining that this was happening and
eventually the cause.
Permission endpoints would trigger 500 errors in cases where the request
did not have correct types for values in the request body. This migrates
all of these endpoints to use the new `validate_fields` function, which
is intended to make validation of fields clearer and more consistent.
This commit also adds a new check to verify that the app which owns the
entity being edited matches. Previously this was not necessary because a
read on the same entity would have always performed the same check and
caused this operation to stop early. (now that an app may have
permission to read entities created by other apps, this is no longer the
case.)
...entity (app, subdomain, etc). When trying to update some non-existing
entity the error message can state that an entity with a particular UID
was not found even if a UID wasn't specified. The UID reported will in
fact be a randomly generated UID because of how default properties work
in entities. This fix makes the error message more specific about which
identifier was used when an entity was not found. This is accomplished
by printing the predicate in a human-readable format.
This update fixes configuration issues in the TypeScript setup by standardizing the tsconfig.json. It sets modern compiler targets (ES2024), uses Node16 module resolution, enables strict type checking, and cleans up test-related exclusions. These changes improve build reliability, prevent casing inconsistencies, and ensure accurate source mapping during development.
By default node has a global `crypto` variable conforming to the
standard for the Web Crypto API. However, this `crypto` object does not
have the `createHash` function, so 'node:crypto' must be imported
instead.
* docs: add Punjabi translation link to README
The Punjabi (ਪੰਜਾਬੀ) translation README.pa.md was added 2 weeks ago but was missing from the translations list in the main README. This adds it to maintain completeness of the translations section.
* Fix Punjabi link formatting in README.md
---------
Co-authored-by: Nariman Jelveh <[email protected]>
* WIP Gemini OpenAI refactor
* refactor: gemini open ai service + geminiCostMap
* Gemini Service fixes
* Cleaning up old Gemini cruft
---------
Co-authored-by: Daniel Salazar <[email protected]>
* Add ElevenLabs TTS provider integration
Adds ElevenLabs text-to-speech support in the backend and frontend. Adds `ElevenLabsTTSService`, updates `PuterAIModule` to register the service, documents configuration, and integrates cost tracking with zero cost in `MeteringService` for now (todo). updates `AI.js` to support 11labs as a provider and adds related tests for `txt2speech` functionality.
* Update 11labs cost map values
* fix: debounce toolbar display after dragging a window
* change naming convention for debounce to match others. (snake case)
* revert changes to package.json that werent meant to be comitted
* Revert "change naming convention for debounce to match others. (snake case)"
This reverts commit aaedee0dfa.
* revert commit aaedee0dfa
* use snake case for drag_release_debounce_timer
This commit adds verification for statically identifiable definite
errors. Sometimes global variables used will be falsely reported as
undefined variables in which case the new file
`mandatory.eslint.config.js` should be updated to include these
definitions in the narrowest scope possible that has these definitions
This is the last error for the mandatory eslint rules. Now we can put a
rule into place so that CI always fails when there's an undefined
variable, which I think is pretty cool.
There's a potential issue here because of an undefined reference, but I
can't seem to reproduce any problem caused by this. However without this
fix this line of code is guarenteed to throw an exception so this fix
should be safe.
This is an error in a handler for a failure case so it shouldn't be
affecting users, but let's handle this error gracefully.
This was a symbol that became not defined after moving PuterFSProvider
to the extension.
LocalDiskStorageController was dependent on putility for TeePromise, but
since putility is a workspace module it's difficult for extensions to
access it (Puter backend core would need to expose it). Since TeePromise
itself is very small and will rarely (if ever) be changed I decided to
move it to a separate package on npm.
Begin work on LocalDiskStorageController in the `puterfs` extension.
This replaces LocalDiskStorageStrategy and LocalDiskStorageService from
the core. The `upload()` method is implemented to verify that it's
working.
This commit by itself will break other storage strategies. The next step
is to allow extensions to register storage controllers for puterfs. Part
of that work is done in this commit by emitting an event to register
storage controllers, but this commit does not include a way to
configure/select storage controllers.
Adding the hasChild method of FSNodeContext as well as a corresponding
method to filesystem providers is prerequisite to moving
FSEntryFetcher's logic into the new puterfs extension.
...use readdir from the provider instead of calling
fast_get_direct_descendants directly on fsEntryService.
This change is prerequisite to removing FSEntryService from core.
The get_capabilities and update_thumbnail methods in PuterFSProvider are
moved to the extension by this commit. This is prerequisite to the
removal of PuterFSProvider in the core.
Now that most of the functionality from PuterFSProvider in core has been
moved to PuterFSProvider in the `puterfs` extension, there are a lot of
unused symbols which need to be cleaned up.
This cleanup reveals that `update_thumbnail` and `get_capabilities` are
the only remaining functions left before PuterFSProvider in core can be
fully removed.
Introduces Mistral OCR integration in backend and updates the `AIInterfaceService` and `MistralAIService` to support new OCR options and response normalization. Updates metering cost map for OCR and annotation usage. Refactors `DriverService` to support interface-specific service aliases. Expands the puter.js `AI.img2txt` API to support flexible options and provider selection, including Mistral OCR.
FileCacheService was still a legacy service extending AdvancedBase. This
commit changes it to extend BaseService and implement the lifecycle
methods consistent with other services. This is a prerequisite for
moving write_overwrite which needs to import the service via
`extension.import` (not possible for legacy services) so that it may
invalidate file cache when a file is written to.
We want this to be fast enough that this benchmark doesn't take a long
time, but part of the effort of making it faster will be running the
benchmark repeatedly, and if it takes a long time then it will take
longer for us to make it faster.
This commit reduces the benchmark size for stat_intensive and
write_intensive so that they don't take several minutes to complete.
These two issues have affected us, but go away without rollup:
- https://github.com/npm/cli/issues/4828
- https://github.com/rollup/rollup/issues/6168
We can just use webpack instead; it has never caused build/npm issues.
This migration was done using AI, by pasting error messages over and
over again until everything worked. Since we're not actively working on
terminal and phoenix (dependents of rollup) currently it doesn't make
sense to focus on doing this migration manually, and any errors not
observed in basic use can be remedied later.
- Added a full French translation of the main README.
- Preserved all formatting, links, code blocks, and HTML elements.
- Ensures feature parity with the English version for French-speaking users.
* feat: comprehensive settings and modal UI/UX improvements
Redesigned settings interface and modal windows with improved visual
hierarchy, spacing, and modern styling throughout the application.
Settings UI improvements:
- Enhanced section headers with proper flexbox layout and centering
- Simplified storage usage display to single percentage with clearer info
- Improved settings cards with consistent spacing and hover states
- Redesigned session manager with horizontal card layout
- Reordered account settings (username → email → password)
- Removed duplicate password option from security tab
Form and input improvements:
- Increased container padding (20px → 24px) for better breathing room
- Tightened label-to-input gap (8px → 6px) for better visual grouping
- Enhanced labels with bolder weight (500 → 600) and refined color
- Larger input fields (12px 14px padding) with smoother corners (6px)
- Added hover states with border color transitions
- Removed distracting box-shadow focus rings across all inputs/selects
Button improvements:
- Modernized primary buttons with solid colors (removed gradients)
- Added flexbox centering for consistent text alignment
- Reduced button text size (13px) for cleaner appearance
- Improved default button styling with refined gray palette
- Better active/hover state transitions
Select dropdown improvements:
- Custom SVG chevron arrow with proper 12px right spacing
- Fixed select resizing issue on focus (removed global border/padding override)
- Full-width selects in modals with consistent styling
- Smooth hover states without size changes
Modal windows:
- Consistent 380px width for form modals, 400px for desktop bg settings
- Unified .settings-form-container class across all modals
- Proper ARIA labels and semantic HTML structure
- Error/success messages with refined colors and better contrast
Desktop background settings:
- Color blocks increased to 32px for easier interaction
- Fixed focus outline clipping with proper overflow handling
- Removed scale effects for cleaner interactions
- Flexbox layout for color grid with proper spacing
- Fixed palette icon display with inline background image
Window chrome:
- Increased default shadow (0 12px 24px, 0.12 opacity)
- Enhanced active window shadow (0 16px 40px, 0.18 opacity)
- Better visual depth and window hierarchy
File organization:
- Moved UIWindowManageSessions to Settings folder
- Created helpers/build_settings_card.js for reusable components
- Updated all imports to reflect new structure
* bring back shadow
* improve 2fa + fix theme not changing on cancel bug + fix couple more issues
* style polish
* remove unused styles
* i18n
* fix search bar clipping
* group reset & customize color buttons
* more polish
* enforce min width/height on resizable
* resizable settings and show full name on hover
* style tweaks
When ll_mkdir functionality was moved to PuterFSProvider, ACL and FSLock
concerns were erroneously moved into PuterFSProvider. The intended
design has ll_mkdir responsible for ACL and FSLock, and providers should
never be responsible for ACL.
An important note: it was noticed during this change that mkdir in
PuterFSProvider implements its own ACL check, instead of the ACL check
being performed in ll_mkdir. This means permissions won't be checked for
other implementors of mkdir! This needs to be fixed before custom
filesystem implementations can be considered production-ready.
According to the package documentation: https://www.npmjs.com/package/mime
> null is returned in cases where an extension is not detected or recognized
This call to `.startsWith()` was causing an exception to be thrown upon
right-clicking files without an extension, making it impossible to fix
them.
The styleguide for Puter's backend expects spaces after top-level not
operators inside conditions. This commit adds an AI-generated eslint
plugin and, since it conflicts with the existing space-unary-ops plugin
from stylistic, also adds a wrapped version of space-unary-ops that
ignores top-level not operators so that this plugin will work as
expected.
This service was registered within FilesystemService for legacy reasons
but now it needs to be accessed by an extension. In order for the
extension import to work as expected this service needs to be registered
at the same phase as other services.
This fixes PD incident Q3ZNFWILVOFKU3. This issue was not caught in
testing - in fact after deleting a user the files were deleted as
expected, but it's unclear to me how I observed that with this issue
present.
This temporary proxy provider will allow methods of the puterfs
filesystem type to be moved to an extension incrementally instead of all
at once. See comment above the class for a more detailed explanation.
There is a case where this.entry.id has a value in FSNodeContext while
this.mysql_id does not. I was under the impression that this state was
not possibole. The cause of this eludes me. This commit does not correct
the root cause - it only adds a workaround to this issue by falling back
to this.entry.id if this.mysql_id is `undefined`.
It might not be okay to assume an fsentry was already fetched when
updating the accessed time in ll_read. I'd like to know what changed
this to make this be the case, if it happens to be the case.
There were two references to `storage` in file.js but the search string
I used only detected one of them. I was looking for more references to
`storage` when I found this one. Also, I realized the metering updates
in file.js become redundant if ll_read is used instead so I've removed
those as well.
Adds an appropriate error at a couple different levels. The first is in
FilesystemService. Callers of FilesystemService.node are expected to
provide either an absolute path or an instance of a filesystem node
selector, but there wasn't an explicit check for this so instead an
arbitrary error (read property of undefined) would be thrown. The second
is a higher-level APIError in the batch executor that's a bit more
helpful than a 500 Internal Server Error.
This commit reduces the indentation level and complex arithmetic inside
the createTempUser function in initgui. It is suspected that this change
should greatly reduce measures of the "cognitive complexity" metric.
Apparently the callback operand of $.fn.fadeOut may be called more than
once if there are multiple matching elements. Although we expect there
to only be one element matching the selector `".captcha-modal"`, someone
editing the CSS and HTML would not expect such consequences to the
logic of captcha.
Calling `.fadeOut()` on the result of a jquery selector (i.e. the
evaluation of `$('.some-element-class')`, when it returns an object with
`length=0`) is a NOOP. That's right, it doesn't throw an error; it just
does nothing. This was preventing a temporary user from being created
when `.captcha-modal` isn't present because [the code intended to execute
after the animation] was never run. (square brackets for clarity because
the English is inherently ambiguous)
The PR I merged before putting this one up had my changes to api.d.ts
which I thought where on this branch - turns out I only thought that
because this branch had that one as a parent.
However #1818 has a simplification that this change overwrites. I'd like
to keep this simplification so this commit is restoring it.
The previous implementation of deleteUser was hard-coded to use the
PuterFSProvider file system type's storage implementation specifically,
even if a different filesystem type is mounted as root or for a
particular user.
This change was tested by creating a user, adding some fsentries, and
then deleting that user. The following classes of filesystem entry were
checked:
- [x] user created directory (with contents)
- [x] directory fsentry was deleted
- [x] user created directory (empty)
- [x] directory fsentry was deleted
- [x] immutable directory
- [x] directory fsentry was deleted
- [x] user created file
- [x] file fsentry was deleted
- [x] file storage was deleted
- [x] user created file in trash
- [x] file fsentry was deleted
- [x] file storage was deleted
Accessing the storage object directly duplicates effort of locating the
correct filesystem provider based on the mountpoint of the file with the
contents being requested; an effort that file.js did not perform which
made it incompatible with filesystem mountpoints.
This change has been made to make it easier to move filesystem type
implementations to extensions, because accessing storage directly will
not be supported after puterfs is an extension.
- A new stt driver in `AIInterfaceService` and `PuterAIModule`.
- added methods for audio transcription and translation in the speech-to-text interface.
- updated cost mapping for stt models in `openAiCostMap.ts`.
- Updated permissions and interfaces to support new speech-to-text features.
- added support for OpenAI as a tts provider in `AIInterfaceService` and `PuterAIModule`.
- Updated cost mapping for OpenAI tts models in `openAiCostMap.ts`.
- improved `Txt2SpeechOptions` interface to include new parameters for provider, model, and response format.
- added tests for OpenAI provider in `txt2speech.test.js` to ensure functionality.
This extension has a copy of memoryfs which is exposed as `testfs`. The
purpose of this is to register a new filesystem type from an extension
to ensure it works as expected and to get feedback on a working example.
* Don't update URL when opening public files via direct URL
* Alert user when attempting to open a nonexistent file
* Fix toolbar autohide in public file urls
* Remove extraneous debug logs
* Properly define stat var in public folder URL handling
* Update window URL when focusing an app opened through file URL
* Localize error messages
* Update OpenAI package to version 6.7.0 and add video generation capabilities
- Updated `openai` dependency in `package-lock.json` and `package.json`.
- Introduced new permissions for video generation in `hardcoded-permissions.js`.
- Added video generation service in `AIInterfaceService.js` and registered it in `PuterAIModule.js`.
- Implemented coercion for video streams in `CoercionService.js`.
- Updated driver service to include video generation.
- Added `txt2video` method and options in `AI.js` and corresponding TypeScript definitions in `index.d.ts`.
* Update openaiVideoCostMap.ts
* Revert "Update openaiVideoCostMap.ts"
This reverts commit 9e66f93605.
* change `txt2video` to `txt2vid`
Instead of switching to test mode, which responds with "Lorem Ipsum"
sample output to test the API, throw an appropriate error message for
content moderation failures. This is especially useful when OpenAI's
moderation is way way way way too aggressive as this confuses users.
I was not able to locate a change causing a configuration regression,
however I do know AI was working in my OSS clone and that I had no
reason to change my AI configuration in my `local.json` file. In any
case, it is clear that configuration was not working as intended.
This commit fixes PuterAIModule which was not enabling OpenAI services
when `openai` was configured within the `services` block, even though
the `services` block configuration is supposed to be the recommended
configuration and the global `openai` config object is supposed to be
deprecated.
This commit also fixes OpenAIImageGenerationService which was not
accepting the current parameter name for the API key (`apiKey`) and
instead only accepted the legacy key (`secret_key`) which created this
interesting problem where using the recommended parameter name would
prevent Puter from booting successfully.
This commit begins the plan towards moving PuterFS to an extension. It
is first necessary to analyze the dependencies and determine which
services and modules are part of PuterFS and which ones are not.
Added a constant for PANEL_WIDTH to standardize panel width across the application. Refactored UIWindow logic to utilize this constant for positioning and resizing, ensuring consistent behavior when panels are open. Restored the getSnapDimensions function to adjust available dimensions based on the taskbar position and open panels.
In the prod environment there is no instance of DevConsoleService. If
methods are called on the service without a check to see if it exists,
this results in "read on undefined" errors that can only be produced in
a prod environment. This was the cause of the issue caused by the
previous log cleanup PR where it looked like "websockets were broken".
The missing undefined check is fixed by #1734, but the change in this
commit will catch future cases.
Additionally, this change will help with moving away from the dev
console.
Often fsentry stats are used to see if an fsentry exists, so fsentry not
found logs are common and expected. This commit disables those by
default. Additionally, logging for cache events is disabled as well,
since those are only helpful when debugging cache specifically.
* Implement detailed usage report table
- Added `number_format` function for flexible number formatting with options for decimals, separators, and negative formatting.
- Updated `UITabUsage.js` to include a toggle for viewing driver usage details, fetching and displaying usage data dynamically.
- Improved CSS styles for driver usage details to improve layout and interactivity.
* Update style.css
* Refactor driver usage display in UITabUsage.js
- Updated UITabUsage.js to improve the layout of driver usage information, including a new header structure for better organization.
- Added CSS styles for the new header layout and adjusted existing styles for improved visual consistency and interactivity.
* fix progress bar logic
* fix: adjust toolbar positioning for sidepanel based on taskbar location
* fix: update window width calculation for left position based on open panels
* chore: add http-server as a dev dependency and update package scripts
* refactor: move maximized window positioning logic to UIWindow and remove from UITaskbar
Removes init/construct logs, moves many boot logs to debug level,
introduces debug level in BootLogger, moves "CONFIGURATION MUTATED AT
RUNTIME" message to debug level and allows config.js to output logs to
the standard logger in context.
- Adjust `UIPopover` positioning when a sidepanel is visible.
- Update `UIWindow` to manage visibility states and adjust toolbar positions accordingly.
- Modify CSS for AI Button to change z-index for better layering.
* perf: move user-user perm checks to flat kv entries
* feat: manage permission for user to user and dev to app file sharing
* fix typings cuz macos sucks
* fix: mac os typecase
* fix: chore macOs typecase
* fix: bad join of permissions
* feat: add check-permissions endpoint for checking an users perms
* Add 'manage' to permission lists in the Sharing dialog
* fix: manage being allowed through our ACL
---------
Co-authored-by: Nariman Jelveh <[email protected]>
* add AI side panel to UIDesktop
* integrated `UIAIChat` component into `UIDesktop` for AI interactions.
* added styles for AI side panel, including buttons and chat message formatting in style.css, enhancing user experience with AI features.
* add support for window-based side panels
* remove window resizing logic that is simply broken
* whitelisting added
* Add `showWindow` and `hideWindow` methods to Puter.js
When /user-protected/change-password (and presumably other endpoints
under /user-protected) receive a preflight request they respond with
HTTP status 401. This is because `.use()` calls on the router apply to
all request methods erroneously.
This commit fixes the issue. Further investigation is required to
determine when preflight requests started happening on this endpoint.
* feat(Translation): added support for Armenian and also added Bulgarian
* fixed
* add license header to bg.js
* Update package-lock.json
---------
Co-authored-by: jelveh <[email protected]>
* improve UIItem and UIWindow to support internationalization for system directory names. Updated UIItem to display localized names for trash, desktop, home, documents, pictures, videos, and public directories. Modified UIWindow to set the window title using localized names for the desktop and home paths.
* refactor UIWindow to use i18n for system directory titles. Updated window title settings for desktop, documents, pictures, videos, public, and trash paths to use localized names, improving user experience across different languages.
* add option to automatically set window title to opened file's name
A new checkbox in the app edit section to allow users to automatically set the window title to the name of the opened file. Updated related functions to handle this new setting, ensuring it is saved and reset correctly.
* Update launch_app.js
Using services such as `kv` which expect an actor in context would not
work in a handler for a lifecycle event such as `'init`' in an
extension. In core backend modules is it generally expected that if a
user actor is not in context a backend service will explicitly specify
that the system actor should be used with the `su` service's `sudo`
method. We cannot require extension developers to add this wrapping code
whenever they want to use kv.
In the future it might be better to have a specific "ExtensionActorType"
for this purpose.
The basic `.get()` and `.set()` calls should be the same between
persistent key-value store (puter-kvstore) and in-memory cache (kv.js).
This commit wraps these methods to support the "shorthand" usage.
The `/drivers/call` endpoint hangs when the JSON middleware produces
(or, is going to produce?) a PayloadTooLargeError. Increasing the limit
avoids this issue for typical use.
The extension documentation mentions imports and exports together very
early on, but extension exports should be used sparingly. I suspect most
extensions with exports will be among Puter's builtin extensions.
Extensions now read configuration objects under the "extensions" block
in the backend configuration. Additionally, a `config.json` for default
values directly in the extension's directory is now supported.
* Add 'Set as Desktop Background' context menu item
* Use the `mime` library to detect images in the `UIItem` context menu
---------
Co-authored-by: Nariman Jelveh <[email protected]>
Removes dead code and reduces branching. In the get_service_or_throw_
method, the changes in this commit show how the branching got more
redundnat in the previous change.
Adds new events that DriverService emits: `create.interfaces` and
`create.drivers`. Returns the functionality of the "drivers" registry,
which now expects objects provided by extensions.
- Implemented `tarItems` function to create tar archives from selected files or directories.
- Added `untarItem` function to extract tar archives.
- Updated UI to include options for downloading and tarring files.
- Enhanced item icon handling to display tar file icons.
- Added translations for tar and untar operations.
- Fixes#1629
The Anthropic SDK preemptively throws an error if it thinks a response
is going to take longer than 10 minutes:
https://github.com/anthropics/anthropic-sdk-typescript#long-requests
According to this documentation, overriding the `timeout` option
disables this error. In this commit the option is changed to the default
value of 10 minutes plus an additional 1 second; it is assumed based on
the documentation's phrasing that it is not necessary to make the
timeout higher but simply to specify a value.
RuntimeModules (a feature for extensions) can be accessed by core
modules through a registry exposed in Context by Kernel. However,
TestKernel was not exposing this same registry which caused an error
when module installation occurred during tests.
Updated the `bindSocketEvents` method to check the `original_client_socket_id` before posting updates for 'cache.updated' and 'item.renamed' events. This prevents unnecessary updates when the event originates from the same client socket.
Updated the `WSPushService` to pass additional metadata during user timestamp updates and event emissions for file system operations. This includes modifications to the `_on_fs_create`, `_on_fs_update`, `_on_fs_move`, and `_on_fs_pending` methods to ensure metadata is consistently included, improving the context for GUI updates.
We do update the path of all child directories by calling
filesystem.update_child_paths(), but this was never done for the user's
actual home directory itself (only everything under it).
The most ideal solution would be to delegate this behavior to the move
operation instead of updating the fsentries table directly, but making
this change right now has a high risk of breaking changes since this the
behavior in this file is very old.
The data extension adds convenient access to the database and kvstore
via it's 'db' and 'kv' exports.
Example usage:
const { db, kv } = extensions.import('data');
await kv.set('some-key', 'some-value');
await db.write('INSERT INTO something (a, b) VALUES (1, 2)');
This commit adds the `extension:list` command for listing extensions.
This command is itself defined in an extension. To make this possible,
an event called 'create.commands' is emitted form CommandService with
the event object holding a function that can be used to add commands.
The custom eslint pluggin for the formatting rule I have for the
expressions in control structures isn't a good fit when the condition is
a single variable named by a single character. This happens a lot with
`catch`. `catch ( e ) {` has too much spacing, but `catch (e) {` looks
relatively normal.
Extensions need to be documented at different layers of concern:
1. How to use/run extensions
2. How to create extensions as a contributor
3. How extensions work under the hood
This documentation addresses the third layer, describing how Kernel
and core modules interact with extensions.
I thought you could:
method() {}
set method (v) { /* ... /* }
but you can't. You have to:
get method() { return (function () {}).bind(this) }
set method (v) { /* ... /* }
I don't know why a setter can't just only shadow setting, but that's
how they designed the language. ¯\_(ツ)_/¯
This change makes sure Kernel skips `.git` directories when scanning
for extensions. This allows me to make a git repository containing
example extensions for Puter.
Previously '{source}' was added but this is a bit difficult to work
with since it's the path from the source file, which is usually the
'src/' directory under the repository. This won't be obvious anyone
who doesn't already know this. '{repo}' just points to the path of
the repository itself.
Extension developers should not have to remember what comes form
where between two different globals. This change makes Extension
effectively a facade (Facade Pattern) containing the behaviors
of both extensions and runtime modules.
RuntimeModule is a new construct which represents the import/export
mechanism for Puter extensions. This can be thought of as analogous
to node's Module class. These are called "runtime modules" because
extensions have less control of what they're consuming than a typical
npm module; i.e. `runtime.import('database')` will provide a version
of 'database' that's compatible with the importing extension, but the
version used can't be locked or otherwise determined by the extension.
* client-cache: remove pulling
* client-cache: fix wrong ts field
* client-cache: purge cache on any local update
* client-cache: last_updated_time -> last_valid_time
* client-cache: update cache on remote update
* client-cache: update last_valid_ts every sec
* client-cache: switch to localstorage
* do the cache and purge test when `setAuthToken` is called
---------
Co-authored-by: Nariman Jelveh <[email protected]>
This commit fixes the block that's meant to match backend files. There
was an error in the arguments for '@stylistic/indent' which was
effectively disabling the entire block. In vscode, it is very unclear
that this is happening, so I had to manually run this command:
npx eslint "src/backend/**/*.js" --debug
This commit also disables @stylistic/quotes; I disagree with this
rule for several reasons:
1. Sometimes the appropriate quote depends on the contents:
i.e. '""""' + "''''" is cleaner than '""""\'\'\'\''.
2. If you argue that mixing quotes between concatenated strings
(like the previous example) is a bad idea, then I can further
state that this rule forces me to mix quotes:
`we use a ${templateString}` + "but can't do it here"
* Complete Bahasa Malaysia (Malay) translation of Puter
* Fix code styling
* Add Malay README.md
* Removed dash from `sub-projek`
* Make `Library` italic
* Add Malay language to `Translations` section
Adds a configuration parameter called "slow" to database config which
adds a hardcoded delay 70ms to database operations. This is useful
when testing for performance issues.
* Add context menu to apps in the start menu
* Start menu context menus: Close other menus
* More bugfixes for start menu context menus
* Start menu context menus: Add/remove from taskbar
* Bugfixes for adding to taskbar through start menu
* Highlight start menu icons when ctxmenu is opened
* Close context menus on start menu kbd navigation
* Reset start menu icon state when ctx menu closed
* Fix multiple start item context menus opening simultaneously
* Remove parent argument from start icon context menus
I translated the last part of the document for the italian language.
All the updates are typo-checked for errors , and there's none.
The translation has been made keeping in mind the italian use of various terms, some of the english words haven't been translated due to the extended use of the orignal term in everyday vocabulary.
* Refactor file system operations in GUI and puter.js to use eventual consistency for stat and readdir calls
This update modifies multiple instances of file system operations to include a consistency option set to 'eventual'. This change aims to improve performance and responsiveness by allowing for eventual consistency in file system interactions across various components, including helpers, UI elements, and IPC handling.
* Update cache expiration time for file system operations in readdir and stat to 1 hour
* feat: add network connectivity monitoring and cache purging
This update introduces a new feature that monitors network connectivity and purges the cache when the connection is lost. The implementation includes event listeners for online/offline changes and visibility changes to ensure cache consistency during network disruptions.
* clean up logs
* Implement the first naive version of `readdir` cache
* Purge the entire cache on every single mutation
Right now we're going to use the very naive, but safe, approach to purge the entire cache whenever there is change in the user's fs. We're going to incrementally improve this; but for now, better safe than sorry!
* Add socket event listeners to flush cache on file system item changes
This update introduces event listeners for 'item.added', 'item.renamed', and 'item.moved' events, triggering a cache flush on each event to ensure data consistency in the file system module.
* increase exp time for the cache
* Update readdir.js
* Update index.js
* refactor: update available_templates function for non-blocking template loading
- Changed the available_templates function to initiate loading templates asynchronously without blocking the UI.
- Initialized window.file_templates with an empty array and updated it once the templates are loaded.
- Added a console log in UIDesktop to track transaction duration upon completion.
* Update UIDesktop.js
Fixed spelling and missing accentuations
Adjusted capitalization for consistency with other strings
Made wording more natural in PT-BR (e.g. “site” instead of “website”, “Login” instead of “Início de Sessão”)
This commit removes debug logs that meet these criteria:
- used console.log instead of the log service
- were left in the source tree accidentally
- show up at boot or during stat/readdir operations
This is not a comprehensrve removal; this is a first pass to get a
few of the trivial cases.
- Introduced `input_image` and `input_image_mime_type` as optional parameters in the AIInterfaceService schema to enhance image processing capabilities.
- Updated `GeminiImageGenerationService` to differentiate between data URLs and web URLs for image handling.
- Added coercion support in CoercionService for converting data URLs to streams, including extraction of content type.
- Documented the txt2img method in AI.js to clarify usage for text and image-to-image generation.
Usually Puter has a UID by this point, but if it ever doesn't we can
fall back on using the path with a `LIKE ? + '%'` query. However,
users before a particular date might have fsentries without a path,
so we need to perform a check on the user's timestamp to avoid issues.
is_empty wasn't working correctly while running concurrently with
fetchEntry because because the check in fetchIsEmpty was too
specific. This commit fixes this issue while also adding support for
a 'path' parameter to is_empty.
- Enhanced the `generate` method to accept base64 encoded input images and their MIME types.
- Implemented validation for input image and MIME type to ensure proper usage.
- Updated the content construction logic to handle both text-to-image and image-to-image generation scenarios.
Earlier I actually thought this wasn't running in prod because when I
run Puter locally the "refresh app cache" message doesn't appear.
I ensured that minlog was off but I forgot that around the same time
I also disabled the "tick" log level by default. If it weren't for
that I would've realized this an hour ago. That said, it's kind of
odd that this seems to be the source of the leak, because this isn't
new behavior.
Replaced inline styles with CSS classes for the captcha modal to improve maintainability and readability. Adjusted JavaScript to accommodate the new structure and ensure proper functionality. Enhanced error handling and loading state management during the captcha verification process.
There used to be an app cache here that would be invalidated but I
think this may have been removed because the invalidation logic
was causing issues. A 30 second cache seems reasonable though, so
let's do that for now.
* chore(i18n/emoji): improve clarity of confirmation and name validation emojis
* chore(i18n/emoji): improve clarity of confirmation and name validation emojis
Previously ES6 Module extensions would only work on versions of node
with --experimental-require-module enabled by default, and provided the
entry file had no top-level await. This commit uses "await import"
conditionally if the "type" in package.json is set to "module".
Sometimes the same fs entry is fetched multiple times concurrently
because of parallel methods with separation of concerns.
After this commit, only one parallel fetch will go through and the
others will wait for it. Subsequent fetches will not occur is the
data that was needed is already there.
The 'quick_check' increases the amount of time it takes to perform a
stat operation significantly proportional to the time it takes to do
a stat because an fsentry fetch occurs before a transient
memoization map is available for an operation.
* the Arabic (العربية) translation of Puter is Completed
* Update ar.js
* updating the Arabic (العربية) translation of Puter
---------
Co-authored-by: jelveh <[email protected]>
For instances where svc_fs.node was called and explicitly passed a
NodePathSelector (instead of being passed a legacy-style object
with a path attribute) this code was failing. This commit moves the
affected code snippet after input coercion and updates references
to use the coerced input.
style: formatting changes were applied to the code. Instead of using
nested conditional blocks we use labelled breaks
Not sure when this went away, but we were always getting the
permission though the file path instead of ID/UUID from what it
looks like, which was hiding this problem.
Add a simple 20 second cache with kv.js to the scan_ method of
PermissionService. This will not improve the performance for
the permission system, but it will invoke it less often.
This is a quick solution for javascript files that should not have Puter
extension code prepended to the top of them. We may want to do something
different in the future like skipping directories named "gui" or
following imports (we can only do that with ESM though) or actually
having a way to run ES modules in their own global context (which is
avaialble in node.js as vm.Module under an experimental flag, but there
is no way to use the default linker for imports in the module);
basically there's no good way to do this and it is very unfortunate.
Previous commit to do this contained accidental other changes that I
staged and forgot about. This commit really only contains the sync for
package-json. This was broken for a while - since when we did work on
AWS secrets manager.
* feat: Differentiate tablets by pointer type
Reclassifies tablets with a mouse/trackpad to use the desktop UI.
This is detected by checking for `(hover: hover)` media query capabilities. This ensures that touch-only tablets retain their original, touch-friendly mobile UI while fixing the bug for users with pointer devices.
* Make sure `matchMedia` exists before using it
---------
Co-authored-by: Nariman Jelveh <[email protected]>
This error message in UIDesktop caused me confusion earlier because it
didn't provide any indication of where the error came from. This commit
adds a string behind the error to specify that it happened while trying
to launch an app.
This commit adds an undefined check for metadata from Puter's desktop
GUI inside a filesystem operation frame; this information won't always
be available.
Allows disabling abuse checks undefined origin checks with config
parameters to make development more convenient. The approach before this
change has been to manually comment out these lines of code.
The extension pseudo-global was only available at the root synchronous
execution context of a module loaded as an extension, which meant it
wasn't available for such things as handler functions for listeners even
though it looks like it should be lexically scoped.
This commit writes a `const` to the top of javascript files in the
runtime copy of an extension so that it works as nearly to a real global
as possible.
A real global isn't possible here for two reasons. First, running in the
same v8 VM as Puter means we can't have distinct global objects with the
same name across different extensions. Second, we can't use node:vm
because we would then be unable to support ES modules, which are
experimental in node:vm and also there's no equivalent to createRequire
for the linker even if we wanted to require the
--experimental-vm-modules flag in our package.json. This seems to be the
best we can do given the state of affairs of the runtime.
Some monitoring services want a system to look like it's failing hard
instead of a system being able to report that it's failing successfully.
This commit adds an alternative to healthcheck that throws 500 when any
service is failing, as though reporting such depended on the services
working, to appease these monitoring services and their semantically
incorrect nature of operation.
This commit message sets the precedent for "mon:" as a conventional
commit style prefix for changes related to system health and monitoring.
This optimization speends up load time for Puter significantly when many
extensions are present. This is also necessary for subsequent changes
which may require prepending code to all the source files inside an
extension, which would be too slow without this optimization.
We can assume Arch users are comfortable with making configuration
changes and observing high volume log output (maybe not true for
alternative distributions of arch, but for base Arch absolutely) so it
probably makes sense to have the log minimizer off for these cases.
* fix(gui): prevent background apps from stealing focus
* remove the `background` option as it's not really needed or used in other parts
---------
Co-authored-by: Nariman Jelveh <[email protected]>
While previously the /rename endpoint sent only a websocket message to
the client, move didn't fire a rename event if the name of the file had
changed. This commit adds a more generalized rename event that can be
reliably used to update a UI whenever the name of a file changes.
* Fix buggy arrow key navigation in start menu
* More fixes for start menu keyboard navigation
* Fix issue with start menu searchbar focus
* Rewritten start menu keyboard navigation
When you need to transform strings or other primitives inside an object
and preserve the object's structure in an optimally memory-efficient
way, this does that.
When /sign is called with UIDs instead of paths, it is possible to get a
response without 'path' properties present in "signed fs item" objects.
This commit addresses the issue by fetching paths from FS node objects
as a last resort.
- Implement a new method to serve a custom 404.html file if it exists in the subdomain root path.
- Update existing error responses to utilize the new custom 404 handling.
- Ensure fallback to default error handling if the custom file is not found or an error occurs during reading.
- Add translations for all previously missing keys in nn.js
- Add translations for UI elements including window titles, alerts, and desktop UI
- Maintain consistent formatting with proper indentation
- Add contextual English comments to aid future translators
- Ensure all keys follow correct naming conventions
Fixes#366
This commit expands on the previously implemented '%appdata%' value for
the 'path' option for "Open File" dialogs and allows it to be a prefix
for arbitrary subdirectories under an app's AppData directory.
This commit adds a 'path' option to showOpenFileDialog by supporting it
in the relevant conditional block in IPC.js. A special path "%appdata%",
which would otherwise produce an error in the file explorer (so no
conflict is possible), will resolve to the appdata directory of the
current app.
* Windows WebDav support
* feat: 2fa support for dav
* fix auth cookie when Basic auth present
* dev: dav: refactor handler, support root level navigation
* dev: dav: JSDOCing important things
* fix: possible edge case of password containing colon character
* feat: direct token login for webdav
* set cookie to not be session cookie
* fx: webdav undefined origin support
Allow apps to launch new instances or other apps with specific files.
The files must be passed as file signature objects, ensuring it was a
file the app was granted access to through a user action.
Adds a 'copy' mode to showSaveFilePicker. In this mode, a source file is
copied to the target file. The file may not exist in another apps
AppData directory. Unlike the 'move' mode, the file can be outside of
the app's AppData directory (a "user" file); in this situation the user
will be prompted to grant permission for the copy action. The app will
have access to the newly-created copy.
Adds service for querying controlling user for a domain. If no user is
verified as allowed to control the domain then we give control to the
'admin' user (to support local configurations of Puter).
After this point, I find myself a bit stuck because DNS queries are
incredibly difficult to test locally when you use tailscale.
With this commit alone, any user can specify "domain" on their
subdomains. This means they could affect the route for domains they
don't control, so this is not production-ready without further changes.
Temporary users can go through email confirmation which effectively
makes these users registered/permanent users. When email is confirmed
they should be moved to the default group for registered users.
* no more global puter object in workers
* also support my as a global in workers
* support incoming user object in workers
* also support myself in puter workers
In EntityStoreService, update and upsert both make use of the
detect_identifier utility function to get an identifier to pass through
to (eventually) SQLES.
For `update`, the `id` object is passed as the argument. Properties are
removed from this object when "redundant identifiers" are extracted to
create the update predicate.
For `upsert`, the `entity` object is passed and `id` is ignored. It is
suspected that this was done for reasons of improved developer
experience for developers using the API. The mutation behavior of
detect_identifier caused issues when trying to modify a property that
can also be used as an identifier, without having another identifier
available. (i.e. need to get UID of a subdomain to change the
`subdomain` property instead of just using `subdomain` to identify it).
This commit modifies the default behavior of detect_identifier to not
remove properties, then adds a flag to preserve the previous behavior
which is set TRUE by `update` since it's widelely used by puter.js and
has higher impact for potential regressions.
This doesn't completely fix the misalignment of selection area but improves a lot of issues with it. A temporary, middle-ground solution until I implement the full-on selection area rendering
* feat(gui): Enhance taskbar functionality and positioning
- Implement dynamic taskbar position management with options for left, bottom, and right placements.
- Update desktop dimensions and window positioning based on taskbar position.
- Add context menu options for changing taskbar position on desktop devices.
- Ensure mobile devices always display the taskbar at the bottom.
- Introduce CSS styles for taskbar positioning and adjust desktop padding accordingly.
* feat(gui): Reinitialize tooltips based on taskbar position
- Implement dynamic tooltip positioning for taskbar items based on the current taskbar location (left, right, bottom).
- Ensure tooltips are destroyed and recreated when the taskbar position is updated, enhancing user experience and consistency.
* feat(gui): Improve taskbar and tooltip positioning
- Add support for dynamic tooltip positioning for the 'top' taskbar location.
- Adjust CSS styles for arrow tooltips to enhance visual alignment and positioning.
- Refine taskbar item positioning for left and right placements to ensure consistent appearance.
* Improve popover positioning based on taskbar location
- Improve `UIPopover` positioning logic to account for left and right taskbar placements.
- Adjust Y position of popovers to ensure they appear correctly below toolbars for left/right taskbars.
- Update CSS styles for arrow tooltips to enforce consistent positioning with !important declarations.
* Refactor context menu positioning logic in UITaskbarItem
- Introduce a helper function to dynamically calculate context menu position based on the taskbar's location (top, bottom, left, right).
- Ensure context menus are positioned correctly relative to the taskbar item, improving usability across different taskbar placements.
* Fix UITaskbar window height calculation for consistent positioning
- Adjust the height calculation for windows in the UITaskbar to remove an unnecessary offset, ensuring accurate window sizing relative to the toolbar height.
- This change improves the visual consistency of maximized windows across different taskbar placements.
* Enhance window snapping and positioning based on taskbar location
- Introduce a new function to calculate snap dimensions and positions dynamically based on the taskbar's location (left, right, bottom).
- Update window snapping logic to ensure windows are positioned correctly relative to the taskbar, improving usability and visual consistency.
- Adjust boundary checks for window placement to account for taskbar height and position, enhancing the overall user experience.
* Update default taskbar position to 'left' and adjust CSS padding for desktop layout
- Change the default taskbar position from 'bottom' to 'left' in UITaskbar.
- Modify CSS to increase left padding for desktop taskbar positioning, enhancing layout consistency.
* Improve CSS for desktop layout with height adjustments
- Update CSS styles for input fields and desktop taskbar to set height to 100vh, ensuring consistent full-page layout across different screen sizes.
- This change improves the visual consistency and usability of the interface.
* Improve desktop selectable interactivity and taskbar tooltip behavior
- Add functionality to mark the desktop as selectable active, improving user interaction with desktop elements.
- Update tooltip display logic to only show when the desktop is not in a selectable state, enhancing usability.
- Adjust CSS styles for desktop layout, ensuring consistent behavior and appearance when the desktop is active or inactive.
* Update default taskbar position logic for first-time and existing users
- Set the taskbar position to 'left' for first-time visitors and default to 'bottom' for returning users without a saved preference.
- This change improves the user experience by providing a more intuitive initial layout for new users while maintaining consistency for existing users.
- Add new animation functionality to the taskbar; icons will enlarge when the mouse hovers over them
- Introduce new CSS properties and styles to support the animation effects
- Implement mouse move and leave event handling in UITaskbar
- Add UITaskBarCreateCurve and UITask components
* Update README.md
* Fixed issue: #1033 (Added app category display in Dev Center in main app list)
* Fixed issue: #1033 (Added app category display in Dev Center in main app list)
* test 1033
* Fixed issue: #1033 (Added app category display in Dev Center in main app list)
* Fixed issue: #1033 (Added app category display in Dev Center in main app list)
* Center the app checkbox
---------
Co-authored-by: jelveh <[email protected]>
- Added login and logout functionality with corresponding UI elements.
- Enhanced layout for user information display and login button.
- Integrated authentication state checks to update UI based on user sign-in status.
- Improved button styles and interactions for better user experience.
- Added user-select: none to disable text selection for better UX.
- Adjusted margins for buttons and elements to improve spacing and alignment.
- Modified the layout of the navigation bar for a cleaner appearance.
- Added a settings button to open a modal for configuring Puter.js URL and API Origin.
- Implemented functions to load and save settings to localStorage.
- Dynamically load the Puter.js script based on user-defined settings.
- Styled the modal and its components for better user experience.
This commit implements uploading Puter files through ai.chat using
Claude's beta "file inputs" feature. To use this, simply specify
`puter_path` in a content part, and that content part will be
transformed into the correct type of content part for the specified file
and the file will be uploaded.
- Introduced a "Reset results" button to clear test container backgrounds and remove error messages.
- Implemented hover styles for the reset button to enhance user interaction.
- Ensured the reset functionality hides the progress panel and resets progress tracking.
- Introduced two new tests: testGetPerformance and testSetPerformance.
- Each test measures the execution time of the respective method and asserts that it completes in under 100ms.
- Ensured correct value retrieval and performance metrics are logged for both tests.
- Added a progress panel to display real-time test execution status, including current test, progress percentage, and elapsed time.
- Introduced styles for the progress panel and its components to enhance visibility and user experience.
- Implemented JavaScript functions to manage progress tracking, including starting and stopping timers, and updating the panel with test results.
- Ensured the progress panel is responsive to test selections and updates dynamically during test execution.
- Adjusted the styles for the test counter to enhance its appearance.
- Removed inline styles from the test counter span for cleaner HTML structure.
- Ensured consistent font size and color for better readability.
- Added a fixed navigation bar for improved accessibility and layout.
- Introduced a test counter to display the number of selected tests.
- Updated styles for better alignment and spacing in the test UI.
- Ensured the counter updates dynamically based on checkbox selections.
- Updated the test UI to include a master checkbox that controls the selection of individual test checkboxes.
- Implemented logic to update the master checkbox state based on the selection of individual checkboxes and group checkboxes.
- Adjusted the margin for h2 checkboxes for improved layout.
- Added sticky positioning for h2 headers in the test section.
- Updated h2 elements to include checkboxes for grouping tests (File System, Key Value Store, AI).
- Implemented event listeners to synchronize individual test checkboxes with their respective group checkboxes.
- Simplified select/unselect all functionality to update group checkboxes accordingly.
All users have access to KV, however the permission system is used
because:
1. KV is a driver, and all drivers have access checks
2. The rate limit policy comes from the permission system
This change uses support for implicit permission shortcuts to prevent
any of the permission association tables from being read. It also
hard-codes the policy so that KV's rate-limit policy is not read from
the policy.json file.
Permission implicators with the "shortcut" option will be checked prior
to concurrent permission scanning. If any of these permissions are
granted, then the concurrent phase of permission scanning will not be
invoked; instead, the user will only see the shortcut permission.
It may be useful to add an option in the future for a full permission
scan, which could be useful in such things as a user interface to help
with permission management.
* experimental Cloudflare Workers for Platforms support
* add support for the puter driver
* stop hardcoding api.puter.localhost
* support destroy from express route as well
* initial worker support
* xhrshim + fixes (incomplete)
* change order of readyState + load event
* remove some debug logs
* change worker/puterUtils into a cjs module
* Cloudflare workers eventtarget workaround
* worker preamble webpack
* edit worker readme to reflect reality
* allow a way to code in api endpoint instead of hardcoding it to api.puter.com
* move cloudflare eventtarget fix to puter-portable template
This is so it gets run before the rest of puter-js initializes
* remove express route for worker
Backend had tests written in mocha as well as a test written for jest
(created by an AI utility, wasn't compatible with mocha tests). The AI
generated test had merit so it was migrated to vitest along with all the
mocha tests, which supports conventions from both frameworks.
Vitest also has an excellent watcher cli.
The root repo package.json now runs unit tests in backend. Before it was
only running tests defined in the _test method of backend services.
* fix: return proper error message when the model is not found
* use global source for the domain
Co-authored-by: Eric Dubé <[email protected]>
---------
Co-authored-by: Eric Dubé <[email protected]>
Closes#1326
- fix mis-handling of aliased models and DRY so it doesn't happen again
- fix where we try to get model details for a pseudo model
(usage-limited)
- fix metering with non-streaming mistral requests
Using LLOWrite outside of HLWrite, which is useful inside a Puter
extension when a simple write operation is being invoked by the backend,
required passing a thumbnail. However, sometimes this is not necessary.
This commit makes it possible run an LLOWrite operation without passing
a thumbnail stream.
The following changes make it easier to host web apps from inside a
Puter extension:
- expose express module to prevent mixing versoins
- allow registration of URLs exempt from origin requirement
Stack traces aren't logged when a health check failure occurs. This was
caused by interfacing with AlarmService directly instead of using the
error service.
The large if...else block for single-item vs multi-item selection
context menu items makes it difficult to extract common behaviors
between the two. For example, the "create shortcut" menu item could be
added by the same code snippet in both cases, and that snippet might
have conditional logic for the number of items (with 1 as a special
case).
The reason to move branching logic to the code snippets that handle
individual menu items is because the previous change to fix shortcuts in
shared directories revealed cross-cutting concerns in branching logic.
Since both single-item and multi-item "create shortcut" options both
have branching to handle the shared directory case, they are now more
similar than different.
Fallbacks from or to the fake-chat service should not be allowed.
Fallbacks to the "costly" model from fake-chat could result in
unintended charges and fallbacks to real models from fake-chat could
result in service abuse.
The SQL statement for creating a group uses syntax that only works under
sqlite. This was caused by introducing anomaly detection when a user
creates a large number of groups in quick succession.
This adds an experimental custom token authentication endpoint to Puter.
This is disabled unless the firebase-auth service is explicitly
configured, and is not yet ready for production use.
* Removed css property overflow: hidden at the parent container which was interfering with the layout calculations and was forcefully clipping child elements
* Replace css property overflow: hidden with contain: paint to fix stacking without masking border-radius
Fixes#1233
Already existing was the functionality to go to puter.local/@username to
access the Public folder belonging to "username". This commit adds the
ability for relative paths such as puter.local/@username/document.md to
access /username/Public/document.md in the suggested app for handling
".md" files.
This is the product of a couple hours of debugging. We can now remove
the uuid entry from the cache for a deleted user without the strange
lockup behavior that was being observed previously. However, it is still
explained exactly how this happened; while this commit addresses the
cause it does not represent an actual understanding of the issue.
What is known is the following:
- /delete-own-user can trigger a complete lockup
- this happens when invalidate_cached_user is called
- kv.del('users:uuid:<uuid of user>') triggers the issue
- ... because get_user returns null and
- configurable_auth middleware accepts the null value
- configurable_auth middleware DOES call next()
- it is unknown why a lockup occurs after this
This allows a logger to be specified in the execution context. If
LogService sees this, it will perform its usual logging but also call
the injected logger.
Driver interfaces don't require specifying the structure of the return
value when it's a JSON object, but parameters require specifying what
parameters can be provided. This commit adds a special wildcard
parameter for interface definitions. When the wildcard parameter is set,
the entire input object is considered as if it were the value of one
parameter.
Instead of puter.drivers.call, make it puter.call. This is accomplished
by allowing puter.js modules to mutate the `puter` object on
initialization. Support for an optional `_init` method, similar to
backend services, is added to Puter modules to help with this.
This commit modifies puter.js to allow calling an
interface+service+method with matching names without redundantly
specifying. The 'ip-geo' service is also renamed to ipgeo to match its
method name and allow a simple:
puter.drivers.call('ipgeo', { ip: '1.2.3.4' })
This commit adds the concept of a toLogFields method on objects which
will determine how they're turned into log fields in LogService. This
method is now implemented on actor to prevent errors when the object is
passed to log functions without being stringified first.
I wasn't able to reprod any memory leak from a user having a large
number of files locally, but it's showing up in logs and maybe could add
up with lots of temp users getting auto-removed. It's worth a shot.
There were issues with async handling in events which can make it
difficult to use event handlers to mutate values provided by an emitter.
This is not an optimal solution: this will await event listeners in
sequence. Ideally, event listeners should be awaited concurrently.
Usage/cost tracking per user was over-fitted to LLM/AI services. This
commit adds CostService and updates AIChatService to use that instead of
updating the `ai_usage` table. The `ai_usage` table is now considered
deprecated.
A service called PermissiveCreditService is enabled by default in
SelfHostedModule. This is so users who host their own Puter instances
don't have to worry about usage limits, since they're providing their
own keys anyway.
Previous logic was:
- on email change, update temporary value
- send email to confirm new email
- temporary value is moved to real email
This doesn't work when an account has not yet confirmed their email
after signup (i.e. user's email_confirmed is still 0). Well, it actually
does work, but the user is only able to confirm the change to their
email and not set their account as having a confirmed email.
New logic has a branch for this case; IFF email_confirmed=0:
- change account confirm code
- send new account confirm email
A logo addition from another PR snuck in. This definitely makes it
consistent with signup, but this logo broken! This commit makes it be
not broken anymore.
* refactor: migrate interfaces.js to new registration mechanism
- Created EntityStoreInterfaceService for crud-q interface\n- Created AnalyticsInterfaceService for puter-analytics interface\n- Added InterfacesModule to load these services\n- Removed interfaces.js\n\nCloses #1131
ai: true
* chore: remove interfaces.js file
ai: true
* fix: DRY CRUD interfaces
This comment is flagged as AI-generated, but Claude rate-limited before
it could actually make the commit so this commit was made by hand. Well,
while I'm writing this commit message I may as well mention that Claud's
rate limits are relentless and it has become impossible to use Claude
for some purposes as a result.
ai: true
* refactor: replace interfaces module with separate Module.js files for entitystore and analytics
- Removed interfaces module\n- Added EntityStoreModule.js to entitystore module\n- Added AnalyticsModule.js to analytics module\n- Updated main index.js to use the new modules directly\n\nai: true
ai: true
* fix: modules exported and registered incorrectly
* feat: add KVStoreModule for puter-kvstore interface
- Created KVStoreModule.js\n- Created KVStoreInterfaceService.js to register the puter-kvstore interface\n- Updated exports.js to include the new module\n\nai: true
* fix: remove index.js from kvstore module
- Removed unnecessary index.js file from kvstore module\n\nai: true
* fix: remove index.js files from analytics and entitystore modules
- Removed unnecessary index.js files from analytics and entitystore modules\n\nai: true
* fix: cleanup mycoder mistakes again
...because it actually threw out my previous commit where I already did
this.
* Added Revis distributed cash to enhance our Captcha Verification system so that we prevent our system from replay attacks
* Fix: There was an error with the implementation of Redis, so I reverted to our previous version that uses in memory storage
* Integrated the captcha verification system into our sign in Form. The captcha verification system now works on both login and sign int
* Remove test files from captcha module
* Update src/backend/src/modules/captcha/middleware/captcha-middleware.js
Co-authored-by: Eric Dubé <[email protected]>
* Update src/backend/src/modules/captcha/middleware/captcha-middleware.js
Co-authored-by: Eric Dubé <[email protected]>
* Now the captcha can be requested on condition, this llaows extenstions to control wether a captcha should be required,
I fixed the code in CaptchaModule to use config
and got rid of the lines that made captcha middleware available since it wasn't used anywhre
* I split the middleware into two distinct parts, so that the frontend can now determine captach requirements. PuterHomePageService can set GUI parameters for captcha requirements. The /whoarewe endpoint provides captcha requirement information and the extensuo system integration is maintained
* Fix security issues with password handling in URL query parameters
* Made sure that the enter key, submits the login request instead of refreshing the captcha
* In development we can now disable the Captcha verification system by running it with CAPTCHA_ENABLED=false npm start
* Went back and modified checkCaptcha so that it checks at the start to check what CAPTCHA_ENABLED is equal to
* Refactor captcha system to use configuration values instead of environment variables
* Fix captcha verification and align with project standards
* Update src/backend/src/modules/captcha/README.md
Co-authored-by: Eric Dubé <[email protected]>
* fix: incorrect service name
* dev: use Endpoint for captcha endpoints
Use Endpoint class, which uses eggspress behind the scenes, which handles
async errors in handlers automatically.
* dev: add extension support and simplify captcha
- removed extra error handling
- removed dormant code
- no distinction between login and signup (for now)
* clean: remove local files
* fix: undefined edge case
---------
Co-authored-by: Eric Dubé <[email protected]>
* feat: add public endpoint for models list
- Created ChatAPIService for public endpoints\n- Added /chat/models and /chat/models/details endpoints\n- Registered service in CoreModule\n- Added tests for the new service\n\nCloses #1227
ai: true
* Update src/backend/src/services/ChatAPIService.js
* Enhanced ai command to perfom other commands
* Enhance AI Command in Puter's shell
* Enahanced ai command to use tooling/function calling
* Fixed circular dependency and added list function to Builtincommand
* Fixed circular dependency and system prompt
- Clarified that the Nodemailer example is for testing MailHog setup\n- Added information about how Puter uses Nodemailer\n- Added references to the EmailService class
ai: true
* docs: improve PuterAI module documentation structure
- Update docmeta.md to describe top-level doc structure\n- Create README.md for PuterAI module documentation\n- Move requests.md content to api_examples.md\n- Add ai_usage_testing.md in contributors directory\n\nCloses #1215\n\nai: true
* docs: remove original requests.md after content migration
Content has been migrated to api_examples.md with improved organization and structure.\n\nai: true
- Renamed 'options' to 'requestParams' to clearly indicate parameters sent to the backend driver\n- Renamed 'settings' to 'userParams' to clearly indicate parameters provided by the user\n- Updated comments to be more descriptive about the purpose of each variable\n\nFixes #1212\n\nai: true
Modified the event handler in AIChatService to only skip usage reporting for fake-chat when it's not using the costly model, allowing the costly model to properly report its usage and costs.
ai: true
Added _init method to FakeChatService to register itself as a provider with AIChatService, ensuring that the service and its models are properly recognized by the system.
ai: true
Added a new 'costly' model to FakeChatService that simulates incurring costs similar to real AI services. This model can be used for testing cost tracking without incurring actual external API costs.
ai: true
This change modifies the SQL query in check_usage_ to only consider AI usage from the past month when checking against limits, rather than all historical usage.
ai: true
* Add support for pasting multiple file extensions at once in Dev Center
* Fix bulk file extension paste functionality in Dev Center
* fix: add try-catch around tippy
* Fix issues with bulk file extension pasting and add comma key support
* Fix issue with duplicate red tags appearing temporarily
* Implement robust bulk file extension paste functionality in Dev Center
* Fix security issue with JSON.stringify to properly escape < characters
* feat: hide icons/show icons feature added to the right-click/secondary click menu on the desktop
* Fix: Changes made to the hide/show desktop icons feature after receiving feedback in the first pull request
* CSS rule added to static CSS file instead of being implemented dynamically
PR 1175 introduced a bug that wasn't caught where alert messages are not
properly assigned. Additionally, the default alert type was "warning"
which is a regression. This commit makes "info" the default alert type
and ensures options.message is the first candidate for the alert message
contents.
* Update README.pl.md
Things I would change:
Line 1: System Operacyjny Internetu -> System Operacyjny Internet
Line 25: system operacyjny internetu -> internetowy system operacyjny
(Original Translation is more like Internet's OS, not Internet OS)
Line 36: Rozwój Lokalny -> Instalacja Lokalna
(Original does not mean programming, but more like growth or evolution)
Line 97: Połącz się z opiekunami -> Skontaktuj się z opiekunami
(Original has meaning, like connecting by cable, not contacting)
* Update README.pl.md
Changed:
Instalacja Lokalna -> Lokalne Środowisko Programistyczne.
This is a step towards getting puter.js to run in node instead of just
in the browser. In node, all the relative imports need to end with the
file extension, and the "type" option in package.json needs to match the
import mechanism used. It was also necessary to migrate
webpack.config.js to ESM syntax, which I would not have done if the
tooling didn't force me to.
* documentation: new documentation for emit features
* Update events documentation and doc_helper.js script
* Update package.json
Co-authored-by: Eric Dubé <[email protected]>
* added manual_overrides.json.js file
* Update doc_helper.js to resolve paths relative to project root and update events documentation
* created a new events.md generated file, differences can be seen.
* added and populated events.md file. Can now compare new and old versions
---------
Co-authored-by: Eric Dubé <[email protected]>
ESLint cannot support our preferred code style for backend without
writing custom plugins. On frontend, we already decided ESLint wasn't a
good fit several months ago. This commit removes the eslint config to
avoid other developer's editors making unwanted whitespace changes.
In backend, we use spaces within control structure parens. This really
does make the code easier to read. In the future, maybe we'll write our
own linter.
* add API to get a list of all available models
* modified listModels() and listModelProviders() for readability.
* remove dead code
---------
Co-authored-by: avijh <[email protected]>
* feat: create and export UsageLimitedChatService for when user exceeds usage limit
* tweak: change comment on usage-limited-chat to better explain action
* fixed whitespace
* tweak: remove test-app from gitignore
* tweak: remove extra spacing in AIChatService usage-limited-chat comment
* tweak: fixed whitespace
* tweak: remove tabbed whitespace in AIChatService
* tweak: remove .qodo from gitignore
* tweak: remove extra enter in AIChatService
* Revert "tweak: remove .qodo from gitignore"
tweak: correct mistake on removing extra enter
This reverts commit e066e294fa.
* tweak: add space at fallback and remove whitespace tabs
* tweak: remove whitespace on brackets
* tweak: remove .qodo and test-app from gitignore
* tweak: add accidentally deleted enter back in
---------
Co-authored-by: Rishabh Shinde <[email protected]>
* Added requestPermission endpoint in SDK, updated IPC handler HeyPuter/puter#1150
* - Updated UIWindowRequestPermission.js to accept multiple permission types
- Updated dialog message for permission window in UIWindowRequestPermission.js
- Updated parameters for call to UIWindowRequestPermission in IPC.js
- Added search_uid.js endpoint to allow GUI searches for fsentry by file UUID HeyPuter#1150
* Updated body and header for Permission Request Dialog HeyPuter#1150
- Replace app uid with app name for header in UIWindowRequestPermission.js
- Added path for file permission request body in UIWindowRequestPermission.js
- Removed previously added search_uid.js api implementation previously as it is replaced by simpler call in gui
* Updated permission description generation in UIWindowRequestPermission.js HeyPuter#1150
* Removed incorrect web handling in IPC.js HeyPuter#1150
* Formatting fixes
* UIAlert with dynamic icon types and default button configurations
* Update src/gui/src/UI/UIAlert.js
Co-authored-by: Eric Dubé <[email protected]>
* Update src/gui/src/UI/UIAlert.js
Co-authored-by: Eric Dubé <[email protected]>
* fix: improve error handling in UIAlert component and reseting package-lock
* fix: update UIAlert to use 'type' for alert type selection
* fix: update UIAlert to use 'type' for button configuration
---------
Co-authored-by: Eric Dubé <[email protected]>
Flex isn't being used in the top bar correctly, which is causing
unpredictable issues when people implement new elements on the top bar.
The best solution for this is to use proper flex values but right now
it's important to get the layout back to normal for production so I'm
implementing this sub-par fix where we always include a spacer element.
* Update README.md
Without clear instructions it wasted a few hours just for setting up.
Atleast no one will face issues with domain name in localhost now
* Making LocalHost website visible
* Making LocalHost website visible v2
I really screwed that up on my first attempt. Puter apps don't trigger
the user-connected websocket event, which rendered thread subscriptions
in apps useless. Furthermore, the uuid of the thread that was subscribed
too wasn't present in the event, which is also pretty useless.
As far as I remember, PermissionService was not using APIError because
it was considered to be only for errors from API endpoints and not
internal calls. However, this never made very much sense: APIError is
really more like "error that Puter's backend actually knows how to
handle" at this point; everything should be APIError and APIError should
probably eventually be renamed.
We were sending a JSON error in what should have been an HTML response.
Additionally, the error message wasn't very clear about the nature of
the problem.
This commit makes everything a ton easier for deployers, adding
configuration options to allow nip.io domains or all origins to access
Puter for ideal LAN or VPN configurations.
I used 'fix' for this instead of 'doc' because I am also adding a
package for code that generates markdown, so this doesn't have the
zero-risk nature typically associated with a "doc: " commit.
I uploaded a video for this one but just realized I never made a commit
for it - it was hiding in my git stash.
So here will be a rare situation that the video link is able to be
placed inside the commit message: https://youtu.be/8XiFR1o5Vuk
As far as I can tell from the block post:
https://blakeembrey.com/posts/2024-09-web-redos/
this vulnerability should not affect releases of Puter before this
update because we do not have any routes with multiple parameters where
the second parameter does not start with '.' or '/'.
However, for the sake of good security hygiene and so `npm audit` looks
nice, we're upgrading the package. (better late than never)
Change username doesn't go through ll_move, and does not adhere to DRY
alongside the /rename operation. This led to an inconsistency where the
rename behavior in the change username operation didn't update the
cached fsentry path.
Some services can't tolerate a message with tool calls and an empty
array set on the content property, despite the fact that OpenAI does
seem to support this.
Mistral has a lot of unnecessary quirks because the SDK coerces to
snake_case. We should see if the OpenAI client works with Mistral, and
it it does we'll use that instead so we don't have to maintain all these
exceptional cases.
This adds an incremental migration from models reporting input and
output tokens, to models reporting full token information. This means
AIChatService doesn't need to lookup the model details or know about the
different types of tokens supported by every model.
The current implementation would break for XAIService because it gets
cumulative usage reports as the stream goes on (whereas OpenAI and
DeepSeek only provide this at the end of the stream).
If these APIs were standardized this would have been so much less
painful, but alas, tool calls are implemented completely differently
between Claude and OpenAI. Good job guys.
- add merging of same-role messages for all normalized inputs
- generalize Claude-specific system message extraction
- remove redundant behavior from Claude
TimeWindow is used by TrackSpendingService for two purposes:
- tracking cost within a time window
- preventing duplicate alarms within a cooldown period
It is important to test this to ensure alarms related to AI costs are
accurate.
Sometimes tool use requests are streamed as JSON, but sometimes they're
streamed as an empty string (causing the JSON parser to error). Had they
not streamed anything we actually would've responded correctly, but
what they stream implies "this empty string is the JSON input" which is
incorrect. Oh well.
The call to sock.write() wasn't waiting for the 'open' event, which
worked fine over non-TLS sockets by chance. Also, responses with only
a single WISP packet were resulting in buffered response data not
being sent to the caller.
One of the test cases has been rendered redundant so it has been
removed. Another test was changed to overwrite a file as it's expected
to already exist.
There was an issue affecting mkdir requests with create_missing_parents
set to true which prevented the correct behavior if some of the listed
parents were already present. This commit ensures mkdir selects the
deepest existing node as the parent before proceeding.
These used to serve a purpose but now they only cause a dependency loop
between LL*/HL* operations and FilesystemService itself, making it
difficult to strategize filesystem behavior.
When getting a stream for an SVG icon from AppIconService with a
previously-fetched stored icon provided, a double-encoding bug was
preventing a valid image from being obtained.
Adds an event for app invalidation.
Moves iconify_apps to AppIconService and adds RecommenededAppsService,
which holds some logic that used to be in get-launch-apps. The event for
app invalidation is then used by RecommenededAppsService to determine
when to clear the recommended apps cache.
Moves AppIconService, OldAppNameService, and ProtectedAppService to the
new apps module to keep things organized, and updates imports. There
were no interesting init errors. Services creating a database at init
were tested for failures but this wasn't an issue. It turns out
initializing with a database accessor before the db service inits is
okay, but using that database accessor at init is not.
There are now several services related to apps, and
RecommendedAppsService is about to be added, making this a good time to
create a separate module for these services and migrate the legacy
service AppInformationService.
During migration it was realized that most of the initialization needed
to occur at boot.consolidation rather than boot.init because the
database needs to be initialized first.
There were a few things which made this rather difficult:
- AWS SDK doesn't appear to have a utility to validate message
signatures.
- The only available node.js module that does this is known to be
unreliable.
- SNS sends 'text/plain' MIME type even though the data is in JSON
format, so a middleware had to be added to account for this.
- We don't accept POST requests with no Origin header. Since SNS doesn't
send the Origin header, an exception had to be made for this.
- The endpoint needs to be public and SNS doesn't seem to have a
proxying utility for developers such as what Stripe has.
- Because of the above point, debugging time was affected by deployment
time to the staging server.
This commit fixes the timing of the /whoami call used for the
PrefixLogger (a logger for puter.js that displays app names) to ensure
the API origin and token are available. This is done by waiting for a
service called 'api-access' to be initialized first.
This was discovered while testing changes for /whoami responses that
display icons, because the current behavior breaks the call for
non-puter.com instances.
Calls to `/whoami` generally don't require app icons. Fetching icons of
the smallest size still incurs round-trip latency from the database and
S3, as well as additional delay for any retries due to failed icon
generation.
Although this is technically a regression in `/whoami`, the impact is
localized to Puter's desktop only because apps are not allowed to
receive taskbar icons.
Current issue with get-launch-apps wasn't fixed by catching errors while
reading the stream so this next attempt catches errors from the call to
start reading.
If the error occurs asynchronously this may not work either.
This happened because the return signature of get_app_icon was changed
so that the MIME type can be returned when the uploaded or default icon
is being used as a fallback. AppES was not updated to account for this
change.
Fix explorer table was always too wide with extra white space on right side causing an unnecessary horizontal scrollbar. Changed width for both the header row and item rows from 100vw to 100%, and added min-width.
Apparently there were two things:
- had to remove contextlink from the test command (that was expected)
- can't import libs from putility in the test environment. The error
produced for this doesn't really explain why.
Updated the romanian translations.
I kept the terms "Professional" and "Business" in English as they are commonly used this way in Romanian in IT services context
I adapted the forms of address to second person singular ("tu") instead of formal ("dumneavoastră") to maintain a friendly and modern tone
I maintained consistency with existing translations in the file
Placeholders (%strong%, %%) were kept in grammatically correct positions for Romanian language
A legacy mkdir function was still being used by the
generate_system_fsentries function. However, it wasn't necessary because
we now associate fsentries by uuid, eliminating the requirement to
create the home directory separately from its subdirectories.
The old mkdir function was removed, and generate_system_fsentries was
moved to a new service called UserService, which is intended to
eventually hold all methods related creating, removing, and updating
users.
* added validation function
* tagify implementation (incomplete)
* tagify implementation (completed)
* feat:implemented Tagify and filetype validation on filetype associaction in dev center
* tweak: removed unnessary tagify from dependency (its streamed from CDN)
* removed unnecessary tagify import
Currently the AI comment writer is trusting the AI to write comment
markers. This means sometimes the syntax of a source file is broken by
comment generation. The instructions in the prompt were pretty clear, so
rather than --fixup'ing the previous commit I'm adding these changes
separately as an interesting case study of how different models behave.
Following this result, I am going to be removing mistral from the
comment writer. It is the most likely to misbehave.
I will also be removing gpt-4o-mini, which sometimes included source
lines despite the "no surrounding text" instruction.
Complete missing Igbo translations in src/gui/src/i18n/translations/ig.js
- Translated all missing keys in the Igbo localization file.
- Ensured cultural appropriateness and accurate representation of English text.
- Carefully handled placeholders like %strong% for proper placement within the translated text.
Adds AIChatService, an implementor of puter-chat-completion which can
delegate to other implementors (implementors that have registered with
AIChatService at initialization) based on details of the request.
Makes AIChatService the test implementation. AIChatService then
delegates to FakeChatService when in test mode.
Adds `models()` method to puter-chat-completion. This method, instead of
returning only the names of supported models, includes other details
such as the cost and maximum output size.
Implements `models()` on Claude and XAI.
Registers Claude and XAI with AIChatService.
Replaces Claude with Grok pretending to be Claude. This is in lieu of a
proper fallback system which will be implemented later.
Grok will always say it's pretending to be Claude rather than
identifying itself as Claude.
This new endpoint shows permissions granted by the current user to the
specified user in the scope of a specified filesystem node, including
permissions on the affecting parent nodes.
This is related to two future tasks:
- prevent users from sharing a file with the same user twice
- add an endpoint to modify the access mode of a shared file
Recursively checking for files with 'see' permission? What was I
thinking? This replaces the disasterously awful approach of scanning a
user's entire file tree to find shares, with an approach which instead
selects on the permissions table and extracts file UUIDs from
permissions.
I need this for development/debugging purposes. I figure I may as well
start developing the system dialog we'll eventually have to create
rather than make a temporary debugging element. This window could
eventually become a full-featured group manager, and can easily be moved
to a settings tab.
This was a really small refactor - about 30mins - that moves the concern
of common constructor args for modules outside of each individual call.
A Context object is now used for common constructor arguments. Some of
the values on this object - such as APIOrigin and authToken - are
following values on the instance of the Puter class. This means that for
some modules it is already possible to eliminate the setAuthToken and
setAPIOrigin listeners (out of scope for this commit). Any which remain
could eventually be replaced with a listener on the Context object
itself.
This commit also moves the initSubmodules method to the top of the class
so that it's easier for new devs to find, in case they're looking into
an issue on a specific module rather than the Puter class itself.
The kdmod module was broken since we renamed packages/ to src/. Also,
the update to mod loading for some unknown reason now requires each call
to require to end with `.js`. As far as I know, this was working
previously.
Allows modules to register a listener to the 'install' event without
creating a Module class. This changes how external modules are
installed.
External modules are now referred to as "extensions"; this commit does
not update the term but does use 'extension' as the name of the global.
This was hilariously difficult to debug. This isn't the first time an
issue like this occurred; this happens because of a deviation between
mysql and sqlite, where a JSON-typed column in mysql will return as a
native object in queries, whereas a JSON-typed column in sqlite is a
string column and will therefore return as an un-parsed JSON string in
queries.
Fixes errors that were noticed being thrown by launch_app, specifically
in the branch of logic when launch_app is called NOT via ExecService.
This branch of logic was added to fix an issue where notepad wasn't
prompting to save unsaved changes on close because data-appusessdk was
not properly set to true. The fix still worked, despite throwing these
errors, because setting data-appUsesSDK to true is the first thing it
does. However, broadcast messages to apps launched with launch_app NOT
via ExecService would have been broken.
Adds a filesystem relay service to GUI-side which currently reports an
exmaple fsentry for /stat and /readdir. Added filesystem services for
both sides. Moved filesystem implementations from src/modules to src/lib
since they're being called by services now rather than modules.
This functionality is effectively disabled unless
src/puter-js/src/services/Filesystem.js is updated to use init_app_fs_()
when the environment is 'app'.
Adds XDIncomingService to manage messages from another window. IPC now
registers with XDIncoming and reports whether it was handled, that way
messages intended to reach GUI can be reliably ignored.
On GUI-side, XDIncomingService will be used by FSRelayService (not yet
implemented) to handle requests for filesystem operations from another
window.
On App-side, XDIncomingService might be used by the PostMessageFS
client-side filesystem implementation terminal to listen for filesystem
events that were relayed by GUI (after a permission check) from their
original websocket source. Either that, or we'll open a filesystem
socket for each app using that app's token.
NoPuterYetService was added because IPC.js is loaded before
globalThis.puter exists, and was the easiest way to still allow IPC's
listener to be registered with XDIncomingService.
APIAccessService was added. This service currently holds auth_token and
api_token and does nothing else. FilesystemService listens to this to
maintain a websocket connection. APIAccessService will help to manage
the complexity of all further code dependent on being informed about
changes to the auth token or origin. Currently in puter.js these are
passed around to several modules which manage the same piece of state
information independantly.
mkdir operation was passing user instead if actor. I really think I
changed this already; getting a crazy deja-vu feeling about it. Maybe a
commit was lost somewhere along the road, but not sure.
Dispatching and listening to events is non-trivial. The apparent
triviality is in implementing a list of listeners and calling them. The
non-triviality is in the nature of what happens to a system when it has
multiple different interfaces to register listeners and publish events.
This commit adds TopicsFeature, which allows any class extending
AdvancedBase to declare topics. A topic is a simple pub/sub channel.
TopicsFeature will manage the state of listeners so the class doesn't
need to. A GC-friendly mechanism for detaching listeners is also provided.
The ServiceManager will replace manual management of services within
initgui, and will also be used within puter.js. Eventually Puter's
backend might use this instead of the existing Container class, although
this will be a large change that needs to be done incrementally.
The difference between ServiceManager and Container is the logic behind
when initialization occurs. Rather than have all services initialized at
once when Container's init() method is called, services are initialized
as soon as their dependencies have been initialized.
Adds CachedFilesystem layer to client filesystem chain. Currently only
stat is implemented. The stat implementation will hold onto an entry for
3 seconds as per hardcoded configuration. Eventually, once invalidation
via websockets is working, this TTL should be extended.
Support for trait method overrides will make it possible to use putility
traits with the decorator pattern while using a proxy class to avoid
redundant re-implementation of proxy methods.
Use of the pattern described above will occur in the implementation of
client-side filesystem caching.
- de-coupled xhr callback passing from the interface of the underlying
filesystem implementation.
- This makes the interface to delegate calls more suitable for use with
the decorator pattern.
- The decorator pattern will be used to manage the complexity of the
caching layer by separating the concerns of different caching methods.
This hides database entries with empty types from the list of suggested
apps for files that have no extension. These entries should also be
removed from the database and the bug causing them should be fixed in
dev center.
This could not be tested locally due to another but only affecting
self-hosted installations. This will be tested in staging in the
meantime while the other bug is being fixed.
Return to phoenix shell when a pty stream is closed by twisp.
Pipes in phoenix with commands from the emulator do not appear to be
working properly, but something in there is working.
This involves establishing the protocol through which phoenix instances
run a command on the emulator. The pty is able to communicate with the
terminal in both directions. This commit adds logs to be removed later.
There are a few things left that this commit does not address:
- handling close of delegate process
- handling sigint from phoenix to delegate process
- closing the connection to twisp
I'll elaborate here because the commit name is confusing. Any time an
app gets a connection to another app, either because it launched that
app (or was launched by that app) or requested a connection to that app,
the ID the app gets to represent the app it's communicating with is now
a pseudo app id rather than the app instance ID. This accomplishes two
things:
1. It's more secure. There are multiple places where GUI assumes that
knowing an app's instance ID means you can do things as that app.
2. Between the same two apps, there may now be more than one connection.
This is useful for situations like Phoenix shell talking to the
emulator in multiple separate instances to pipe commands. (this is
coming later)
Changing the email address on an account that did not already have a
confirmed email would result in the email_confirmed column never being
set. This commit fixes that.
Additionally, an SQL statement using the unconfirmed email to identify a
row was changed so it now uses the user ID instead, which is safer.
Resolves: 759
The literal translation for Pictures IS Gambar-gambar, but after reviewing how it looks on live demo Puter, this translation seems a bit off, since other word like Videos is not Video-video, documents is not Dokumen-dokumen.
So, I think it's better to just translate Pictures to Gambar only. Indonesian actually does not care about singular and plural. If we really need to emphasize it plural, we just repeat the word. Which in this context, it is not that necessary to emphasize it.
This is in preparation for the chat completions driver. OpenAI asks that
a user ID be provided in requests when service is being provided to
other users, so we deterministically generate different UUIDs for this
purpose to prevent user information from being exposed.
This issue was caused by an INSERT statement which adds the admin user
to the admin group. The admin user is created at initialization, so for
new installs it does not exist at the time migration scripts are run.
Additionally, new javascript-coded migrations (.mig.js) would not have
run for new installs because of redundant (WET; not DRY) code for
initial setup.
This commit also improves error handling of the migration service, which
was necessary to diagnose this issue.
In the future, setup always needs to be tested after updating migration
scripts, even though migration of existing databases is where most of
the issues will happen.
Resolves: #639
> Drivers are services that apps on Puter can use. For example, drivers support many of the features in the [Puter SDK](https://docs.puter.com/). If you're not sure if what you're suggesting is a driver, you should use the "Feature Request" template instead.
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name:Node.js CI
on:
push:
branches:["main"]
pull_request:
branches:["main"]
jobs:
build:
runs-on:ubuntu-latest
strategy:
matrix:
node-version:[20.x, 21.x, 22.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
Guidance for AI coding agents working in this repository. Read this before making changes. FOLLOW GUIDANCE AS CLOSELY AS POSSIBLE. If you think the guidance is wrong, raise an issue or flag a maintainer — don't just do what you think is right. This is the source of truth for how we write code, tests, and docs in this repo.
## Documentation Index
Use these as the source of truth before exploring further:
- [README.md](README.md) — project overview and quickstart.
- [SECURITY.md](SECURITY.md) — how to report vulnerabilities (do not file them publicly).
- [BUG-BOUNTY.md](BUG-BOUNTY.md) — bounty program scope.
- [TRADEMARK.md](TRADEMARK.md) — trademark usage.
---
## Backend
The backend is organized as a layered stack inspired by Controller–Service–Repository with dependency injection. Every layer only depends on the layers beneath it, and `PuterServer` ([src/backend/server.ts](src/backend/server.ts)) wires the whole thing together.
| **Controllers** | [src/backend/controllers/](src/backend/controllers/) | Route handlers. Parse + validate input, apply per-route gates (auth, subdomain, rate limit, body parsers via `RouteOptions`), call services, format responses. |
| **Drivers** | [src/backend/drivers/](src/backend/drivers/) | Optional. RPC-style handlers exposed over `/drivers/*`. Thin shells that validate RPC inputs and call into services/stores. |
| **Services** | [src/backend/services/](src/backend/services/) | Business logic. Assume the caller is already authenticated/authorized — services do not run auth gates themselves. |
| **Stores** | [src/backend/stores/](src/backend/stores/) | Persistence. Wraps clients with the domain shape services consume (rows, entities, KV namespaces). |
| **Config** | `config.*.json` → `IConfig` | Flat, typed config object every layer receives at construction. |
Each layer receives the layers beneath it through its constructor. Dependencies are explicit and traceable from `PuterServer`.
### Cross-layer rules
- **Don't reach across layers.** Controllers do not poke clients directly; services do not register routes. If you want to, the abstraction is wrong — fix the abstraction.
- **Don't call sideways within a layer for code reuse.** If two services need the same logic, lift it into a util/helper. Services should not depend on other services for shared code.
- **Prefer explicit arguments over `Context` (ALS).** Reach for [Context](src/backend/core/context.ts) only when the value is genuinely request-scoped and would otherwise thread through many layers. Today it's used sparingly — mostly for `actor` and `req`.
### Extensions
Extensions live in [extensions/](extensions/) and parallel the layered stack. They are for **non-crucial parts of the system** — things Puter still works without if removed. If a feature is load-bearing for clients, it belongs in core, not in an extension (see [whoami](extensions/whoami.ts) as the cautionary example).
The `extension` global ([src/backend/extensions.ts](src/backend/extensions.ts)) exposes:
-`extension.registerClient/Store/Service/Driver/Controller(name, Class)` for first-class additions.
-`extension.on(event, handler)` and `extension.get/post/put/delete/patch/use(path, opts?, handler)` for the lightweight common case. `opts` is the same `RouteOptions` controllers use.
-`extension.import('client' | 'store' | 'service' | 'controller' | 'driver')` returns a lazy proxy to instantiated objects. `extension.config` exposes live config.
### Language & file conventions
- **Modules:** We transpile and build as needed — write ES modules, not CommonJS.
- **TypeScript preferred for new files.** Existing JS is fine; convert opportunistically when you're already touching a file.
- **Reuse types before inventing them.** Search for an existing type first; extend it if close. Only define a new type when nothing fits.
- **Make new types findable.** Co-locate them with the layer/module that owns them, export from the obvious entry point, and use a descriptive `PascalCase` name. Don't hide types in random files where future readers won't grep them.
- **Naming:** `camelCase` for variables/functions, `PascalCase` for classes and for files containing a class (`AuthService.ts`, `KVStoreDriver.ts`).
### Comments
Keep comments light. Prefer self-documenting code — clear names, small functions, obvious flow. Add a comment **only** when:
- The _why_ is non-obvious (a hidden constraint, a workaround, a subtle invariant).
- A non-trivial usage detail would otherwise trip the next reader.
Don't restate what the code already says. Don't write comments that reference the current task or PR or version of something — those rot.
**No ticket references in code or test comments.** Don't write `PUT-1234`, `AUTH-3`, `GUI-2`, `// fix for FOO-99`, `// per ROLLOUT-1`, or section headers like `// -- PUT-1020: ... --`. The ticket exists in git history and the issue tracker; the code should describe the _why_ in domain terms ("logout cascade transparently invalidates...") not project-management terms ("the cascade from AUTH-3..."). Same rule for test-block names and section dividers — describe what's being tested, not which ticket asked for it.
**Use plain ASCII `-` in comment section dividers, not box-drawing characters.** Write `// -- Section name --`, not `// ── Section name ──`. The `─` (U+2500) character renders inconsistently in some editors and diff tools and adds nothing over `-`.
### Tests
When adding new behavior (function, endpoint, driver method, branch of logic), add a test for it.
- Use Vitest for unit and integration tests. Test files go next to the code they test, named `*.test.ts` or `*.test.js`.
- **Mock data, not methods.** Stub the inputs (fixtures, fake rows, sample payloads) rather than mocking the function under test or the layer beneath it. Over-mocking produces tests that pass while production breaks. If you must mock, mock at a real boundary (a client/external service), not within the same layer you're testing.
- Prefer test server over mocking deps. We have existing test utilities for running full test server to boot deps based on config. (see [src/backend/testUtil.ts](src/backend/testUtil.ts)).
- **Hit a real database / real client where reasonable.** Integration shapes catch the things unit tests with mocks miss.
- **Regression tests for bug fixes.** A test that fails before your fix and passes after is the cheapest insurance against the bug coming back.
- If something is genuinely hard to test (UI animation, third-party glue), skip it but say so in the PR.
### Security & privacy
Before opening a PR, scan the diff for:
- Logs, error messages, or responses leaking internal paths, secrets, tokens, env vars, or other users' data.
- Debug routes, test credentials, commented-out auth checks.
- Endpoints returning more than the caller actually needs.
When in doubt, return less. Auth-, permission-, or data-export-related changes deserve an explicit callout in the PR description.
### Working rules of thumb
- **Run it, don't just compile it.** "It type-checks" is not "it works." Exercise the code path end-to-end at least once.
- **Read the neighbors before writing.** Match the shape of similar things already in the tree. If you genuinely think the existing pattern is wrong, raise it — don't quietly diverge.
- **Boy Scout Rule, proportional to the change.** Fix the obvious typo, dead import, or missing typehint in files you're already touching. Don't ride a refactor along with a bug fix — that just makes review harder.
- **Understand what you commit.** AI assistance is fine; shipping code you couldn't defend in review is not.
We at **Puter** are committed to maintaining a secure experience for our users and community. We greatly value the contributions of security researchers and welcome responsible disclosure of security issues.
## Scope
The following are in scope for this program:
* **The Puter open-source project** (available at [github.com/HeyPuter/puter](https://github.com/HeyPuter/puter))
* **`puter.com`**
* **`api.puter.com`**
Out-of-scope:
* Third-party services, applications, or libraries not maintained by Puter.
* Social engineering attacks (e.g., phishing against staff).
* Denial of Service (DoS), spam, or volumetric attacks.
* Physical security issues.
## Known Non-Issues (Please Check Before Submitting)
The following have already been reviewed and determined **not to be vulnerabilities**. Reports that only re-describe one of these are **not eligible for a reward** and will be closed as non-issues — even if they include new code references. Please review this list before submitting:
* **XSS / CORS / token issues scoped to `api.puter.com`.** The primary user session cookie lives on `puter.com`, not on the API origin, so reflected/stored XSS, CORS, or token handling on `api.puter.com` is generally out of scope. Two exceptions we *do* evaluate on their merits — please report these: (a) attacker-controlled content served **inline** (e.g. an HTML `Content-Type`) from API file/response endpoints, and (b) anything that abuses the app-scoped `puter_token_v2` companion cookie set on the API host.
* **SSRF via `secureFetch`.** Production routes outbound requests through an isolated proxy that has no access to internal/SSRF-sensitive resources.
* **Attacks that depend on guessing an `appInstanceID` or app UID.** These are random 128-bit secret values and are not considered guessable.
* **Apps invoking drivers, creating workers, or using KV.** Applications are intended to do this; worker permissions are scoped to the owning app. This is by design.
* **App metadata or app user-count "leaks".** This information is currently public by design.
* **General "token in a URL" / token-lifetime designs** — signed directory URLs exposing children, a write signature implying read, or app tokens outliving a web session. These are current intended behaviors.
* **Missing PKCE, unverified `id_token` signatures, or other OIDC hardening.** Provider tokens are obtained through a server-to-server authorization-code exchange with the provider's token endpoint over TLS, so the resulting `id_token` / userinfo claims are trusted from that channel rather than from local JWKS signature verification — the callback never accepts a caller-supplied `id_token`. Adding local signature / `aud` / `iss` / `exp` checks is welcome defense-in-depth (please open a GitHub issue/PR), but their absence is not an account-takeover vector on its own.
* **JWT "algorithm confusion" / unpinned `algorithms` in `jwt.verify`.** Puter's session tokens are HMAC-signed (HS256) with a server-side secret, and there is no asymmetric public key anywhere in the verification path, so `alg`-substitution attacks do not apply. Explicitly pinning `algorithms` is a fine hardening PR, but it is not a vulnerability.
* **Static-source "SQL injection" in internal pagination.** Findings such as `LIMIT ${limit}` in list/notification queries: the limit is numerically coerced and clamped before it reaches the query, so it is not reachable with attacker-controlled string input. Hardening PRs to the internal stores are welcome, but these are not exploitable as reported.
* **Deprecated `saveTo*` GUI app messages.** The legacy `saveToDesktop` / `saveToDocuments` / etc. app-IPC handlers can create — never overwrite — new files in standard user folders. The behavior is non-destructive, path-traversal-safe, and deprecated (slated for removal); it is not treated as a sandbox escape.
* **Best-practice suggestions** such as login/registration username enumeration (kept intentionally for UX) or unauthenticated unsubscribe links (industry norm).
* **Rate-limiting suggestions for TURN credential issuance** (intentional; not billed per tunnel).
If you believe you have a **genuinely new** exploit chain that defeats one of these rationales (for example, demonstrating a sensitive credential that really is reachable on `api.puter.com`), say so explicitly and show why the reasoning above does not apply.
## Rules of Engagement
To participate, you must:
1.**Report responsibly**: Provide detailed steps to reproduce the issue, including proof-of-concept code, screenshots, or a screen recording (see *Proof of Reproduction* below).
2.**Do no harm**: Do not exfiltrate, modify, or delete data. Only access your own account or test data.
3.**Respect availability**: Do not perform denial-of-service attacks or automated scans that degrade service.
4.**Follow disclosure policy**: Do not publicly disclose vulnerabilities until we have confirmed and patched the issue.
5.**Act in good faith**: Make every effort to avoid privacy violations, destruction of data, and interruption or degradation of services.
6.**Check the Known Non-Issues list**: Reports matching an item in the "Known Non-Issues" section above are not eligible and will be closed.
Reports that do not meet these guidelines may not be eligible for a reward.
## Proof of Reproduction
Reports must demonstrate a **working, reproducible exploit with real impact** — not a theoretical or static-source-review finding. Please include:
* Exact steps to reproduce, the relevant request/response or code path, and the commit or version you tested.
* The **observed** result versus the **expected** result.
* For client-side, UI, or authentication-flow bugs: a short screen recording (≤ 2 minutes) showing the exploit working end-to-end on a real Puter instance.
* For server-side bugs: a runnable proof-of-concept.
Reports based solely on reading the source ("source review only, not tested") or unverified AI/LLM-generated reports are the **lowest triage priority and are generally not eligible**. If you used an AI tool to help find an issue, you must personally verify that it actually reproduces before submitting.
Please submit **one issue per report**. Bundled "audit packs" of many speculative findings will be declined; send each confirmed issue separately.
We aim to acknowledge receipt within **72 hours** and provide a resolution timeline.
## Reward Structure
We offer monetary rewards based on the severity of the vulnerability, as determined by our internal assessment (using CVSS as a guide).
* **Critical: \$1,000 – \$2,000**
* **High: \$500 – \$1,000**
* **Medium: \$200 – \$500**
* **Low: \$50 – \$100**
Non-security issues, suggestions, and best practices feedback are always welcome, but may not qualify for a reward.
If multiple researchers report the same issue, the bounty will be awarded to the first eligible report we receive.
## Payments Disclaimer
All reward amounts are **guidelines only**. Final decisions about eligibility, severity classification, and payout amount are made at the sole discretion of the Puter security team. We reserve the right to determine whether a report qualifies for a bounty, and whether any payment will be issued at all. Submitting a report does not guarantee compensation.
### Payment Method Requirement
At this time, **payments will only be made via PayPal**. To be eligible to receive a bounty, researchers must have a valid PayPal account capable of receiving payments. We are unable to process payments through other services or methods at this time.
## Legal Safe Harbor
If you make a good-faith effort to comply with this policy, we will consider your research to be authorized. If you inadvertently access data outside your own account, stop immediately and include details in your report so we can investigate and remediate.
* **backend:** add script service ([30550fc](https://github.com/HeyPuter/puter/commit/30550fcddda18469735499546de502d29b85e2ad))
* **backend:** Add tab completion to server console command arguments ([fa81dca](https://github.com/HeyPuter/puter/commit/fa81dca9507b7fa0f82099b75f2ab89c865626ac))
* **backend:** Add tab-completion to server console command names ([e1e76c6](https://github.com/HeyPuter/puter/commit/e1e76c6be71fdeb3b6246307b626734d8dc26f86))
* **backend:** add tip of day ([2d8e624](https://github.com/HeyPuter/puter/commit/2d8e6240c61dc6301f49cbdcd1c3b04736f9ca93))
* **backend:** allow services to provide user properties ([522664d](https://github.com/HeyPuter/puter/commit/522664d415c33342500defec309c2ff15bc94804))
* **backend:** allow services to provide whoami values ([fccabf1](https://github.com/HeyPuter/puter/commit/fccabf1bc0c4418f3599222616dd63bf98c14fe1))
* **backend:** improve logger and reduce logs ([4bdad75](https://github.com/HeyPuter/puter/commit/4bdad75766d0617a164024b39b79bf5373c495a6))
* Display app icon and description in embeds ([ef298ce](https://github.com/HeyPuter/puter/commit/ef298ce3aa3ce90224e883fb0ba33f9cd3a3da44))
* get first test working on share-test service ([88d6bee](https://github.com/HeyPuter/puter/commit/88d6bee9546f36d689c53ec7fe95f01f772f5211))
* **git:** Add --color and --no-color options ([d6dd1a5](https://github.com/HeyPuter/puter/commit/d6dd1a5bb0a2b2bba2cfe86d2e51ff2a6e42841c))
* **git:** Add a --debug option, which sets the DEBUG global ([fa3df72](https://github.com/HeyPuter/puter/commit/fa3df72f6ed2d45a440ebc2aacbbae67bf042478))
* **git:** Add authentication to clone, fetch, and pull. ([364d580](https://github.com/HeyPuter/puter/commit/364d580ff896691ee70d3735f495c720651a9f41))
* **git:** Add diff display to `show` and `log` subcommands ([3cad1ec](https://github.com/HeyPuter/puter/commit/3cad1ec436f99a78f782ab9576325d4341284964))
* **git:** Add start-revision and file arguments to `git log` ([49c2f16](https://github.com/HeyPuter/puter/commit/49c2f163515d2130c17a6f6a6a16bc27ea69336a))
* **git:** Allow checking out a commit instead of a branch ([057b3ac](https://github.com/HeyPuter/puter/commit/057b3acf00af49c005b9bf7069c5d22983a32e1e))
* **git:** Color output for `git status` files ([bab5204](https://github.com/HeyPuter/puter/commit/bab5204209aa2efc0c053643677a78db6ede0929))
* **git:** Display file contents as a string for `git show FILE_OID` ([a680371](https://github.com/HeyPuter/puter/commit/a68037111a04580cfa2688694a68ef6ac7a495fa))
* **git:** Display ref names in `git log` and `git show` ([45cdfcb](https://github.com/HeyPuter/puter/commit/45cdfcb5bfa66937b33054a127e0b17001f3faa4))
* **git:** Format output closer to canonical git ([60976b1](https://github.com/HeyPuter/puter/commit/60976b1ed61984d9d290f3a0ae99dd97632e9909))
* **git:** Handle detached HEAD in `git status` and `git branch --list` ([2c9b1a3](https://github.com/HeyPuter/puter/commit/2c9b1a3ffc3d5e282ffe5b83a86314e99445bbc6))
* **git:** Make `git add` work for deleted files ([9551544](https://github.com/HeyPuter/puter/commit/955154468f48e45028dad2e916708d6a763affad))
* **git:** Make shorten_hash() guaranteed to produce a unique hash ([dd10a37](https://github.com/HeyPuter/puter/commit/dd10a377493c0d8f10a1ac8779dc27f3f3bf6c37))
* **git:** Resolve more forms of commit reference ([b6906bb](https://github.com/HeyPuter/puter/commit/b6906bbcaaa50fc8a8c60beb6d2d38bcb7dda758))
* **git:** Understand references like `HEAD^` and `main~3` ([711dbc0](https://github.com/HeyPuter/puter/commit/711dbc0d2fde9c2ddc6c86f64fb4caa7837c9dcb))
* implicit access from apps to shared appdata dirs ([31d4eb0](https://github.com/HeyPuter/puter/commit/31d4eb090efb340fdfb7cb6b751145e859624eeb))
* introduce notification selection via driver ([c5334b0](https://github.com/HeyPuter/puter/commit/c5334b0e19cf9762f536ec482c3ff872e9c12399))
* **phoenix:** Add --dump and --file options to sed ([f250f86](https://github.com/HeyPuter/puter/commit/f250f86446a506f24fa2ad396328e3a2212a68d0))
* **phoenix:** Add more commands to sed, including labels and branching ([306014a](https://github.com/HeyPuter/puter/commit/306014adc77a7ca155feb95d1146cb46ee075b52))
* **phoenix:** Expose parsed arg tokens to apps that request them ([4067c82](https://github.com/HeyPuter/puter/commit/4067c82486c99cad20f41927ad39ebea438b717f))
* **phoenix:** Implement an `exit` builtin ([3184d34](https://github.com/HeyPuter/puter/commit/3184d3482c7b95c0fd1fc0745555ff82fc9a8c99))
* **phoenix:** Implement parsing of sed scripts ([0d4f907](https://github.com/HeyPuter/puter/commit/0d4f907b6675b15bd50a55f50aa28f0803b18b7b))
* **phoenix:** Make `clear` clear scrollback unless `-x` is given ([75a989a](https://github.com/HeyPuter/puter/commit/75a989a7b69bfdfdf69e5f0365027c5b27d8bfc6))
* **Phoenix:** Pass command line arguments and ENV when launching apps ([8f1c4fc](https://github.com/HeyPuter/puter/commit/8f1c4fcda98e72a7b970e8c6fc2fe39a5e012264))
* **phoenix:** Respond to exit status codes ([5de3052](https://github.com/HeyPuter/puter/commit/5de305202656a172b187dac87543d6c1c69a2958))
* **phoenix:** Show actual host name in prompt and neofetch ([4539408](https://github.com/HeyPuter/puter/commit/4539408a218a50244dc615cf7de56c29dcac53e6))
* rate-limit for excessive groups ([4af279a](https://github.com/HeyPuter/puter/commit/4af279a72fc9de89ddc3ba51806ca3760a36265d))
* re-send unreads on login ([02fc4d8](https://github.com/HeyPuter/puter/commit/02fc4d86b7166fb4803be5d28e2a593d6b7d9785))
* register dev center to apps ([10f4d7d](https://github.com/HeyPuter/puter/commit/10f4d7d50ce9314f9c3888c74cb17c8ebbecee98))
* send notification when file gets shared ([2f6c428](https://github.com/HeyPuter/puter/commit/2f6c428a403a006f7878861d2f0356c3294519be))
* start directory index frame ([fb1e2f2](https://github.com/HeyPuter/puter/commit/fb1e2f21fb67aefe0602f6c978199c7cd019bbf7))
* support canonical puter.js url in dev ([fd41ae2](https://github.com/HeyPuter/puter/commit/fd41ae217c7a9f7229326f62a829471580a744bd))
* **ui:** add new components ([577bd59](https://github.com/HeyPuter/puter/commit/577bd59b6cc94810e851ad544f8234e25a4e6e27))
* **ui:** add new components ([38ba425](https://github.com/HeyPuter/puter/commit/38ba42575ce9f3506f8ce219b9580202b3ed9993))
* update share endpoint to support more things ([dd5fde5](https://github.com/HeyPuter/puter/commit/dd5fde5130c1840ab598e6622766ae835142e58a))
### Bug Fixes
* add app_uid param to kv interface ([f7a0549](https://github.com/HeyPuter/puter/commit/f7a054956b8739a3bc305a49faee929ea0da1e15))
* add missing columns for public directory update ([b10302a](https://github.com/HeyPuter/puter/commit/b10302ad744fd9c58f9735743e075815183c772c))
* Add missing file extension to 0009_app-prefix-fix.sql in DB init ([a8160a8](https://github.com/HeyPuter/puter/commit/a8160a8cdcdd6aff98728a6f1643d93386e6bb5a))
* add permission implicator for file modes ([e63ab3a](https://github.com/HeyPuter/puter/commit/e63ab3a67f6555eb13d6af477a8da9f1b54d6608))
* **backend:** remove a bad thing that really doesn't work ([8d22276](https://github.com/HeyPuter/puter/commit/8d22276f13106f7642d11da30b1500817a20ad43))
* bug introduced when refactoring /share to Sequence ([ecb9978](https://github.com/HeyPuter/puter/commit/ecb997885c1efb766827c84d2ffb8dc6ddabe992))
* check subdomain earlier for /apps ([4e3a24e](https://github.com/HeyPuter/puter/commit/4e3a24e6093e279e210765e07e436f4e63b74072))
* do not delegate to select on read like ever that is really dumb ([a2a10b9](https://github.com/HeyPuter/puter/commit/a2a10b94be59403e03fb08bec5d7c056ce5b554f))
* docker runtime fail because stdout columns ([94c0449](https://github.com/HeyPuter/puter/commit/94c0449437ce4cb26d00a15a3f277bc7b09367b4))
* fix issues with apps in /share endpoint ([0cf90ee](https://github.com/HeyPuter/puter/commit/0cf90ee39af6548d271dec45ed8ee9e6df1cd14d))
* fix owner ids for default apps ([283f409](https://github.com/HeyPuter/puter/commit/283f409a662d126e7f3ce811f1467ac6fab9a522))
* fix permission cascade properly this time ([de58866](https://github.com/HeyPuter/puter/commit/de5886698e1eae2b250baac174b57029f3244e96))
* Fix phoenix app prefix and TokenService test ([afb9d86](https://github.com/HeyPuter/puter/commit/afb9d866b5091058711db931cde904947e661c15))
* fix that fix ([b126b67](https://github.com/HeyPuter/puter/commit/b126b670940a0e20cfe7bd0eba3db891bab5c142))
* **git:** Make git commit display detached HEAD correctly ([73d0f5a](https://github.com/HeyPuter/puter/commit/73d0f5a90cb5dcbadfc6d0fd22f14e8bc0e61f86))
* group permission audit table ([7d2f6d2](https://github.com/HeyPuter/puter/commit/7d2f6d256f56e30d752e9999c6e8bde68f9d9637))
* handle subpaths under another user ([d128cee](https://github.com/HeyPuter/puter/commit/d128ceed6f4928fa0793815feb2e2715cd273ff8))
* handling of batch requests with zero files ([c0063a8](https://github.com/HeyPuter/puter/commit/c0063a871fd891a1774f1bee00e86170fed249fa))
* i forgot to test reloading ([7eabb43](https://github.com/HeyPuter/puter/commit/7eabb43bd4257b4129d67eaeda2aa27e8268dc78))
* improve console experience on mac ([15465bf](https://github.com/HeyPuter/puter/commit/15465bfc5035a64762f7c86a3d38af8be6be5b59))
* incorrect error from suggested_apps ([b648817](https://github.com/HeyPuter/puter/commit/b648817f2743c2b6214ebe4177d921c9b9027594))
* Make polyfilled import.meta.filename getter a valid function ([85c6798](https://github.com/HeyPuter/puter/commit/85c679844869b6b05fcbda231d8dc7026a66da97))
* null email in request to /share ([bf63144](https://github.com/HeyPuter/puter/commit/bf63144f7a79c48bd650ae851ddd0c8a10d748c3))
* Only run Component initialization functions once ([5b43358](https://github.com/HeyPuter/puter/commit/5b43358219402bee3eadf4a0f184a4b924d3293b))
* **parsely:** Make Repeat parser work when no separator is given ([9b4d16f](https://github.com/HeyPuter/puter/commit/9b4d16fbe9d5698c57f9da725a22b528a7d7cac2))
* **phoenix:** Add missing newlines to sed command output ([e047b0b](https://github.com/HeyPuter/puter/commit/e047b0bf302284da61e677432e4cc25b531b24f2))
* **phoenix:** Gracefully handle completing a non-existent path ([d76e713](https://github.com/HeyPuter/puter/commit/d76e7130cba9f0ca05940abafe4fd1a41464aa83))
* property validation on some permission endpoints ([0855f2b](https://github.com/HeyPuter/puter/commit/0855f2b36eca3bbdaa8429cbde3aa1242e8e96ee))
* readdir on file ([a72ec97](https://github.com/HeyPuter/puter/commit/a72ec9799ac3bd76ceafa22cce149e373a13f3b9))
* remove last component when share URL is file ([1166e69](https://github.com/HeyPuter/puter/commit/1166e69c76688d1811701c56cd4df9d38e286793))
* remove legacy permission check in stat ([f2c6e01](https://github.com/HeyPuter/puter/commit/f2c6e01296e4214336e63bc2d69bcbf17f59890f))
* Remove null or duplicate app entries from suggest_app_for_fsentry() ([6900233](https://github.com/HeyPuter/puter/commit/6900233c5aaa2d1a49f495e9f9a060796757a91e))
* **security:** Move token for socket.io to request body ([49b257e](https://github.com/HeyPuter/puter/commit/49b257ecffbb1e12090b86a67528a5ad09da69db))
* switch share notif username to sender ([cd65217](https://github.com/HeyPuter/puter/commit/cd65217f5cda1c986ee231e2eeeef5abefa36ecb))
* **Terminal:** Accept input from Chrome on Android ([4ef3e53](https://github.com/HeyPuter/puter/commit/4ef3e53de34f0097950a7e707ca2483863beafb5))
* Throw an error when readdir is called on a non-directory ([46eb4ed](https://github.com/HeyPuter/puter/commit/46eb4ed2b96c235e10e15645a30d2f192a1af0de))
* type error in puter-site ([d96f924](https://github.com/HeyPuter/puter/commit/d96f924cad7a13ea6e9084bb0ebb79ecc5fcb8a3))
* ui color input attributes ([d9c4fbb](https://github.com/HeyPuter/puter/commit/d9c4fbbd1dcce12ee05ee33652a5fa518196463d))
* **ui:** improve Component base class ([f8780d0](https://github.com/HeyPuter/puter/commit/f8780d032b10138851c22af53b8610c578139acc))
* **security:** add ip rate limiting ([ccf1afc](https://github.com/HeyPuter/puter/commit/ccf1afc93c24ee7f9a126216209a185d6b4d9fe4))
* Show "Deleting /foo" in progress window when deleting files ([f07c13a](https://github.com/HeyPuter/puter/commit/f07c13a50cee790eec44bce2f6e56fbcbf73f9b0))
### Bug Fixes
* Add missing file extension to 0009_app-prefix-fix.sql in DB init ([a8160a8](https://github.com/HeyPuter/puter/commit/a8160a8cdcdd6aff98728a6f1643d93386e6bb5a))
* Add missing TextEncoder to PTT ([8d4a1e0](https://github.com/HeyPuter/puter/commit/8d4a1e0ed3872e2c82b9e4be9b6d8b359e9cea09))
* fix error handling for outdated node versions ([4c1d5a4](https://github.com/HeyPuter/puter/commit/4c1d5a4b6d009ce075897d499d3517219bd745a4))
* Fix phoenix app prefix and TokenService test ([afb9d86](https://github.com/HeyPuter/puter/commit/afb9d866b5091058711db931cde904947e661c15))
* increase QR code size ([d2de46e](https://github.com/HeyPuter/puter/commit/d2de46edfbc05d132d5c929f6935b82515fbbda0))
* Make PathCommandProvider reject queries with path separators ([d733119](https://github.com/HeyPuter/puter/commit/d73311945610417a1ebc7bb0723ced0a599594b4))
* Make url variable accessible to all users of it ([2f30ae7](https://github.com/HeyPuter/puter/commit/2f30ae7a825adcd8da95888c38fe39c34acee0ff))
* Only run Component initialization functions once ([5b43358](https://github.com/HeyPuter/puter/commit/5b43358219402bee3eadf4a0f184a4b924d3293b))
* Remove null or duplicate app entries from suggest_app_for_fsentry() ([6900233](https://github.com/HeyPuter/puter/commit/6900233c5aaa2d1a49f495e9f9a060796757a91e))
* **security:** always use application/octet-stream ([74e213a](https://github.com/HeyPuter/puter/commit/74e213a534dbf2844c8cebeee7eb59ec70de306e))
* **security:** Move token for socket.io to request body ([49b257e](https://github.com/HeyPuter/puter/commit/49b257ecffbb1e12090b86a67528a5ad09da69db))
Welcome to Puter, the open-source distributed internet operating system. We're excited to have you contribute to our project, whether you're reporting bugs, suggesting new features, or contributing code. This guide will help you get started with contributing to Puter in different ways.
Thanks for contributing. These rules aren't strictly enforced — but following them makes every PR easier. If anything's unclear, ping a core maintainer or open the PR and ask.
<br>
New to the backend? Start with [doc/architecture.md](doc/architecture.md).
# Report bugs
---
Before reporting a bug, please check our [the issues on our GitHub repository](https://github.com/HeyPuter/puter/issues) to see if the bug has already been reported. If it has, you can add a comment to the existing issue with any additional information you have.
## 1. Test it. Run it.
If you find a new bug in Puter, please [open an issue on our GitHub repository](https://github.com/HeyPuter/puter/issues/new). We'll do our best to address the issue as soon as possible. When reporting a bug, please include as much information as possible, including:
Run the affected code path end-to-end before opening a PR. "It builds" is not "it works."
- A clear and descriptive title
- A description of the issue
- Steps to reproduce the bug
- Expected behavior
- Actual behavior
- Screenshots, if applicable
- Your host operating system and browser
- Your Puter version, location, ...
Add tests for new behavior, endpoints, or bug fixes. If something's genuinely hard to test, say so in the PR.
Please open a separate issue for each bug you find.
## 2. Follow existing patterns
Maintainers will apply the appropriate labels to your issue.
Match the shape of similar code already in the repo. [doc/architecture.md](doc/architecture.md) is the source of truth for layers, wiring, and naming. If you think a pattern is wrong, raise it — don't quietly diverge.
<br>
## 3. Don't expose system or user information
# Suggest new features
Scan your diff for stray logs, debug routes, internal paths, secrets, tokens, or user data in errors/responses. When in doubt, return less. Flag any auth, permission, or data-export changes in the PR description.
If you have an idea for a new feature in Puter, please open a new discussion thread on our [GitHub repository](https://github.com/HeyPuter/puter/discussions) to discuss your idea with the community. We'll do our best to respond to your suggestion as soon as possible.
For private security reports, see [SECURITY.md](SECURITY.md).
When suggesting a new feature, please include as much information as possible, including:
## 4. AI-assisted code is fine — understood code is required
- A clear and descriptive title
- A description of the feature
- The problem the feature will solve
- Any relevant screenshots or mockups
- Any relevant links or resources
Don't commit code you couldn't have written, debugged, or defended yourself. Read the diff, run it, and be ready to explain it in review.
<br>
## 5. Update docs for API changes
# Contribute code
If you change puter-js APIs (drivers or endpoints used by puter-js), update [developer docs](src/docs/). puter-js itself may also need updating.
If you'd like to contribute code to Puter, you need to fork the project and submit a pull request. If this is your first time contributing to an open-source project, we recommend reading this short guide by GitHub on [how to contribute to a project](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project).
## 6. Boy Scout Rule — leave it 1% better
We'll review your pull request and work with you to get your changes merged into the project.
Fix the typo, the dead import, the missing test, the bit you had to read twice. Keep cleanup proportional to the change — no refactors riding along on bug fixes.
We maintain a list of issues that are good for first-time contributors. You can find these issues by searching for the [`good first issue`](https://github.com/HeyPuter/puter/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label in our [GitHub repository](https://github.com/HeyPuter/puter). These issues are designed to be relatively easy to fix, and we're happy to help you get started. Pick an issue that interests you, and leave a comment on the issue to let us know you're working on it.
---
<br>
## Opening a PR
## Documentation for Contributors
- One thing per PR where possible.
- Describe **what** and **why**; the diff shows how.
- Mention how you tested user-visible changes.
- Drafts welcome.
See [doc/contributors/index.md](./doc/contributors/index.md) for more information.
---
<br>
## Commit Messages
Use the imperative, as is the convention in the Linux kernel:
- correct: `Improve performance of readdir`
- incorrect: `Improved readdir`
- incorrect: `Improving readdir`
We have the following exceptions to this rule:
- If the commit message is in _past tense_, it's a shorthand for the following:
-`Apply changes that would be applied after one had <past tense message>`
- If the commit message is in _present tense_, it's shorthand for the following:
-`Apply changes that would be applied after <present-tense message>`
For example, the following are correct:
-`Improved readdir`
- interpret this as: `Apply changes that would be applied after one had improved readdir`
-`Improving readdir`
- interpret this as: `Apply changes that would be applied after improving readdir`
<br>
## Code Review
Once you've submitted your pull request, the project maintainers will review your changes. We may suggest some changes or improvements. This is a normal part of the process, and your contributions are greatly appreciated!
<br>
## Contribution License Agreement (CLA)
Like many open source projects, we require contributors to sign a Contribution License Agreement (CLA) before we can accept your code. When you open a pull request for the first time, a bot will automatically add a comment with a link to the CLA. You can sign the CLA electronically by following the link and filling out the form.
<br>
# Getting Help
If you have any questions about Puter, please feel free to reach out to us through the following channels:
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">The Internet OS! Free, Open-Source, and Self-Hostable.</h3>
<h3 align="center">The Open-Source Internet Computer!</h3>
<p align="center">
<a href="https://puter.com/"><strong>« LIVE DEMO »</strong></a>
<a href="https://puter.com/?ref=github.com"><strong>« LIVE DEMO »</strong></a>
Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. Puter can be used as:
Puter is an advanced, open-source, self-hostable internet computer designed to be feature-rich, fast, and highly extensible.
- A privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time.
- A platform for building and publishing websites, web apps, and games.
- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powerful features.
- A remote desktop environment for servers and workstations.
- A friendly, open-source project and community to learn about web development, cloud computing, distributed systems, and much more!
### 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](https://online-notepad.com) and [Voice Recorder](https://voice-recorder.com) to [Spreadsheet](https://apps.puter.com/app/spreadsheet) and [Camera](https://online-camera.com), 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](https://developer.puter.com/ai/) to [Cloud Storage](https://developer.puter.com/object-storage/) and [Database](https://developer.puter.com/key-value-database/) to [Serverless Workers](https://developer.puter.com/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](https://apps.puter.com/) to reach and monetize users.
<br/>
@@ -43,34 +45,30 @@ Puter is an advanced, open-source internet operating system designed to be featu
```bash
git clone https://github.com/HeyPuter/puter
cd puter
cp .env.example .env
npm install
npm start
```
**→** This should launch Puter at http://puter.localhost:4100
This will launch Puter at http://localhost:4000 (or the next available port).
This repository is licensed under AGPL-3.0; However, our SDK (puter.js) is also available under Apache 2.0, as indicated by the license file in that section (packages/puter-js) of this repository.
We are always happy to help you with any questions you may have. Don't hesitate to ask!
This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses.
<br/>
## Credits
## Translations
The default wallpaper is created by [Milad Fakurian](https://unsplash.com/photos/blue-orange-and-yellow-wallpaper-E8Ufcyxz514) and published on [Unsplash](https://unsplash.com/).
Icons by [Papirus](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme) under GPL-3.0 license.
Icons by [Iconoir](https://iconoir.com/) under MIT license.
Icons by [Elementary Icons](https://github.com/elementary/icons) under GPL-3.0 license.
Icons by [Tabler Icons](https://tabler.io/) under MIT license.
Icons by [bootstrap-icons](https://icons.getbootstrap.com/) under MIT license.
<img src="https://puter.com/images/logo.png" alt="Puter Technologies Inc. Logo" width="150"/>
<br>
This trademark policy was prepared to help you understand how to use the Puter trademarks, service marks and logos with Puter Technologies Inc.'s Puter software.
While some of our software is available under a free and open source software license, that copyright license does not include a license to use our trademark, and this Policy is intended to explain how to use our marks consistent with background law and community expectation.
This Policy covers:
1. Our **word** trademarks and service marks: Puter Technologies Inc., Puter, Puter.com
2. Our **logos**: The Puter Technologies Inc. logo at the top of this policy
This policy encompasses all trademarks and service marks, whether they are registered or not.
<br>
<br>
## 1. GENERAL GUIDELINES
Whenever you use one of our marks, you must always do so in a way that does not mislead anyone about what they are getting and from whom. For example, you cannot say you are providing the Puter software when you're providing a modified version of it, because recipients may not understand the differences between your modified versions and our own.
You also cannot use our logo on your website in a way that suggests that your website is an official website or that we endorse your website.
You can, though, say you like the Puter software, that you participate in the Puter community, that you are providing an unmodified version of the Puter software.
You may not use or register our marks, or variations of them as part of your own trademark, service mark, domain name, company name, trade name, product name or service name.
Trademark law does not allow your use of names or trademarks that are too similar to ours. You therefore may not use an obvious variation of any of our marks or any phonetic equivalent, foreign language equivalent, takeoff, or abbreviation for a similar or compatible product or service. We would consider the following too similar to one of our Marks:
- MyPuter
- PuterFooBar
<br>
<br>
## 2. ACCEPTABLE USES
<br>
### Distribution of Unmodified Software
When you redistribute an unmodified copy of Puter software, you must retain all trademarks, logos, and notices we have placed on the software to identify its origin. This includes:
* Binary distributions exactly as we provide them
* Source code distributions exactly as we provide them
* Documentation and other materials directly from our official repositories
<br>
### Distribution of Modified Software
If you distribute a modified version of Puter software, you:
* Must remove all Puter logos from the modified software
* May use our word marks (but not logos) to accurately describe the software's origin
* Must clearly indicate that the software has been modified
* Must include a notice stating: "This software is a modified version of Puter software and is not endorsed by Puter Technologies Inc."
Example of acceptable description: "This software is derived from Puter software and includes modifications for [describe your changes]."
<br>
### Compatibility Statements
You may use our word marks (but not logos) to accurately describe your software's compatibility with Puter software under these conditions:
* Your statements about compatibility must be accurate and not misleading
* You must include the following notice: "Puter is a trademark of Puter Technologies Inc. This [product/service] is not affiliated with or endorsed by Puter Technologies Inc."
* You may not suggest that Puter Technologies Inc. has certified or approved your software
<br>
### Products Built for Puter
You may describe your product as working with or being built for Puter if:
* Your product is fully compatible with the documented Puter APIs
* Your product name follows this format: "[Your Product Name] for Puter"
* You include this notice in all materials: "Puter is a trademark of Puter Technologies Inc. [Your Product Name] is not affiliated with or endorsed by Puter Technologies Inc."
* Your branding and marketing materials do not create confusion about the source of your product
<br>
### Open Source Projects
For open source projects that interact with or extend Puter software:
* You may use "puter" as part of your project name only if:
* The name is in the format "[descriptor]-puter" (e.g., "auth-puter", "backup-puter")
* The project's README clearly states it's not officially associated with Puter
* The project maintains compatibility with current Puter APIs
* You must not use our logos without explicit permission
* You must include appropriate trademark attribution notices
<br>
### Community Activities
You may use our word marks (but not logos) for non-commercial community activities:
* User groups and meetups focused on Puter software
* Educational content about Puter software
* Blog posts, videos, articles, or tutorials about Puter software
Conditions for community use:
* Activities must be non-commercial
* Any fees charged must only cover actual costs
* You must include appropriate trademark attribution
* You must not suggest official endorsement without explicit permission
<br>
### Merchandise and Promotional Items
You may not create merchandise or promotional items bearing our marks without explicit written permission from Puter Technologies Inc.
<br>
### Academic and Research Use
You may use our word marks (but not logos) in:
* Academic papers
* Research publications
* Technical documentation
* Educational materials
Include appropriate citations and trademark attributions in such uses.
<br>
### Online Content and Social Media
When using our marks in online content:
* You may use our word marks in hashtags, handles, or usernames if:
* The content is clearly about Puter software
* You don't imply official status
* You include appropriate trademark attribution
* You must not register social media accounts that could be confused with official Puter accounts
<br>
### APIs and Development
When developing with Puter APIs:
* You may use our word marks to accurately describe your integration
* You must not use our marks in a way that suggests your API or service is endorse by
Puter or provided by Puter
* You must include appropriate trademark attribution
All uses described above must also comply with the General Guidelines section of this policy and maintain the integrity of our marks as described in the How to Display Our Marks section.
<br>
### No Domain Names
You must not register any domain that includes our word marks or any variant or combination of them.
<br>
<br>
## 3. HOW TO DISPLAY OUR MARKS
When you have the right to use our mark, here is how to display it.
<br>
### Trademark marking and legends
The first or most prominent mention of a mark on a webpage, document, or documentation should be accompanied by a symbol indicating whether the mark is a registered trademark ("®") or an unregistered trademark ("™"). If you don't know which applies, contact us.
Place the following notice at the foot of the page where you have used the mark: "Puter is trademark of Puter Technologies Inc."
<br>
### Use of trademarks in text
**Always use trademarks in their exact form with the correct spelling, neither abbreviated, hyphenated, or combined with any other word or words.**
Unacceptable: Puter-DB
**Don't pluralize a trademark.**
Unacceptable: I have seventeen Puters running in my lab.
**Always use a trademark as an adjective modifying a noun.**
Unacceptable: This is a Puter.
Acceptable: This is a Puter software application.
<br>
### Use of Logos
You may not change any logo except to scale it. This means you may not add decorative elements, change the colors, change the proportions, distort it, add elements, or combine it with other logos.
However, when the context requires the use of black-and-white graphics and the logo is color, you may reproduce the logo in a manner that produces a black-and-white image.
<br>
<br>
## This Document
These guidelines are based on the Model Trademark Guidelines, available at http://www.modeltrademarkguidelines.org., used under a Creative Commons Attribution 3.0 Unported license: https://creativecommons.org/licenses/by/3.0/deed.en_US.
short_description:`Puter is a privacy-first personal cloud that houses all your files, apps, and games in one private and secure place, accessible from anywhere at any time.`,
}));
})
app.use(express.static('./'));
if(env==="prod"){
// make sure to serve the ./dist/ folder maps to the root of the website
Loosely inspired by the Controller–Service–Repository pattern with dependency injection. The backend is organized as a stack of layers where each layer only depends on the layers beneath it, and `PuterServer` ([src/backend/server.ts](../src/backend/server.ts)) instantiates each layer in order and hands the instances down to the next.
DRV["Drivers (optional) — RPC handlers on /drivers/*"]
SVC["Services — business logic, no auth"]
STR["Stores — persistence / domain shapes"]
CLI["Clients — sql, redis, s3, dynamo, email, …"]
CFG["Config — IConfig"]
REQ --> CTRL
CTRL --> DRV
DRV --> SVC
SVC --> STR
STR --> CLI
CLI --> CFG
style REQ fill:#0ea5e9,stroke:#0369a1,color:#fff
style CTRL fill:#1d4ed8,stroke:#1e3a8a,color:#fff
style DRV fill:#2563eb,stroke:#1e40af,color:#fff
style SVC fill:#4f46e5,stroke:#3730a3,color:#fff
style STR fill:#7c3aed,stroke:#5b21b6,color:#fff
style CLI fill:#9333ea,stroke:#6b21a8,color:#fff
style CFG fill:#334155,stroke:#1e293b,color:#fff
```
Each layer only depends on the layers beneath it, and every dependency is injected through the constructor by `PuterServer`. Extensions sit alongside this stack and can register into any layer — see [Extensions](#extensions) below.
| Layer | Lives in | Responsibility |
| --- | --- | --- |
| **Controllers** | [src/backend/controllers/](../src/backend/controllers/) | Route handlers. Parse + validate input, apply per-route gates (auth, subdomain, rate limit, body parsers — see `RouteOptions`), call into services, format responses. |
| **Drivers** | [src/backend/drivers/](../src/backend/drivers/) | Optional. RPC-style handlers exposed over the `/drivers/*` surface (`puter-kvstore`, `puter-chat-completion`, …). A driver is a thin shell that validates RPC inputs and calls into services/stores; controllers can hold a typed reference to drivers when they need the same logic over HTTP. |
| **Services** | [src/backend/services/](../src/backend/services/) | Business logic. Assume the caller is already authenticated/authorized — services do not run auth gates themselves. |
| **Stores** | [src/backend/stores/](../src/backend/stores/) | Persistence and storage logic. Wraps clients with the domain shape services consume (rows, entities, KV namespaces). |
| **Config** | `config.*.json` → `IConfig` | The flat, typed config object every layer receives at construction. |
Each layer receives the layers beneath it through its constructor, so dependencies are explicit and traceable from `PuterServer`. A controller does not reach into a client directly; if it needs one, the right move is usually a service.
## Entry point: `PuterServer`
`PuterServer` is the bootstrap. It:
1. Loads any configured extension directories (`config.extensions`) so extensions can register before instantiation begins.
2. Instantiates each layer in order — clients → stores → services → drivers → controllers — merging in anything extensions have registered for that layer.
3. Wires global middleware, mounts controller routes through `PuterRouter` (which translates `RouteOptions` into the gate/parser middleware chain), and mounts extension routes through the same materializer.
4. Fires `onServerStart` hooks across every layer once HTTP is listening, and `onServerPrepareShutdown` / `onServerShutdown` on the way down.
## Context (ALS)
We use [`Context`](../src/backend/core/context.ts) — backed by `AsyncLocalStorage` — to carry per-request state without threading it through every function signature. It is used **sparingly**, mostly for `actor` and `req`. The request-context middleware opens a scope per request after the auth probe runs; anything inside a request handler can call `Context.get('actor')` / `Context.get('req')` instead of plumbing it as an argument.
Prefer explicit arguments. Reach for `Context` only when the value is truly request-scoped and would otherwise need to thread through many layers.
## Extensions
Extensions live alongside core ([packages/puter/extensions/](../extensions/)) and parallel the layered stack. They are meant for **non-crucial parts of the system** — things Puter still works without if removed.
- **Good extensions**: [thumbnails](../extensions/thumbnails.ts), [serverInfo](../extensions/serverInfo.ts), [devWatcher](../extensions/devWatcher.ts) — opt-in features cleanly bolted on.
- **Should probably be core**: [metering](../extensions/metering.ts), [appTelemetry](../extensions/appTelemetry.ts) — clients now expect these to be present, so the "extension" framing is misleading.
- **Shouldn't have been an extension**: [whoami](../extensions/whoami.ts) — it's load-bearing for every authenticated client. Keep this one in mind as a cautionary example when deciding whether something belongs in an extension.
### Extension API
The `extension` global ([src/backend/extensions.ts](../src/backend/extensions.ts)) exposes:
- **Layer registration** for first-class additions:
- **Lightweight wrappers** for the common case where a full class isn't worth it:
-`extension.on(event, handler)` — subscribe to event-bus events.
-`extension.get(path, opts?, handler)` / `.post` / `.put` / `.delete` / `.patch` / `.head` / `.options` / `.all` / `.use` — register routes. The `opts` shape is the same `RouteOptions` controllers use, so `subdomain`, `requireAuth`, `adminOnly`, body parsers, etc. all work identically.
- **Cross-layer access**: `extension.import('client' | 'store' | 'service' | 'controller' | 'driver')` returns a lazy proxy to instantiated objects, and `extension.config` exposes the live config.
- **TypeScript preferred** in new code where feasible. Existing JS is fine; convert opportunistically when you're already touching a file.
- **`camelCase`** for variable/function names; **`PascalCase`** for classes and for files that contain a class (`AuthService.ts`, `KVStoreDriver.ts`).
- **Deduplicate**. If two services need the same logic, lift it into a util/helper rather than calling sideways across the same layer — services should not depend on other services for code reuse.
- **Don't reach across layers.** Controllers do not poke clients directly; services do not register routes. If you find yourself wanting to, that's usually a signal the abstraction is wrong.
<h3 align="center"><img width="80" alt="Puter.com، الحاسوب السحابي الشخصي: جميع ملفاتك وتطبيقاتك وألعابك في مكان واحد يمكن الوصول إليه من أي مكان في أي وقت." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">نظام تشغيل الإنترنت! مجاني ومفتوح المصدر وقابل للاستضافة الذاتية.</h3>
<p>بيوتر هو نظام تشغيل إنترنت متقدم ومفتوح المصدر، مصمم ليكون غنيًا بالميزات وسريعًا بشكل استثنائي وقابلًا للتوسع بدرجة كبيرة. يمكن استخدام بيوتر كـ:</p>
<ul>
<li>سحابة شخصية تعطي الأولوية للخصوصية لحفظ جميع ملفاتك وتطبيقاتك وألعابك في مكان آمن واحد، يمكن الوصول إليه من أي مكان وفي أي وقت.</li>
<li>منصة لبناء ونشر المواقع الإلكترونية وتطبيقات الويب والألعاب</li>
<li>بديل لـ Dropbox وGoogle Drive وOneDrive وغيرها، مع واجهة جديدة وميزات قوية.</li>
<li>بيئة سطح مكتب عن بُعد للخوادم ومحطات العمل.</li>
<li>مشروع ومجتمع ودود ومفتوح المصدر للتعلم عن تطوير الويب والحوسبة السحابية والأنظمة الموزعة والكثير غير ذلك!</li>
</ul>
</div>
<br/>
## البدء
### 💻 التطوير المحلي
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
سيؤدي هذا إلى تشغيل Puter على http://puter.localhost:4100 (أو المنفذ التالي المتاح).
نحن دائمًا سعداء لمساعدتك في أي أسئلة قد تكون لديك. لا تتردد في السؤال!
<br/>
## الترخيص
هذا المستودع، بما في ذلك جميع محتوياته ومشاريعه الفرعية ووحداته ومكوناته، مرخص تحت [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) ما لم ينص على خلاف ذلك صراحةً. قد تخضع المكتبات الخارجية المدرجة في هذا المستودع لتراخيصها الخاصة.
<h3 align="center"><img width="80" alt="Puter.com, ব্যক্তিগত ক্লাউড কম্পিউটার: আপনার সমস্ত ফাইল, অ্যাপস, এবং গেম এক জায়গায়, যেকোনো সময়, যেকোনো স্থান থেকে অ্যাক্সেসযোগ্য।" src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">ইন্টারনেট ওএস! ফ্রি, ওপেন-সোর্স, এবং সেল্ফ-হোস্টেবল।</h3>
Puter একটি উন্নত, ওপেন-সোর্স ইন্টারনেট অপারেটিং সিস্টেম যা বৈশিষ্ট্যপূর্ণ, অত্যন্ত দ্রুত এবং উচ্চ মাত্রায় সম্প্রসারণযোগ্য। Puter ব্যবহার করা যেতে পারে:
- একটি প্রাইভেসি-প্রথম পার্সোনাল ক্লাউড হিসাবে যা আপনার সমস্ত ফাইল, অ্যাপস এবং গেমসকে এক জায়গায় নিরাপদে রাখে, যেকোনো সময় যেকোনো স্থান থেকে অ্যাক্সেসযোগ্য।
- ওয়েবসাইট, ওয়েব অ্যাপ এবং গেম তৈরি ও প্রকাশ করার একটি প্ল্যাটফর্ম হিসাবে।
- ড্রপবক্স, গুগল ড্রাইভ, ওয়ানড্রাইভ ইত্যাদির বিকল্প হিসাবে একটি নতুন ইন্টারফেস এবং শক্তিশালী বৈশিষ্ট্য সহ।
- সার্ভার এবং ওয়ার্কস্টেশনের জন্য একটি রিমোট ডেস্কটপ এনভায়রনমেন্ট হিসাবে।
- ওয়েব ডেভেলপমেন্ট, ক্লাউড কম্পিউটিং, ডিস্ট্রিবিউটেড সিস্টেম এবং আরও অনেক কিছু শিখতে একটি বন্ধুত্বপূর্ণ, ওপেন-সোর্স প্রকল্প এবং কমিউনিটি হিসাবে!
<br/>
## শুরু করার জন্য
## 💻 লোকাল ডেভেলপমেন্ট
```bash
Copy code
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
এটি Puter কে http://puter.localhost:4100 (অথবা পরবর্তী উপলব্ধ পোর্টে) চালু করবে।
মেইনটেইনার এবং কমিউনিটির সাথে এই চ্যানেলগুলির মাধ্যমে সংযোগ করুন:
- বাগ রিপোর্ট বা ফিচার রিকোয়েস্ট? অনুগ্রহ করে একটি ইস্যু খুলুন।
- ডিসকর্ড: discord.com/invite/PQcx7Teh8u
- X (টুইটার): x.com/HeyPuter
- রেডিট: reddit.com/r/puter/
- মাস্টডন: mastodon.social/@puter
- সিকিউরিটি ইস্যু? security@puter.com
- মেইনটেইনারদের ইমেইল করুন hi@puter.com এ
আপনার যেকোনো প্রশ্নের জন্য আমরা সবসময় সাহায্য করতে প্রস্তুত। জিজ্ঞাসা করতে দ্বিধা করবেন না!
<br/>
## লাইসেন্স
এই রিপোজিটরি, এর সমস্ত বিষয়বস্তু, সাব-প্রকল্প, মডিউল, এবং কম্পোনেন্ট সহ [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) লাইসেন্সের অধীনে লাইসেন্সকৃত, যদি অন্যথায় স্পষ্টভাবে উল্লেখ না করা হয়। এই রিপোজিটরিতে অন্তর্ভুক্ত তৃতীয় পক্ষের লাইব্রেরিগুলি তাদের নিজস্ব লাইসেন্সের অধীনে হতে পারে।
<h3 align="center"><img width="80" alt="Puter.com, Den Personlige Cloudcomputer: Alle dine filer, apps og spil på ét sted tilgængelige fra hvor som helst til enhver tid." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Internet OS'et! Gratis, Open-Source og kan selvhostes.</h3>
Puter er et avanceret, open-source internetoperativsystem designet til at være funktionsrigt, exceptionelt hurtigt og meget udvideligt. Puter kan bruges som:
- En privatlivsfokuseret personlig sky til at opbevare alle dine filer, apps og spil på ét sikkert sted, tilgængeligt hvor som helst og når som helst.
- En platform til at bygge og publicere hjemmesider, webapplikationer og spil.
- Et alternativ til Dropbox, Google Drive, OneDrive osv. med et friskt interface og kraftfulde funktioner.
- Et fjernskrivebordsmiljø for servere og arbejdsstationer.
- Et venligt, open-source projekt og fællesskab til at lære om webudvikling, cloud computing, distribuerede systemer og meget mere!
<br/>
## Kom godt i gang
### 💻 Lokal Udvikling
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Dette vil starte Puter på http://puter.localhost:4100 (eller den næste tilgængelige port).
Vi er altid glade for at hjælpe dig med eventuelle spørgsmål, du måtte have. Tøv ikke med at spørge!
<br/>
## Licens
Dette repository, inklusive alt dets indhold, underprojekter, moduler og komponenter, er licenseret under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), medmindre andet er udtrykkeligt angivet. Tredjepartsbiblioteker inkluderet i dette repository kan være underlagt deres egne licenser.
<h3 align="center"><img width="80" alt="Puter.com, Der persönliche Cloud-Computer: Alle Ihre Dateien, Apps und Spiele an einem Ort, jederzeit und überall zugänglich." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Das Internet-Betriebssystem! Kostenlos, Open-Source und selbst hostbar.</h3>
Puter ist ein fortschrittliches, Open-Source-Internet-Betriebssystem, das funktionsreich, außergewöhnlich schnell und hochgradig erweiterbar konzipiert wurde. Puter kann verwendet werden als:
- Eine datenschutzfreundliche persönliche Cloud, um alle Ihre Dateien, Apps und Spiele an einem sicheren Ort aufzubewahren, jederzeit und überall zugänglich.
- Eine Plattform zum Erstellen und Veröffentlichen von Websites, Webanwendungen und Spielen.
- Eine Alternative zu Dropbox, Google Drive, OneDrive usw. mit einer frischen Benutzeroberfläche und leistungsstarken Funktionen.
- Eine Remote-Desktop-Umgebung für Server und Workstations.
- Ein freundliches, Open-Source-Projekt und eine Community, um mehr über Webentwicklung, Cloud Computing, verteilte Systeme und vieles mehr zu lernen!
<br/>
## Erste Schritte
### 💻 Lokale Entwicklung
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Dies startet Puter unter http://puter.localhost:4100 (oder dem nächsten verfügbaren Port).
Wir helfen Ihnen gerne bei allen Fragen, die Sie haben könnten. Zögern Sie nicht zu fragen!
<br/>
## Lizenz
Dieses Repository, einschließlich aller Inhalte, Unterprojekte, Module und Komponenten, ist unter [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) lizenziert, sofern nicht ausdrücklich anders angegeben. In diesem Repository enthaltene Bibliotheken von Drittanbietern können ihren eigenen Lizenzen unterliegen.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">The Internet OS! Free, Open-Source, and Self-Hostable.</h3>
Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. Puter can be used as:
- A privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time.
- A platform for building and publishing websites, web apps, and games.
- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powerful features.
- A remote desktop environment for servers and workstations.
- A friendly, open-source project and community to learn about web development, cloud computing, distributed systems, and much more!
<br/>
## Getting Started
### 💻 Local Development
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
This will launch Puter at http://puter.localhost:4100 (or the next available port).
We are always happy to help you with any questions you may have. Don't hesitate to ask!
<br/>
## License
This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses.
<h3 align="center"><img width="80" alt="Puter.com, El Computador Personal en Nube: Todos tus archivos, apps y juegos en un solo lugar accesible desde cualquier lugar en cualquier momento" src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">El Sistema Operativo de Internet! Gratis, de Código abierto, y Autohospedable.</h3>
<p align="center">
<a href="https://puter.com/"><strong>« DEMO EN VIVO »</strong></a>
Puter es un sistema operativo en internet avanzado y de código abierto, diseñado para ser rico en funcionalidades, excepcionalmente rápido y altamente extensible. Puter puede ser usado como:
- Una nube personal privada para almacenar todos tus archivos, aplicaciones y juegos en un lugar seguro, accesible y desde cualquier lugar en cualquier momento.
- Una plataforma para construir y publicar páginas web, aplicativos sobre la web y juegos.
- Una alternativa a Dropbox, Google Drive, OneDrive, etc. con una interfaz fresca y llena de funcionalidades.
- Un entorno de escritorio remoto para servidores y estaciones de trabajo.
- Un proyecto y comunidad abiertas y amigables para aprender sobre desarrollo web, computación en la nube, sistemas distribuidos y mucho más!
<br/>
## Primeros Pasos
### 💻 Desarrollo Local
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
✨ Esto ejecutará Puter en http://puter.localhost:4100 (o el siguiente puerto disponible).
Si esto no funciona, consulta [First Run Issues](./doc/self-hosters/first-run-issues.md) para obtener pasos de solución de problemas.
✨ Esto ejecutará Puter en http://puter.localhost:4100 (o el siguiente puerto disponible).
<br/>
### 🚀 Auto-Hospedaje
Para guías detalladas sobre cómo auto-hospedar Puter, incluyendo opciones de configuración y mejores prácticas, consulta nuestra [Documentación de Auto-Hospedaje](https://github.com/HeyPuter/puter/blob/main/doc/self-hosters/instructions.md).
### ☁️ Puter.com
Puter está disponible como servicio alojado en [**puter.com**](https://puter.com).
<br/>
## Requerimientos del sistema
- **Sistemas operativos:** Linux, macOS, Windows
- **RAM:** 2GB mínimo (4GB recomendados)
- **Almacenamiento:** 1GB de espacio libre
- **Node.js:** Versión 16+ (Versión 23+ recomendada)
- **npm:** Última version estable
<br/>
## Soporte
Conéctate con los mantenedores y la comunidad a través de estos canales:
- Reporte de bug o solicitud de funcionalidad? Por favor [abrir un issue](https://github.com/HeyPuter/puter/issues/new/choose).
Estamos siempre felices de ayudar con cualquier pregunta que puedas tener. No dudes en preguntar!
<br/>
## Licencia
Este repositorio, incluyendo todo su contenido, sub-proyectos, modulos y componentes, esta licenciado bajo [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) a menos que se indique explícitamente lo contrario. Librerías de terceros incluidos en este repositorio pueden estar sujetas a sus propias licencias.
<h3 align="center"><img width="80" alt="Puter.com، رایانش ابری شخصی: همه فایلها، برنامهها و بازیهای شما در یک مکان قابل دسترسی از هر جا و در هر زمان." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">سیستمعامل اینترنت! رایگان، متنباز، و قابل میزبانی شخصی.</h3>
<p>پیوتر یک سیستم عامل تحت وب پیشرفتهی متنباز است که به منظور ایجاد ویژگیهای متنوع، سرعت بسیار بالا، و مقیاسپذیری طراحی شده است. از پیوتر میتوان بهعنوان:</p>
<ul>
<li>یک فضای ابری شخصی که بر حریم خصوصی تمرکز دارد و تمام فایلها، برنامهها، و بازیهای شما را در یک مکان امن ذخیره میکند، قابل دسترسی از هر جا و در هر زمان.</li>
<li>پلتفرمی برای ساخت و انتشار وبسایتها، اپلیکیشنهای وب، و بازیها.</li>
<li>جایگزینی برای Dropbox، Google Drive، OneDrive، و سایر موارد، با یک رابط کاربری مدرن و قابلیتهای قدرتمند.</li>
<li>یک محیط دسکتاپ از راه دور برای سرورها و ایستگاههای کاری.</li>
<li> یک پروژه و جامعهی متنباز دوستانه برای یادگیری توسعه وب، رایانش ابری، سیستمهای توزیعشده، و موارد دیگر نام برد!</li>
</ul>
</div>
<br/>
## نحوهی استفاده
### 💻 توسعهی محلی
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
این کار پیوتر را در http://puter.localhost:4100 (یا پورت در دسترس بعدی) اجرا میکند.
ما همیشه از پاسخگویی به سوالات شما خرسند هستیم. در سوال پرسیدن درنگ نکنید!
## گواهی
این مخزن، شامل تمام محتویات، پروژههای فرعی، ماژولها و اجزای آن، تحت مجوز [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) است مگر آنکه خلاف آن بهطور صریح ذکر شده باشد. کتابخانههای خارجی ممکن است گواهیهای جداگانه داشته باشند.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Internetin käyttöjärjestelmä! Ilmainen, avoimen lähdekoodin ja itse isännöitävä.</h3>
Puter on kehittynyt, avoimen lähdekoodin internetin käyttöjärjestelmä, joka on suunniteltu olemaan ominaisuuksiltaan rikas, poikkeuksellisen nopea ja erittäin laajennettava. Puteria voidaan käyttää:
- Yksityisyyttä kunnioittavana henkilökohtaisena pilvenä, johon voit tallentaa kaikki tiedostosi, sovelluksesi ja pelisi turvallisesti yhdessä paikassa, josta ne ovat saatavilla missä tahansa ja milloin tahansa.
- Alustana verkkosivustojen, web-sovellusten ja pelien rakentamiseen ja julkaisemiseen.
- Vaihtoehtona Dropboxille, Google Drivelle, OneDrivelle jne. tuoreella käyttöliittymällä ja tehokkailla ominaisuuksilla.
- Etätyöpöytäympäristönä palvelimille ja työasemille.
- Ystävällisenä, avoimen lähdekoodin projektina ja yhteisönä, jossa voit oppia verkkokehityksestä, pilvipalveluista, hajautetuista järjestelmistä ja paljon muusta!
<br/>
## Aloittaminen
### 💻 Paikallinen kehitys
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Tämä käynnistää Puterin osoitteessa http://puter.localhost:4100 (tai seuraavassa vapaassa portissa).
Olemme aina valmiita auttamaan sinua kaikissa kysymyksissäsi. Älä epäröi kysyä!
<br/>
## Lisenssi
Tämä repository, mukaan lukien kaikki sen sisältö, aliprojektit, moduulit ja komponentit, on lisensoitu [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt)-lisenssillä, ellei toisin mainita. Tämän repositoryn mukana tulevat kolmannen osapuolen kirjastot voivat olla omien lisenssiensä alaisia.
<h3 align="center"><img width="80" alt="Puter.com, L'ordinateur cloud personnel : Tous vos fichiers, applications et jeux en un seul endroit accessible de partout à tout moment." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">L'OS Internet ! Gratuit, open-source et auto-hébergeable.</h3>
Puter est un système d'exploitation internet avancé, open-source, conçu pour être riche en fonctionnalités, extrêmement rapide et hautement extensible. Puter peut être utilisé comme :
- Un cloud personnel axé sur la confidentialité pour garder tous vos fichiers, applications et jeux en un seul endroit sécurisé, accessible de partout à tout moment.
- Une plateforme pour créer et publier des sites web, des applications web et des jeux.
- Une alternative à Dropbox, Google Drive, OneDrive, etc. avec une interface renouvelée et des fonctionnalités puissantes.
- Un environnement de bureau à distance pour serveurs et stations de travail.
- Un projet et une communauté open-source accueillants pour apprendre le développement web, l'informatique en nuage, les systèmes distribués, et bien plus encore !
<br/>
## Démarrage
### 💻 Développement Local
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Cela lancera Puter à http://puter.localhost:4100 (ou au port disponible suivant).
Nous sommes toujours heureux de vous aider avec toutes les questions que vous pourriez avoir. N'hésitez pas à nous demander !
<br/>
## License
Ce dépôt, y compris tout son contenu, sous-projets, modules et composants, est licencié sous [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) sauf indication contraire explicite. Les bibliothèques tierces incluses dans ce dépôt peuvent être soumises à leurs propres licences.
אנחנו תמיד שמחים לעזור עם כל שאלה שיש. אל תהסס לשאול!
<br/>
## רישיון
ספריה זו, כולל כל התכנים שלה, תתי הפרויקטים, המודולים והרכיבים שלה, מורשית תחת [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) אלא אם נאמר אחרת במפורש. לספריות צד שלישי הכלולות בספרייה זו עשויות להיות רישיונות משלהן.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: आपकी सारी फाइलें, ऐप्स, और गेम एक ही जगह, जिसे कहीं से भी कभी भी एक्सेस किया जा सकता है।" src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">इंटरनेट ओएस! फ्री, ओपन-सोर्स, और सेल्फ-होस्टेबल।</h3>
Puter एक एडवांस्ड, ओपन-सोर्स इंटरनेट ऑपरेटिंग सिस्टम है जिसे फीचर-रिच, तेज़ और एक्सटेंडेबल बनाने के लिए डिज़ाइन किया गया है। Puter का उपयोग आप निम्नलिखित चीजों के लिए कर सकते हैं:
- एक प्राइवेसी-फर्स्ट पर्सनल क्लाउड, जो आपकी सभी फाइलों, ऐप्स और गेम्स को एक सेफ जगह पर रखता है, जिसे आप कहीं से भी कभी भी एक्सेस कर सकते हैं।
- वेबसाइट्स, वेब ऐप्स और गेम्स बनाने और पब्लिश करने का एक प्लेटफ़ॉर्म।
- Dropbox, Google Drive, OneDrive आदि का एक शानदार और पावरफुल इंटरफ़ेस वाला विकल्प।
- सर्वर और वर्कस्टेशन के लिए एक रिमोट डेस्कटॉप एनवायरनमेंट।
- एक फ्रेंडली ओपन-सोर्स प्रोजेक्ट और कम्युनिटी, जहां आप वेब डेवलपमेंट, क्लाउड कंप्यूटिंग, डिस्ट्रीब्यूटेड सिस्टम्स और बहुत कुछ सीख सकते हैं।
<br/>
## शुरुआत कैसे करें?
### 💻 लोकल डेवलपमेंट
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
✨ यह Puter को
<font color="red"> http://puter.localhost:4100 </font> (या अगले उपलब्ध पोर्ट) पर लॉन्च करेगा।
अगर यह काम नहीं करता, तो [First Run Issues](./doc/self-hosters/first-run-issues.md) देखें।
<font color="red"> http://puter.localhost:4100 (or the next available port). </font> (या अगले उपलब्ध पोर्ट) पर लॉन्च करेगा।
<br/>
### 🚀 सेल्फ-होस्टिंग
सेल्फ-होस्टिंग के लिए विस्तृत गाइड, कॉन्फ़िगरेशन ऑप्शन्स और बेस्ट प्रैक्टिसेज जानने के लिए हमारी [Self-Hosting Documentation](https://github.com/HeyPuter/puter/blob/main/doc/self-hosters/instructions.md) देखें।
<br/>
### ☁️ Puter.com
Puter [**puter.com**](https://puter.com) पर एक होस्टेड सर्विस के रूप में भी उपलब्ध है।
<br/>
## सिस्टम आवश्यकताएँ
* **ऑपरेटिंग सिस्टम्स:** Linux, macOS, Windows
* **RAM:** कम से कम 2GB (4GB रिकमेंडेड)
* **डिस्क स्पेस:** 1GB फ्री स्पेस
* **Node.js:** वर्जन 16+ (वर्जन 23+ रिकमेंडेड)
* **npm:** लेटेस्ट स्टेबल वर्जन
<br/>
## सपोर्ट
नीचे दिए गए माध्यमों से आप मेंटेनर्स और कम्युनिटी से जुड़ सकते हैं:
* बग रिपोर्ट या फीचर रिक्वेस्ट? [यहाँ issue खोलें](https://github.com/HeyPuter/puter/issues/new/choose)।
आपके किसी भी सवाल में मदद करने के लिए हम हमेशा तैयार हैं!
<br/>
## लाइसेंस
यह रिपॉज़िटरी और इसके सभी कंटेंट्स [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) लाइसेंस के अंतर्गत आते हैं जब तक कि कुछ और स्पष्ट रूप से ना लिखा हो। इसमें शामिल थर्ड-पार्टी लाइब्रेरीज़ अपने-अपने लाइसेंस के अधीन हो सकती हैं।
<br/>
## अनुवाद
Puter के डॉक्यूमेंटेशन कई भाषाओं में उपलब्ध हैं, जिनमें शामिल हैं:
<h3 align="center"><img width="80" alt="Puter.com, A személyi felhő számítógép: Minden fájl, alkalmazás és játék egy helyen elérhető bárhonnan, bármikor." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Az internetes oprendszer! Ingyenes, nyílt-forráskódú, saját szerveren futtatható.</h3>
A Puter egy fejlett, nyílt forráskódú internetes operációs rendszer, amelyet úgy terveztek, hogy funkciókban gazdag, kivételesen gyors és nagymértékben bővíthető legyen. A Puter a következőképpen használható:
- Egy adatvédelmet előtérbe helyező személyes felhő, amely minden fájlt, alkalmazást és játékot egy biztonságos helyen tart. Bárhonnan és bármikor elérhető.
- Egy platform weboldalak, web-appok, és játékok készítéséhez/közzétételéhez.
- A Dropbox, Google Drive, OneDrive (stb.) alternatívája megújult felülettel és hatékony funkciókkal.
- Egy távoli desktop-környezet szervereknek és workstation-öknek.
- Egy barátságos, nyílt forráskódú projekt és közösség, amely a webfejlesztéssel, a felhőalapú számítástechnikával, elosztott rendszerekkel és sok más érdekes témával foglalkozik!
<br/>
## Első lépések
### 💻 Helyi (lokális) fejlesztés
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Ezzel a http://puter.localhost:4100 -on futtatjuk Putert. (vagy a legközelebbi elérhető porton).
Mindig örömmel segítünk bármilyen felmerülő kérdésben. Bátran kérdezz tőlünk!
<br/>
## License
Ez a repo, beleértve annak minden tartalmát, alprojektjeit, moduljait és komponenseit, az [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) licenc alatt áll, hacsak másképp nem rendelkeznek róla. A repoban szereplő harmadik fél által fejlesztett könyvtárak saját licencfeltételek alá eshetnek.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Ինտերնետ ՕՀ! Անվճար, բաց կոդով և ինքնահոսթ հնարավորությամբ։</h3>
Puter-ը առաջադեմ, բաց կոդով ինտերնետային օպերացիոն համակարգ է, որը նախագծված է լինել ֆունկցիոնալ հարուստ, բացառիկ արագ և բարձր ընդլայնելի։ Puter-ը կարող է օգտագործվել հետևյալ կերպ․
- Անձնական ամպային համակարգ՝ առաջնային գաղտնիությամբ, որը թույլ է տալիս պահել ձեր բոլոր ֆայլերը, հավելվածները և խաղերը մեկ անվտանգ վայրում, որը հասանելի է ցանկացած վայրից և ցանկացած ժամանակ։
- Պլատֆորմ կայքերի, վեբ հավելվածների և խաղերի ստեղծման և հրապարակման համար։
- Dropbox, Google Drive, OneDrive և այլ ծառայությունների այլընտրանք՝ նոր ինտերֆեյսով և հզոր գործառույթներով։
- Հեռավոր աշխատասեղանի միջավայր սերվերների և աշխատանքային կայանների համար։
- Պարզ, բաց կոդով նախագիծ և համայնք՝ վեբ ծրագրավորման, ամպային հաշվարկների, բաշխված համակարգերի և այլ թեմաների մասին սովորելու համար։
<br/>
## Սկսել
### 💻 Լոկալ ծրագրավորում
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Սա կգործակի Puter-ը հետևյալ հասցեով՝ http://puter.localhost:4100 (կամ հաջորդ հասանելի պորտով)։
Մենք միշտ ուրախ ենք օգնել ձեզ ցանկացած հարցում։ Մի կաշկանդվեք հարցնել։
<br/>
## Լիցենզիա
Այս պահոցարանը, ներառյալ բոլոր իր բովանդակությունը, ենթա-պրոյեկտները, մոդուլները և բաղադրիչները, լիցենզավորվում են [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) լիցենզիայի տակ, եթե այլ կերպ հստակ նշված չէ։ Այս պահոցարանում ներառված երրորդ կողմի գրադարանները կարող են ենթարկվել իրենց սեփական լիցենզիաներին։
<h3 align="center"><img width="80" alt="Puter.com, Komputer Cloud Pribadi: Semua file, aplikasi, dan permainan Anda berada di satu tempat yang dapat diakses dari mana saja kapan saja." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Sistem Operasi Internet! Gratis, Sumber Terbuka, dan Dapat Dihosting Sendiri.</h3>
Puter adalah sistem operasi internet canggih, open-source, yang dirancang untuk menjadi kaya fitur, sangat cepat, dan sangat dapat diperluas. Puter dapat digunakan sebagai:
- Cloud pribadi yang mengutamakan privasi untuk menyimpan semua file, aplikasi, dan permainan Anda di satu tempat yang aman, yang dapat diakses dari mana saja kapan saja.
- Platform untuk membangun dan mempublikasikan situs web, aplikasi web, dan permainan.
- Alternatif untuk Dropbox, Google Drive, OneDrive, dll. Dengan antarmuka baru dan fitur-fitur canggih.
- Lingkungan desktop jarak jauh untuk server dan workstation.
- Proyek dan komunitas open-source yang ramah untuk belajar tentang pengembangan web, komputasi gemawan (cloud), sistem terdistribusi, dan banyak lagi!
<br/>
## Memulai
### 💻 Pengembangan Lokal
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Ini akan menjalankan Puter di http://puter.localhost:4100 (atau di port berikutnya yang tersedia)
Kami selalu senang membantu Anda dengan pertanyaan apa pun yang Anda miliki. Jangan ragu untuk bertanya!
<br/>
## Lisensi
Repositori ini, termasuk semua isinya, sub-proyek, modul, dan komponen, dilisensikan di bawah [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) kecuali dinyatakan sebaliknya secara eksplisit. Perpustakaan pihak ketiga yang termasuk dalam repositori ini mungkin tunduk pada lisensinya sendiri.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Il sistema operativo di Internet! Gratuito, Open-Source e Auto-Hostabile.</h3>
Puter è un sistema operativo di Internet avanzato e open-source, progettato per essere ricco di funzionalità, eccezionalmente veloce e altamente estensibile. Puter può essere utilizzato come:
- Un cloud personale che tiene conto della privacy per conservare tutti i file, le app e i giochi in un luogo sicuro, accessibile da qualsiasi luogo e in qualsiasi momento.
- Una piattaforma per creare e pubblicare siti web, app e giochi.
- Un'alternativa a Dropbox, Google Drive, OneDrive, ecc. con un'interfaccia nuova e funzioni potenti.
- Un ambiente desktop remoto per server e workstation.
- Un progetto e una comunità open-source amichevole per imparare lo sviluppo web, il cloud computing, i sistemi distribuiti e molto altro ancora!
<br/>
## Getting Started
### 💻 Local Development
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
In questo modo Puter verrà avviato all'indirizzo http://puter.localhost:4100 (o alla prossima porta disponibile).
Siamo sempre felici di aiutarvi con qualsiasi domanda. Non esitate a chiedere!
<br/>
## Licenza
Questo repository, compresi tutti i suoi contenuti, sottoprogetti, moduli e componenti, è concesso in licenza [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), a meno che non sia esplicitamente indicato diversamente. Le librerie di terze parti incluse in questo repository possono essere soggette alle loro licenze.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Puter: 인터넷 OS! 무료이고 오픈소스이며 자체 호스팅이 가능합니다.</h3>
이 저장소는 모든 내용, 하위 프로젝트, 모듈 및 구성 요소를 포함하여 명시적으로 달리 명시되지 않는 한 [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) 라이선스 하에 제공됩니다. 이 저장소에 포함된 제3자 라이브러리는 해당 라이브러리의 고유 라이선스를 따를 수 있습니다.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">ഇന്റർനെറ്റ് ഓപ്പറേറ്റിംഗ് സിസ്റ്റം!<br> സൗജന്യവും, ഓപ്പൺ സോഴ്സും സ്വയം ഹോസ്റ്റ് ചെയ്യാൻ പറ്റുന്നതും</h3>
ഫീച്ചറുകളാൽ സമ്പുഷ്ടവും അസാധാരണമാംവിധം വേഗതയേറിയതും,വളരെ വിപുലീകരിക്കാവുന്നതുമായ ഒരു നൂതന, ഓപ്പൺ സോഴ്സ് ഇന്റർനെറ്റ് ഓപ്പറേറ്റിംഗ് സിസ്റ്റമാണ് പ്യൂട്ടർ. പ്യൂട്ടർ ഇനിപ്പറയുന്ന രീതിയിൽ ഉപയോഗിക്കാം:
- നിങ്ങളുടെ എല്ലാ ഫയലുകളും ആപ്പുകളും ഗെയിമുകളും ഒരു സുരക്ഷിത സ്ഥലത്ത് സൂക്ഷിക്കുന്നതിനുള്ള, സ്വകാര്യതയ്ക്ക് മുൻഗണന കൊടുക്കുന്ന ആദ്യത്തെ വ്യക്തിഗത ക്ലൗഡ്, എവിടെ നിന്നും എപ്പോൾ വേണമെങ്കിലും ആക്സസ് ചെയ്യാൻ കഴിയും.
- വെബ്സൈറ്റുകൾ, വെബ് ആപ്പുകൾ, ഗെയിമുകൾ എന്നിവ നിർമ്മിക്കുന്നതിനും പ്രസിദ്ധീകരിക്കുന്നതിനുമുള്ള ഒരു പ്ലാറ്റ്ഫോം.
- പുതിയ ഇന്റർഫേസും, ശക്തമായ ഫീച്ചറുകളും അടങ്ങിയ, ഡ്രോപ്പ്ബോക്സ്, ഗൂഗിൾ ഡ്രൈവ്, വൺഡ്രൈവ് മുതലായവയ്ക്കുള്ള ബദൽ.
- സെർവറുകൾക്കും വർക്ക്സ്റ്റേഷനുകൾക്കും, ഒരു വിദൂര ഡെസ്ക്ടോപ്പ് പരിസ്ഥിതി.
- വെബ് ഡെവലപ്മെന്റ്, ക്ലൗഡ് കംപ്യൂട്ടിംഗ്, ഡിസ്ട്രിബ്യൂട്ടഡ് സിസ്റ്റങ്ങൾ എന്നിവയെ കുറിച്ചും, അതിലേറെ കാര്യങ്ങളെ കുറിച്ചും അറിയാനുള്ള സൗഹൃദപരവും ഓപ്പൺ സോഴ്സുമായ പ്രോജക്റ്റും കമ്മ്യൂണിറ്റിയും!
<br/>
## തുടങ്ങാനായി
### 💻 ലോക്കൽ ഡെവലപ്മെന്റ്
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
ഇത് http://puter.localhost:4100 (അല്ലെങ്കിൽ അടുത്ത ലഭ്യമായ പോർട്ടിൽ) എന്നതിൽ Puter സമാരംഭിക്കും
നിങ്ങൾക്ക് ഉണ്ടായേക്കാവുന്ന ഏത് ചോദ്യങ്ങളിലും നിങ്ങളെ സഹായിക്കുന്നതിൽ ഞങ്ങൾക്ക് എപ്പോഴും സന്തോഷമുണ്ട്. ചോദിക്കാൻ മടിക്കേണ്ട!
<br/>
## ലൈസൻസ്
ഈ ശേഖരം, അതിന്റെ എല്ലാ ഉള്ളടക്കങ്ങളും, ഉപപദ്ധതികളും, മൊഡ്യൂളുകളും, ഘടകങ്ങളും ഉൾപ്പെടെ, [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) എന്നതിന് കീഴിൽ ലൈസൻസുള്ളതാണ്. ഈ ശേഖരത്തിൽ ഉൾപ്പെടുത്തിയിരിക്കുന്ന മൂന്നാം കക്ഷി ലൈബ്രറികൾ അവരുടെ സ്വന്തം ലൈസൻസുകൾക്ക് വിധേയമായിരിക്കാം.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: Semua fail, apl, dan permainan anda di satu tempat yang boleh diakses dari mana sahaja pada bila-bila masa." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Sistem Operasi Internet! Percuma, Sumber Terbuka, dan Boleh Dihoskan Sendiri.</h3>
Puter ialah sistem operasi internet sumber terbuka yang maju dan direka untuk kaya dengan ciri kefungsian, kepantasan luar biasa dan kebolehluasan yang tinggi. Puter boleh digunakan sebagai:
- Storan awan peribadi yang mendahulukan privasi untuk menyimpan semua fail, aplikasi dan permainan anda di satu tempat yang selamat dan boleh diakses dari mana sahaja pada bila-bila masa.
- Platform untuk membina dan menerbitkan laman web, aplikasi web dan permainan.
- Alternatif kepada Dropbox, Google Drive, OneDrive, dan lain-lain dengan antara muka yang baharu dan ciri kefungsian berkuasa tinggi.
- Persekitaran desktop awan untuk server dan stesen kerja.
- Projek dan komuniti sumber terbuka yang mesra untuk mempelajari pembangunan laman web, pengkomputeran awan, sistem teragih, dan banyak lagi!
<br/>
## Mulakan
### 💻 Pembangunan Lokal
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Ini akan melancarkan Puter di http://puter.localhost:4100 (atau port seterusnya yang tersedia).
Kami sentiasa gembira untuk membantu anda dengan apa-apa soalan. Jangan takut untuk bertanya!
<br/>
## Lesen
Repositori ini, termasuklah kandungannya, subprojek, modul dan komponen, dilesenkan di bawah [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) melainkan dinyatakan sebaliknya. *Library* pihak ketiga yang terkandung dalam repositori ini tertakluk kepada lesen mereka sendiri.
<!-- The word `Library` is kept as is to avoid confusion since the direct translation `Perpustakaan/Pustaka` is never used in the tech context and doesn't convey the same meaning among Malay community if used in this situation -->
<h3 align="center"><img width="80" alt="Puter.com, De Persoonlijke Cloud Computer: Al je bestanden, apps en games op één plek, overal en altijd toegankelijk." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Het Internet OS! Gratis, Open-Source en Zelf te Hosten.</h3>
Puter is een geavanceerd, open-source internetbesturingssysteem ontworpen om functierijk, uitzonderlijk snel en zeer uitbreidbaar te zijn. Puter kan worden gebruikt als:
- Een privacy-gerichte persoonlijke cloud om al je bestanden, apps en games op één veilige plek te bewaren, overal en altijd toegankelijk.
- Een platform voor het bouwen en publiceren van websites, web-apps en games.
- Een alternatief voor Dropbox, Google Drive, OneDrive, etc. met een frisse interface en krachtige functies.
- Een externe desktopomgeving voor servers en werkstations.
- Een vriendelijk, open-source project en gemeenschap om te leren over webontwikkeling, cloud computing, gedistribueerde systemen en veel meer!
<br/>
## Aan de slag
### 💻 Lokale Ontwikkeling
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Dit zal Puter starten op http://puter.localhost:4100 (of de eerstvolgende beschikbare poort).
We helpen je graag met al je vragen. Aarzel niet om te vragen!
<br/>
## Licentie
Deze repository, inclusief alle inhoud, subprojecten, modules en componenten, is gelicentieerd onder [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) tenzij expliciet anders vermeld. Bibliotheken van derden die in deze repository zijn opgenomen, kunnen onderworpen zijn aan hun eigen licenties.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center"><img width="80" alt="Puter.com, Osobisty Komputer Chmurowy: Wszystkie twoje pliki, aplikacje i gry w jednym miejscu, dostępne z dowolnego miejsca o dowolnej porze." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center"> System Operacyjny Internet! Darmowy, Open-Source i Możliwy do Samodzielnego Hostowania.</h3>
Puter to zaawansowany, open-source'owy internetowy system operacyjny, zaprojektowany tak, aby był bogaty w funkcje, wyjątkowo szybki i wysoce rozszerzalny. Puter może być używany jako:
- Prywatna chmura osobista do przechowywania wszystkich plików, aplikacji i gier w jednym bezpiecznym miejscu, dostępnym z dowolnego miejsca o dowolnej porze.
- Platforma do budowania i publikowania stron internetowych, aplikacji webowych i gier.
- Alternatywa dla Dropbox, Google Drive, OneDrive itp. ze świeżym interfejsem i potężnymi funkcjami.
- Zdalne środowisko pulpitu dla serwerów i stacji roboczych.
- Przyjazny, open-source'owy projekt i społeczność do nauki o tworzeniu stron internetowych, chmurze obliczeniowej, systemach rozproszonych i wielu innych!
<br/>
## Rozpoczęcie pracy
## 💻 Lokalne środowisko developerskie
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
To uruchomi Puter na http://puter.localhost:4100 (lub na następnym dostępnym porcie).
Puter jest dostępny jako usługa hostowana na [**puter.com**](https://puter.com).
<br/>
## Wymagania systemowe
- **Systemy operacyjne:** Linux, macOS, Windows
- **RAM:** Minimum 2GB (zalecane 4GB)
- **Przestrzeń dyskowa:** 1GB wolnego miejsca
- **Node.js:** Wersja 16+ (zalecana wersja 22+)
- **npm:** Najnowsza stabilna wersja
<br/>
## Wsparcie
Skontaktuj się z opiekunami i społecznością przez te kanały:
- Raport o błędzie lub prośba o funkcję? Proszę otworzyć zgłoszenie.
- Discord: discord.com/invite/PQcx7Teh8u
- X (Twitter): x.com/HeyPuter
- Reddit: reddit.com/r/puter/
- Mastodon: mastodon.social/@puter
- Problemy z bezpieczeństwem? security@puter.com
- Email do opiekunów: hi@puter.com
Zawsze chętnie pomożemy Ci z wszelkimi pytaniami, jakie możesz mieć. Nie wahaj się pytać!
<br/>
## Licencja
To repozytorium, w tym cała jego zawartość, podprojekty, moduły i komponenty, jest licencjonowane na podstawie [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), chyba że wyraźnie zaznaczono inaczej. Biblioteki stron trzecich zawarte w tym repozytorium mogą podlegać własnym licencjom.
<h3 align="center"><img width="80" alt="Puter.com, O Computador Pessoal em Nuvem: Todos os seus arquivos, aplicativos e jogos em um único lugar, acessíveis de qualquer lugar e a qualquer hora." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">O Sistema Operacional da Internet! Gratuito, de Código Aberto e Auto-Hospedável.</h3>
<p align="center">
<a href="https://puter.com/"><strong>« DEMONSTRAÇÃO AO VIVO »</strong></a>
Puter é um sistema operacional de internet avançado e de código aberto, projetado para ser rico em recursos, excepcionalmente rápido e altamente extensível. Puter pode ser usado como:
- Um serviço de nuvem pessoal com foco na privacidade para manter todos os seus arquivos, aplicativos e jogos em um local seguro, acessível de qualquer lugar e a qualquer hora.
- Uma plataforma para construir e publicar websites, aplicativos web e jogos.
- Uma alternativa ao Dropbox, Google Drive, OneDrive, etc., com uma interface renovada e recursos poderosos.
- Um ambiente de desktop remoto para servidores e estações de trabalho.
- Um projeto e comunidade de código aberto e amigável para aprender sobre desenvolvimento web, computação em nuvem, sistemas distribuídos e muito mais!
<br/>
## Iniciando o Projeto
### 💻 Desenvolvimento Local
```
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
✨ Isso iniciará o Puter em http://puter.localhost:4100 (ou na próxima porta disponível).
Se isso não funcionar, consulte [First Run Issues](./doc/self-hosters/first-run-issues.md) para solucionar os problemas.
✨ Isso iniciará o Puter em http://puter.localhost:4100 (ou na próxima porta disponível).
<br/>
### 🚀 Auto-Hospedagem
Para guia detalhados sobre como auto-hospedar o Puter, incluindo opções de configuração e melhores práticas, consulte nossa [Documentação de Auto-Hospedagem](https://github.com/HeyPuter/puter/blob/main/doc/self-hosters/instructions.md).
### ☁️ Puter.com
O Puter está disponível como um serviço hospedado em [**puter.com**](https://puter.com).
<br/>
## Requerimentos do sistema
- **Sistema operacional:** Linux, macOS, Windows
- **RAM:** 2GB mínimo (4GB recomendado)
- **Espaço de disco:** 1GB de espaço disponível
- **Node.js:** Versão 16+ (Versão 23+ recomendada)
- **npm:** Última versão estável
<br/>
## Suporte
Conecte-se com os mantenedores e a comunidade através destes canais:
- Relato de bug ou solicitação de recurso? Por favor, [abra um tópico](https://github.com/HeyPuter/puter/issues/new/choose).
Estamos sempre felizes em ajudá-lo com quaisquer perguntas que você possa ter. Não hesite em perguntar!
<br/>
## Licença
Este repositório, incluindo todos os seus conteúdos, subprojetos, módulos e componentes, está licenciado sob [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) a menos que explicitamente indicado de outra forma. Bibliotecas de terceiros incluídas neste repositório podem estar sujeitas às suas próprias licenças.
<h3 align="center"><img width="80" alt="Puter.com, calculatorul personal în cloud: toate fișierele, aplicațiile și jocurile tale într-un singur loc, accesibile de oriunde și oricând." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Sistemul de operare al internetului! Gratuit, open-source și găzduibil autonom.</h3>
<p align="center">
<img alt="Dimensiunea repoului GitHub" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="Versiunea de pe GitHub" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=ultima%20versiune"> <img alt="Licență GitHub" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« DEMO LIVE »</strong></a>
<a href="https://hackerone.com/puter_h1b">Program de recompense pentru identificarea bugurilor</a>
</p>
<h3 align="center"><img width="800" style="border-radius:5px;" alt="captură de ecran" src="https://assets.puter.site/puter.com-screenshot-3.webp"></h3>
<br/>
## Puter
Puter este un sistem de operare pe internet, avansat, open-source, conceput să fie bogat în funcționalități, excepțional de rapid și foarte extensibil. Puter poate fi folosit ca:
* Un cloud personal cu accent pe confidențialitate, pentru a-ți păstra toate fișierele, aplicațiile și jocurile într-un singur loc securizat, accesibil de oriunde și oricând.
* O platformă pentru a construi și publica site-uri, aplicații web și jocuri.
* O alternativă la Dropbox, Google Drive, OneDrive etc., cu o interfață nouă și funcționalități puternice.
* Un mediu desktop la distanță pentru servere și stații de lucru.
* Un proiect și o comunitate, open-source și prietenoase, pentru a învăța despre dezvoltare web, cloud computing, sisteme distribuite și multe altele!
<br/>
## Fă primii pași
### 💻 Dezvoltare locală
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Aceasta va porni Puter la [http://puter.localhost:4100](http://puter.localhost:4100) (sau pe următorul port disponibil).
Suntem întotdeauna bucuroși să te ajutăm cu orice întrebări ai. Nu ezita să ne pui întrebări!
<br/>
## Licență
Acest repository, inclusiv tot conținutul său, subproiectele, modulele și componentele, este licențiat sub [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), cu excepția cazurilor în care se menționează explicit altfel. Bibliotecile terțe incluse în acest repository pot fi supuse propriilor lor licențe.
<h3 align="center"><img width="80" alt="Puter.com, персональный облачный компьютер: все ваши файлы, приложения и игры в одном месте, доступные из любой точки мира в любое время." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Интернет ОС! Бесплатная, с открытым исходным кодом и возможностью самостоятельной установки.</h3>
Puter — это передовая операционная система с открытым исходным кодом, разработанная для обеспечения широкого функционала, исключительной скорости и высокой масштабируемости. Puter можно использовать как:
- Персональное облако с приоритетом конфиденциальности для хранения всех ваших файлов, приложений и игр в одном безопасном месте, доступном из любой точки мира в любое время.
- Платформа для создания и публикации веб-сайтов, веб-приложений и игр.
- Альтернатива Dropbox, Google Drive, OneDrive и т. д. с новым интерфейсом и мощными функциями.
- Удаленное рабочее окружение для серверов и рабочих станций.
- Дружественный проект с открытым исходным кодом и сообщество для изучения веб-разработки, облачных вычислений, распределенных систем и многого другого!
<br/>
## Начало работы
### 💻 Локальная разработка
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Это запустит Puter по адресу http://puter.localhost:4100 (или на следующем доступном порту).
Мы всегда рады помочь вам с любыми вопросами. Не стесняйтесь спрашивать!
<br/>
## Лицензия
Этот репозиторий, включая все его содержимое, подпроекты, модули и компоненты, лицензирован в соответствии с [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), если явно не указано иное. Сторонние библиотеки, включенные в этот репозиторий, могут подпадать под действие их собственных лицензий.
<h3 align="center"><img width="80" alt="Puter.com, Den personliga molndatorn: Alla dina filer, appar och spel på ett ställe tillgängliga var som helst när som helst." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Internet OS! Gratis, öppen källkod och självhostad.</h3>
Puter är ett avancerat, öppen källkod internetoperativsystem designat för att vara funktionsrikt, exceptionellt snabbt och mycket utbyggbart. Puter kan användas som:
- Ett integritetsfokuserat personligt moln för att hålla alla dina filer, appar och spel på ett säkert ställe, tillgängligt var som helst när som helst.
- En plattform för att bygga och publicera webbplatser, webbappar och spel.
- Ett alternativ till Dropbox, Google Drive, OneDrive, etc. med ett fräscht gränssnitt och kraftfulla funktioner.
- En fjärrskrivbordsmiljö för servrar och arbetsstationer.
- Ett vänligt, öppen källkod-projekt och gemenskap för att lära sig om webbutveckling, molndatorer, distribuerade system och mycket mer!
<br/>
## Komma igång
### 💻 Lokal Utveckling
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Detta kommer att starta Puter på http://puter.localhost:4100 (eller nästa lediga port).
Vi hjälper dig gärna med eventuella frågor du kan ha. Tveka inte att fråga!
<br/>
## Licens
Detta arkiv, inklusive allt dess innehåll, delprojekt, moduler och komponenter, är licensierat under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) om inte annat uttryckligen anges. Tredjepartsbibliotek som ingår i detta arkiv kan vara föremål för sina egna licenser.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: உங்கள் கோப்புகள், ஆப்ஸ் மற்றும் கேம்கள் அனைத்தும் ஒரே இடத்தில் எங்கிருந்தும் எந்த நேரத்திலும் அணுகலாம்." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">இன்டர்நெட் OS! இலவசம், ஓப்பன் சோர்ஸ் மற்றும் Self-Hostable</h3>
புட்டர்(putter) என்பது ஒரு மேம்பட்ட, திறந்த மூல இலவசமாக இணைய இயக்க முறைமையாகும், இது அம்சம் நிறைந்ததாகவும், விதிவிலக்காக வேகமாகவும், அதிக விரிவாக்கக்கூடியதாகவும் வடிவமைக்கப்பட்டுள்ளது. புட்டரை இவ்வாறு பயன்படுத்தலாம்:
- உங்கள் கோப்புகள், பயன்பாடுகள் மற்றும் கேம்கள் அனைத்தையும் ஒரே பாதுகாப்பான இடத்தில் வைத்திருக்க, எந்த நேரத்திலும் எங்கிருந்தும் அணுகக்கூடிய தனியுரிமை-முதல் தனிப்பட்ட கிளவுட்.
- இணையதளங்கள், இணைய பயன்பாடுகள் மற்றும் கேம்களை உருவாக்கி வெளியிடுவதற்கான தளம் இதுவாகும்.
- புதிய இடைமுகம் மற்றும் சக்திவாய்ந்த அம்சங்களுடன் Dropbox, Google Drive, OneDrive போன்றவற்றுக்கு மாற்றீடாக உபயோகிக்க கூடியது.
- சர்வர்கள் மற்றும் பணிநிலையங்களுக்கான தொலைநிலை டெஸ்க்டாப்(desktop) சூழல்.
- வலை மேம்பாடு, கிளவுட் கம்ப்யூட்டிங், விநியோகிக்கப்பட்ட அமைப்புகள் மற்றும் பலவற்றைப் பற்றி அறிந்து ஒரு நட்பு ரீதியான, திறந்த மூல திட்டம் மற்றும் சமூக அறிவியலில் சார்ந்த ஒன்று.
<br/>
## தொடங்குதல்
### 💻 உள்ளூர் வளர்ச்சி
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
``` தொடக்கம்
```
இது புட்டரை <http://puter.localhost:4100> இல் தொடங்கும் (அல்லது அடுத்து கிடைக்கும் இடம்).
உங்களுக்கு ஏதேனும் கேள்விகள் இருந்தால் உங்களுக்கு உதவ நாங்கள் எப்போதும் மகிழ்ச்சியடைகிறோம். தயங்காமல் கேளுங்கள்!
<br/>
## உரிமம்
இந்தக் களஞ்சியமானது, அதன் அனைத்து உள்ளடக்கங்கள், துணைத் திட்டங்கள், தொகுதிகள் மற்றும் கூறுகள் உட்பட, வெளிப்படையாகக் கூறப்படாவிட்டால், [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) இன் கீழ் உரிமம் பெற்றுள்ளது. . இந்தக் களஞ்சியத்தில் சேர்க்கப்பட்டுள்ள மூன்றாம் தரப்பு நூலகங்கள் அவற்றின் சொந்த உரிமங்களுக்கு உட்பட்டதாக இருக்கும்.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: మీ అన్ని ఫైల్లు, యాప్లు మరియు గేమ్లను ఒకే స్థలంలో ఎక్కడి నుండైనా ఎప్పుడైనా యాక్సెస్ చేయవచ్చు." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center"> ఇంటర్నెట్ OS! ఉచిత, ఓపెన్ సోర్స్, and Self-Hostable.</h3>
పుటర్ అనేది అధునాతన, ఓపెన్ సోర్స్ ఇంటర్నెట్ ఆపరేటింగ్ సిస్టమ్, ఇది ఫీచర్-రిచ్, అనూహ్యంగా వేగవంతమైన మరియు అత్యంత విస్తరించదగినదిగా రూపొందించబడింది. పుటర్ను ఇలా ఉపయోగించవచ్చు:
- మీ అన్ని ఫైల్లు, యాప్లు మరియు గేమ్లను ఒకే సురక్షిత స్థలంలో ఉంచడానికి గోప్యత-మొదటి వ్యక్తిగత క్లౌడ్, ఎప్పుడైనా ఎక్కడి నుండైనా యాక్సెస్ చేయవచ్చు.
- వెబ్సైట్లు, వెబ్ యాప్లు మరియు గేమ్లను రూపొందించడానికి మరియు ప్రచురించడానికి ఒక వేదిక.
- తాజా ఇంటర్ఫేస్ మరియు శక్తివంతమైన ఫీచర్లతో Dropbox, Google Drive, OneDrive మొదలైన వాటికి ప్రత్యామ్నాయం.
- సర్వర్లు మరియు వర్క్స్టేషన్ల కోసం రిమోట్ డెస్క్టాప్ వాతావరణం.
- వెబ్ డెవలప్మెంట్, క్లౌడ్ కంప్యూటింగ్, డిస్ట్రిబ్యూట్ సిస్టమ్లు మరియు మరిన్నింటి గురించి తెలుసుకోవడానికి స్నేహపూర్వక, ఓపెన్ సోర్స్ ప్రాజెక్ట్ మరియు కమ్యూనిటీ!
<br/>
## ప్రారంభించడం
### లోకల్ డెవలప్మెంట్
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
ఇది http://puter.localhost:4100 (లేదా తదుపరి అందుబాటులో ఉన్న పోర్ట్) వద్ద పుటర్ని ప్రారంభిస్తుంది.
ఇది పని చేయకపోతే, దీని కోసం [మొదటి రన్ సమస్యలు](./doc/first-run-issues.md) చూడండి
మీకు ఏవైనా సందేహాలు ఉంటే మీకు సహాయం చేయడానికి మేము ఎల్లప్పుడూ సంతోషిస్తాము. అడగడానికి సంకోచించకండి!
<br/>
## లైసెన్సు
ఈ రిపోజిటరీ, దాని మొత్తం కంటెంట్లు, ఉప-ప్రాజెక్ట్లు, మాడ్యూల్స్ మరియు కాంపోనెంట్లతో సహా, [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) కింద లైసెన్స్ని కలిగి ఉంటుంది. . ఈ రిపోజిటరీలో చేర్చబడిన థర్డ్-పార్టీ లైబ్రరీలు వాటి స్వంత లైసెన్స్లకు లోబడి ఉండవచ్చు.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center"><img width="80" alt="Puter.com, Kişisel Bulut Bilgisayar: Tüm dosyalarınız, uygulamalarınız ve oyunlarınız her zaman her yerden erişilebilen tek bir yerde." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">İnternet İşletim Sistemi! Ücretsiz, Açık Kaynaklı ve Kendi Kendine Barındırılabilir</h3>
Puter, zengin özelliklere sahip, son derece hızlı ve son derece genişletilebilir olacak şekilde tasarlanmış gelişmiş, açık kaynaklı bir internet işletim sistemidir. Puter şu şekilde kullanılabilir:
- Tüm dosyalarınızı, uygulamalarınızı ve oyunlarınızı tek bir güvenli yerde tutmak için gizlilik öncelikli bir kişisel bulut, her yerden her zaman erişilebilir.
- Web siteleri, web uygulamaları ve oyunlar oluşturmak ve yayınlamak için bir platform.
- Yeni bir arayüz ve güçlü özelliklerle Dropbox, Google Drive, OneDrive vb. uygulamalara bir alternatif.
- Sunucular ve iş istasyonları için bir uzak masaüstü ortamı.
- Web geliştirme, bulut bilişim, dağıtık sistemler ve çok daha fazlası hakkında bilgi edinmek için dost canlısı, açık kaynaklı bir proje ve topluluk!
<br/>
## Başlarken
### 💻 Yerel Geliştirme
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Bu, Puter'ı http://puter.localhost:4100 adresinde (veya bir sonraki kullanılabilir portta) başlatacaktır.
Sorularınız varsa size her zaman yardımcı olmaktan mutluluk duyarız. Sormaktan çekinmeyin!
<br/>
## Lisans
Bu depo, tüm içeriği, alt projeleri, modülleri ve bileşenleri dahil olmak üzere, aksi açıkça belirtilmedikçe [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) altında lisanslanmıştır. Bu depoda yer alan üçüncü taraf kütüphaneler kendi lisanslarına tabi olabilir.
<h3 align="center"><img width="80" alt="Puter.com, The Personal Cloud Computer: Всі ваші файли, додатки та ігри в одному місці, доступні з будь-якого куточка світу в будь-який час." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Інтернет ОС! Безкоштовна, відкрита та self-hosted.</h3>
<p align="center">
<img alt="Розмір репозиторію на GitHub" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="Остання версія на GitHub" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=latest%20version"> <img alt="Ліцензія GitHub" src="https://img.shields.io/github/license/HeyPuter/puter">
Puter — це просунута, інтернет-ОС, з відкритим кодом, створена для того, щоб бути багатофункціональною, надзвичайно швидкою та розширюваною. Puter може використовуватися як:
- Приватний хмарний сервіс для збереження всіх ваших файлів, додатків і ігор у безпечному місці, доступному в будь-який час з будь-якого місця.
- Платформа для створення та публікації вебсайтів, вебдодатків і ігор.
- Альтернатива Dropbox, Google Drive, OneDrive і тд, з свіженьким інтерфейсом та потужними функціями.
- Віддалене робоче середовище для серверів і робочих станцій.
- Дружній, відкритий проєкт та спільнота для вивчення веброзробки, хмарних обчислень, розподілених систем і багато іншого!
<br/>
## Початок роботи
### Локальна розробка
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Це запустить Puter на http://puter.localhost:4100 (або на наступному доступному порті).
Ми завжди готові допомогти Вам з будь-якими питаннями, що можуть виникнути. Не соромтеся ставити нам питання!
<br/>
## License
Цей репорзиторій, включаючи увесь його контент, дочірні проєкти, модулі, і компоненти, ліцензовано за [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), якщо явно не вказано інше. Сторонні бібліотеки, включені в цей репозиторій, можуть підпадати під дію інших ліцензій.
<h3 align="center"><img width="80" alt="Puter.com, ذاتی کلاؤڈ کمپیوٹر: آپ کی تمام فائلیں، ایپس، اور کھیل ایک جگہ پر، کہیں سے بھی اور کسی بھی وقت قابل رسائی۔" src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">انٹرنیٹ OS! مفت، اوپن سورس، اور خود میزبان.</h3>
ایک جدید، اوپن سورس انٹرنیٹ آپریٹنگ سسٹم ہے جو کہ خصوصیات سے بھرپور، بہت تیز، اور انتہائی توسیع پذیر ہے۔ Puter
: کو استعمال کیا جا سکتا ہے Puter
- ایک پرائیویسی فرسٹ ذاتی کلاؤڈ کے طور پر تاکہ آپ کی تمام فائلیں، ایپس، اور کھیل ایک محفوظ جگہ پر رکھی جا سکیں، کہیں سے بھی اور کسی بھی وقت قابل رسائی ہوں۔
- ویب سائٹس، ویب ایپس، اور کھیل بنانے اور شائع کرنے کے لئے ایک پلیٹ فارم کے طور پر۔
- وغیرہ کا متبادل، نئے انٹرفیس اور طاقتور خصوصیات کے ساتھ۔ Dropbox، Google Drive، OneDrive
- سرورز اور ورک اسٹیشنز کے لیے ایک ریموٹ ڈیسک ٹاپ ماحول کے طور پر۔
- ویب ڈویلپمنٹ، کلاؤڈ کمپیوٹنگ، تقسیم شدہ نظاموں، اور بہت کچھ سیکھنے کے لیے ایک دوستانہ، اوپن سورس پروجیکٹ اور کمیونٹی!
<br/>
## شروع کرنے کا طریقہ
### 💻 مقامی ترقی
```bash
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
یہ Puter کو http://puter.localhost:4100 (یا اگلے دستیاب پورٹ) پر لانچ کرے گا۔
ہم ہمیشہ آپ کی مدد کے لیے خوش ہیں۔ سوالات پوچھنے میں ہچکچاہٹ نہ کریں
!
<br/>
## لائسنس
اس ریپوزٹری، بشمول اس کے تمام مواد، ذیلی پروجیکٹس، ماڈیولز، اور کمپوننٹس، کو [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) کے تحت لائسنس کیا گیا ہے جب تک کہ واضح طور پر کہیں اور نہ کہا گیا ہو۔ اس ریپوزٹری میں شامل تھرڈ پارٹی لائبریریاں اپنی لائسنس کے تابع ہو سکتی ہیں۔
<h3 align="center"><img width="80" alt="Puter.com, Máy Tính Đám Mây Cá Nhân: Tất cả các tệp, ứng dụng, và trò chơi của bạn ở một nơi, có thể truy cập từ bất cứ đâu vào bất kỳ lúc nào." src="https://assets.puter.site/puter-logo.png"></h3>
<h3 align="center">Hệ điều hành Internet! Miễn phí, Mã nguồn mở và Có thể tự lưu trữ.</h3>
<p align="center">
<img alt="Kích thước repo GitHub" src="https://img.shields.io/github/repo-size/HeyPuter/puter"> <img alt="Phiên bản phát hành GitHub" src="https://img.shields.io/github/v/release/HeyPuter/puter?label=Phi%C3%AAn%20b%E1%BA%A3n%20ph%C3%A1t%20h%C3%A0nh%20GitHub"> <img alt="Giấy phép GitHub" src="https://img.shields.io/github/license/HeyPuter/puter">
</p>
<p align="center">
<a href="https://puter.com/"><strong>« DEMO TRỰC TIẾP »</strong></a>
Puter là một hệ điều hành internet tiên tiến, mã nguồn mở được thiết kế để có nhiều tính năng, tốc độ vượt trội và khả năng mở rộng cao. Puter có thể được sử dụng như:
- Một đám mây cá nhân ưu tiên quyền riêng tư để lưu trữ tất cả các tệp, ứng dụng và trò chơi của bạn ở một nơi an toàn, có thể truy cập từ bất cứ đâu, bất cứ lúc nào.
- Một nền tảng để xây dựng và xuất bản các trang web, ứng dụng web và trò chơi.
- Một sự thay thế cho Dropbox, Google Drive, OneDrive, v.v. với giao diện mới mẻ và nhiều tính năng mạnh mẽ.
- Một môi trường máy tính từ xa cho các máy chủ và máy trạm.
- Một dự án thân thiện, mã nguồn mở và cộng đồng để học hỏi về phát triển web, điện toán đám mây, hệ thống phân tán và nhiều hơn nữa!
<br/>
## Bắt Đầu
## 💻 Phát Triển Cục Bộ
```bash
Copy code
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
```
Điều này sẽ khởi chạy Puter tại http://puter.localhost:4100 (hoặc cổng kế tiếp có sẵn).
Puter có sẵn dưới dạng dịch vụ lưu trữ tại [**puter.com**](https://puter.com).
<br/>
## Yêu Cầu Hệ Thống
- **Hệ Điều Hành:** Linux, macOS, Windows
- **RAM:** Tối thiểu 2GB (Khuyến nghị 4GB)
- **Dung Lượng Ổ Cứng:** Còn trống 1GB
- **Node.js:** Phiên bản 16+ (Khuyến nghị phiên bản 22+)
- **npm:** Phiên bản ổn định mới nhất
<br/>
## Hỗ Trợ
Kết nối với các nhà bảo trì và cộng đồng thông qua các kênh sau:
- Báo cáo lỗi hoặc yêu cầu tính năng? Vui lòng mở một vấn đề.
- Discord: discord.com/invite/PQcx7Teh8u
- X (Twitter): x.com/HeyPuter
- Reddit: reddit.com/r/puter/
- Mastodon: mastodon.social/@puter
- Vấn đề bảo mật? security@puter.com
- Email các nhà bảo trì tại hi@puter.com
Chúng tôi luôn sẵn sàng giúp đỡ bạn với bất kỳ câu hỏi nào bạn có. Đừng ngần ngại hỏi!
<br/>
## Giấy Phép
Kho lưu trữ này, bao gồm tất cả nội dung, dự án con, mô-đun và thành phần của nó, được cấp phép theo [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), trừ khi được tuyên bố rõ ràng khác. Các thư viện của bên thứ ba được bao gồm trong kho lưu trữ này có thể phải tuân theo các giấy phép riêng của chúng.
<metaname="description"content="Puter is a privacy-first personal cloud to keep all your files, apps, and games in one private and secure place, accessible from anywhere at any time.">
<metaproperty="og:description"content="Puter is a privacy-first personal cloud to keep all your files, apps, and games in one private and secure place, accessible from anywhere at any time.">
<metaname="twitter:description"content="Puter is a privacy-first personal cloud to keep all your files, apps, and games in one private and secure place, accessible from anywhere at any time.">
The GUI is a single page application (SPA) and as best practice any route under root (`/*`) should preferably load the `index.html` file. However, there are situations where we want to load a custom page for a specific route: for example, the `/privacy` route may need to load a page that contains your privacy policy and has nothing to do with the GUI application. In these cases it is ok to load a custom page as long as the following essential GUI routes are loaded with the GUI (i.e. `index.html` file):
-`/app/*`
-`/action/*`
In other words, consider the routes above as "reserved" for Puter.
### Best Practices
- The `title` tags and meta tags (`<title></title>`, `<meta property="og:title"`, `<meta name="twitter:title"`, ...) should be dynamically set by the server. For example, if the URL is of an app (e.g. `https://puter.com/app/editor`) the `title` tags and meta tags should contain the app's title rather than the generic Puter title.
- The `description` meta tags (`<meta name="description"`, `<meta property="og:description"`, `<meta name="twitter:description"`, ...) should be dynamically set by the server. For example, if the URL is of an app (e.g. `https://puter.com/app/editor`) the `description` meta tags should contain the app's description rather than the generic Puter description.
- Make sure to escape any HTML code that is dynamically added to the HTML page. For example, if the app's description is `Puter is a <b>privacy-first</b> personal cloud to keep all your files, apps, and games in one private and secure place, accessible from anywhere at any time.` the `<b>` tag should be escaped to `<b>` so that the browser doesn't interpret it as an HTML tag.
- Make sure to replace all new line characters with space when dynamically adding text to the HTML page.
- Generally, for UX and SEO reasons make sure that the tags are filled with relevant information about the state the URL is representing. E.g. is the user on the desktop or an app?
Ensure the hosting device has a static IP address to prevent potential connectivity issues due to IP changes. This setup will enable seamless access to Puter and its services across your local network.
### Using Hosts Files
The hosts file is a straightforward way to map domain names to IP addresses on individual devices. It's simple to set up but requires manual changes on each device that needs access to the domains.
#### Windows
1. Open Notepad as an administrator.
2. Open the file located at `C:\Windows\System32\drivers\etc\hosts`.
3. Add lines for your domain and subdomain with the server's IP address, in the
following format:
```
192.168.1.10 puter.local
192.168.1.10 api.puter.local
```
#### For macOS and Linux:
1. Open a terminal.
2. Edit the hosts file with a text editor, e.g., `sudo nano /etc/hosts`.
3. Add lines for your domain and subdomain with the server's IP address, in the
following format:
```
192.168.1.10 puter.local
192.168.1.10 api.puter.local
```
4. Save and exit the editor.
### Using Router Configuration
Some routers allow you to add custom DNS rules, letting you configure domain names network-wide without touching each device.
1. Access your router’s admin interface (usually through a web browser).
2. Look for DNS or DHCP settings.
3. Add custom DNS mappings for `puter.local` and `api.puter.local` to the hosting device's IP address.
4. Save the changes and reboot the router if necessary.
This method's availability and steps may vary depending on your router's model and firmware.
### Using Local DNS
Setting up a local DNS server on your network allows for flexible and scalable domain name resolution. This method works across all devices automatically once they're configured to use the DNS server.
#### Options for DNS Software:
- **Pi-hole**: Acts as both an ad-blocker and a DNS server. Ideal for easy setup and maintenance.
- **BIND9**: Offers comprehensive DNS server capabilities for complex setups.
- **dnsmasq**: Lightweight and suitable for smaller networks or those new to running a DNS server.
**contributors note:** feel free to add any software you're aware of
which might help with this to the list. Also, feel free to add instructions here for specific software; our goal is for Puter to be easy to setup with tools you're already familiar with.
#### General Steps:
1. Choose and install DNS server software on a device within your network.
2. Configure the DNS server to resolve `puter.local` and `api.puter.local` to the IP address of your Puter hosting device.
3. Update your router's DHCP settings to distribute the DNS server's IP address to all devices on the network.
By setting up a local DNS server, you gain the most flexibility and control over your network's domain name resolution, ensuring that all devices can access Puter and its API without manual configuration.
## Production Configuration
Please note the self-hosting feature is still in alpha and a public production
deployment is not recommended at this time. However, if you wish to host
publicly you can do so following the same steps you normally would to configure
a domain name and ensuring the `api` subdomain points to the server as well.
> The self-hosted version of Puter is currently in alpha stage and should not be used in production yet. It is under active development and may contain bugs, other issues. Please exercise caution and use it for testing and evaluation purposes only.
### Self-Hosting Differences
Currently, the self-hosted version of Puter is different in a few ways from [Puter.com](https://puter.com):
- There is no built-in way to install or create other apps (see below)
- Several "core" apps are missing, such as **Code** or **Draw**, because we can't include them in this repository
- Some icons are different
Work is ongoing to improve the **App Center** and make it available on self-hosted.
Until then, it's possible to add other apps by manually editing the database file.
This process is not recommended unless you know what you are doing.
The file will appear after you first launch Puter, and should be found in `puter/data/puter-database.sqlite` for Docker,
or `volatile/runtime/puter-database.sqlite` otherwise.
You will need a database tool that can understand SQLite databases.
<br/>
## Configuration
Running the server will generate a configuration file in one of these locations:
-`config/config.json` when [Using Docker](#using-docker)
-`volatile/config/config.json` in [Local Development](#local-development)
-`/etc/puter/config.json` on a server (or within a Docker container)
### Domain Name
To access Puter on your device, you can simply go to the address printed in
the server console (usually `puter.localhost:4100`).
To access Puter from another device, a domain name must be configured, as well as
an `api` subdomain. For example, `example.local` might be the domain name pointing
to the IP address of the server running puter, and `api.example.com` must point to
this address as well. This domain must be specified in the configuration file
(usually `volatile/config/config.json`) as well.
See [domain configuration](./domains.md) for more information.
### Configure the Port
- You can specify a custom port by setting `http_port` to a desired value
- If you're using a reverse-proxy such as nginx or cloudflare, you should
also set `pub_port` to the public (external) port (usually `443`)
- If you have HTTPS enabled on your reverse-proxy, ensure that
`protocol` in config.json is set accordingly
### Default User
By default, Puter will create a user called `default_user`.
This user will have a randomly generated password, which will be printed
in the development console.
A warning will persist in the dev console until this user's
password is changed. Please login to this user and change the password as
`docker-compose.yml` brings up Puter **plus every external service it needs** — MariaDB, Valkey, DynamoDB-local, RustFS S3, nginx — wired together. Closest thing to a production deployment you can self-manage on a single host.
## One-line installer (recommended)
```bash
curl -fsSL https://raw.githubusercontent.com/HeyPuter/puter/main/install.sh | sh
```
Generates secrets, writes `.env` + `puter/config/config.json`, downloads `docker-compose.yml` from the OSS repo, and runs `docker compose up -d`. Re-running is safe — it won't overwrite existing config (set `PUTER_FORCE=1` to rotate). Use the manual steps below if you want to inspect or tweak each step yourself.
## Requirements
- **Docker** with the `compose` plugin.
- A **domain** with DNS access — you need a wildcard record (`*.your-domain.com` → server IP). Puter routes by subdomain (`api.<domain>`, `site.<domain>`, `app.<domain>`).
- Optional: **TLS certs** (or `certbot` to grab them — see Step 3).
| `puter-ollama-init` | `ollama/ollama` | One-shot — pulls the default model (`tinyllama`) on first boot |
State lives under `./puter/data/<service>/`.
---
## Step 1 — Create `.env` and `puter/config/config.json`
> ⚠️ **Run this whole block in one shell session.** It generates secrets once and writes them into both `.env` (read by docker compose) and `config.json` (read by Puter). The two files **must** agree on the MariaDB password and the S3 secret — if they drift, MariaDB initialises with one password and Puter tries to log in with another, and you get `ER_ACCESS_DENIED_ERROR`.
```bash
MARIADB_ROOT_PASSWORD=$(openssl rand -hex 32)
MARIADB_PASSWORD=$(openssl rand -hex 32)
S3_SECRET_KEY=$(openssl rand -hex 32)
JWT_SECRET=$(openssl rand -hex 64)
JWT_SECRET_V2=$(openssl rand -hex 64)
URL_SIGNATURE_SECRET=$(openssl rand -hex 64)
cat > .env <<EOF
HTTP_PORT=80
# HTTPS_PORT=443 # uncomment after enabling TLS in Step 3
Replace `puter.localhost`, `site.puter.localhost`, `host.puter.localhost`, `dev.puter.localhost` and `app.puter.localhost` with your actual domain (or leave it for a localhost-only trial).
Why these knobs:
-`jwt_secret` + `jwt_secret_v2` — Puter signs new auth tokens with `jwt_secret_v2` (v2 token format, `kid: 'v2'` JWT header). `jwt_secret` is verify-only and lets tokens minted before this version (cookies still in users' browsers, stored API tokens) keep working. `allow_v1_tokens: true` keeps that fallback enabled. Fresh installs can leave it as-is; future versions will flip the flag to `false` and retire `jwt_secret` entirely once legacy tokens have drained.
-`env: "prod"` — the bundled `config.default.json` ships with `env: "dev"` (matches the source-tree `npm run start=gui` workflow, which expects webpack-dev-server emitting a CSS manifest). Self-host runs against pre-built static bundles, so `env: "prod"` makes the homepage emit the `/dist/bundle.min.css``<link>` tag instead of waiting on a manifest that doesn't exist.
-`database.migrationPaths` — Puter applies the bundled MySQL/MariaDB schema on boot. The migration files are idempotent, so it is safe to leave this configured across restarts.
-`dynamo.bootstrapTables: true` — Puter creates its KV table on boot. **Only set against a local emulator**, never real AWS.
-`dynamo.aws` keys are dummies; DynamoDB-local doesn't validate them but the AWS SDK requires _something_. **Note:** DynamoDB uses `access_key` / `secret_key` (snake_case); S3 below uses `accessKeyId` / `secretAccessKey` (camelCase). Not interchangeable.
-`providers.ollama.enabled: false` — Puter auto-probes a local Ollama at `127.0.0.1:11434` by default; without one running you'd see `ECONNREFUSED` on every boot. To run a bundled Ollama, see [Optional: local LLM (Ollama)](#optional-local-llm-ollama) below.
-`s3.s3Config.forcePathStyle: true` — RustFS / MinIO / fauxqs need path-style URLs (`<endpoint>/<bucket>`). Real AWS S3 wants virtual-hosted (`<bucket>.<endpoint>`) — drop this flag (or set `false`) when you swap to real S3.
-`s3.s3Config.publicEndpoint` — `endpoint` (`http://s3:9000`) only resolves inside the docker network; presigned upload/download URLs handed to the browser need a host-reachable URL. nginx routes the `s3.<domain>` subdomain to RustFS internally and preserves the Host header end-to-end (required for S3 signature validation), so the browser hits the same port/protocol as the rest of the app — no separate published port, no mixed-content surprises when you turn on TLS. Switch to `https://s3.<your-domain>` once you enable TLS in Step 3. Real AWS S3 doesn't need this — its endpoint is already public; drop the field entirely.
-`trust_proxy: 1` — nginx terminates TLS and forwards `X-Forwarded-For`. Without this, `req.ip` is the docker-network address of the nginx container instead of the real client IP, which breaks rate limiting and IP-based audit logs. `1` = one trusted hop (nginx). Bump to `2` if you put Cloudflare in front of nginx; never set `true` (it trusts every hop and makes XFF forgeable).
> If you ever change `MARIADB_PASSWORD` after first boot, `.env` alone won't update MariaDB — its credentials are baked into `./puter/data/mariadb/` on first init. Either rotate the password inside MariaDB by hand or `docker compose down && rm -rf ./puter/data/mariadb` to start fresh.
## Step 2 — Point DNS at the server \[Optional\]
In your DNS provider, add records for the main domain plus the subdomains Puter and nginx route on (`api.*`, `site.*`, `app.*`, `s3.*`):
```
A puter.localhost → <your server's public IP>
A *.puter.localhost → <your server's public IP>
A site.puter.localhost → <your server's public IP>
A *.site.puter.localhost → <your server's public IP>
A host.puter.localhost → <your server's public IP>
A *.host.puter.localhost → <your server's public IP>
A app.puter.localhost → <your server's public IP>
A *.app.puter.localhost → <your server's public IP>
A dev.puter.localhost → <your server's public IP>
A *.dev.puter.localhost → <your server's public IP>
```
The wildcards are required — Puter routes via subdomains (`api.*`, `app.*`, etc.) and nginx routes browser S3 traffic via `s3.*` to RustFS.
## Step 3 — TLS (recommended for public installs) \[Optional\]
Skip this for a quick local demo. Don't skip it for users typing passwords.
**Get a wildcard cert.** Easiest path with Let's Encrypt + DNS-01 (works for wildcards):
```bash
sudo certbot certonly --manual --preferred-challenges dns \
The cert needs to cover `*.puter.localhost` so that `s3.puter.localhost` (browser S3 endpoint), plus Puter's own `api.*` / `app.*` subdomains, all validate.
Drop the resulting `fullchain.pem` and `privkey.pem` into `./puter/tls/`.
**Wire nginx to use them:**
1. Open [nginx/nginx.conf](../nginx/nginx.conf), uncomment **both**`# server { listen 443 ssl … }` blocks (one for `s3.*`, one for the catch-all).
2. (Optional) Replace the body of the port-80 blocks with `return 301 https://$host$request_uri;` to force HTTPS everywhere.
3. In [docker-compose.yml](../docker-compose.yml), uncomment the `443:443` port mapping under the `nginx` service.
The bundled `puter-nginx` mirrors production and is the supported default — it terminates TLS (Step 3) and forwards every Host to Puter. But plenty of self-hosters already run their own edge proxy (Caddy, Traefik, HAProxy, a cloud load balancer, another nginx). You can put Puter behind it instead; Puter doesn't terminate TLS itself in any setup, so "your proxy does TLS" is just a matter of pointing it at the Puter container and getting a handful of details right.
You can keep the bundled nginx as the single hop your proxy talks to, or bypass it and forward straight to the Puter container on port `4100` (uncomment the `4100:4100` mapping under the `puter` service in [docker-compose.yml](../docker-compose.yml), or attach your proxy to the compose network). Either works — what matters is the rules below.
**The rules that actually matter** (getting any of these wrong is what causes the redirect loops and "Invalid Host header" failures people hit):
1. **Don't rewrite the `Host` header.** Puter routes entirely on Host — `api.<domain>`, `site.<domain>`, `app.<domain>` are all distinguished by the incoming host. Forward the original host through unchanged. Do **not** rewrite external hostnames to an internal name like `puter.local`; that forces you to remap every subdomain by hand and still breaks signed-URL and CORS checks. Most proxies preserve Host by default — just don't override it.
2. **The external domain must equal `domain` in your `config.json`.** If users reach the box at `puter.example.com`, then `domain` must be `puter.example.com` and the hosting domains must be its real subdomains (`site.puter.example.com`, `app.puter.example.com`, …) — exactly as the installer/`config.json` lays them out. Puter rejects hosts it doesn't recognize with `Invalid Host header`.
3. **Set `protocol` to match the public scheme.** When your proxy terminates TLS, set `"protocol": "https"` (installer: `PUTER_PROTOCOL=https`). Puter builds its origins, redirects, signed S3 URLs, and OIDC callback URLs from this — leave it `http` behind an HTTPS proxy and you get redirect loops, broken logins, and mixed-content errors.
4. **Forward the standard proxy headers.** Puter needs:
- `Host` — the original request host (rule 1).
- `X-Forwarded-Proto` — the **external** scheme (`https`), so Puter knows TLS was terminated upstream.
- `X-Forwarded-For` — the real client IP (rate limiting + audit logs).
- `Upgrade` / `Connection` — passed through for WebSocket / socket.io upgrades, or the realtime connection silently fails.
5. **Set `trust_proxy` to the number of hops in front of Puter.** One external proxy talking directly to Puter → `"trust_proxy": 1` (installer: `PUTER_TRUST_PROXY=1`). A second proxy in front (e.g. Cloudflare → your proxy → Puter) → `2`. This is the count of proxies between the client and Puter, **including** the bundled nginx if you keep it. Too low and `req.ip` becomes a proxy address (breaks rate limiting); never set `true` (it trusts every hop and makes `X-Forwarded-For` forgeable).
6. **Route the wildcard to Puter.** Your proxy must forward `*.<domain>` (covering `api.*`, `app.*`, and `s3.<domain>`) and `*.site.<domain>` (and any other hosting domains) to Puter — same wildcard DNS as Step 2. Puter does the per-subdomain routing internally; the proxy just needs to hand it the traffic with the Host intact.
With those in place the rest of the stack is unchanged — `docker compose up -d` as below.
## Step 4 — Bring it up
```bash
docker compose up -d
```
First boot takes ~30s while MariaDB initialises and Puter applies the schema + default apps. Watch:
```bash
docker compose logs -f puter
```
Healthy startup:
```
[config] override from /etc/puter/config.json
[mysql] running migrations from /opt/puter/dist/src/backend/clients/database/migrations/mysql: 2 file(s)
[mysql] applied mysql_mig_1.sql (...)
[mysql] applied mysql_mig_2.sql (9 statements)
```
Then open **<https://puter.local>** (or `http://` if you skipped TLS). Login is `admin` — the temp password is printed once in the puter container logs on first boot:
```bash
docker compose logs puter | grep tmp_password
```
Change it in Settings after first login.
## Additional configuration
All optional. Drop any of the blocks below into `puter/config/config.json` and `docker compose restart puter`. See [config.template.jsonc](../config.template.jsonc) for the full list. Per-key documentation lives in [src/backend/types.ts](../src/backend/types.ts).
### PostgreSQL database
> **Community contribution — expect rough edges.** PostgreSQL support was contributed by the community and is not run by Puter.com production. It boots, applies the bundled schema, and exercises the common user/app/fsentry/session/permission/OIDC flows in the integration tests, but less-traveled SQL call sites may still need porting. If you hit a query that doesn't work on Postgres, please open an issue. For production self-hosting today, MariaDB/MySQL and SQLite are the supported defaults.
The bundled Docker Compose stack still defaults to MariaDB. To use PostgreSQL instead, run a PostgreSQL service yourself, point Puter at it, and use the PostgreSQL migration path:
You may use `"connectionString": "postgres://puter:...@postgres:5432/puter"` instead of the host/user/password fields. Puter only needs normal PostgreSQL connection details and the migration path; CloudNativePG is one possible Kubernetes operator, but no operator-specific manifests are required by Puter.
### Email (SMTP)
Used for password resets, email confirmation, and notifications. Without it those flows silently fail.
To require email confirmation before login, also set `"strict_email_verification_required": true`.
### Sign in with Google (or another OIDC provider)
```json
"oidc": {
"providers": {
"google": {
"client_id": "...apps.googleusercontent.com",
"client_secret": "...",
"scopes": "openid email profile"
}
}
}
```
Add `https://puter.<your-domain>/auth/oidc/callback/login` to the OAuth client's authorized redirect URIs in the Google Cloud Console. For non-Google providers, replace `google` with a custom id and supply `authorization_endpoint` / `token_endpoint` / `userinfo_endpoint` explicitly.
The `client_id` is your Apple Services ID. `team_id`, `key_id`, and `private_key` come from the Apple Developer Portal (Keys section — create a key with "Sign in with Apple" enabled). The `private_key` is the contents of the `.p8` file Apple provides. Add `https://puter.<your-domain>/auth/oidc/callback/login` and `https://puter.<your-domain>/auth/oidc/callback/signup` as return URLs in the Apple Services ID configuration.
### Sign in with Microsoft
```json
"oidc": {
"providers": {
"microsoft": {
"client_id": "YOUR_APPLICATION_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET_VALUE",
"tenant_id": "YOUR_TENANT_ID"
}
}
}
```
Register an app in the Azure Portal (Microsoft Entra ID → App registrations). The `client_id` is the Application (client) ID, `client_secret` is a client secret value, and `tenant_id` is the Directory (tenant) ID. Use `common` as `tenant_id` to allow any Microsoft account (personal and organizational); omit it to default to `common`. Add `https://puter.<your-domain>/auth/oidc/callback/login` and `https://puter.<your-domain>/auth/oidc/callback/signup` as redirect URIs under Authentication in the app registration.
### AI providers
Any provider with a key set is auto-enabled. Same shape as `ollama` above:
```json
"providers": {
"claude": { "apiKey": "sk-ant-..." },
"openai-completion": { "apiKey": "sk-..." },
"gemini": { "apiKey": "..." },
"openai-image-generation": { "apiKey": "sk-..." }
}
```
Full provider list (chat, image, video, TTS, OCR) is in the template.
### Per-user storage quota
Default is 100 MB per user.
```json
"storage_capacity": 5368709120, // 5 GB
"is_storage_limited": true
```
Set `is_storage_limited: false` for unlimited (bounded by host disk).
### Captcha on signup / login
Built-in proof-of-work captcha — no external service needed.
The `ollama` and `ollama-init` services live behind a compose profile so they don't run unless you ask for them. By default, `puter/config/config.json` has `"ollama": { "enabled": false }` — Puter skips the auto-probe entirely. To run a local model:
`ollama-init` exits 0 once the model is pulled. Subsequent boots find the model already on disk and the pull is a fast no-op.
Without `--profile ai`, the `ollama` containers stay down and Puter (with `enabled: false`) doesn't try to reach them — the rest of the stack runs identically.
For GPU acceleration (NVIDIA), uncomment the `deploy:` block under the `ollama` service in [docker-compose.yml](../docker-compose.yml). Requires `nvidia-container-toolkit` on the host.
## Building from source instead of pulling
If you want to test local Dockerfile changes against the full stack, uncomment the `build:` block in [docker-compose.yml](../docker-compose.yml) under the `puter` service, change `pull_policy: always` → `pull_policy: never`, then:
```bash
docker compose up -d --build
```
---
## Managing running backend
```bash
# update
docker compose pull
docker compose up -d
# logs
docker compose logs -f puter
# stop, keep data
docker compose down
# stop, NUKE all state (irreversible)
docker compose down
rm -rf puter/data
```
Migrations re-apply idempotently across pulls. Volumes are preserved.
## Troubleshooting
**Site loads but I get "Bad Gateway" / nginx errors.**
The puter container failed to come up. `docker compose logs puter` will tell you which dependency rejected it (most often DB password mismatch between `.env` and `config.json`).
**Login screen says "admin password not set".**
First-boot temp password is logged once. Find it: `docker compose logs puter | grep "tmp_password"`. After login, change it in Settings.
**Healthcheck reports unhealthy but the site works.**
The healthcheck hits `puter.localhost:4100/test` from inside the container. If you changed `domain` or `port`, the check still uses defaults. The site itself is fine.
**Nothing resolves at `puter.example.com` after DNS changes.**
DNS propagates slowly. `dig puter.example.com` and `dig api.puter.example.com` should both return your server IP. If not, give it 5–60 minutes.
**`docker compose up` hangs at "waiting for service to be healthy".**
`docker compose ps` shows which container is unhealthy. MariaDB takes ~20–30s on a cold boot; everything else under 5s. If something stays unhealthy, `logs <service>` will tell you why.
**`Error: DynamoDB aws config requires both access_key and secret_key`.**
You wrote `accessKeyId` / `secretAccessKey` under `dynamo.aws`. That config block uses snake_case (`access_key` / `secret_key`). Only the `s3.s3Config` block uses camelCase.
`SELECT COUNT(*) AS n FROM user_to_app_permissions
WHERE permission = 'flag:app-is-authenticated' AND app_id = ?`,
[(appasRecord<string,unknown>).id],
))asArray<{n: number}>;
res.json({count: row?.n??0});
};
extension.get(
'/app-telemetry/users',
{subdomain:'api',requireAuth: true},
handleAppTelemetryUsers,
);
extension.get(
'/app-telemetry/user-count',
{subdomain:'api',requireAuth: true},
handleAppTelemetryUserCount,
);
Loaded 100 of 2131 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.