Files
kiosk/manifest.ts
T
Claude Opus 5 ed9bf828f8 oas plugin: manifest and schema
the schema is deliberately over-specified. there are no migrations - install
generates and creates, swallowing 'already exists', so a column added in v2 is
silently absent on every machine that installed v1. email survived that only
because its table had never held a row; oas_builds holds real rows from the
first publish.

legal values are CHECK constraints rather than free text, per the house rule:
platform, signing, device kind and status. oneOf() uses sql.raw because an
interpolated value binds as a parameter and postgres refuses IN ($1, $2).

two decisions worth naming:

version is TEXT despite being numeric. it is an identifier, it appears in a
path, and 2026081801 is already at the edge of a 32-bit int. fixed width means
lexicographic sort is correct.

oas_user_keys stores the key twice - a hash to check against, and an encrypted
copy because the mobile app must READ the key back to build an install URL. the
platform's own api_keys needs no such thing because nothing re-displays them.

udid is uniquely indexed only WHERE NOT NULL: many rows sit pending without one,
but a captured identifier is one physical device and must not be claimable twice.
2026-08-18 01:16:07 +00:00

33 lines
1.3 KiB
TypeScript

import type { PluginManifest } from '@@/plugins/manifest';
// OAS — Officer Application Services. Build, sign and deliver iOS and Android apps to registered
// devices: what EAS does, self-hosted.
//
// Ported from the standalone Bun/Hono service in `officer-oas/`, whose access control was an invite key
// held in a browser's local storage. The rule we actually want is "the people already registered on the
// platform", which is the thing the platform already knows how to enforce — so the key stops being
// something a person holds and becomes something an account has.
//
// `appName` is the directory name: `oas`.
export const manifest: PluginManifest = {
publisher: 'officerdev',
version: '1.0.0',
platform: '>=1.0.0',
label: 'OAS',
summary: 'Build, sign and install iOS and Android apps on your own devices',
icon: 'Smartphone',
color: '#a78bfa',
// One permission over the whole surface, which is also all the platform offers: the first entry
// claims the plugin's entire route surface. Owner-only actions (publishing, retention, other people's
// devices) are enforced inside the router with `isSuperAdmin`, not by a second permission.
permissions: [
{
key: 'oas',
label: 'App install',
description: 'Install Officer apps on your own devices',
},
],
};