import { Hono } from "hono"; import { E2EE_PROTOCOL_VERSION } from "../../e2ee/protocol"; import type { FeatureFlagSource } from "../../feature-flags"; import type { AppEnv } from "../app"; import type { ApiDeps } from "../types/api-deps"; /** * Ceiling on any JSON body `readJsonBody` accepts, enforced as bytes arrive * rather than after the whole request is buffered. * * Shared by all three callers (push register, push unregister, client-log) * rather than a per-route bound: none of them legitimately posts more than a * few KB, so one ceiling well above any real payload — and far below what * would pressure memory — covers all three. A release-build client shipping * this is the reason it's needed at all: a dev build behind Metro never sent * enough to matter. */ export declare const MAX_JSON_BODY_BYTES: number; /** * What push this server can actually deliver. * * Reported on `GET /api/info` and `GET /api/push/health` so a client can hide an * affordance the server can never honour instead of registering tokens nothing * will ever send to. It cannot be inferred from `/api/push/health`'s `available`, * which reports whether the SQLite token store opened — that is `true` on a * server holding no APNs credentials at all. */ export interface PushCapability { /** * Live Activity (ActivityKit) push. True only when APNs credentials resolved * *and* the sender was wired, so it is the same fact the boot log reports as * `live_activity.enabled` / `live_activity.disabled`. */ liveActivity: boolean; /** * Ordinary "your turn" notifications over Expo's relay (`WaitingInputNotifier`). * True when the notifier was wired, which needs only the push token store: * Expo holds the app's credentials, so no APNs key or env var is involved. * Independent of `liveActivity` — neither implies the other. */ notifications: boolean; /** * The server stores and enforces per-device notification preferences * (`PATCH /api/push/preferences`, `POST /api/push/test`). Absent on an older * server, which is how a client tells "not supported" from "turned off". */ preferences: boolean; /** Why `liveActivity` is false; absent when it is true. Names env vars, never values. */ liveActivityReason?: string; /** Why `notifications` is false; absent when it is true. */ notificationsReason?: string; } /** * Describe push capability for a client. * * `wired` is the server's own wiring state rather than a re-read of the * environment: credentials alone are not enough, since each notifier is only * built when the push token store opened too. */ export declare function describePushCapability(wired: { liveActivity: boolean; notifications: boolean; }, env?: NodeJS.ProcessEnv): PushCapability; /** * Envelope version this build speaks. The same number the pair QR carries as `v`. * * @deprecated Re-exported from `src/e2ee/protocol.ts`, which is the canonical * home: the record layer needs this constant and a crypto module importing a * Hono route module would invert the dependency direction (NONCE-DESIGN §4). * The name stays here because released call sites and tests import it from this * module. */ export { E2EE_PROTOCOL_VERSION }; /** * Whether a client should encrypt to this server, and why not when it should not. * * The contract is `push`'s: additive, and **absent means "older server, * unknown"** rather than "unsupported". A client reads `enabled` to decide * whether to attempt a handshake — never `supported` alone, which only says the * code path exists. * * `required` is the stage-3 bit (refuse plaintext from *any* client) and is * false until that is an explicit product decision. It is reported rather than * omitted because an absent field means "unknown", and "unknown" is the wrong * answer to a question this server can answer. */ export interface E2eeCapability { supported: boolean; enabled: boolean; version: number; required: boolean; /** * This build accepts the WebSocket ticket as a `tb-ticket.` * subprotocol offer and selects `threadbase-e2ee-v1`, which is the only way a * browser can present one. A property of the build, like `supported`. Absent * means an older server that only reads `X-TB-Ticket`: a browser client must * refuse encrypted pairing there rather than fall back to plaintext. */ wsTicketSubprotocol: boolean; /** Why `enabled` is false while `supported` is true; absent otherwise. */ reason?: string; } export declare function describeE2eeCapability(flagEnabled: boolean, /** * Which rung of the precedence chain decided the flag, when the caller knows * it. An operator who typed `--no-e2ee` and reads "set --feature e2ee=true" * has been answered with the wrong question; naming the rung that actually * decided is the difference between a reason and a template. */ flagSource?: FeatureFlagSource): E2eeCapability; /** * The switch that turned encryption off, in the operator's own terms — the * thing they typed or set, never the resolver's rung name. Shared by the boot * warning and `/api/info` so the two never describe one switch two ways. * * `cli` covers both spellings of one switch — `--no-e2ee` and * `--feature e2ee=false` land on the same rung. `override` is unreachable for * `e2ee` today (the only override rung is `codexSystemPromptEnabled`) but the * type demands an answer, and this one is at least true. */ export declare const E2EE_OFF_SWITCH: Record, string>; /** * This server's identity public key, or `undefined` when the key file cannot be * read — which `JSON.stringify` renders as an absent field, exactly what the * `/api/info` contract says absent means. * * Deliberately different from the CLI's answer to the same failure. `/api/info` * is how a client discovers capabilities and renders its server list, so a * corrupt key file must cost verification and nothing else; turning it into a * 500 would take down the whole endpoint over a file unrelated to the rest of * the response. The pair banner throws instead, because a QR that cannot carry * `spk` is a QR worth refusing to print — and `serve` already degrades that * into a warn plus a QR-less banner (`cli/index.ts`). */ export declare function describeServerIdentityKey(): string | undefined; /** * Requests per window this endpoint accepts per authenticated caller. A log * sink, not a handshake, so it's generous: legitimate batching (mobile * shipping slow-request timings) lands well under one request per second. * 120/min gives 2x headroom over "a batch every second" before refusing. */ export declare const CLIENT_LOG_RATE_LIMIT = 120; export declare const CLIENT_LOG_RATE_WINDOW_MS = 60000; /** Entries beyond this in one batch are dropped, not logged. */ export declare const MAX_CLIENT_LOG_ENTRIES = 200; export declare const createMiscRoutes: (deps: Pick) => Hono; //# sourceMappingURL=misc.routes.d.ts.map