Gateway: status route with per-route results, test push, reconnect and unpair
This commit is contained in:
1 parent
e6fd2b8f51
commit
9707daf1fe
9 files changed
+398
-55
No files matched your search
+54
-2
@@ -11,19 +11,25 @@ import type {
|
||||
ProjectsResponse,
|
||||
PushRegistration,
|
||||
RespondRequest,
|
||||
PushResult,
|
||||
SendMessageRequest,
|
||||
StatusResponse,
|
||||
} from "./contract.ts";
|
||||
import type { Db, DeviceRow } from "./db.ts";
|
||||
import type { Hub } from "./hub.ts";
|
||||
import type { Pusher } from "./push.ts";
|
||||
import { HostError, type T3Host } from "./t3/host.ts";
|
||||
import { RpcError } from "./t3/rpc.ts";
|
||||
import type { ApprovalDecision, ModelSelection, ThreadShell } from "./t3/types.ts";
|
||||
import { buildFeed, buildSummary, buildThreadDetail, hostSummary, type SummaryCache } from "./views.ts";
|
||||
import { buildFeed, buildSummary, buildThreadDetail, hostStatusDetail, hostSummary, type SummaryCache } from "./views.ts";
|
||||
|
||||
export interface ApiDeps {
|
||||
db: Db;
|
||||
hub: Hub;
|
||||
cache: SummaryCache;
|
||||
pusher: Pusher;
|
||||
/** When the gateway started, for the status screen. */
|
||||
startedAt: string;
|
||||
log?: (message: string) => void;
|
||||
}
|
||||
|
||||
@@ -50,7 +56,7 @@ class HttpError extends Error {
|
||||
const json = (body: unknown, status = 200) => Response.json(body, { status });
|
||||
const accepted = () => new Response(null, { status: 202 });
|
||||
|
||||
export function createRoutes({ db, hub, cache, log = () => {} }: ApiDeps) {
|
||||
export function createRoutes({ db, hub, cache, pusher, startedAt, log = () => {} }: ApiDeps) {
|
||||
let pairFailures: number[] = [];
|
||||
|
||||
/** Wraps a handler with device auth and error mapping. */
|
||||
@@ -131,6 +137,52 @@ export function createRoutes({ db, hub, cache, log = () => {} }: ApiDeps) {
|
||||
}),
|
||||
},
|
||||
|
||||
"/v1/device": {
|
||||
/** Unpairs the watch asking. */
|
||||
DELETE: authed<"/v1/device">((_req, device) => {
|
||||
db.devices.revoke(device.id);
|
||||
log(`unpaired device ${device.name} (${device.id})`);
|
||||
return new Response(null, { status: 204 });
|
||||
}),
|
||||
},
|
||||
|
||||
"/v1/device/test-push": {
|
||||
POST: authed<"/v1/device/test-push">(async (_req, device) =>
|
||||
json(
|
||||
(await pusher.sendTo(device, {
|
||||
title: "WristCode",
|
||||
body: "Test notification. Pushes reach this watch.",
|
||||
category: "test",
|
||||
data: {},
|
||||
collapseId: "test",
|
||||
})) satisfies PushResult,
|
||||
),
|
||||
),
|
||||
},
|
||||
|
||||
"/v1/status": {
|
||||
GET: authed((_req, device) => {
|
||||
const expiries = new Map(hub.rows().map((row) => [row.id, row.token_expires_at]));
|
||||
return json({
|
||||
hosts: hub.list().map((host) => hostStatusDetail(host, expiries.get(host.id) ?? null)),
|
||||
gateway: { startedAt, pushConfigured: pusher.configured, lastPush: pusher.last },
|
||||
device: {
|
||||
name: device.name,
|
||||
pairedAt: device.created_at,
|
||||
pushRegistered: device.apns_token !== null,
|
||||
apnsEnvironment: device.apns_env,
|
||||
},
|
||||
} satisfies StatusResponse);
|
||||
}),
|
||||
},
|
||||
|
||||
"/v1/hosts/:hostId/reconnect": {
|
||||
POST: authed<"/v1/hosts/:hostId/reconnect">((req) => {
|
||||
findHost(req.params.hostId).reconnect();
|
||||
return accepted();
|
||||
}),
|
||||
},
|
||||
|
||||
"/v1/feed": {
|
||||
GET: authed(async () => json(await buildFeed(hub.list(), cache))),
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user