Files
technitium-console/hub/routes.ts
T
DenozordecandClaude Opus 5.5 6acd2d656d Hub stage 2: install, update and uninstall apps on several servers
Writes use only <ID>_ADMIN_TOKEN and need the apps.write capability.
Store URLs are resolved from each server's own listing. The config is saved
to history before an uninstall. Zip uploads are fanned out to the servers.
Every target's result is audited. The console gets a row menu on the
matrix, a target picker, a results dialog with Retry failed, the store and
install from file in All servers mode, and single-server actions for writers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 16:11:40 +07:00

51 lines
1.9 KiB
TypeScript

/*
What each `/api/<path>` does and who may call it. `kind` says what it touches:
`read` (no change), `write-one` (changes one server) and `write-all` (changes every server).
A path that is not listed is refused. The app writes need `apps.write`.
Not in the table: `status`, `user/login`, `user/session/get` and `user/logout`, which the
server answers itself before the table is consulted.
*/
import type { Capability } from './users.ts'
export type RouteKind = 'read' | 'write-one' | 'write-all'
export interface Route {
kind: RouteKind
capability: Capability
}
const read = (capability: Capability = 'read'): Route => ({ kind: 'read', capability })
const writeOne = (capability: Capability): Route => ({ kind: 'write-one', capability })
const writeAll = (capability: Capability): Route => ({ kind: 'write-all', capability })
export const ROUTES: Record<string, Route> = {
'dashboard/stats/get': read(),
'dashboard/stats/getTop': read(),
'dashboard/metrics/json': read(),
'apps/list': read(),
'logs/query': read(),
'logs/list': read(),
'settings/get': read(),
'user/checkForUpdate': read(),
'admin/cluster/state': read(),
// The hub's own namespace; never forwarded to a server.
'hub/audit/list': read('audit.read'),
'hub/apps/matrix': read(),
'apps/listStoreApps': read(),
// Writes. They go to a server's ADMIN token only; see apps-write.ts. apps/config/set waits for a later stage.
'apps/downloadAndInstall': writeOne('apps.write'),
'apps/downloadAndUpdate': writeOne('apps.write'),
'apps/uninstall': writeOne('apps.write'),
'apps/install': writeOne('apps.write'),
'apps/update': writeOne('apps.write'),
'hub/apps/run': writeAll('apps.write'),
'hub/apps/upload': writeAll('apps.write'),
}
export function routeFor(apiPath: string): Route | undefined {
return Object.hasOwn(ROUTES, apiPath) ? ROUTES[apiPath] : undefined
}
export const isHubPath = (apiPath: string): boolean => apiPath.startsWith('hub/')