SDK: app and connection
An app calls connect() once and works with the returned PithyxApp from then on. This page lists that object with every method, the permission each needs and the error codes it rejects with, plus the protocol messages, the formatters and the manifest types.
Generated from the TSDoc comments of @pithyx/sdk 1.0.0-rc.9 at build time; the text below the headings is the comment in the source.
Interfaces
Section titled “Interfaces”PithyxApp
Section titled “PithyxApp”The API an app works with. The same object for core apps and sandboxed apps; only the transport differs. Every method that talks to the desktop returns a promise and rejects with a PithyxError.
Every such call can also reject with sdk.request.timeout (no answer within 15 seconds, see
REQUEST_TIMEOUT), sdk.transport.closed (the window closed or the desktop signed out),
sdk.request.invalid (parameters outside the limits the method states) and sdk.method.unknown (the desktop does
not serve the method to this app; check PithyxApp.supports first). The permissions are the manifest’s
permissions that an administrator granted; context.permissions lists the ones the app holds now.
Properties
Section titled “Properties”context
Section titled “context”readonly context: AppContext;What the desktop told the app at start. The SDK keeps it current with the events: theme, language, locale,
timeZone, sizeClass, permissions, visible, online, logLevel, backend.status and storage. Needs no
permission. Reading it after the connection closed throws sdk.transport.closed.
format
Section titled “format”readonly format: Formatters;Dates, numbers, sizes and lists in the user’s language and time zone. Needs no permission.
window
Section titled “window”readonly window: object;The app’s own window; every call acts on the window that makes it. Needs no permission.
setTitle()
Section titled “setTitle()”setTitle(title): Promise<void>;Sets the title in the title bar and the taskbar, at most 200 characters.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
title |
string |
The new title, plain text. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”sdk.request.invalid when the title is longer than 200 characters.
close()
Section titled “close()”close(): Promise<void>;Closes the window without asking beforeClose.
Returns
Section titled “Returns”Promise<void>
setSize()
Section titled “setSize()”setSize(size): Promise<{ width: number; height: number;}>;Asks for a new free size; resolves with the size the desktop gave the window.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
size |
{ width: number; height: number; } |
The wished size in CSS pixels; the desktop may clamp it. |
size.width |
number |
Width in CSS pixels. |
size.height |
number |
Height in CSS pixels. |
Returns
Section titled “Returns”Promise<{
width: number;
height: number;
}>
The size the window got.
Throws
Section titled “Throws”sdk.request.invalid when a value is not a finite number.
setDirty()
Section titled “setDirty()”setDirty(dirty): Promise<void>;Marks the window as having unsaved changes or not. Once called, beforeClose is asked only while the window is
dirty.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
dirty |
boolean |
Whether the window has unsaved changes. |
Returns
Section titled “Returns”Promise<void>
requestAttention()
Section titled “requestAttention()”requestAttention(): Promise<void>;Makes the taskbar entry pulse until the user looks; never takes the focus.
Returns
Section titled “Returns”Promise<void>
ready()
Section titled “ready()”ready(): Promise<void>;Ends the desktop’s loading placeholder, for an app whose manifest sets window.loading.untilReady because it
first loads its data. Without that setting the placeholder goes when the app connects, and this does nothing.
Returns
Section titled “Returns”Promise<void>
readonly log: object;The app’s log in the Log Center, where administrators see it next to the system’s logs (source app/<id>, with
the signed-in user). Every entry also appears in the browser console. info, warn and error always go to the
daemon, debug only while an administrator switched debug logging on for the app (context.logLevel). Calls
return at once and never throw: the SDK collects entries for a moment and sends them together, and drops entries
when the app logs faster than its limit (bursts of 200, then 20 a second). Never log secrets such as passwords or
tokens. Messages are cut at 4000 characters, data at 20 fields of 1000 characters. Needs no permission.
debug()
Section titled “debug()”debug(message, data?): void;Details only needed while looking for a fault; reaches the daemon only while debug logging is on.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
message |
string |
What happened, in English. |
data? |
LogData |
Fields that describe it, for example { file: 'a.jpg' }. |
Returns
Section titled “Returns”void
info()
Section titled “info()”info(message, data?): void;Something worth knowing happened.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
message |
string |
What happened, in English. |
data? |
LogData |
Fields that describe it. |
Returns
Section titled “Returns”void
warn()
Section titled “warn()”warn(message, data?): void;Something went wrong but the app carries on.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
message |
string |
What happened, in English. |
data? |
LogData |
Fields that describe it. |
Returns
Section titled “Returns”void
error()
Section titled “error()”error(message, data?): void;Something failed.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
message |
string |
What happened, in English. |
data? |
LogData |
Fields that describe it. |
Returns
Section titled “Returns”void
log(message, data?): void;The same as info, for code written against console.log.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
message |
string |
What happened, in English. |
data? |
LogData |
Fields that describe it. |
Returns
Section titled “Returns”void
Example
Section titled “Example”app.log.warn('Upload retried', { file: name, attempt: 2 });session
Section titled “session”readonly session: object;Small state of this window that survives a reload and moves with “Get desktop from …”. Needs no permission.
save()
Section titled “save()”save(state): Promise<void>;Saves the window’s state with the desktop layout, at most 16 KB as JSON.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
state |
unknown |
Any JSON value, for example the open folder and the scroll position. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”app.storage.too_large when the state is larger than 16 KB as JSON.
restore()
Section titled “restore()”restore(): Promise<unknown>;The state saved before the last reload or on another device, or null. Never rejects.
Returns
Section titled “Returns”Promise<unknown>
The saved state, or null.
storage
Section titled “storage”readonly storage: object;Values the app keeps per user on the box; sandboxed apps have no localStorage. Keys have at most 128 characters,
values at most 64 KB as JSON, and an app keeps at most 1 MB per user. Needs no permission.
get<T>(key): Promise<T | null>;The value stored under key, or null.
Type Parameters
Section titled “Type Parameters”| Type Parameter | Default type |
|---|---|
T |
unknown |
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
key |
string |
1 to 128 characters. |
Returns
Section titled “Returns”Promise<T | null>
The stored value, or null when there is none.
Throws
Section titled “Throws”app.storage.key_invalid when the key is empty or longer than 128 characters.
set(key, value): Promise<void>;Stores a value under key, replacing an earlier one.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
key |
string |
1 to 128 characters. |
value |
unknown |
Any JSON value, at most 64 KB as JSON. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”app.storage.key_invalid when the key is empty or longer than 128 characters.
Throws
Section titled “Throws”app.storage.too_large when the value is larger than 64 KB or the app would keep more than 1 MB for
the user.
remove()
Section titled “remove()”remove(key): Promise<void>;Removes the value under key, if there is one; a missing key is no error.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
key |
string |
1 to 128 characters. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”app.storage.key_invalid when the key is empty or longer than 128 characters.
keys()
Section titled “keys()”keys(): Promise<string[]>;Every key the app stored for this user.
Returns
Section titled “Returns”Promise<string[]>
The keys, in no particular order.
backend
Section titled “backend”readonly backend: object;The app’s own backend, through the daemon’s proxy. Paths are relative to an endpoint: the default api at
/apps/<id>/api/, any other endpoint <name> at /apps/<id>/api-<name>/. The SDK adds a token for the signed-in
user; the backend learns the user from the proxy’s X-Pithyx-* headers. A name the manifest does not declare
fails with sdk.backend.endpoint_unknown. Needs no permission; an app without a backend has no endpoint.
url(path, options?): Promise<string>;A full URL with the token as ?pithyx-token=, for <img>, <video> or a download link. It is valid as long as
its token, at least 30 seconds and at most 5 minutes; ask again for a new one.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
path |
string |
The path below the endpoint, with an optional query; it may not leave the endpoint with ... |
options? |
{ endpoint?: string; } |
The endpoint; api when left out. |
options.endpoint? |
string |
The name of an endpoint the manifest declares; api when left out. |
Returns
Section titled “Returns”Promise<string>
The absolute URL with the token.
Throws
Section titled “Throws”sdk.backend.endpoint_unknown when the app has no backend or the manifest declares no such endpoint.
Throws
Section titled “Throws”sdk.request.invalid when the path leaves the endpoint.
Throws
Section titled “Throws”app.backend.missing when the app has no backend.
Throws
Section titled “Throws”app.app.not_found when the user may no longer open the app.
fetch()
Section titled “fetch()”fetch(path, init?): Promise<Response>;fetch against the backend with Authorization: Bearer <token> and without cookies. Resolves with the response
whatever its status; a request that does not reach the box fails with sdk.backend.unreachable.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
path |
string |
The path below the endpoint, with an optional query; it may not leave the endpoint with ... |
init? |
RequestInit & object |
What fetch takes, plus the endpoint. |
Returns
Section titled “Returns”Promise<Response>
The backend’s response, also for 4xx and 5xx; the proxy answers 503 app.backend.unavailable while
the backend is updating or unavailable.
Throws
Section titled “Throws”sdk.backend.endpoint_unknown when the app has no backend or the manifest declares no such endpoint.
Throws
Section titled “Throws”sdk.backend.unreachable when the request gets no answer.
Throws
Section titled “Throws”sdk.request.invalid when the path leaves the endpoint.
socket()
Section titled “socket()”socket(path, options?): Promise<WebSocket>;Opens a WebSocket to the backend with a one-time ticket (?pithyx-ticket=, valid 30 seconds).
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
path |
string |
The path below the endpoint; it may not leave the endpoint with ... |
options? |
{ endpoint?: string; protocols?: string | string[]; } |
The endpoint and the subprotocols. |
options.endpoint? |
string |
The name of an endpoint the manifest declares; api when left out. |
options.protocols? |
string | string[] |
WebSocket subprotocols, as new WebSocket takes them. |
Returns
Section titled “Returns”Promise<WebSocket>
The WebSocket, still connecting; wss: on HTTPS and ws: on plain HTTP.
Throws
Section titled “Throws”sdk.backend.endpoint_unknown when the app has no backend or the manifest declares no such endpoint.
Throws
Section titled “Throws”sdk.request.invalid when the path leaves the endpoint.
token()
Section titled “token()”token(): Promise<BackendToken>;The current token, for clients that build their own requests. The SDK keeps it until 30 seconds before it
expires and fetches a new one after that or after permissionsChange.
Returns
Section titled “Returns”Promise<BackendToken>
The token and when it expires.
Throws
Section titled “Throws”app.backend.missing when the app has no backend.
Throws
Section titled “Throws”app.app.not_found when the user may no longer open the app.
Example
Section titled “Example”const messages = await (await app.backend.fetch('/messages')).json();const stats = await app.backend.fetch('/stats', { endpoint: 'metrics' });avatar.src = await app.backend.url('/avatar/1');const live = await app.backend.socket('/live');directory
Section titled “directory”readonly directory: object;The users and groups of the box. Needs directory.read; the app’s own user is in context.user without it.
users()
Section titled “users()”users(): Promise<DirectoryUser[]>;Every active user of the box.
Returns
Section titled “Returns”Promise<DirectoryUser[]>
The users, without deactivated ones.
Throws
Section titled “Throws”app.permission.denied without the directory.read permission.
groups()
Section titled “groups()”groups(): Promise<DirectoryGroup[]>;Every group of the box, without the built-in group of all users.
Returns
Section titled “Returns”Promise<DirectoryGroup[]>
The groups.
Throws
Section titled “Throws”app.permission.denied without the directory.read permission.
contextMenu
Section titled “contextMenu”readonly contextMenu: object;A context menu drawn by the desktop, also over the edge of the app’s window. Needs no permission.
show()
Section titled “show()”show(at, items): Promise<string | null>;Shows a menu drawn by the desktop at at (CSS pixels in the app’s window) and resolves with the id of the
picked entry, or null when the user dismissed it. Call it from a contextmenu or click handler.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
at |
Point |
Where the menu opens, relative to the window’s content. |
items |
ContextMenuItem[] |
1 to 50 entries and separators. |
Returns
Section titled “Returns”Promise<string | null>
The id of the picked entry, or null.
Throws
Section titled “Throws”sdk.request.invalid when there are no entries, more than 50, or an entry exceeds its limits.
clipboard
Section titled “clipboard”readonly clipboard: object;The clipboard, through the desktop. Needs no permission.
writeText()
Section titled “writeText()”writeText(text): Promise<void>;Copies text, also over plain HTTP where the frame has no Clipboard API. Only for a user action.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
text |
string |
At most 1 MB of text. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”sdk.request.invalid when the text is longer than 1 MB.
readonly files: object;Files. The first group works on files the user handed to the app (files.read, files.write); the second is the
file manager API over shares and named storage (files.shares for shares). See Methods for every call.
A FileLocation is { storage: id } for a storage request of the manifest or { share: id } for a share;
versions, restoreVersion and trash take only a share (ShareLocation). The
daemon checks the app’s permissions and the user’s own rights on every call: a share needs files.shares, its
content also files.read or files.write, and changes need write access to the share (fs.share.read_only
otherwise). Common failures: app.permission.denied, fs.share.not_found, fs.share.unavailable (its pool is
missing or locked), app.storage.not_found (no such storage request or not mapped), fs.path.invalid,
fs.entry.not_found and fs.entry.access_denied. A desktop may lack a method; check
PithyxApp.supports.
pick()
Section titled “pick()”pick(options?): Promise<FileRef[]>;Lets the user pick files in the desktop’s file dialog. Resolves with an empty list when the user cancels.
Needs files.read; must follow a user action in the window
(otherwise it resolves with an empty list). The app can read the chosen files, and write them with
files.write, without files.shares.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
options? |
{ multiple?: boolean; extensions?: string[]; } |
Whether several files may be picked and which extensions are offered. |
options.multiple? |
boolean |
Whether the user may pick more than one file. |
options.extensions? |
string[] |
Extensions without dot, for example ['jpg', 'png']; every file when left out. |
Returns
Section titled “Returns”Promise<FileRef[]>
The picked files, empty when the user cancelled.
Throws
Section titled “Throws”app.permission.denied without the files.read permission.
saveAs()
Section titled “saveAs()”saveAs(suggestedName, data): Promise<FileRef | null>;Lets the user choose where to save data in the desktop’s save dialog. Resolves with null when the user
cancels. Needs files.write; must follow a user action in the window
(otherwise it resolves with null).
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
suggestedName |
string |
The name the dialog proposes. |
data |
Blob |
The content to save. |
Returns
Section titled “Returns”Promise<FileRef | null>
The saved file, or null when the user cancelled.
Throws
Section titled “Throws”app.permission.denied without the files.write permission.
read()
Section titled “read()”read(file): Promise<Blob>;The content of a file the app was handed. Needs files.read.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
file |
FileRef |
A handle from pick, open, launch.file or openFile. |
Returns
Section titled “Returns”Promise<Blob>
The content.
Throws
Section titled “Throws”app.permission.denied without the files.read permission.
Throws
Section titled “Throws”fs.entry.not_found when the file is gone.
write()
Section titled “write()”write(file, data): Promise<FileRef>;Replaces the content of a writable file the app was handed. Needs files.write.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
file |
FileRef |
A handle whose writable is true. |
data |
Blob |
The new content. |
Returns
Section titled “Returns”Promise<FileRef>
The handle with the new size and change time.
Throws
Section titled “Throws”app.permission.denied without the files.write permission.
Throws
Section titled “Throws”fs.share.read_only when the user may only read the share.
Throws
Section titled “Throws”fs.volume.full when the pool has no space left.
url(file): Promise<{ url: string; expiresAt: string;}>;A short-lived URL for <img>, <video> or fetch with range requests, valid 5 minutes and only for this file.
Needs files.read.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
file |
FileRef |
A handle from pick, open, launch.file or openFile. |
Returns
Section titled “Returns”Promise<{
url: string;
expiresAt: string;
}>
The URL and when it expires.
Throws
Section titled “Throws”app.permission.denied without the files.read permission.
open()
Section titled “open()”open(location, path): Promise<FileRef>;A handle for a file in a named storage or a share, for read, write and url. A share needs files.shares.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
FileLocation |
A storage request or a share. |
path |
string |
The file, relative to the location. |
Returns
Section titled “Returns”Promise<FileRef>
The handle; writable says whether the app may write it.
Throws
Section titled “Throws”app.permission.denied without files.shares for a share.
Throws
Section titled “Throws”fs.entry.not_found when there is no such file.
shares()
Section titled “shares()”shares(): Promise<ShareInfo[]>;The shares the user can use, with the user’s access to each. Needs files.shares. The sharesChanged event says
when the list may have changed.
Returns
Section titled “Returns”Promise<ShareInfo[]>
The shares, without their place on the host.
Throws
Section titled “Throws”app.permission.denied without the files.shares permission.
list()
Section titled “list()”list( location, path, page?): Promise<FolderPage>;One page of a folder (default 100 entries, at most 1000), in natural name order unless sort says otherwise.
Pass the page’s nextCursor as cursor for the next one; cursors stay valid while the folder changes. A share
needs files.shares.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
FileLocation |
A storage request or a share. |
path |
string |
The folder, relative to the location; "" for its root. |
page? |
{ cursor?: string; limit?: number; sort?: SortKey; order?: SortOrder; } |
Cursor, size and order of the page. |
page.cursor? |
string |
The nextCursor of the previous page. |
page.limit? |
number |
Entries per page, 100 when left out, at most 1000. |
page.sort? |
SortKey |
What to sort by; name when left out. |
page.order? |
SortOrder |
Ascending or descending; asc when left out. |
Returns
Section titled “Returns”Promise<FolderPage>
One page of entries.
Throws
Section titled “Throws”app.permission.denied without files.shares for a share.
Throws
Section titled “Throws”fs.entry.not_found or fs.entry.not_folder when the path is no folder.
Throws
Section titled “Throws”fs.cursor.invalid when the cursor belongs to another listing.
watch()
Section titled “watch()”watch(location, path): Promise<string>;Starts live changes of a folder and resolves with the id that its folderChanged events carry. Watch only
folders on screen and call unwatch when leaving them; a watch never wakes a sleeping disk. Needs files.shares.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
FileLocation |
A share. |
path |
string |
The folder, relative to the share. |
Returns
Section titled “Returns”Promise<string>
The watch id.
Throws
Section titled “Throws”app.permission.denied without the files.shares permission.
unwatch()
Section titled “unwatch()”unwatch(watch): Promise<void>;Ends a watch; no more folderChanged events come for it.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
watch |
string |
The id watch resolved with. |
Returns
Section titled “Returns”Promise<void>
upload()
Section titled “upload()”upload( location, folder, name, data, options?): Promise<FileEntry>;Uploads data as name into folder. The file appears only when it is complete. An existing name fails with
fs.entry.exists unless overwrite; with an upload id, uploadProgress events report the bytes sent. The
call has no time limit, since it lasts as long as the transfer. A share needs files.shares and write access.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
FileLocation |
A storage request or a share. |
folder |
string |
The folder, relative to the location. |
name |
string |
The file name, 1 to 255 characters without /. |
data |
Blob |
The content. |
options? |
{ overwrite?: boolean; upload?: string; } |
Whether to replace an existing file and the id for progress events. |
options.overwrite? |
boolean |
Replace a file of the same name. Set it only when the user asked for it. |
options.upload? |
string |
An id of the app’s choice; uploadProgress events carry it. |
Returns
Section titled “Returns”Promise<FileEntry>
The new entry.
Throws
Section titled “Throws”fs.entry.exists when the name is taken and overwrite is not set.
Throws
Section titled “Throws”fs.share.read_only when the user may only read the share.
Throws
Section titled “Throws”fs.volume.full when the pool has no space left.
Throws
Section titled “Throws”fs.upload.incomplete when the transfer broke off.
Throws
Section titled “Throws”sdk.transfer.cancelled when the user cancelled the upload in the taskbar.
download()
Section titled “download()”download(location, path): Promise<void>;Downloads a file to the user’s device through the browser. Needs files.shares.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
FileLocation |
A share. |
path |
string |
The file, relative to the share. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”app.permission.denied without the files.shares permission.
createFolder()
Section titled “createFolder()”createFolder(location, path): Promise<FileEntry>;Creates a folder at path; its parent must exist and the name must be free (fs.entry.exists). A share needs
files.shares and write access.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
FileLocation |
A storage request or a share. |
path |
string |
The new folder, relative to the location. |
Returns
Section titled “Returns”Promise<FileEntry>
The new entry.
Throws
Section titled “Throws”fs.entry.exists when the name is taken.
Throws
Section titled “Throws”fs.entry.not_found when the parent folder does not exist.
Throws
Section titled “Throws”fs.share.read_only when the user may only read the share.
rename()
Section titled “rename()”rename( location, path, name): Promise<FileEntry>;Renames the entry at path to name within its folder; an existing name is never replaced. Needs files.shares
and write access.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
FileLocation |
A share. |
path |
string |
The entry, relative to the share. |
name |
string |
The new name, 1 to 255 characters without /. |
Returns
Section titled “Returns”Promise<FileEntry>
The renamed entry.
Throws
Section titled “Throws”fs.entry.exists when the name is taken.
Throws
Section titled “Throws”fs.name.invalid when the name is not allowed.
run(operation): Promise<JobInfo>;Starts a copy, move or delete as a job and resolves with it at once; jobChanged events follow its progress
until it finishes. A whole folder is named with { all: true, except }, never with every name. Deleting moves
to the share’s recycle bin unless permanent, which only an explicit request of the user may set. Source and
target may each be a share or a storage request: a share needs files.shares, files.read where entries are
copied or moved from and files.write where anything changes; a storage request needs its mapping, for changes
one for reading and writing, and never reaches beyond the mapped folder. The user needs the access too.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
operation |
FileOperation |
What to do with which entries, and where to. |
Returns
Section titled “Returns”Promise<JobInfo>
The job as it started; failures of single entries end up in its problem.
Throws
Section titled “Throws”fs.operation.invalid when the operation does not fit (a target for delete, none for copy).
Throws
Section titled “Throws”fs.operation.into_itself when a folder would be copied or moved into itself.
versions()
Section titled “versions()”versions(location, path): Promise<FileVersion[]>;Earlier versions of the entry at path from the snapshots of the share’s dataset, newest first; also of an
entry deleted since. Empty when the share has no snapshots. Needs files.shares and read access to the share.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
ShareLocation |
A share. |
path |
string |
The entry, relative to the share; not its root. |
Returns
Section titled “Returns”Promise<FileVersion[]>
The versions, newest first.
restoreVersion()
Section titled “restoreVersion()”restoreVersion( location, path, snapshot, options?): Promise<JobInfo>;Copies a version back as a job: next to the current entry as “name (version date)”, or over it with
overwrite (files are replaced, folders merged), which only an explicit request of the user may set. Needs
files.shares and write access.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
ShareLocation |
A share. |
path |
string |
The entry, relative to the share; not its root. |
snapshot |
string |
The snapshot of a version from versions. |
options? |
{ overwrite?: boolean; } |
Whether to replace the current entry. |
options.overwrite? |
boolean |
Replace the current entry instead of restoring next to it. |
Returns
Section titled “Returns”Promise<JobInfo>
The job as it started.
Throws
Section titled “Throws”fs.version.not_found when the snapshot or the entry in it is gone.
readonly jobs: object;The jobs the app started with files.run, files.restoreVersion and trash.*.
cancel()
Section titled “cancel()”cancel(job): Promise<void>;Cancels a job the app started; a job that already finished stays as it is.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
job |
number |
The id of the job. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”jobs.job.not_found when there is no such job of the user.
readonly trash: object;The recycle bin of a share. Needs files.shares; reading it needs read access to the share, changing it write
access.
list()
Section titled “list()”list(location, page?): Promise<TrashPage>;One page of the bin, newest first, with the share’s retention.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
ShareLocation |
A share. |
page? |
{ cursor?: string; limit?: number; } |
Cursor and size of the page. |
page.cursor? |
string |
The nextCursor of the previous page. |
page.limit? |
number |
Items per page. |
Returns
Section titled “Returns”Promise<TrashPage>
One page of items.
Throws
Section titled “Throws”app.permission.denied without the files.shares permission.
restore()
Section titled “restore()”restore( location, ids, onConflict?): Promise<JobInfo>;Puts items back where they were, recreating missing folders, as a job. A taken name gets a free one (“name
(2)”) unless onConflict says otherwise.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
ShareLocation |
A share. |
ids |
number[] |
1 to 1000 item ids from list. |
onConflict? |
ConflictPolicy |
What to do with a taken name; rename when left out. |
Returns
Section titled “Returns”Promise<JobInfo>
The job as it started.
delete()
Section titled “delete()”delete(location, ids): Promise<JobInfo>;Deletes items of the bin for good, as a job. Only after the user confirmed it.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
ShareLocation |
A share. |
ids |
number[] |
1 to 1000 item ids from list. |
Returns
Section titled “Returns”Promise<JobInfo>
The job as it started.
empty()
Section titled “empty()”empty(location): Promise<JobInfo>;Deletes everything in the bin for good, as a job. Only after the user confirmed it.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
location |
ShareLocation |
A share. |
Returns
Section titled “Returns”Promise<JobInfo>
The job as it started.
readonly ui: object;The desktop’s own dialogs. Needs no permission.
showError()
Section titled “showError()”showError(error): Promise<void>;Shows the desktop’s error dialog for a failure, with the translated text of its code, so the app needs no texts
of its own for daemon and SDK errors. A code the desktop does not know (the app’s own) shows the error’s
detail instead, so give such an error a detail in the user’s language. The request id goes to the browser
console, never into the dialog.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
error |
unknown |
A PithyxError, a problem, or anything else, which shows as an unexpected error. |
Returns
Section titled “Returns”Promise<void>
Methods
Section titled “Methods”notify()
Section titled “notify()”notify(notification): Promise<{ id: string;}>;Shows a notification and resolves with its id. Needs notifications. A click on one of its actions (or on the
notification) comes back as notificationAction, or as launch.notification when no window was open.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
notification |
NotificationRequest |
Title, body, level, buttons, data and tag; the limits are on NotificationRequest. |
Returns
Section titled “Returns”Promise<{
id: string;
}>
The id of the notification, which notificationAction carries.
Throws
Section titled “Throws”app.permission.denied without the notifications permission.
Throws
Section titled “Throws”sdk.request.invalid when a text, the buttons or the data exceed their limits.
setBadge()
Section titled “setBadge()”setBadge(count): Promise<void>;A counter on the app’s taskbar entry; 0 or null removes it. Needs no permission.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
count |
number | null |
A whole number of at least 0, or null. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”sdk.request.invalid when the count is negative or not a whole number.
openUrl()
Section titled “openUrl()”openUrl(url): Promise<void>;Opens an https:, http: or mailto: URL in a new browser tab, without a reference to the desktop. Needs no
permission.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
url |
string |
An absolute URL of at most 2048 characters. |
Returns
Section titled “Returns”Promise<void>
Throws
Section titled “Throws”sdk.request.invalid for any other scheme (javascript:, data:) or a longer URL.
supports()
Section titled “supports()”supports(method): boolean;Whether the desktop supports a method. Methods added after 1.0 may be missing on an older desktop; a call to a
method it does not support fails with sdk.method.unknown.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
method |
keyof Methods |
A method name of Methods, such as files.watch. |
Returns
Section titled “Returns”boolean
Whether context.capabilities lists it.
on<E>(event, handler): () => void;Listens to an event of the desktop (see Events). Returns a function that stops listening.
Type Parameters
Section titled “Type Parameters”| Type Parameter |
|---|
E extends keyof Events |
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
event |
E |
The event name. |
handler |
EventHandler<E> |
Called with the event’s data each time it arrives. |
Returns
Section titled “Returns”A function that removes the handler.
() => void
answer()
Section titled “answer()”answer<Q>(query, handler): void;Answers a question of the desktop (beforeClose, beforeUnload). One handler per question; the last one wins.
The answer to beforeUnload is ignored: it cannot be refused, only used to save.
Type Parameters
Section titled “Type Parameters”| Type Parameter |
|---|
Q extends keyof Queries |
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
query |
Q |
The question. |
handler |
QueryHandler<Q> |
Returns the answer, also asynchronously within the question’s time limit. |
Returns
Section titled “Returns”void
call()
Section titled “call()”call<M>(method, params): Promise<Methods[M]["result"]>;Low-level call of any method, for methods newer than this SDK’s typed helpers. It needs what the method needs and fails like it.
Type Parameters
Section titled “Type Parameters”| Type Parameter |
|---|
M extends keyof Methods |
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
method |
M |
A method name of Methods. |
params |
Methods[M]["params"] |
The method’s parameters. |
Returns
Section titled “Returns”Promise<Methods[M]["result"]>
The method’s result.
Throws
Section titled “Throws”sdk.method.unknown when the desktop does not serve the method.
CreateAppOptions
Section titled “CreateAppOptions”How createApp and connect set up the app.
Properties
Section titled “Properties”themeRoot?
Section titled “themeRoot?”optional themeRoot?: HTMLElement | null;Where the theme tokens go; the SDK sets them on document.documentElement by default. Null to skip.
timeout?
Section titled “timeout?”optional timeout?: number;Time limit of a call in milliseconds; REQUEST_TIMEOUT when left out.
origin?
Section titled “origin?”optional origin?: string;The box’s address for backend URLs; by default taken from the window’s own URL.
Formatters
Section titled “Formatters”Formatters in the user’s language and time zone, as app.format has them. None of them throws or needs a permission.
Methods
Section titled “Methods”date()
Section titled “date()”date(value, options?): string;A date, for example “Sep 27, 2026”.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
value |
string | Date |
An ISO 8601 string or a Date. |
options? |
DateTimeFormatOptions |
Intl.DateTimeFormat options; { dateStyle: 'medium' } when left out. |
Returns
Section titled “Returns”string
The date in the user’s time zone.
time()
Section titled “time()”time(value, options?): string;A time of day, for example “14:05”.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
value |
string | Date |
An ISO 8601 string or a Date. |
options? |
DateTimeFormatOptions |
Intl.DateTimeFormat options; { timeStyle: 'short' } when left out. |
Returns
Section titled “Returns”string
The time in the user’s time zone.
dateTime()
Section titled “dateTime()”dateTime(value, options?): string;Date and time.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
value |
string | Date |
An ISO 8601 string or a Date. |
options? |
DateTimeFormatOptions |
Intl.DateTimeFormat options; medium date and short time when left out. |
Returns
Section titled “Returns”string
Date and time in the user’s time zone.
relative()
Section titled “relative()”relative(value, now?): string;How long ago or how far ahead, for example “5 minutes ago”, in the largest unit that fits.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
value |
string | Date |
An ISO 8601 string or a Date. |
now? |
Date |
The moment to compare with; the current time when left out. |
Returns
Section titled “Returns”string
The distance in words, such as “yesterday” or “in 3 hours”.
number()
Section titled “number()”number(value, options?): string;A number with the user’s separators, for example “1,234.5”.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
value |
number |
The number. |
options? |
NumberFormatOptions |
Intl.NumberFormat options. |
Returns
Section titled “Returns”string
The formatted number.
bytes()
Section titled “bytes()”bytes(value): string;A byte count with decimal units, as the desktop shows sizes (10 GB, 4 TB).
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
value |
number |
The size in bytes. |
Returns
Section titled “Returns”string
The size with one decimal below 100 of its unit.
list()
Section titled “list()”list(values, options?): string;A list, for example “Anna, Ben and Chris”.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
values |
readonly string[] |
The items, already as text. |
options? |
ListFormatOptions |
Intl.ListFormat options; a conjunction when left out. |
Returns
Section titled “Returns”string
The joined list.
AppManifest
Section titled “AppManifest”The app manifest (pithyx.json at the root of an app package). It tells the daemon and the desktop what the app is, what it may do and how its window and backend behave. The icon is always icon.svg next to it. This schema is a stable contract: a new optional field is a minor change, anything else a major one. Unknown fields are errors.
Properties
Section titled “Properties”$schema?
Section titled “$schema?”optional $schema?: string;Path or URL of this schema, for editors. Ignored by the box.
manifestVersion
Section titled “manifestVersion”manifestVersion: 1;The manifest schema this file follows.
id: string;version
Section titled “version”version: string;SemVer 2.0 version of the app, without build metadata, for example 1.2.0 or 2.0.0-beta.1.
name: LocalizedName;description?
Section titled “description?”optional description?: LocalizedText;author
Section titled “author”author: AppAuthor;license?
Section titled “license?”optional license?: string;SPDX license expression of the app, for example MIT or MIT OR Apache-2.0.
homepage?
Section titled “homepage?”optional homepage?: string;The app’s website or source repository.
entry: string;Path of the HTML page the desktop loads in the sandboxed window, inside frontend/ of the package, for example frontend/index.html. Segments never start with a dot.
sdk: string;SemVer range of @pithyx/sdk the app was built against, for example ^1.0.0.
pithyx?
Section titled “pithyx?”optional pithyx?: string;SemVer range of the Pithyx versions the app runs on, for example >=0.1.0. Optional; without it the app claims to run on every version. A box installs a version only when its own version is in the range, and lists a catalog version only then. Unlike npm, a box running a prerelease matches by plain SemVer precedence, so >=0.1.0 includes 0.2.0-beta.1, while ^0.1.0 does not (it ends below 0.2.0-0). Catalogs require it.
dataVersion?
Section titled “dataVersion?”optional dataVersion?: number;The version of the format of the app’s stored data (volumes, its stored values and the files of its storage requests), an integer from 1. Optional. Raise it with every release that converts data in a way the previous version cannot read. A box goes back to an older version from a catalog only when both declare the same dataVersion; going back to the version before an update with its snapshot works without it.
permissions
Section titled “permissions”permissions: Permission[];The permissions the app asks for. Each one appears in the install dialog and can be revoked later.
window
Section titled “window”window: WindowManifest;storage?
Section titled “storage?”optional storage?: StorageRequest[];Places for files the app needs, each mapped by an administrator to a folder in a shared folder.
Max Items
Section titled “Max Items”16
fileHandlers?
Section titled “fileHandlers?”optional fileHandlers?: FileHandler[];Files the app can open.
Max Items
Section titled “Max Items”32
backend?
Section titled “backend?”optional backend?: BackendManifest;LocalizedName
Section titled “LocalizedName”A short text in several languages, keyed by BCP 47 language tag, for example the app’s name or a storage request’s name. en is required and used when nothing else matches. One line, at most 60 characters per language.
Indexable
Section titled “Indexable”[k: string]: stringThe text in the language of the key, a BCP 47 language tag such as de or pt-BR. One line, at most 60 characters.
This interface was referenced by LocalizedName’s JSON-Schema definition
via the patternProperty “^[a-z]{2,3}(-[A-Za-z0-9]{1,8})*$”.
Properties
Section titled “Properties”en: string;The English text, shown when no other language matches. One line, at most 60 characters.
LocalizedText
Section titled “LocalizedText”A text in several languages, keyed by BCP 47 language tag, for example the app’s description of one or two sentences for the store and the install dialog. en is required and used when nothing else matches. At most 500 characters per language; line breaks are allowed.
Indexable
Section titled “Indexable”[k: string]: stringThe text in the language of the key, a BCP 47 language tag such as de or pt-BR. At most 500 characters; line breaks are allowed.
This interface was referenced by LocalizedText’s JSON-Schema definition
via the patternProperty “^[a-z]{2,3}(-[A-Za-z0-9]{1,8})*$”.
Properties
Section titled “Properties”en: string;The English text, shown when no other language matches. At most 500 characters; line breaks are allowed.
AppAuthor
Section titled “AppAuthor”Who makes the app.
Properties
Section titled “Properties”name: string;A person or an organization.
optional url?: string;The author’s website.
WindowManifest
Section titled “WindowManifest”How the app’s windows behave. defaultSize is the size of a new window when the user has no remembered size for the app; minSize is the smallest size on screens that can fit it, at most defaultSize in both dimensions.
Properties
Section titled “Properties”instances
Section titled “instances”instances: 'single' | 'multi';single: opening the app again focuses the user’s existing window on this device and passes the launch arguments to it (launch event). multi: every launch opens a new window.
defaultSize
Section titled “defaultSize”defaultSize: WindowSize;minSize
Section titled “minSize”minSize: WindowSize;loading?
Section titled “loading?”optional loading?: WindowLoading;WindowSize
Section titled “WindowSize”A size in CSS pixels.
Properties
Section titled “Properties”width: number;The width in CSS pixels.
height
Section titled “height”height: number;The height in CSS pixels.
WindowLoading
Section titled “WindowLoading”What a window shows before the app is ready. The desktop always draws the app’s icon and name in a new window and an indicator after 300 ms, until the app connected (or, with untilReady, until it called app.window.ready()). While the backend starts, a line of text says so; without text it is the desktop’s own, such as “Starting Lists …”. text is the line shown while the backend starts, in the user’s language, for example “Opening your lists …”: say what happens in plain words, without technical terms.
Properties
Section titled “Properties”optional text?: LocalizedName;untilReady?
Section titled “untilReady?”optional untilReady?: boolean;Whether the window keeps the placeholder after the app connected until it calls app.window.ready(), for an app that first loads its data. The desktop removes it after 30 seconds in any case. Default false.
NotificationAction
Section titled “NotificationAction”A button of a notification.
Properties
Section titled “Properties”id: string;Comes back in notificationAction; 1 to 64 characters.
label: string;Plain text, 1 to 40 characters, translated by the app.
NotificationActivation
Section titled “NotificationActivation”What the app learns when the user clicks one of its notifications.
Properties
Section titled “Properties”notification
Section titled “notification”notification: string;The id notify resolved with.
action
Section titled “action”action: string | null;The id of the button the user clicked, or null for a click on the notification itself.
data: unknown;The data the app passed to notify, or null.
NotificationRequest
Section titled “NotificationRequest”A notification the app shows. The app translates the texts; it knows the locale from the context. It appears as a toast with the app’s icon and stays in the user’s notification history (at most 200 entries, 30 days).
Properties
Section titled “Properties”title: string;Plain text, 1 to 200 characters.
optional body?: string;Plain text, at most 1000 characters.
level?
Section titled “level?”optional level?: "info" | "success" | "warning" | "error";How the toast looks; info when left out.
actions?
Section titled “actions?”optional actions?: NotificationAction[];At most 2 buttons. A click sends notificationAction, or starts the app with launch.notification.
optional data?: unknown;Data that comes back with notificationAction, at most 4 KB as JSON.
optional tag?: string;Replaces the app’s earlier notification with the same tag for this user, for example one per chat. 1 to 64 characters.
DirectoryUser
Section titled “DirectoryUser”A user of the box, as directory.users lists it. Deactivated users are left out.
Properties
Section titled “Properties”id: number;Stable id of the user: the Linux uid, also X-Pithyx-User-Id for the backend; never given to another user.
name: string;The user name, lower case.
displayName
Section titled “displayName”displayName: string | null;The name to show, if the user set one.
groups
Section titled “groups”groups: number[];Ids of the user’s groups (see directory.groups); the built-in group every user belongs to is left out.
DirectoryGroup
Section titled “DirectoryGroup”A group of the box, as directory.groups lists it. The built-in group every user belongs to is left out.
Properties
Section titled “Properties”id: number;Stable id (the group’s Linux gid).
name: string;The group’s name.
description
Section titled “description”description: string;Free text, may be empty.
A point in CSS pixels, relative to the top left corner of the app’s window content.
Properties
Section titled “Properties”x: number;Distance from the left edge.
y: number;Distance from the top edge.
LogRecord
Section titled “LogRecord”One entry of the app’s log, as the SDK sends it (see app.log).
Properties
Section titled “Properties”level: LogLevel;How serious the entry is.
message
Section titled “message”message: string;At most 4000 characters; the SDK cuts longer ones.
optional data?: Record<string, string>;At most 20 fields with texts of at most 1000 characters; the SDK cuts the rest.
Methods
Section titled “Methods”Every method an app can call: parameters and result. A method name is part of the stable API; a new method is a minor change and appears in AppContext.capabilities.
Properties
Section titled “Properties”window.setTitle
Section titled “window.setTitle”window.setTitle: object;Sets the window title (shown in the title bar and the taskbar). At most 200 characters.
params
Section titled “params”params: object;params.title
Section titled “params.title”title: string;result
Section titled “result”result: undefined;window.close
Section titled “window.close”window.close: object;Closes the window. beforeClose is not sent for a close the app asked for.
params
Section titled “params”params: Record<string, never>;result
Section titled “result”result: undefined;window.setDirty
Section titled “window.setDirty”window.setDirty: object;Marks the window as having unsaved changes or not. Once an app called it, the desktop asks beforeClose only
while the window is dirty; an app that never calls it is asked on every close.
params
Section titled “params”params: object;params.dirty
Section titled “params.dirty”dirty: boolean;result
Section titled “result”result: undefined;window.requestAttention
Section titled “window.requestAttention”window.requestAttention: object;Makes the window’s taskbar entry pulse until the user looks at it. It never brings the window to the front or takes the focus.
params
Section titled “params”params: Record<string, never>;result
Section titled “result”result: undefined;window.ready
Section titled “window.ready”window.ready: object;Ends the desktop’s loading placeholder of the window. Only needed with the manifest’s window.loading.untilReady;
otherwise the placeholder goes when the app connects. Calling it again does nothing.
params
Section titled “params”params: Record<string, never>;result
Section titled “result”result: undefined;window.setSize
Section titled “window.setSize”window.setSize: object;Asks for a new free size. The desktop may clamp it; the result is the size the window got.
params
Section titled “params”params: object;params.width
Section titled “params.width”width: number;params.height
Section titled “params.height”height: number;result
Section titled “result”result: object;result.width
Section titled “result.width”width: number;result.height
Section titled “result.height”height: number;log.write
Section titled “log.write”log.write: object;Writes entries to the app’s log in the Log Center (source app/<id>, with the signed-in user). The SDK batches
app.log calls into this method; apps do not call it directly. At most 100 entries per call; the
daemon keeps each app within a rate limit and drops the rest. No permission needed.
params
Section titled “params”params: object;params.entries
Section titled “params.entries”entries: LogRecord[];result
Section titled “result”result: undefined;notify
Section titled “notify”notify: object;Shows a notification and resolves with its id. Needs the notifications permission.
params
Section titled “params”params: NotificationRequest;result
Section titled “result”result: object;result.id
Section titled “result.id”id: string;setBadge
Section titled “setBadge”setBadge: object;A counter on the app’s taskbar entry: a positive integer shows it, 0 or null removes it.
params
Section titled “params”params: object;params.count
Section titled “params.count”count: number | null;result
Section titled “result”result: undefined;session.save
Section titled “session.save”session.save: object;Saves small state of this window (the current folder, a scroll position) with the desktop layout, at most 16 KB as JSON. It comes back in the init context after a reload and with “Get desktop from …”.
params
Section titled “params”params: object;params.state
Section titled “params.state”state: unknown;result
Section titled “result”result: undefined;storage.get
Section titled “storage.get”storage.get: object;Reads a value the app stored for this user, or null.
params
Section titled “params”params: object;params.key
Section titled “params.key”key: string;result
Section titled “result”result: unknown;storage.set
Section titled “storage.set”storage.set: object;Stores a value for this user, on the daemon (sandboxed apps have no localStorage). Keys have at most 128
characters, values at most 64 KB as JSON, and an app keeps at most 1 MB per user.
params
Section titled “params”params: object;params.key
Section titled “params.key”key: string;params.value
Section titled “params.value”value: unknown;result
Section titled “result”result: undefined;storage.remove
Section titled “storage.remove”storage.remove: object;Removes a value the app stored for this user; a missing key is no error.
params
Section titled “params”params: object;params.key
Section titled “params.key”key: string;result
Section titled “result”result: undefined;storage.keys
Section titled “storage.keys”storage.keys: object;Every key the app stored for this user.
params
Section titled “params”params: Record<string, never>;result
Section titled “result”result: string[];backend.token
Section titled “backend.token”backend.token: object;A token for the app’s backend, valid 5 minutes and for every endpoint of the app. app.backend.fetch and
app.backend.url send it for the app (as Authorization: Bearer or ?pithyx-token=). The daemon’s proxy checks
it and hands the backend the user as X-Pithyx-User, X-Pithyx-User-Id, X-Pithyx-Groups and
X-Pithyx-Admin; those headers are the only identity a backend may trust. With renew the desktop drops the
token it holds and issues a new one: the SDK asks so after the proxy refused a token as app.token.invalid, for
example because the box restarted.
params
Section titled “params”params: object;params.renew?
Section titled “params.renew?”optional renew?: boolean;result
Section titled “result”result: BackendToken;backend.ticket
Section titled “backend.ticket”backend.ticket: object;A one-time ticket for one WebSocket to an endpoint of the app’s backend (app.backend.socket uses it).
params
Section titled “params”params: object;params.endpoint
Section titled “params.endpoint”endpoint: string;result
Section titled “result”result: BackendTicket;directory.users
Section titled “directory.users”directory.users: object;Every user of the box. Needs directory.read.
params
Section titled “params”params: Record<string, never>;result
Section titled “result”result: DirectoryUser[];directory.groups
Section titled “directory.groups”directory.groups: object;Every group of the box. Needs directory.read.
params
Section titled “params”params: Record<string, never>;result
Section titled “result”result: DirectoryGroup[];contextMenu.show
Section titled “contextMenu.show”contextMenu.show: object;Shows a context menu that the desktop draws at at (at most 50 entries) and resolves with the id of the entry
the user picked, or null when the menu was dismissed.
params
Section titled “params”params: object;params.at
Section titled “params.at”at: Point;params.items
Section titled “params.items”items: ContextMenuItem[];result
Section titled “result”result: string | null;clipboard.writeText
Section titled “clipboard.writeText”clipboard.writeText: object;Copies text to the clipboard, at most 1 MB. Call it only for a user action, such as a click on Copy.
params
Section titled “params”params: object;params.text
Section titled “params.text”text: string;result
Section titled “result”result: undefined;openUrl
Section titled “openUrl”openUrl: object;Opens an https:, http: or mailto: URL in a new browser tab, without a reference to the desktop.
params
Section titled “params”params: object;params.url
Section titled “params.url”url: string;result
Section titled “result”result: undefined;files.pick
Section titled “files.pick”files.pick: object;The file API (served from step 6 on; check supports). The only way an app reaches files: sandboxed apps have no
file system, and the daemon checks the app’s permissions and the user’s rights on every call.
Opens the desktop’s file dialog; resolves with the files the user picked, empty when cancelled. Needs files.read.
params
Section titled “params”params: object;params.multiple?
Section titled “params.multiple?”optional multiple?: boolean;params.extensions?
Section titled “params.extensions?”optional extensions?: string[];result
Section titled “result”result: FileRef[];files.saveAs
Section titled “files.saveAs”files.saveAs: object;Opens the desktop’s save dialog; resolves with the new file, or null when cancelled. Needs files.write.
params
Section titled “params”params: object;params.suggestedName
Section titled “params.suggestedName”suggestedName: string;params.data
Section titled “params.data”data: Blob;result
Section titled “result”result: FileRef | null;files.read
Section titled “files.read”files.read: object;Reads a file the app was given. Needs files.read.
params
Section titled “params”params: object;params.file
Section titled “params.file”file: FileRef;result
Section titled “result”result: Blob;files.write
Section titled “files.write”files.write: object;Replaces the contents of a writable file. Needs files.write.
params
Section titled “params”params: object;params.file
Section titled “params.file”file: FileRef;params.data
Section titled “params.data”data: Blob;result
Section titled “result”result: FileRef;files.url
Section titled “files.url”files.url: object;A URL for <img>, <video> or fetch that streams the file (with range requests) without the desktop session,
valid 5 minutes and only for this file. Needs files.read.
params
Section titled “params”params: object;params.file
Section titled “params.file”file: FileRef;result
Section titled “result”result: object;result.url
Section titled “result.url”url: string;result.expiresAt
Section titled “result.expiresAt”expiresAt: string;files.list
Section titled “files.list”files.list: object;Lists a folder one page at a time (default 100 entries, at most 1000), in natural name order unless sort says
otherwise. Pass the page’s nextCursor for the next one. Needs files.shares for a share.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: FileLocation;params.path
Section titled “params.path”path: string;params.cursor?
Section titled “params.cursor?”optional cursor?: string;params.limit?
Section titled “params.limit?”optional limit?: number;params.sort?
Section titled “params.sort?”optional sort?: SortKey;params.order?
Section titled “params.order?”optional order?: SortOrder;result
Section titled “result”result: FolderPage;files.open
Section titled “files.open”files.open: object;A handle for a file in a named storage or a share, for files.read, files.write and files.url.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: FileLocation;params.path
Section titled “params.path”path: string;result
Section titled “result”result: FileRef;files.shares
Section titled “files.shares”files.shares: object;The shares the user can use, with the user’s access to each; sharesChanged says when to ask again.
params
Section titled “params”params: Record<string, never>;result
Section titled “result”result: ShareInfo[];files.watch
Section titled “files.watch”files.watch: object;Starts live changes of a folder: folderChanged events with the returned watch id arrive while the watch is
open. Watch only folders on screen and call files.unwatch when leaving them; a watch never wakes a disk.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: FileLocation;params.path
Section titled “params.path”path: string;result
Section titled “result”result: object;result.watch
Section titled “result.watch”watch: string;files.unwatch
Section titled “files.unwatch”files.unwatch: object;Ends a watch started with files.watch.
params
Section titled “params”params: object;params.watch
Section titled “params.watch”watch: string;result
Section titled “result”result: undefined;files.upload
Section titled “files.upload”files.upload: object;Uploads a file into a folder. The file appears only when it is complete; an existing name fails with
fs.entry.exists unless overwrite. With an upload id, uploadProgress events report the bytes sent.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: FileLocation;params.folder
Section titled “params.folder”folder: string;params.name
Section titled “params.name”name: string;params.data
Section titled “params.data”data: Blob;params.overwrite?
Section titled “params.overwrite?”optional overwrite?: boolean;params.upload?
Section titled “params.upload?”optional upload?: string;result
Section titled “result”result: FileEntry;files.download
Section titled “files.download”files.download: object;Downloads a file to the user’s device through the browser.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: FileLocation;params.path
Section titled “params.path”path: string;result
Section titled “result”result: undefined;files.createFolder
Section titled “files.createFolder”files.createFolder: object;Creates a folder; its parent must exist.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: FileLocation;params.path
Section titled “params.path”path: string;result
Section titled “result”result: FileEntry;files.rename
Section titled “files.rename”files.rename: object;Renames an entry within its folder; an existing name is never replaced (fs.entry.exists).
params
Section titled “params”params: object;params.location
Section titled “params.location”location: FileLocation;params.path
Section titled “params.path”path: string;params.name
Section titled “params.name”name: string;result
Section titled “result”result: FileEntry;files.run
Section titled “files.run”files.run: object;Starts a copy, move or delete as a job and resolves with it at once; jobChanged events follow its progress
until it finishes. Deleting moves to the share’s recycle bin unless permanent. Source and target may each be a
share or a storage request.
params
Section titled “params”params: FileOperation;result
Section titled “result”result: JobInfo;files.versions
Section titled “files.versions”files.versions: object;Earlier versions of a file or folder from the snapshots of the share’s dataset, newest first; also of an entry deleted since. A file is listed once per distinct content and not while it equals the current file. Empty when the share has no snapshots. Needs read access to the share.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: ShareLocation;params.path
Section titled “params.path”path: string;result
Section titled “result”result: FileVersion[];files.restoreVersion
Section titled “files.restoreVersion”files.restoreVersion: object;Copies a version back as a job: next to the current entry as “name (version date)”, or over it with
overwrite (files are replaced, folders merged). Needs write access to the share.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: ShareLocation;params.path
Section titled “params.path”path: string;params.snapshot
Section titled “params.snapshot”snapshot: string;params.overwrite?
Section titled “params.overwrite?”optional overwrite?: boolean;result
Section titled “result”result: JobInfo;jobs.cancel
Section titled “jobs.cancel”jobs.cancel: object;Cancels a job the app started; a finished job stays as it is.
params
Section titled “params”params: object;params.job
Section titled “params.job”job: number;result
Section titled “result”result: undefined;trash.list
Section titled “trash.list”trash.list: object;One page of a share’s recycle bin, newest first. Needs read access to the share.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: ShareLocation;params.cursor?
Section titled “params.cursor?”optional cursor?: string;params.limit?
Section titled “params.limit?”optional limit?: number;result
Section titled “result”result: TrashPage;trash.restore
Section titled “trash.restore”trash.restore: object;Puts items back where they were, recreating missing folders, as a job. A taken name gets a free one unless
onConflict says otherwise.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: ShareLocation;params.ids
Section titled “params.ids”ids: number[];params.onConflict?
Section titled “params.onConflict?”optional onConflict?: ConflictPolicy;result
Section titled “result”result: JobInfo;trash.delete
Section titled “trash.delete”trash.delete: object;Deletes items of the recycle bin for good, as a job. Only after the user confirmed it.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: ShareLocation;params.ids
Section titled “params.ids”ids: number[];result
Section titled “result”result: JobInfo;trash.empty
Section titled “trash.empty”trash.empty: object;Deletes everything in the recycle bin for good, as a job. Only after the user confirmed it.
params
Section titled “params”params: object;params.location
Section titled “params.location”location: ShareLocation;result
Section titled “result”result: JobInfo;ui.showError
Section titled “ui.showError”ui.showError: object;Shows the desktop’s error dialog for a problem, with its translated text and the request id to copy. Use it for failures the user has to know about; the app does not need its own error texts for daemon codes.
params
Section titled “params”params: object;params.problem
Section titled “params.problem”problem: Problem;result
Section titled “result”result: undefined;ConnectMessage
Section titled “ConnectMessage”What the desktop posts to the iframe window, with the app’s port transferred.
Properties
Section titled “Properties”type: 'pithyx:connect';Always pithyx:connect.
Endpoint
Section titled “Endpoint”One end of a connection.
Methods
Section titled “Methods”post()
Section titled “post()”post(message): void;Sends a message to the other end.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
message |
unknown |
Structured-clone data. |
Returns
Section titled “Returns”void
listen()
Section titled “listen()”listen(handler): void;Registers the single message handler of this end; a second call replaces the first handler.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
handler |
(message) => void |
Called with each message from the other end. |
Returns
Section titled “Returns”void
close()
Section titled “close()”close(): void;Closes this end; nothing is sent or received after it.
Returns
Section titled “Returns”void
Type Aliases
Section titled “Type Aliases”type AppId = string;The author’s domain reversed plus the app name: 3 to 5 parts of lowercase letters, digits and dashes, at most 100 characters, for example com.mueller.chat or io.github.jan.chat. Unique per box. org.pithyx.* is reserved for the system apps and the official catalog.
Permission
Section titled “Permission”type Permission = | 'files.read' | 'files.write' | 'files.shares' | 'notifications' | 'directory.read' | 'network.internet' | 'network.lan';A permission an app declares. Nothing is granted by using an API: the install dialog lists every declared permission, an administrator confirms them for the app, and each one can be revoked later (the app gets permissionsChange). Which users may use the app at all is a separate grant per user and group. The daemon checks every permission on every call that reaches data or leaves the window. An update that declares a new permission waits until an administrator confirms it; the old version keeps running. files.read: read files the user opens with the app or picks in a desktop file dialog. files.write: write those files, and save new files where the user chooses in a desktop save dialog. files.shares: browse every shared folder the user may access, with the user’s own rights. notifications: show notifications. directory.read: list all users and groups of the box. network.internet: outgoing connections to the internet, from the window (connect-src https:) and from the backend. network.lan: outgoing connections from the backend to the local network (private, shared and link-local addresses such as 192.168.0.0/16); without it the backend reaches no other device in the LAN, also with network.internet. The box itself is never reachable.
ElevatedPermission
Section titled “ElevatedPermission”type ElevatedPermission = | 'docker.socket' | 'host.network' | 'host.pid' | 'host.full' | `device:/dev/${string}` | `capability:${string}`;A right beyond the sandbox, for the backend only (D71): host.network (the host’s network namespace), host.pid (the host’s process namespace), device:<path under /dev> (one device node, for example device:/dev/dri/renderD128), capability:<NAME> (one Linux capability without the CAP_ prefix, for example capability:NET_ADMIN), docker.socket (the Docker Engine API through the daemon’s filtering proxy) and host.full (a privileged container: root on the host). The schema describes the planned rights; Pithyx 1.0.0 refuses every one of them with app.elevated.unsupported, and a later version grants them to administrators only, after a confirmation with password and TOTP.
ContextMenuItem
Section titled “ContextMenuItem”type ContextMenuItem = | { id: string; label: string; disabled?: boolean; checked?: boolean; danger?: boolean; shortcut?: string; } | { separator: true; };An entry of a context menu the desktop draws for the app; the app translates the labels.
Union Members
Section titled “Union Members”Type Literal
Section titled “Type Literal”{ id: string; label: string; disabled?: boolean; checked?: boolean; danger?: boolean; shortcut?: string;}id: string;Comes back from contextMenu.show when the user picks the entry; 1 to 64 characters.
label: string;Plain text, 1 to 100 characters.
disabled?
Section titled “disabled?”optional disabled?: boolean;Shows the entry greyed out; it cannot be picked.
checked?
Section titled “checked?”optional checked?: boolean;Shows a check mark.
danger?
Section titled “danger?”optional danger?: boolean;Marks a destructive entry, such as Delete.
shortcut?
Section titled “shortcut?”optional shortcut?: string;A key hint shown next to the label, for example Ctrl+C. The app handles the keys itself.
Type Literal
Section titled “Type Literal”{ separator: true;}separator
Section titled “separator”separator: true;A line between groups of entries.
LogLevel
Section titled “LogLevel”type LogLevel = 'debug' | 'info' | 'warn' | 'error';How serious a log entry is. The Log Center filters by it; debug is for details only needed while looking for a fault.
LogData
Section titled “LogData”type LogData = Record<string, string | number | boolean | null>;Fields that describe a log entry beyond its message, for example { file: 'a.jpg', attempt: 2 }.
MethodName
Section titled “MethodName”type MethodName = keyof Methods;The name of a method an app can call.
AppMessage
Section titled “AppMessage”type AppMessage = | { type: 'hello'; protocol: number; sdk: string; } | { type: 'request'; id: number; method: string; params: unknown; } | { type: 'reply'; id: number; answer: unknown; };A message from the app to the desktop.
Union Members
Section titled “Union Members”Type Literal
Section titled “Type Literal”{ type: 'hello'; protocol: number; sdk: string;}type: 'hello';The first message on the port.
protocol
Section titled “protocol”protocol: number;The protocol version the app speaks.
sdk: string;The SDK version the app was built with.
Type Literal
Section titled “Type Literal”{ type: 'request'; id: number; method: string; params: unknown;}type: 'request';A call of a method.
id: number;Unique per connection; the response carries it back.
method
Section titled “method”method: string;A method name of Methods.
params
Section titled “params”params: unknown;The method’s parameters.
Type Literal
Section titled “Type Literal”{ type: 'reply'; id: number; answer: unknown;}type: 'reply';The answer to a query.
id: number;The id of the query.
answer
Section titled “answer”answer: unknown;The answer the question expects.
HostMessage
Section titled “HostMessage”type HostMessage = | { type: 'init'; protocol: number; context: AppContext; } | { type: 'refuse'; problem: Problem; } | { type: 'response'; id: number; ok: true; result: unknown; } | { type: 'response'; id: number; ok: false; problem: Problem; } | { type: 'event'; event: string; data: unknown; } | { type: 'query'; id: number; query: string; data: unknown; };A message from the desktop to the app.
Union Members
Section titled “Union Members”Type Literal
Section titled “Type Literal”{ type: 'init'; protocol: number; context: AppContext;}type: 'init';The answer to hello: the app may start.
protocol
Section titled “protocol”protocol: number;The protocol version both sides use.
context
Section titled “context”context: AppContext;Everything the app needs to start.
Type Literal
Section titled “Type Literal”{ type: 'refuse'; problem: Problem;}type: 'refuse';The answer to hello when the desktop cannot serve the app; the port closes after it.
problem
Section titled “problem”problem: Problem;Why, for example sdk.protocol.unsupported.
Type Literal
Section titled “Type Literal”{ type: 'response'; id: number; ok: true; result: unknown;}type: 'response';The result of a request.
id: number;The id of the request.
ok: true;The call succeeded.
result
Section titled “result”result: unknown;The method’s result.
Type Literal
Section titled “Type Literal”{ type: 'response'; id: number; ok: false; problem: Problem;}type: 'response';The failure of a request.
id: number;The id of the request.
ok: false;The call failed.
problem
Section titled “problem”problem: Problem;Why it failed.
Type Literal
Section titled “Type Literal”{ type: 'event'; event: string; data: unknown;}type: 'event';An event of Events.
event: string;The event name.
data: unknown;The event’s data.
Type Literal
Section titled “Type Literal”{ type: 'query'; id: number; query: string; data: unknown;}type: 'query';A question of Queries the app answers with reply.
id: number;Unique per connection; the reply carries it back.
query: string;The question’s name.
data: unknown;What the question carries.
Variables
Section titled “Variables”REQUEST_TIMEOUT
Section titled “REQUEST_TIMEOUT”const REQUEST_TIMEOUT: 15000 = 15_000;An app waits this long for a response before a call fails with sdk.request.timeout. Calls that move a whole file
(files.upload, files.read, files.write) take as long as the transfer, and the dialogs of files.pick and
files.saveAs as long as the user; none of them has a time limit.
UNTIMED_METHODS
Section titled “UNTIMED_METHODS”const UNTIMED_METHODS: readonly string[];Calls without a time limit, because they last as long as a transfer or as the user takes.
SDK_VERSION
Section titled “SDK_VERSION”const SDK_VERSION: string = version;The version of this SDK package, from its package.json. The npm packages @pithyx/sdk, @pithyx/ui and
@pithyx/cli share one SemVer line of their own, separate from the Pithyx product version: a new method,
event or optional field is a minor release, a removed or changed one a major release.
Deprecations last one major version: anything marked @deprecated in major N keeps working through all of major
N + 1 and goes away in N + 2 at the earliest. The desktop of major N + 1 still serves apps built against SDK N
(see MIN_PROTOCOL_VERSION).
PROTOCOL_VERSION
Section titled “PROTOCOL_VERSION”const PROTOCOL_VERSION: 1 = 1;The version of the wire protocol between an app and the desktop. It changes only when a message changes in a way an
older side cannot ignore. Additions (new methods, events, optional fields) keep the protocol version; apps find
them through AppContext.capabilities.
The desktop supports every protocol version from MIN_PROTOCOL_VERSION up to this one, so an app built against an older SDK keeps working after a desktop update.
MIN_PROTOCOL_VERSION
Section titled “MIN_PROTOCOL_VERSION”const MIN_PROTOCOL_VERSION: 1 = 1;The oldest protocol version this SDK’s host side still accepts.
Functions
Section titled “Functions”createApp()
Section titled “createApp()”function createApp(endpoint, options?): Promise<PithyxApp>;Connects an app over a transport end: sends hello, waits for init, and returns the app API. Rejects with
sdk.protocol.unsupported when the desktop refuses the app’s protocol version. Core apps use it with
inProcessPair; sandboxed apps call connect instead.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
endpoint |
Endpoint |
The app’s end of the transport. |
options |
CreateAppOptions |
Theme root, call time limit and the box’s address. |
Returns
Section titled “Returns”Promise<PithyxApp>
The app API, once the desktop sent init.
Throws
Section titled “Throws”sdk.protocol.unsupported when the desktop does not speak the SDK’s protocol version.
createFormatters()
Section titled “createFormatters()”function createFormatters(current): Formatters;Formatters that follow the locale and time zone current returns at each call. app.format is built with it; an
app needs it only to format outside the desktop, for example in tests.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
current |
() => object |
Returns the locale and the time zone to use now. |
Returns
Section titled “Returns”The formatters.
connect()
Section titled “connect()”function connect(options?): Promise<PithyxApp>;Connects a sandboxed app to the desktop. It accepts exactly one pithyx:connect message, only from the parent
window (the desktop that framed the app) and only with exactly one transferred port; every other window message is
ignored, before and after. Rejects with sdk.transport.closed when no desktop connects in time, for example when
the page was opened outside the desktop. From then on a right-click in the app never opens the browser’s own menu,
except in text fields; an app shows its own menu by listening for contextmenu.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
options |
CreateAppOptions & object |
Theme root, call time limit and box address as for createApp, plus how long to wait for the desktop. |
Returns
Section titled “Returns”Promise<PithyxApp>
The app API, once the desktop accepted the app.
Throws
Section titled “Throws”sdk.transport.closed when no desktop connects within the time limit.
Throws
Section titled “Throws”sdk.protocol.unsupported when the desktop does not speak the SDK’s protocol version.
portEndpoint()
Section titled “portEndpoint()”function portEndpoint(port): Endpoint;An end backed by a MessagePort (third-party apps in sandboxed iframes).
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
port |
MessagePort |
The port the desktop transferred with pithyx:connect. |
Returns
Section titled “Returns”The transport end; closing it closes the port.
inProcessPair()
Section titled “inProcessPair()”function inProcessPair(): [Endpoint, Endpoint];A pair of connected ends inside one page (core apps). Messages are cloned with structuredClone and delivered in
a later microtask, exactly like a MessagePort would, so nothing works in-process that would fail in an iframe.
Returns
Section titled “Returns”The two connected ends: one for the app, one for the host. Closing either closes both.