# SDK: App und Verbindung

> connect(), das Objekt PithyxApp mit allen Methoden, die Formatierer, die Transporte und die Typen des Manifests.

Source: https://pithyx.org/de/docs/reference/sdk/app/
Markdown: https://pithyx.org/de/docs/reference/sdk/app.md

Eine App ruft einmal `connect()` auf und arbeitet danach mit dem zurückgegebenen `PithyxApp`. Diese Seite listet dieses Objekt mit jeder Methode, der Berechtigung, die sie braucht, und den Fehlercodes, mit denen sie ablehnt, dazu die Protokollnachrichten, die Formatierer und die Typen des Manifests.

Beim Build aus den TSDoc-Kommentaren von @pithyx/sdk 1.0.0-rc.9 erzeugt; der Text unter den Überschriften ist der Kommentar im Quelltext und bleibt Englisch.

## Schnittstellen

### 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](https://pithyx.org/de/docs/reference/sdk/errors/#pithyxerror).

Every such call can also reject with [`sdk.request.timeout`](https://pithyx.org/de/docs/reference/errors/#sdk.request.timeout) (no answer within 15 seconds, see
[REQUEST\_TIMEOUT](#request_timeout)), [`sdk.transport.closed`](https://pithyx.org/de/docs/reference/errors/#sdk.transport.closed) (the window closed or the desktop signed out),
[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) (parameters outside the limits the method states) and [`sdk.method.unknown`](https://pithyx.org/de/docs/reference/errors/#sdk.method.unknown) (the desktop does
not serve the method to this app; check [PithyxApp.supports](#supports) first). The permissions are the manifest's
`permissions` that an administrator granted; `context.permissions` lists the ones the app holds now.

#### Eigenschaften

##### context

```ts
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`](https://pithyx.org/de/docs/reference/errors/#sdk.transport.closed).

##### format

```ts
readonly format: Formatters;
```

Dates, numbers, sizes and lists in the user's language and time zone. Needs no permission.

##### window

```ts
readonly window: object;
```

The app's own window; every call acts on the window that makes it. Needs no permission.

###### setTitle()

```ts
setTitle(title): Promise<void>;
```

Sets the title in the title bar and the taskbar, at most 200 characters.

###### Parameter

| Parameter | Typ      | Beschreibung               |
| --------- | -------- | -------------------------- |
| `title`   | `string` | The new title, plain text. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when the title is longer than 200 characters.

###### close()

```ts
close(): Promise<void>;
```

Closes the window without asking `beforeClose`.

###### Rückgabewert

`Promise`\<`void`\>

###### setSize()

```ts
setSize(size): Promise<{
  width: number;
  height: number;
}>;
```

Asks for a new free size; resolves with the size the desktop gave the window.

###### Parameter

| Parameter     | Typ                                          | Beschreibung                                             |
| ------------- | -------------------------------------------- | -------------------------------------------------------- |
| `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.                                    |

###### Rückgabewert

`Promise`\<\{
`width`: `number`;
`height`: `number`;
\}\>

The size the window got.

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when a value is not a finite number.

###### setDirty()

```ts
setDirty(dirty): Promise<void>;
```

Marks the window as having unsaved changes or not. Once called, `beforeClose` is asked only while the window is
dirty.

###### Parameter

| Parameter | Typ       | Beschreibung                            |
| --------- | --------- | --------------------------------------- |
| `dirty`   | `boolean` | Whether the window has unsaved changes. |

###### Rückgabewert

`Promise`\<`void`\>

###### requestAttention()

```ts
requestAttention(): Promise<void>;
```

Makes the taskbar entry pulse until the user looks; never takes the focus.

###### Rückgabewert

`Promise`\<`void`\>

###### ready()

```ts
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.

###### Rückgabewert

`Promise`\<`void`\>

##### log

```ts
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()

```ts
debug(message, data?): void;
```

Details only needed while looking for a fault; reaches the daemon only while debug logging is on.

###### Parameter

| Parameter | Typ                   | Beschreibung                                              |
| --------- | --------------------- | --------------------------------------------------------- |
| `message` | `string`              | What happened, in English.                                |
| `data?`   | [`LogData`](#logdata) | Fields that describe it, for example `{ file: 'a.jpg' }`. |

###### Rückgabewert

`void`

###### info()

```ts
info(message, data?): void;
```

Something worth knowing happened.

###### Parameter

| Parameter | Typ                   | Beschreibung               |
| --------- | --------------------- | -------------------------- |
| `message` | `string`              | What happened, in English. |
| `data?`   | [`LogData`](#logdata) | Fields that describe it.   |

###### Rückgabewert

`void`

###### warn()

```ts
warn(message, data?): void;
```

Something went wrong but the app carries on.

###### Parameter

| Parameter | Typ                   | Beschreibung               |
| --------- | --------------------- | -------------------------- |
| `message` | `string`              | What happened, in English. |
| `data?`   | [`LogData`](#logdata) | Fields that describe it.   |

###### Rückgabewert

`void`

###### error()

```ts
error(message, data?): void;
```

Something failed.

###### Parameter

| Parameter | Typ                   | Beschreibung               |
| --------- | --------------------- | -------------------------- |
| `message` | `string`              | What happened, in English. |
| `data?`   | [`LogData`](#logdata) | Fields that describe it.   |

###### Rückgabewert

`void`

###### log()

```ts
log(message, data?): void;
```

The same as `info`, for code written against `console.log`.

###### Parameter

| Parameter | Typ                   | Beschreibung               |
| --------- | --------------------- | -------------------------- |
| `message` | `string`              | What happened, in English. |
| `data?`   | [`LogData`](#logdata) | Fields that describe it.   |

###### Rückgabewert

`void`

###### Beispiel

```ts
app.log.warn('Upload retried', { file: name, attempt: 2 });
```

##### session

```ts
readonly session: object;
```

Small state of this window that survives a reload and moves with "Get desktop from ...". Needs no permission.

###### save()

```ts
save(state): Promise<void>;
```

Saves the window's state with the desktop layout, at most 16 KB as JSON.

###### Parameter

| Parameter | Typ       | Beschreibung                                                         |
| --------- | --------- | -------------------------------------------------------------------- |
| `state`   | `unknown` | Any JSON value, for example the open folder and the scroll position. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`app.storage.too_large`](https://pithyx.org/de/docs/reference/errors/#app.storage.too_large) when the state is larger than 16 KB as JSON.

###### restore()

```ts
restore(): Promise<unknown>;
```

The state saved before the last reload or on another device, or null. Never rejects.

###### Rückgabewert

`Promise`\<`unknown`\>

The saved state, or null.

##### storage

```ts
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()

```ts
get<T>(key): Promise<T | null>;
```

The value stored under `key`, or null.

###### Typenparameter

| Typenparameter | Standardtyp |
| -------------- | ----------- |
| `T`            | `unknown`   |

###### Parameter

| Parameter | Typ      | Beschreibung         |
| --------- | -------- | -------------------- |
| `key`     | `string` | 1 to 128 characters. |

###### Rückgabewert

`Promise`\<`T` \| `null`\>

The stored value, or null when there is none.

###### Throws

[`app.storage.key_invalid`](https://pithyx.org/de/docs/reference/errors/#app.storage.key_invalid) when the key is empty or longer than 128 characters.

###### set()

```ts
set(key, value): Promise<void>;
```

Stores a value under `key`, replacing an earlier one.

###### Parameter

| Parameter | Typ       | Beschreibung                           |
| --------- | --------- | -------------------------------------- |
| `key`     | `string`  | 1 to 128 characters.                   |
| `value`   | `unknown` | Any JSON value, at most 64 KB as JSON. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`app.storage.key_invalid`](https://pithyx.org/de/docs/reference/errors/#app.storage.key_invalid) when the key is empty or longer than 128 characters.

###### Throws

[`app.storage.too_large`](https://pithyx.org/de/docs/reference/errors/#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()

```ts
remove(key): Promise<void>;
```

Removes the value under `key`, if there is one; a missing key is no error.

###### Parameter

| Parameter | Typ      | Beschreibung         |
| --------- | -------- | -------------------- |
| `key`     | `string` | 1 to 128 characters. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`app.storage.key_invalid`](https://pithyx.org/de/docs/reference/errors/#app.storage.key_invalid) when the key is empty or longer than 128 characters.

###### keys()

```ts
keys(): Promise<string[]>;
```

Every key the app stored for this user.

###### Rückgabewert

`Promise`\<`string`[]\>

The keys, in no particular order.

##### backend

```ts
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`](https://pithyx.org/de/docs/reference/errors/#sdk.backend.endpoint_unknown). Needs no permission; an app without a backend has no endpoint.

###### url()

```ts
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.

###### Parameter

| Parameter           | Typ                          | Beschreibung                                                                                  |
| ------------------- | ---------------------------- | --------------------------------------------------------------------------------------------- |
| `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.                           |

###### Rückgabewert

`Promise`\<`string`\>

The absolute URL with the token.

###### Throws

[`sdk.backend.endpoint_unknown`](https://pithyx.org/de/docs/reference/errors/#sdk.backend.endpoint_unknown) when the app has no backend or the manifest declares no such endpoint.

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when the path leaves the endpoint.

###### Throws

[`app.backend.missing`](https://pithyx.org/de/docs/reference/errors/#app.backend.missing) when the app has no backend.

###### Throws

[`app.app.not_found`](https://pithyx.org/de/docs/reference/errors/#app.app.not_found) when the user may no longer open the app.

###### fetch()

```ts
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`](https://pithyx.org/de/docs/reference/errors/#sdk.backend.unreachable).

###### Parameter

| Parameter | Typ                      | Beschreibung                                                                                  |
| --------- | ------------------------ | --------------------------------------------------------------------------------------------- |
| `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.                                                        |

###### Rückgabewert

`Promise`\<`Response`\>

The backend's response, also for 4xx and 5xx; the proxy answers 503 [`app.backend.unavailable`](https://pithyx.org/de/docs/reference/errors/#app.backend.unavailable) while
the backend is updating or unavailable.

###### Throws

[`sdk.backend.endpoint_unknown`](https://pithyx.org/de/docs/reference/errors/#sdk.backend.endpoint_unknown) when the app has no backend or the manifest declares no such endpoint.

###### Throws

[`sdk.backend.unreachable`](https://pithyx.org/de/docs/reference/errors/#sdk.backend.unreachable) when the request gets no answer.

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when the path leaves the endpoint.

###### socket()

```ts
socket(path, options?): Promise<WebSocket>;
```

Opens a WebSocket to the backend with a one-time ticket (`?pithyx-ticket=`, valid 30 seconds).

###### Parameter

| Parameter            | Typ                                                                | Beschreibung                                                          |
| -------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------- |
| `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.                |

###### Rückgabewert

`Promise`\<`WebSocket`\>

The WebSocket, still connecting; `wss:` on HTTPS and `ws:` on plain HTTP.

###### Throws

[`sdk.backend.endpoint_unknown`](https://pithyx.org/de/docs/reference/errors/#sdk.backend.endpoint_unknown) when the app has no backend or the manifest declares no such endpoint.

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when the path leaves the endpoint.

###### token()

```ts
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`.

###### Rückgabewert

`Promise`\<[`BackendToken`](https://pithyx.org/de/docs/reference/sdk/backend/#backendtoken)\>

The token and when it expires.

###### Throws

[`app.backend.missing`](https://pithyx.org/de/docs/reference/errors/#app.backend.missing) when the app has no backend.

###### Throws

[`app.app.not_found`](https://pithyx.org/de/docs/reference/errors/#app.app.not_found) when the user may no longer open the app.

###### Beispiel

```ts
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

```ts
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()

```ts
users(): Promise<DirectoryUser[]>;
```

Every active user of the box.

###### Rückgabewert

`Promise`\<[`DirectoryUser`](#directoryuser)[]\>

The users, without deactivated ones.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `directory.read` permission.

###### groups()

```ts
groups(): Promise<DirectoryGroup[]>;
```

Every group of the box, without the built-in group of all users.

###### Rückgabewert

`Promise`\<[`DirectoryGroup`](#directorygroup)[]\>

The groups.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `directory.read` permission.

##### contextMenu

```ts
readonly contextMenu: object;
```

A context menu drawn by the desktop, also over the edge of the app's window. Needs no permission.

###### show()

```ts
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.

###### Parameter

| Parameter | Typ                                     | Beschreibung                                            |
| --------- | --------------------------------------- | ------------------------------------------------------- |
| `at`      | [`Point`](#point)                       | Where the menu opens, relative to the window's content. |
| `items`   | [`ContextMenuItem`](#contextmenuitem)[] | 1 to 50 entries and separators.                         |

###### Rückgabewert

`Promise`\<`string` \| `null`\>

The `id` of the picked entry, or null.

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when there are no entries, more than 50, or an entry exceeds its limits.

##### clipboard

```ts
readonly clipboard: object;
```

The clipboard, through the desktop. Needs no permission.

###### writeText()

```ts
writeText(text): Promise<void>;
```

Copies text, also over plain HTTP where the frame has no Clipboard API. Only for a user action.

###### Parameter

| Parameter | Typ      | Beschreibung          |
| --------- | -------- | --------------------- |
| `text`    | `string` | At most 1 MB of text. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when the text is longer than 1 MB.

##### files

```ts
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](#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`](https://pithyx.org/de/docs/reference/errors/#fs.share.read_only)
otherwise). Common failures: [`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied), [`fs.share.not_found`](https://pithyx.org/de/docs/reference/errors/#fs.share.not_found), [`fs.share.unavailable`](https://pithyx.org/de/docs/reference/errors/#fs.share.unavailable) (its pool is
missing or locked), [`app.storage.not_found`](https://pithyx.org/de/docs/reference/errors/#app.storage.not_found) (no such storage request or not mapped), [`fs.path.invalid`](https://pithyx.org/de/docs/reference/errors/#fs.path.invalid),
[`fs.entry.not_found`](https://pithyx.org/de/docs/reference/errors/#fs.entry.not_found) and [`fs.entry.access_denied`](https://pithyx.org/de/docs/reference/errors/#fs.entry.access_denied). A desktop may lack a method; check
[PithyxApp.supports](#supports).

###### pick()

```ts
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`.

###### Parameter

| Parameter             | Typ                                                      | Beschreibung                                                                    |
| --------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `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. |

###### Rückgabewert

`Promise`\<[`FileRef`](https://pithyx.org/de/docs/reference/sdk/files/#fileref)[]\>

The picked files, empty when the user cancelled.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.read` permission.

###### saveAs()

```ts
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).

###### Parameter

| Parameter       | Typ      | Beschreibung                  |
| --------------- | -------- | ----------------------------- |
| `suggestedName` | `string` | The name the dialog proposes. |
| `data`          | `Blob`   | The content to save.          |

###### Rückgabewert

`Promise`\<[`FileRef`](https://pithyx.org/de/docs/reference/sdk/files/#fileref) \| `null`\>

The saved file, or null when the user cancelled.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.write` permission.

###### read()

```ts
read(file): Promise<Blob>;
```

The content of a file the app was handed. Needs `files.read`.

###### Parameter

| Parameter | Typ                                                | Beschreibung                                               |
| --------- | -------------------------------------------------- | ---------------------------------------------------------- |
| `file`    | [`FileRef`](https://pithyx.org/de/docs/reference/sdk/files/#fileref) | A handle from `pick`, `open`, `launch.file` or `openFile`. |

###### Rückgabewert

`Promise`\<`Blob`\>

The content.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.read` permission.

###### Throws

[`fs.entry.not_found`](https://pithyx.org/de/docs/reference/errors/#fs.entry.not_found) when the file is gone.

###### write()

```ts
write(file, data): Promise<FileRef>;
```

Replaces the content of a writable file the app was handed. Needs `files.write`.

###### Parameter

| Parameter | Typ                                                | Beschreibung                       |
| --------- | -------------------------------------------------- | ---------------------------------- |
| `file`    | [`FileRef`](https://pithyx.org/de/docs/reference/sdk/files/#fileref) | A handle whose `writable` is true. |
| `data`    | `Blob`                                             | The new content.                   |

###### Rückgabewert

`Promise`\<[`FileRef`](https://pithyx.org/de/docs/reference/sdk/files/#fileref)\>

The handle with the new size and change time.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.write` permission.

###### Throws

[`fs.share.read_only`](https://pithyx.org/de/docs/reference/errors/#fs.share.read_only) when the user may only read the share.

###### Throws

[`fs.volume.full`](https://pithyx.org/de/docs/reference/errors/#fs.volume.full) when the pool has no space left.

###### url()

```ts
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`.

###### Parameter

| Parameter | Typ                                                | Beschreibung                                               |
| --------- | -------------------------------------------------- | ---------------------------------------------------------- |
| `file`    | [`FileRef`](https://pithyx.org/de/docs/reference/sdk/files/#fileref) | A handle from `pick`, `open`, `launch.file` or `openFile`. |

###### Rückgabewert

`Promise`\<\{
`url`: `string`;
`expiresAt`: `string`;
\}\>

The URL and when it expires.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.read` permission.

###### open()

```ts
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`.

###### Parameter

| Parameter  | Typ                                                          | Beschreibung                        |
| ---------- | ------------------------------------------------------------ | ----------------------------------- |
| `location` | [`FileLocation`](https://pithyx.org/de/docs/reference/sdk/files/#filelocation) | A storage request or a share.       |
| `path`     | `string`                                                     | The file, relative to the location. |

###### Rückgabewert

`Promise`\<[`FileRef`](https://pithyx.org/de/docs/reference/sdk/files/#fileref)\>

The handle; `writable` says whether the app may write it.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without `files.shares` for a share.

###### Throws

[`fs.entry.not_found`](https://pithyx.org/de/docs/reference/errors/#fs.entry.not_found) when there is no such file.

###### shares()

```ts
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.

###### Rückgabewert

`Promise`\<[`ShareInfo`](https://pithyx.org/de/docs/reference/sdk/files/#shareinfo)[]\>

The shares, without their place on the host.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.shares` permission.

###### list()

```ts
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`.

###### Parameter

| Parameter      | Typ                                                                                                                                                                           | Beschreibung                                             |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| `location`     | [`FileLocation`](https://pithyx.org/de/docs/reference/sdk/files/#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`](https://pithyx.org/de/docs/reference/sdk/files/#sortkey); `order?`: [`SortOrder`](https://pithyx.org/de/docs/reference/sdk/files/#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`](https://pithyx.org/de/docs/reference/sdk/files/#sortkey)                                                                                                                            | What to sort by; `name` when left out.                   |
| `page.order?`  | [`SortOrder`](https://pithyx.org/de/docs/reference/sdk/files/#sortorder)                                                                                                                        | Ascending or descending; `asc` when left out.            |

###### Rückgabewert

`Promise`\<[`FolderPage`](https://pithyx.org/de/docs/reference/sdk/files/#folderpage)\>

One page of entries.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without `files.shares` for a share.

###### Throws

[`fs.entry.not_found`](https://pithyx.org/de/docs/reference/errors/#fs.entry.not_found) or [`fs.entry.not_folder`](https://pithyx.org/de/docs/reference/errors/#fs.entry.not_folder) when the path is no folder.

###### Throws

[`fs.cursor.invalid`](https://pithyx.org/de/docs/reference/errors/#fs.cursor.invalid) when the cursor belongs to another listing.

###### watch()

```ts
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`.

###### Parameter

| Parameter  | Typ                                                          | Beschreibung                       |
| ---------- | ------------------------------------------------------------ | ---------------------------------- |
| `location` | [`FileLocation`](https://pithyx.org/de/docs/reference/sdk/files/#filelocation) | A share.                           |
| `path`     | `string`                                                     | The folder, relative to the share. |

###### Rückgabewert

`Promise`\<`string`\>

The watch id.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.shares` permission.

###### unwatch()

```ts
unwatch(watch): Promise<void>;
```

Ends a watch; no more `folderChanged` events come for it.

###### Parameter

| Parameter | Typ      | Beschreibung                  |
| --------- | -------- | ----------------------------- |
| `watch`   | `string` | The id `watch` resolved with. |

###### Rückgabewert

`Promise`\<`void`\>

###### upload()

```ts
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`](https://pithyx.org/de/docs/reference/errors/#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.

###### Parameter

| Parameter            | Typ                                                          | Beschreibung                                                             |
| -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------ |
| `location`           | [`FileLocation`](https://pithyx.org/de/docs/reference/sdk/files/#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.             |

###### Rückgabewert

`Promise`\<[`FileEntry`](https://pithyx.org/de/docs/reference/sdk/files/#fileentry)\>

The new entry.

###### Throws

[`fs.entry.exists`](https://pithyx.org/de/docs/reference/errors/#fs.entry.exists) when the name is taken and `overwrite` is not set.

###### Throws

[`fs.share.read_only`](https://pithyx.org/de/docs/reference/errors/#fs.share.read_only) when the user may only read the share.

###### Throws

[`fs.volume.full`](https://pithyx.org/de/docs/reference/errors/#fs.volume.full) when the pool has no space left.

###### Throws

[`fs.upload.incomplete`](https://pithyx.org/de/docs/reference/errors/#fs.upload.incomplete) when the transfer broke off.

###### Throws

[`sdk.transfer.cancelled`](https://pithyx.org/de/docs/reference/errors/#sdk.transfer.cancelled) when the user cancelled the upload in the taskbar.

###### download()

```ts
download(location, path): Promise<void>;
```

Downloads a file to the user's device through the browser. Needs `files.shares`.

###### Parameter

| Parameter  | Typ                                                          | Beschreibung                     |
| ---------- | ------------------------------------------------------------ | -------------------------------- |
| `location` | [`FileLocation`](https://pithyx.org/de/docs/reference/sdk/files/#filelocation) | A share.                         |
| `path`     | `string`                                                     | The file, relative to the share. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.shares` permission.

###### createFolder()

```ts
createFolder(location, path): Promise<FileEntry>;
```

Creates a folder at `path`; its parent must exist and the name must be free ([`fs.entry.exists`](https://pithyx.org/de/docs/reference/errors/#fs.entry.exists)). A share needs
`files.shares` and write access.

###### Parameter

| Parameter  | Typ                                                          | Beschreibung                              |
| ---------- | ------------------------------------------------------------ | ----------------------------------------- |
| `location` | [`FileLocation`](https://pithyx.org/de/docs/reference/sdk/files/#filelocation) | A storage request or a share.             |
| `path`     | `string`                                                     | The new folder, relative to the location. |

###### Rückgabewert

`Promise`\<[`FileEntry`](https://pithyx.org/de/docs/reference/sdk/files/#fileentry)\>

The new entry.

###### Throws

[`fs.entry.exists`](https://pithyx.org/de/docs/reference/errors/#fs.entry.exists) when the name is taken.

###### Throws

[`fs.entry.not_found`](https://pithyx.org/de/docs/reference/errors/#fs.entry.not_found) when the parent folder does not exist.

###### Throws

[`fs.share.read_only`](https://pithyx.org/de/docs/reference/errors/#fs.share.read_only) when the user may only read the share.

###### rename()

```ts
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.

###### Parameter

| Parameter  | Typ                                                          | Beschreibung                                   |
| ---------- | ------------------------------------------------------------ | ---------------------------------------------- |
| `location` | [`FileLocation`](https://pithyx.org/de/docs/reference/sdk/files/#filelocation) | A share.                                       |
| `path`     | `string`                                                     | The entry, relative to the share.              |
| `name`     | `string`                                                     | The new name, 1 to 255 characters without `/`. |

###### Rückgabewert

`Promise`\<[`FileEntry`](https://pithyx.org/de/docs/reference/sdk/files/#fileentry)\>

The renamed entry.

###### Throws

[`fs.entry.exists`](https://pithyx.org/de/docs/reference/errors/#fs.entry.exists) when the name is taken.

###### Throws

[`fs.name.invalid`](https://pithyx.org/de/docs/reference/errors/#fs.name.invalid) when the name is not allowed.

###### run()

```ts
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.

###### Parameter

| Parameter   | Typ                                                            | Beschreibung                                 |
| ----------- | -------------------------------------------------------------- | -------------------------------------------- |
| `operation` | [`FileOperation`](https://pithyx.org/de/docs/reference/sdk/files/#fileoperation) | What to do with which entries, and where to. |

###### Rückgabewert

`Promise`\<[`JobInfo`](https://pithyx.org/de/docs/reference/sdk/files/#jobinfo)\>

The job as it started; failures of single entries end up in its `problem`.

###### Throws

[`fs.operation.invalid`](https://pithyx.org/de/docs/reference/errors/#fs.operation.invalid) when the operation does not fit (a target for delete, none for copy).

###### Throws

[`fs.operation.into_itself`](https://pithyx.org/de/docs/reference/errors/#fs.operation.into_itself) when a folder would be copied or moved into itself.

###### versions()

```ts
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.

###### Parameter

| Parameter  | Typ                                                            | Beschreibung                                    |
| ---------- | -------------------------------------------------------------- | ----------------------------------------------- |
| `location` | [`ShareLocation`](https://pithyx.org/de/docs/reference/sdk/files/#sharelocation) | A share.                                        |
| `path`     | `string`                                                       | The entry, relative to the share; not its root. |

###### Rückgabewert

`Promise`\<[`FileVersion`](https://pithyx.org/de/docs/reference/sdk/files/#fileversion)[]\>

The versions, newest first.

###### restoreVersion()

```ts
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.

###### Parameter

| Parameter            | Typ                                                            | Beschreibung                                               |
| -------------------- | -------------------------------------------------------------- | ---------------------------------------------------------- |
| `location`           | [`ShareLocation`](https://pithyx.org/de/docs/reference/sdk/files/#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. |

###### Rückgabewert

`Promise`\<[`JobInfo`](https://pithyx.org/de/docs/reference/sdk/files/#jobinfo)\>

The job as it started.

###### Throws

[`fs.version.not_found`](https://pithyx.org/de/docs/reference/errors/#fs.version.not_found) when the snapshot or the entry in it is gone.

##### jobs

```ts
readonly jobs: object;
```

The jobs the app started with `files.run`, `files.restoreVersion` and `trash.*`.

###### cancel()

```ts
cancel(job): Promise<void>;
```

Cancels a job the app started; a job that already finished stays as it is.

###### Parameter

| Parameter | Typ      | Beschreibung         |
| --------- | -------- | -------------------- |
| `job`     | `number` | The `id` of the job. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`jobs.job.not_found`](https://pithyx.org/de/docs/reference/errors/#jobs.job.not_found) when there is no such job of the user.

##### trash

```ts
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()

```ts
list(location, page?): Promise<TrashPage>;
```

One page of the bin, newest first, with the share's retention.

###### Parameter

| Parameter      | Typ                                                            | Beschreibung                           |
| -------------- | -------------------------------------------------------------- | -------------------------------------- |
| `location`     | [`ShareLocation`](https://pithyx.org/de/docs/reference/sdk/files/#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.                        |

###### Rückgabewert

`Promise`\<[`TrashPage`](https://pithyx.org/de/docs/reference/sdk/files/#trashpage)\>

One page of items.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `files.shares` permission.

###### restore()

```ts
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.

###### Parameter

| Parameter     | Typ                                                              | Beschreibung                                          |
| ------------- | ---------------------------------------------------------------- | ----------------------------------------------------- |
| `location`    | [`ShareLocation`](https://pithyx.org/de/docs/reference/sdk/files/#sharelocation)   | A share.                                              |
| `ids`         | `number`[]                                                       | 1 to 1000 item ids from `list`.                       |
| `onConflict?` | [`ConflictPolicy`](https://pithyx.org/de/docs/reference/sdk/files/#conflictpolicy) | What to do with a taken name; `rename` when left out. |

###### Rückgabewert

`Promise`\<[`JobInfo`](https://pithyx.org/de/docs/reference/sdk/files/#jobinfo)\>

The job as it started.

###### delete()

```ts
delete(location, ids): Promise<JobInfo>;
```

Deletes items of the bin for good, as a job. Only after the user confirmed it.

###### Parameter

| Parameter  | Typ                                                            | Beschreibung                    |
| ---------- | -------------------------------------------------------------- | ------------------------------- |
| `location` | [`ShareLocation`](https://pithyx.org/de/docs/reference/sdk/files/#sharelocation) | A share.                        |
| `ids`      | `number`[]                                                     | 1 to 1000 item ids from `list`. |

###### Rückgabewert

`Promise`\<[`JobInfo`](https://pithyx.org/de/docs/reference/sdk/files/#jobinfo)\>

The job as it started.

###### empty()

```ts
empty(location): Promise<JobInfo>;
```

Deletes everything in the bin for good, as a job. Only after the user confirmed it.

###### Parameter

| Parameter  | Typ                                                            | Beschreibung |
| ---------- | -------------------------------------------------------------- | ------------ |
| `location` | [`ShareLocation`](https://pithyx.org/de/docs/reference/sdk/files/#sharelocation) | A share.     |

###### Rückgabewert

`Promise`\<[`JobInfo`](https://pithyx.org/de/docs/reference/sdk/files/#jobinfo)\>

The job as it started.

##### ui

```ts
readonly ui: object;
```

The desktop's own dialogs. Needs no permission.

###### showError()

```ts
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.

###### Parameter

| Parameter | Typ       | Beschreibung                                                                                                                  |
| --------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `error`   | `unknown` | A [PithyxError](https://pithyx.org/de/docs/reference/sdk/errors/#pithyxerror), a problem, or anything else, which shows as an unexpected error. |

###### Rückgabewert

`Promise`\<`void`\>

#### Methoden

##### notify()

```ts
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.

###### Parameter

| Parameter      | Typ                                           | Beschreibung                                                                                              |
| -------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `notification` | [`NotificationRequest`](#notificationrequest) | Title, body, level, buttons, data and tag; the limits are on [NotificationRequest](#notificationrequest). |

###### Rückgabewert

`Promise`\<\{
`id`: `string`;
\}\>

The id of the notification, which `notificationAction` carries.

###### Throws

[`app.permission.denied`](https://pithyx.org/de/docs/reference/errors/#app.permission.denied) without the `notifications` permission.

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when a text, the buttons or the data exceed their limits.

##### setBadge()

```ts
setBadge(count): Promise<void>;
```

A counter on the app's taskbar entry; 0 or null removes it. Needs no permission.

###### Parameter

| Parameter | Typ                | Beschreibung                           |
| --------- | ------------------ | -------------------------------------- |
| `count`   | `number` \| `null` | A whole number of at least 0, or null. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) when the count is negative or not a whole number.

##### openUrl()

```ts
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.

###### Parameter

| Parameter | Typ      | Beschreibung                                |
| --------- | -------- | ------------------------------------------- |
| `url`     | `string` | An absolute URL of at most 2048 characters. |

###### Rückgabewert

`Promise`\<`void`\>

###### Throws

[`sdk.request.invalid`](https://pithyx.org/de/docs/reference/errors/#sdk.request.invalid) for any other scheme (`javascript:`, `data:`) or a longer URL.

##### supports()

```ts
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`](https://pithyx.org/de/docs/reference/errors/#sdk.method.unknown).

###### Parameter

| Parameter | Typ                         | Beschreibung                                                 |
| --------- | --------------------------- | ------------------------------------------------------------ |
| `method`  | keyof [`Methods`](#methods) | A method name of [Methods](#methods), such as `files.watch`. |

###### Rückgabewert

`boolean`

Whether `context.capabilities` lists it.

##### on()

```ts
on<E>(event, handler): () => void;
```

Listens to an event of the desktop (see [Events](https://pithyx.org/de/docs/reference/sdk/events-context/#events)). Returns a function that stops listening.

###### Typenparameter

| Typenparameter                                                                |
| ----------------------------------------------------------------------------- |
| `E` _extends_ keyof [`Events`](https://pithyx.org/de/docs/reference/sdk/events-context/#events) |

###### Parameter

| Parameter | Typ                                                                          | Beschreibung                                       |
| --------- | ---------------------------------------------------------------------------- | -------------------------------------------------- |
| `event`   | `E`                                                                          | The event name.                                    |
| `handler` | [`EventHandler`](https://pithyx.org/de/docs/reference/sdk/events-context/#eventhandler)\<`E`\> | Called with the event's data each time it arrives. |

###### Rückgabewert

A function that removes the handler.

() => `void`

##### answer()

```ts
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.

###### Typenparameter

| Typenparameter                                                                  |
| ------------------------------------------------------------------------------- |
| `Q` _extends_ keyof [`Queries`](https://pithyx.org/de/docs/reference/sdk/events-context/#queries) |

###### Parameter

| Parameter | Typ                                                                          | Beschreibung                                                              |
| --------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `query`   | `Q`                                                                          | The question.                                                             |
| `handler` | [`QueryHandler`](https://pithyx.org/de/docs/reference/sdk/events-context/#queryhandler)\<`Q`\> | Returns the answer, also asynchronously within the question's time limit. |

###### Rückgabewert

`void`

##### call()

```ts
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.

###### Typenparameter

| Typenparameter                            |
| ----------------------------------------- |
| `M` _extends_ keyof [`Methods`](#methods) |

###### Parameter

| Parameter | Typ                                        | Beschreibung                          |
| --------- | ------------------------------------------ | ------------------------------------- |
| `method`  | `M`                                        | A method name of [Methods](#methods). |
| `params`  | [`Methods`](#methods)\[`M`\]\[`"params"`\] | The method's parameters.              |

###### Rückgabewert

`Promise`\<[`Methods`](#methods)\[`M`\]\[`"result"`\]\>

The method's result.

###### Throws

[`sdk.method.unknown`](https://pithyx.org/de/docs/reference/errors/#sdk.method.unknown) when the desktop does not serve the method.

---

### CreateAppOptions

How [createApp](#createapp) and `connect` set up the app.

#### Eigenschaften

##### themeRoot?

```ts
optional themeRoot?: HTMLElement | null;
```

Where the theme tokens go; the SDK sets them on `document.documentElement` by default. Null to skip.

##### timeout?

```ts
optional timeout?: number;
```

Time limit of a call in milliseconds; [REQUEST\_TIMEOUT](#request_timeout) when left out.

##### origin?

```ts
optional origin?: string;
```

The box's address for backend URLs; by default taken from the window's own URL.

---

### Formatters

Formatters in the user's language and time zone, as `app.format` has them. None of them throws or needs a permission.

#### Methoden

##### date()

```ts
date(value, options?): string;
```

A date, for example "Sep 27, 2026".

###### Parameter

| Parameter  | Typ                     | Beschreibung                                                            |
| ---------- | ----------------------- | ----------------------------------------------------------------------- |
| `value`    | `string` \| `Date`      | An ISO 8601 string or a `Date`.                                         |
| `options?` | `DateTimeFormatOptions` | `Intl.DateTimeFormat` options; `{ dateStyle: 'medium' }` when left out. |

###### Rückgabewert

`string`

The date in the user's time zone.

##### time()

```ts
time(value, options?): string;
```

A time of day, for example "14:05".

###### Parameter

| Parameter  | Typ                     | Beschreibung                                                           |
| ---------- | ----------------------- | ---------------------------------------------------------------------- |
| `value`    | `string` \| `Date`      | An ISO 8601 string or a `Date`.                                        |
| `options?` | `DateTimeFormatOptions` | `Intl.DateTimeFormat` options; `{ timeStyle: 'short' }` when left out. |

###### Rückgabewert

`string`

The time in the user's time zone.

##### dateTime()

```ts
dateTime(value, options?): string;
```

Date and time.

###### Parameter

| Parameter  | Typ                     | Beschreibung                                                             |
| ---------- | ----------------------- | ------------------------------------------------------------------------ |
| `value`    | `string` \| `Date`      | An ISO 8601 string or a `Date`.                                          |
| `options?` | `DateTimeFormatOptions` | `Intl.DateTimeFormat` options; medium date and short time when left out. |

###### Rückgabewert

`string`

Date and time in the user's time zone.

##### relative()

```ts
relative(value, now?): string;
```

How long ago or how far ahead, for example "5 minutes ago", in the largest unit that fits.

###### Parameter

| Parameter | Typ                | Beschreibung                                                |
| --------- | ------------------ | ----------------------------------------------------------- |
| `value`   | `string` \| `Date` | An ISO 8601 string or a `Date`.                             |
| `now?`    | `Date`             | The moment to compare with; the current time when left out. |

###### Rückgabewert

`string`

The distance in words, such as "yesterday" or "in 3 hours".

##### number()

```ts
number(value, options?): string;
```

A number with the user's separators, for example "1,234.5".

###### Parameter

| Parameter  | Typ                   | Beschreibung                 |
| ---------- | --------------------- | ---------------------------- |
| `value`    | `number`              | The number.                  |
| `options?` | `NumberFormatOptions` | `Intl.NumberFormat` options. |

###### Rückgabewert

`string`

The formatted number.

##### bytes()

```ts
bytes(value): string;
```

A byte count with decimal units, as the desktop shows sizes (10 GB, 4 TB).

###### Parameter

| Parameter | Typ      | Beschreibung       |
| --------- | -------- | ------------------ |
| `value`   | `number` | The size in bytes. |

###### Rückgabewert

`string`

The size with one decimal below 100 of its unit.

##### list()

```ts
list(values, options?): string;
```

A list, for example "Anna, Ben and Chris".

###### Parameter

| Parameter  | Typ                 | Beschreibung                                            |
| ---------- | ------------------- | ------------------------------------------------------- |
| `values`   | readonly `string`[] | The items, already as text.                             |
| `options?` | `ListFormatOptions` | `Intl.ListFormat` options; a conjunction when left out. |

###### Rückgabewert

`string`

The joined list.

---

### 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.

#### Eigenschaften

##### $schema?

```ts
optional $schema?: string;
```

Path or URL of this schema, for editors. Ignored by the box.

##### manifestVersion

```ts
manifestVersion: 1;
```

The manifest schema this file follows.

##### id

```ts
id: string;
```

##### version

```ts
version: string;
```

SemVer 2.0 version of the app, without build metadata, for example `1.2.0` or `2.0.0-beta.1`.

##### name

```ts
name: LocalizedName;
```

##### description?

```ts
optional description?: LocalizedText;
```

##### author

```ts
author: AppAuthor;
```

##### license?

```ts
optional license?: string;
```

SPDX license expression of the app, for example `MIT` or `MIT OR Apache-2.0`.

##### homepage?

```ts
optional homepage?: string;
```

The app's website or source repository.

##### entry

```ts
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

```ts
sdk: string;
```

SemVer range of `@pithyx/sdk` the app was built against, for example `^1.0.0`.

##### pithyx?

```ts
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?

```ts
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

```ts
permissions: Permission[];
```

The permissions the app asks for. Each one appears in the install dialog and can be revoked later.

##### window

```ts
window: WindowManifest;
```

##### storage?

```ts
optional storage?: StorageRequest[];
```

Places for files the app needs, each mapped by an administrator to a folder in a shared folder.

###### Max Items

16

##### fileHandlers?

```ts
optional fileHandlers?: FileHandler[];
```

Files the app can open.

###### Max Items

32

##### backend?

```ts
optional backend?: BackendManifest;
```

---

### 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.

#### Indexierbar

```ts
[k: string]: string
```

The 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})*$".

#### Eigenschaften

##### en

```ts
en: string;
```

The English text, shown when no other language matches. One line, at most 60 characters.

---

### 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.

#### Indexierbar

```ts
[k: string]: string
```

The 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})*$".

#### Eigenschaften

##### en

```ts
en: string;
```

The English text, shown when no other language matches. At most 500 characters; line breaks are allowed.

---

### AppAuthor

Who makes the app.

#### Eigenschaften

##### name

```ts
name: string;
```

A person or an organization.

##### url?

```ts
optional url?: string;
```

The author's website.

---

### 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.

#### Eigenschaften

##### instances

```ts
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

```ts
defaultSize: WindowSize;
```

##### minSize

```ts
minSize: WindowSize;
```

##### loading?

```ts
optional loading?: WindowLoading;
```

---

### WindowSize

A size in CSS pixels.

#### Eigenschaften

##### width

```ts
width: number;
```

The width in CSS pixels.

##### height

```ts
height: number;
```

The height in CSS pixels.

---

### 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.

#### Eigenschaften

##### text?

```ts
optional text?: LocalizedName;
```

##### untilReady?

```ts
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

A button of a notification.

#### Eigenschaften

##### id

```ts
id: string;
```

Comes back in `notificationAction`; 1 to 64 characters.

##### label

```ts
label: string;
```

Plain text, 1 to 40 characters, translated by the app.

---

### NotificationActivation

What the app learns when the user clicks one of its notifications.

#### Eigenschaften

##### notification

```ts
notification: string;
```

The id `notify` resolved with.

##### action

```ts
action: string | null;
```

The `id` of the button the user clicked, or null for a click on the notification itself.

##### data

```ts
data: unknown;
```

The `data` the app passed to `notify`, or null.

---

### 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).

#### Eigenschaften

##### title

```ts
title: string;
```

Plain text, 1 to 200 characters.

##### body?

```ts
optional body?: string;
```

Plain text, at most 1000 characters.

##### level?

```ts
optional level?: "info" | "success" | "warning" | "error";
```

How the toast looks; `info` when left out.

##### actions?

```ts
optional actions?: NotificationAction[];
```

At most 2 buttons. A click sends `notificationAction`, or starts the app with `launch.notification`.

##### data?

```ts
optional data?: unknown;
```

Data that comes back with `notificationAction`, at most 4 KB as JSON.

##### tag?

```ts
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

A user of the box, as `directory.users` lists it. Deactivated users are left out.

#### Eigenschaften

##### id

```ts
id: number;
```

Stable id of the user: the Linux uid, also `X-Pithyx-User-Id` for the backend; never given to another user.

##### name

```ts
name: string;
```

The user name, lower case.

##### displayName

```ts
displayName: string | null;
```

The name to show, if the user set one.

##### groups

```ts
groups: number[];
```

Ids of the user's groups (see `directory.groups`); the built-in group every user belongs to is left out.

---

### DirectoryGroup

A group of the box, as `directory.groups` lists it. The built-in group every user belongs to is left out.

#### Eigenschaften

##### id

```ts
id: number;
```

Stable id (the group's Linux gid).

##### name

```ts
name: string;
```

The group's name.

##### description

```ts
description: string;
```

Free text, may be empty.

---

### Point

A point in CSS pixels, relative to the top left corner of the app's window content.

#### Eigenschaften

##### x

```ts
x: number;
```

Distance from the left edge.

##### y

```ts
y: number;
```

Distance from the top edge.

---

### LogRecord

One entry of the app's log, as the SDK sends it (see `app.log`).

#### Eigenschaften

##### level

```ts
level: LogLevel;
```

How serious the entry is.

##### message

```ts
message: string;
```

At most 4000 characters; the SDK cuts longer ones.

##### data?

```ts
optional data?: Record<string, string>;
```

At most 20 fields with texts of at most 1000 characters; the SDK cuts the rest.

---

### 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](https://pithyx.org/de/docs/reference/sdk/events-context/#capabilities).

#### Eigenschaften

##### window.setTitle

```ts
window.setTitle: object;
```

Sets the window title (shown in the title bar and the taskbar). At most 200 characters.

###### params

```ts
params: object;
```

###### params.title

```ts
title: string;
```

###### result

```ts
result: undefined;
```

##### window.close

```ts
window.close: object;
```

Closes the window. `beforeClose` is not sent for a close the app asked for.

###### params

```ts
params: Record<string, never>;
```

###### result

```ts
result: undefined;
```

##### window.setDirty

```ts
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

```ts
params: object;
```

###### params.dirty

```ts
dirty: boolean;
```

###### result

```ts
result: undefined;
```

##### window.requestAttention

```ts
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

```ts
params: Record<string, never>;
```

###### result

```ts
result: undefined;
```

##### window.ready

```ts
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

```ts
params: Record<string, never>;
```

###### result

```ts
result: undefined;
```

##### window.setSize

```ts
window.setSize: object;
```

Asks for a new free size. The desktop may clamp it; the result is the size the window got.

###### params

```ts
params: object;
```

###### params.width

```ts
width: number;
```

###### params.height

```ts
height: number;
```

###### result

```ts
result: object;
```

###### result.width

```ts
width: number;
```

###### result.height

```ts
height: number;
```

##### log.write

```ts
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

```ts
params: object;
```

###### params.entries

```ts
entries: LogRecord[];
```

###### result

```ts
result: undefined;
```

##### notify

```ts
notify: object;
```

Shows a notification and resolves with its id. Needs the `notifications` permission.

###### params

```ts
params: NotificationRequest;
```

###### result

```ts
result: object;
```

###### result.id

```ts
id: string;
```

##### setBadge

```ts
setBadge: object;
```

A counter on the app's taskbar entry: a positive integer shows it, 0 or null removes it.

###### params

```ts
params: object;
```

###### params.count

```ts
count: number | null;
```

###### result

```ts
result: undefined;
```

##### session.save

```ts
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

```ts
params: object;
```

###### params.state

```ts
state: unknown;
```

###### result

```ts
result: undefined;
```

##### storage.get

```ts
storage.get: object;
```

Reads a value the app stored for this user, or null.

###### params

```ts
params: object;
```

###### params.key

```ts
key: string;
```

###### result

```ts
result: unknown;
```

##### storage.set

```ts
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

```ts
params: object;
```

###### params.key

```ts
key: string;
```

###### params.value

```ts
value: unknown;
```

###### result

```ts
result: undefined;
```

##### storage.remove

```ts
storage.remove: object;
```

Removes a value the app stored for this user; a missing key is no error.

###### params

```ts
params: object;
```

###### params.key

```ts
key: string;
```

###### result

```ts
result: undefined;
```

##### storage.keys

```ts
storage.keys: object;
```

Every key the app stored for this user.

###### params

```ts
params: Record<string, never>;
```

###### result

```ts
result: string[];
```

##### backend.token

```ts
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`](https://pithyx.org/de/docs/reference/errors/#app.token.invalid), for
example because the box restarted.

###### params

```ts
params: object;
```

###### params.renew?

```ts
optional renew?: boolean;
```

###### result

```ts
result: BackendToken;
```

##### backend.ticket

```ts
backend.ticket: object;
```

A one-time ticket for one WebSocket to an endpoint of the app's backend (`app.backend.socket` uses it).

###### params

```ts
params: object;
```

###### params.endpoint

```ts
endpoint: string;
```

###### result

```ts
result: BackendTicket;
```

##### directory.users

```ts
directory.users: object;
```

Every user of the box. Needs `directory.read`.

###### params

```ts
params: Record<string, never>;
```

###### result

```ts
result: DirectoryUser[];
```

##### directory.groups

```ts
directory.groups: object;
```

Every group of the box. Needs `directory.read`.

###### params

```ts
params: Record<string, never>;
```

###### result

```ts
result: DirectoryGroup[];
```

##### contextMenu.show

```ts
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

```ts
params: object;
```

###### params.at

```ts
at: Point;
```

###### params.items

```ts
items: ContextMenuItem[];
```

###### result

```ts
result: string | null;
```

##### clipboard.writeText

```ts
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

```ts
params: object;
```

###### params.text

```ts
text: string;
```

###### result

```ts
result: undefined;
```

##### openUrl

```ts
openUrl: object;
```

Opens an `https:`, `http:` or `mailto:` URL in a new browser tab, without a reference to the desktop.

###### params

```ts
params: object;
```

###### params.url

```ts
url: string;
```

###### result

```ts
result: undefined;
```

##### files.pick

```ts
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

```ts
params: object;
```

###### params.multiple?

```ts
optional multiple?: boolean;
```

###### params.extensions?

```ts
optional extensions?: string[];
```

###### result

```ts
result: FileRef[];
```

##### files.saveAs

```ts
files.saveAs: object;
```

Opens the desktop's save dialog; resolves with the new file, or null when cancelled. Needs `files.write`.

###### params

```ts
params: object;
```

###### params.suggestedName

```ts
suggestedName: string;
```

###### params.data

```ts
data: Blob;
```

###### result

```ts
result: FileRef | null;
```

##### files.read

```ts
files.read: object;
```

Reads a file the app was given. Needs `files.read`.

###### params

```ts
params: object;
```

###### params.file

```ts
file: FileRef;
```

###### result

```ts
result: Blob;
```

##### files.write

```ts
files.write: object;
```

Replaces the contents of a writable file. Needs `files.write`.

###### params

```ts
params: object;
```

###### params.file

```ts
file: FileRef;
```

###### params.data

```ts
data: Blob;
```

###### result

```ts
result: FileRef;
```

##### files.url

```ts
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

```ts
params: object;
```

###### params.file

```ts
file: FileRef;
```

###### result

```ts
result: object;
```

###### result.url

```ts
url: string;
```

###### result.expiresAt

```ts
expiresAt: string;
```

##### files.list

```ts
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

```ts
params: object;
```

###### params.location

```ts
location: FileLocation;
```

###### params.path

```ts
path: string;
```

###### params.cursor?

```ts
optional cursor?: string;
```

###### params.limit?

```ts
optional limit?: number;
```

###### params.sort?

```ts
optional sort?: SortKey;
```

###### params.order?

```ts
optional order?: SortOrder;
```

###### result

```ts
result: FolderPage;
```

##### files.open

```ts
files.open: object;
```

A handle for a file in a named storage or a share, for `files.read`, `files.write` and `files.url`.

###### params

```ts
params: object;
```

###### params.location

```ts
location: FileLocation;
```

###### params.path

```ts
path: string;
```

###### result

```ts
result: FileRef;
```

##### files.shares

```ts
files.shares: object;
```

The shares the user can use, with the user's access to each; `sharesChanged` says when to ask again.

###### params

```ts
params: Record<string, never>;
```

###### result

```ts
result: ShareInfo[];
```

##### files.watch

```ts
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

```ts
params: object;
```

###### params.location

```ts
location: FileLocation;
```

###### params.path

```ts
path: string;
```

###### result

```ts
result: object;
```

###### result.watch

```ts
watch: string;
```

##### files.unwatch

```ts
files.unwatch: object;
```

Ends a watch started with `files.watch`.

###### params

```ts
params: object;
```

###### params.watch

```ts
watch: string;
```

###### result

```ts
result: undefined;
```

##### files.upload

```ts
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`](https://pithyx.org/de/docs/reference/errors/#fs.entry.exists) unless `overwrite`. With an `upload` id, `uploadProgress` events report the bytes sent.

###### params

```ts
params: object;
```

###### params.location

```ts
location: FileLocation;
```

###### params.folder

```ts
folder: string;
```

###### params.name

```ts
name: string;
```

###### params.data

```ts
data: Blob;
```

###### params.overwrite?

```ts
optional overwrite?: boolean;
```

###### params.upload?

```ts
optional upload?: string;
```

###### result

```ts
result: FileEntry;
```

##### files.download

```ts
files.download: object;
```

Downloads a file to the user's device through the browser.

###### params

```ts
params: object;
```

###### params.location

```ts
location: FileLocation;
```

###### params.path

```ts
path: string;
```

###### result

```ts
result: undefined;
```

##### files.createFolder

```ts
files.createFolder: object;
```

Creates a folder; its parent must exist.

###### params

```ts
params: object;
```

###### params.location

```ts
location: FileLocation;
```

###### params.path

```ts
path: string;
```

###### result

```ts
result: FileEntry;
```

##### files.rename

```ts
files.rename: object;
```

Renames an entry within its folder; an existing name is never replaced ([`fs.entry.exists`](https://pithyx.org/de/docs/reference/errors/#fs.entry.exists)).

###### params

```ts
params: object;
```

###### params.location

```ts
location: FileLocation;
```

###### params.path

```ts
path: string;
```

###### params.name

```ts
name: string;
```

###### result

```ts
result: FileEntry;
```

##### files.run

```ts
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

```ts
params: FileOperation;
```

###### result

```ts
result: JobInfo;
```

##### files.versions

```ts
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

```ts
params: object;
```

###### params.location

```ts
location: ShareLocation;
```

###### params.path

```ts
path: string;
```

###### result

```ts
result: FileVersion[];
```

##### files.restoreVersion

```ts
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

```ts
params: object;
```

###### params.location

```ts
location: ShareLocation;
```

###### params.path

```ts
path: string;
```

###### params.snapshot

```ts
snapshot: string;
```

###### params.overwrite?

```ts
optional overwrite?: boolean;
```

###### result

```ts
result: JobInfo;
```

##### jobs.cancel

```ts
jobs.cancel: object;
```

Cancels a job the app started; a finished job stays as it is.

###### params

```ts
params: object;
```

###### params.job

```ts
job: number;
```

###### result

```ts
result: undefined;
```

##### trash.list

```ts
trash.list: object;
```

One page of a share's recycle bin, newest first. Needs read access to the share.

###### params

```ts
params: object;
```

###### params.location

```ts
location: ShareLocation;
```

###### params.cursor?

```ts
optional cursor?: string;
```

###### params.limit?

```ts
optional limit?: number;
```

###### result

```ts
result: TrashPage;
```

##### trash.restore

```ts
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

```ts
params: object;
```

###### params.location

```ts
location: ShareLocation;
```

###### params.ids

```ts
ids: number[];
```

###### params.onConflict?

```ts
optional onConflict?: ConflictPolicy;
```

###### result

```ts
result: JobInfo;
```

##### trash.delete

```ts
trash.delete: object;
```

Deletes items of the recycle bin for good, as a job. Only after the user confirmed it.

###### params

```ts
params: object;
```

###### params.location

```ts
location: ShareLocation;
```

###### params.ids

```ts
ids: number[];
```

###### result

```ts
result: JobInfo;
```

##### trash.empty

```ts
trash.empty: object;
```

Deletes everything in the recycle bin for good, as a job. Only after the user confirmed it.

###### params

```ts
params: object;
```

###### params.location

```ts
location: ShareLocation;
```

###### result

```ts
result: JobInfo;
```

##### ui.showError

```ts
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

```ts
params: object;
```

###### params.problem

```ts
problem: Problem;
```

###### result

```ts
result: undefined;
```

---

### ConnectMessage

What the desktop posts to the iframe window, with the app's port transferred.

#### Eigenschaften

##### type

```ts
type: 'pithyx:connect';
```

Always `pithyx:connect`.

---

### Endpoint

One end of a connection.

#### Methoden

##### post()

```ts
post(message): void;
```

Sends a message to the other end.

###### Parameter

| Parameter | Typ       | Beschreibung           |
| --------- | --------- | ---------------------- |
| `message` | `unknown` | Structured-clone data. |

###### Rückgabewert

`void`

##### listen()

```ts
listen(handler): void;
```

Registers the single message handler of this end; a second call replaces the first handler.

###### Parameter

| Parameter | Typ                   | Beschreibung                                 |
| --------- | --------------------- | -------------------------------------------- |
| `handler` | (`message`) => `void` | Called with each message from the other end. |

###### Rückgabewert

`void`

##### close()

```ts
close(): void;
```

Closes this end; nothing is sent or received after it.

###### Rückgabewert

`void`

## Typenaliasse

### AppId

```ts
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

```ts
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

```ts
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`](https://pithyx.org/de/docs/reference/errors/#app.elevated.unsupported), and a later version grants them to administrators only, after a confirmation with password and TOTP.

---

### ContextMenuItem

```ts
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-Mitglieder

##### Typenliteral

```ts
{
  id: string;
  label: string;
  disabled?: boolean;
  checked?: boolean;
  danger?: boolean;
  shortcut?: string;
}
```

###### id

```ts
id: string;
```

Comes back from `contextMenu.show` when the user picks the entry; 1 to 64 characters.

###### label

```ts
label: string;
```

Plain text, 1 to 100 characters.

###### disabled?

```ts
optional disabled?: boolean;
```

Shows the entry greyed out; it cannot be picked.

###### checked?

```ts
optional checked?: boolean;
```

Shows a check mark.

###### danger?

```ts
optional danger?: boolean;
```

Marks a destructive entry, such as Delete.

###### shortcut?

```ts
optional shortcut?: string;
```

A key hint shown next to the label, for example `Ctrl+C`. The app handles the keys itself.

---

##### Typenliteral

```ts
{
  separator: true;
}
```

###### separator

```ts
separator: true;
```

A line between groups of entries.

---

### LogLevel

```ts
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

```ts
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

```ts
type MethodName = keyof Methods;
```

The name of a method an app can call.

---

### AppMessage

```ts
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-Mitglieder

##### Typenliteral

```ts
{
  type: 'hello';
  protocol: number;
  sdk: string;
}
```

###### type

```ts
type: 'hello';
```

The first message on the port.

###### protocol

```ts
protocol: number;
```

The protocol version the app speaks.

###### sdk

```ts
sdk: string;
```

The SDK version the app was built with.

---

##### Typenliteral

```ts
{
  type: 'request';
  id: number;
  method: string;
  params: unknown;
}
```

###### type

```ts
type: 'request';
```

A call of a method.

###### id

```ts
id: number;
```

Unique per connection; the `response` carries it back.

###### method

```ts
method: string;
```

A method name of [Methods](#methods).

###### params

```ts
params: unknown;
```

The method's parameters.

---

##### Typenliteral

```ts
{
  type: 'reply';
  id: number;
  answer: unknown;
}
```

###### type

```ts
type: 'reply';
```

The answer to a `query`.

###### id

```ts
id: number;
```

The `id` of the query.

###### answer

```ts
answer: unknown;
```

The answer the question expects.

---

### HostMessage

```ts
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-Mitglieder

##### Typenliteral

```ts
{
  type: 'init';
  protocol: number;
  context: AppContext;
}
```

###### type

```ts
type: 'init';
```

The answer to `hello`: the app may start.

###### protocol

```ts
protocol: number;
```

The protocol version both sides use.

###### context

```ts
context: AppContext;
```

Everything the app needs to start.

---

##### Typenliteral

```ts
{
  type: 'refuse';
  problem: Problem;
}
```

###### type

```ts
type: 'refuse';
```

The answer to `hello` when the desktop cannot serve the app; the port closes after it.

###### problem

```ts
problem: Problem;
```

Why, for example [`sdk.protocol.unsupported`](https://pithyx.org/de/docs/reference/errors/#sdk.protocol.unsupported).

---

##### Typenliteral

```ts
{
  type: 'response';
  id: number;
  ok: true;
  result: unknown;
}
```

###### type

```ts
type: 'response';
```

The result of a `request`.

###### id

```ts
id: number;
```

The `id` of the request.

###### ok

```ts
ok: true;
```

The call succeeded.

###### result

```ts
result: unknown;
```

The method's result.

---

##### Typenliteral

```ts
{
  type: 'response';
  id: number;
  ok: false;
  problem: Problem;
}
```

###### type

```ts
type: 'response';
```

The failure of a `request`.

###### id

```ts
id: number;
```

The `id` of the request.

###### ok

```ts
ok: false;
```

The call failed.

###### problem

```ts
problem: Problem;
```

Why it failed.

---

##### Typenliteral

```ts
{
  type: 'event';
  event: string;
  data: unknown;
}
```

###### type

```ts
type: 'event';
```

An event of [Events](https://pithyx.org/de/docs/reference/sdk/events-context/#events).

###### event

```ts
event: string;
```

The event name.

###### data

```ts
data: unknown;
```

The event's data.

---

##### Typenliteral

```ts
{
  type: 'query';
  id: number;
  query: string;
  data: unknown;
}
```

###### type

```ts
type: 'query';
```

A question of [Queries](https://pithyx.org/de/docs/reference/sdk/events-context/#queries) the app answers with `reply`.

###### id

```ts
id: number;
```

Unique per connection; the `reply` carries it back.

###### query

```ts
query: string;
```

The question's name.

###### data

```ts
data: unknown;
```

What the question carries.

## Variablen

### REQUEST\_TIMEOUT

```ts
const REQUEST_TIMEOUT: 15000 = 15_000;
```

An app waits this long for a response before a call fails with [`sdk.request.timeout`](https://pithyx.org/de/docs/reference/errors/#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

```ts
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

```ts
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](#min_protocol_version)).

---

### PROTOCOL\_VERSION

```ts
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](#min_protocol_version) up to this one, so an app built
against an older SDK keeps working after a desktop update.

---

### MIN\_PROTOCOL\_VERSION

```ts
const MIN_PROTOCOL_VERSION: 1 = 1;
```

The oldest protocol version this SDK's host side still accepts.

## Funktionen

### createApp()

```ts
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`](https://pithyx.org/de/docs/reference/errors/#sdk.protocol.unsupported) when the desktop refuses the app's protocol version. Core apps use it with
[inProcessPair](#inprocesspair); sandboxed apps call `connect` instead.

#### Parameter

| Parameter  | Typ                                     | Beschreibung                                       |
| ---------- | --------------------------------------- | -------------------------------------------------- |
| `endpoint` | [`Endpoint`](#endpoint)                 | The app's end of the transport.                    |
| `options`  | [`CreateAppOptions`](#createappoptions) | Theme root, call time limit and the box's address. |

#### Rückgabewert

`Promise`\<[`PithyxApp`](#pithyxapp)\>

The app API, once the desktop sent `init`.

#### Throws

[`sdk.protocol.unsupported`](https://pithyx.org/de/docs/reference/errors/#sdk.protocol.unsupported) when the desktop does not speak the SDK's protocol version.

---

### createFormatters()

```ts
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.

#### Parameter

| Parameter | Typ            | Beschreibung                                     |
| --------- | -------------- | ------------------------------------------------ |
| `current` | () => `object` | Returns the locale and the time zone to use now. |

#### Rückgabewert

[`Formatters`](#formatters)

The formatters.

---

### connect()

```ts
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`](https://pithyx.org/de/docs/reference/errors/#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`.

#### Parameter

| Parameter | Typ                                                | Beschreibung                                                                                                       |
| --------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `options` | [`CreateAppOptions`](#createappoptions) & `object` | Theme root, call time limit and box address as for [createApp](#createapp), plus how long to wait for the desktop. |

#### Rückgabewert

`Promise`\<[`PithyxApp`](#pithyxapp)\>

The app API, once the desktop accepted the app.

#### Throws

[`sdk.transport.closed`](https://pithyx.org/de/docs/reference/errors/#sdk.transport.closed) when no desktop connects within the time limit.

#### Throws

[`sdk.protocol.unsupported`](https://pithyx.org/de/docs/reference/errors/#sdk.protocol.unsupported) when the desktop does not speak the SDK's protocol version.

---

### portEndpoint()

```ts
function portEndpoint(port): Endpoint;
```

An end backed by a `MessagePort` (third-party apps in sandboxed iframes).

#### Parameter

| Parameter | Typ           | Beschreibung                                            |
| --------- | ------------- | ------------------------------------------------------- |
| `port`    | `MessagePort` | The port the desktop transferred with `pithyx:connect`. |

#### Rückgabewert

[`Endpoint`](#endpoint)

The transport end; closing it closes the port.

---

### inProcessPair()

```ts
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.

#### Rückgabewert

\[[`Endpoint`](#endpoint), [`Endpoint`](#endpoint)\]

The two connected ends: one for the app, one for the host. Closing either closes both.
