feat(service): the Mac's commands are sealed for following over Neon Realtime, claimed by id

Merged
CH
10d ago
+551-13

Stack 4 · Mac commands, on #4228 (luke/live-same-user). The service side of following the Mac's commands through the live layer: Neon Realtime where LUKE_REALTIME=on, and the held poll (#4272) everywhere else. It replaces the always-on held read of GET /api/mac-commands.

The held read does three jobs: it marks the Mac as listening, waits for commands, and claims them. A live read writes nothing, so each job gets its own procedure, on #4273's kinds:

  • live.macCommands (GET /api/live/mac-commands?kinds=): the commands of the named kinds that no Mac of the account has claimed, as one statement (macCommandsLiveStatement: user_id = $1 AND kind IN (…) AND claimed_at IS NULL, no clock window). It goes through sealedParts and is checked by sameUser like every live read. The reader sorts the rows (macCommandsOfLiveRows, earliest queued first, a shell row's text or a browser row's params).
  • macCommands.claim (POST /api/mac-commands/claim {id}): claims one command by id. The CLAIM_WINDOW is enforced here, on the service's clock. It answers with the command or not-found. Bearer only.
  • macCommands.listening (POST /api/mac-commands/listening {kinds}): markMacListening for the named kinds. Bearer only.

The held GET /api/mac-commands and the result routes are unchanged for released desktops.

Tests:

  • mac-command-store.test.ts: the live statement delivers only the account's own commands of the named kinds, and a claim by id takes a command once, for its own account, inside the window.
  • mac-commands-procedures.test.ts: claim and listening, byte for byte. A cookie is refused.
  • live-procedures.test.ts: the read is sealed for the bearer and the named kinds, and a read naming another account gets 401.
  • live-statements.test.ts: mac.commands calls only immutable functions, and Neon's drizzleAdapter seals it.
  • mac-command-client.test.ts: live names the kinds and the user (a 401 means signed out), and claim.

Checked piece by piece: tsc for features, service and database; vitest over features, service live, mac-commands and the store; knip; oxlint.