pastilhas 464e2ddf6e say what this plugin is for, in the store's words
tags are how the marketplace is browsed rather than scrolled: a list of them on
the left, the plugins that carry one on the right. a closed vocabulary
(PLUGIN_TAGS in the platform) because free text becomes homelab, home-lab, Home
Lab and selfhosted inside a month, and a filter list of synonyms is worse than
no filter at all.

declared here rather than curated in the catalogue, so a plugin can say what it
is and nobody edits a table when one ships. the marketplace caches it on sync,
exactly as it already does for label and summary.
2026-08-27 06:49:33 +00:00
2026-08-19 06:51:04 +01:00
2026-08-18 01:16:07 +00:00

Kiosk

Build, sign and install Officer's iOS and Android apps on your own registered devices. What EAS does, self-hosted.

  • A catalogue of builds, newest per app per platform, with an Install button that hands itms-services:// to iOS or a plain URL to Android.
  • A per-user key that authorises artefact downloads. Held in memory by the app and re-read on demand, so rotating one costs nothing.
  • Device records — who owns which iPhone or iPad, and whether Apple knows about it yet.

Status — read before installing

Nothing here has run. Ported on 2026-08-18 from the standalone service that was called OAS. The authenticated API and the two panels exist and typecheck; no endpoint has answered a request.

What works, in principle

GET /apps, GET /apps/:appName, GET /key, POST /key/rotate, GET /install/:appName/:platform/:version, POST /installs, and the device and build verbs. All under /api/kiosk, all requiring a platform session.

What is missing, and why

Installing will not work yet. Four requests in the flow arrive with no session — iOS installd fetching the manifest and the .ipa, the device posting its UDID, and Safari downloading a .mobileconfig — and a plugin cannot serve an unauthenticated route today. UNPROTECTED_API_PREFIXES is hardcoded in the platform and plugin routers mount only behind the account gate.

So GET /install/... returns a correct-looking URL pointing at a route that does not exist. That is deliberate: the URL shape is what the mobile app builds against, and it stops being a dead end the day the platform gains unauthenticatedPaths. Those routes then land in api/public.ts, kept separate from api/router.ts so the two surfaces cannot be confused by anyone reading either.

Enrolment is not ported for the same reason — it is entirely public routes.

Artefacts arrive by rsync, into $OFFICER_ROOT/data/kiosk/. The plugin records metadata about files already on disk; it does not accept uploads, because the platform's shared upload route caps at 5MB and no .ipa will ever satisfy that.

Notes

  • PUBLIC_URL must be HTTPS with a certificate iOS already trusts. It fetches the manifest and binary itself and declines silently otherwise, which looks exactly like a broken build.
  • Table names are prefixed kiosk_. There are no migrations — see the note at the top of db/schema.ts.
  • The plugin is currently appName: kiosk. If the plugin storefront takes that name, this one is renamed; see docs/kiosk-ecosystem.md in the platform.
S
Description
Officer Kiosk — build, sign and install iOS and Android apps on your own devices
Readme
2.2 MiB
Languages
TypeScript 100%