Skip to content

Apps ​

Manage app permissions, identity grants, and contact visibility. Used primarily by the Wish Dashboard.

App lifecycle ​

app.list (void): App[] ​

List all registered apps with their permissions.

app.remove (wsid: Buffer): bool ​

Remove an app and all its permissions.

Identity grants ​

Apps are sandboxed — they only see identities explicitly granted to them.

app.grantIdentity (wsid: Buffer, uid: Buffer): bool ​

Grant an identity to an app. The app will see this identity in identity.list and can receive peers for it.

app.revokeIdentity (wsid: Buffer, uid: Buffer): bool ​

Revoke an identity from an app.

Contact visibility ​

By default, apps cannot see any contacts. Contact visibility must be configured per app, per identity.

app.setContacts (wsid: Buffer, uid: Buffer, settings: { mode, contacts? }): bool ​

Set contact visibility for an app.

Modes:

  • 'none' — no contacts visible (default)
  • 'all' — all contacts visible
  • 'allow' — only listed contacts visible
  • 'deny' — all contacts except listed ones
typescript
await app.request('app.setContacts', [wsid, uid, { mode: 'all' }]);

// Only specific contacts
await app.request('app.setContacts', [wsid, uid, {
    mode: 'allow',
    contacts: [bobUid, carolUid]
}]);

WARNING

Contact visibility changes only take effect on new connections. Existing connections won't see updated permissions until reconnected.

app.getContacts (wsid: Buffer, uid: Buffer): { mode, contacts } ​

Get contact visibility settings for an app.

Admin privileges ​

app.setAdmin (wsid: Buffer, admin: bool): bool ​

Set admin privileges for an app.

Peer inspection ​

app.peers (wsid: Buffer): RemotePeer[] ​

List the remote hosts currently running the app's protocol — i.e. the app-level peers that are online right now. wish-core walks its active connections and reports one entry per connection whose remote side speaks the target app's protocol, so this is genuinely peer-level (an app is present), not merely a list of connected devices.

This is the way to seed presence state on startup; pair it with the live online/offline events (or the peer.online/peer.offline signals) to keep it current.

Each entry (RemotePeer):

typescript
{
    ruid: Buffer;      // remote identity
    rhid: Buffer;      // remote host (device)
    bytesIn: number;
    bytesOut: number;
    transport: string; // "tcp" | "utp"
}

Note this is narrower than the full Peer tuple from the online/offline events (no luid/rsid/protocol) — the protocol is implied by the wsid you queried, and luid by the app's grants.

Admin request routing ​

Regular apps ask the admin app for help via admin.request. The kernel forwards each request to admin apps as an admin.request signal — { id, appId, appName, requestType, access? }, where requestType is the app's kind and access its args object, verbatim — and keeps it pending until answered.

admin.requests (void): AdminRequest[] ​

List the requests not yet answered, in the same shape as the signal. Call it after subscribing to signals: a request may predate your admin app (on mobile the admin UI is often started by the request), so signal-only delivery misses it.

admin.response (id: int, success: bool, message?: string): bool ​

Answer a request. The kernel drops it from the pending list and emits an admin.response signal { id, requestType, success, message? } to the requesting app. Always answer — also when the user dismisses or a newer request supersedes an older one — or the request lingers in admin.requests.

Handling by kind (Wish's convention; the kernel enforces none of it): identity → consent flow, then app.grantIdentity + app.setContacts per the access hint, then admin.response(id, true); identity.contact / identity.join → steer the People view to access.uid, answer when the user is done. Unknown kinds → show, decline with a message.