Skip to content

Cap the cost of history.watch #214

Description

@HMarzban

Problem

Among the history read ops, only history.list is gated. The cooldown check tests the list type alone (apps/hocuspocus.server/src/hocuspocus.server.ts:297), through listCoolingDown (apps/hocuspocus.server/src/hocuspocus.server.ts:116). history.revert carries its own separate cooldown (apps/hocuspocus.server/src/hocuspocus.server.ts:151).

history.watch has no cap at all. Each call reads one row and base64-encodes the whole document (apps/hocuspocus.server/src/lib/history-stateless.ts:147-155, encoder at apps/hocuspocus.server/src/lib/history-stateless.ts:90).

That encode is synchronous work on the shared process event loop. The Throttle extension only covers onConnect, so no per-frame cap stands behind it (apps/hocuspocus.server/src/hocuspocus.server.ts:91). A client that loops over versions therefore pays no cost cap.

What to do

Add a cost cap to the watch arm. Shape it as a bytes-per-connection budget, not as a cooldown.

Keep the recorded decision at apps/hocuspocus.server/src/hocuspocus.server.ts:293-296. A cooldown on watch would walk the client through its own list, because the client answers a refusal by asking for the next version. Do not re-propose one.

Acceptance

  • A client that requests every version in a tight loop is refused once its budget is spent.
  • A single normal watch still returns the snapshot.

Notes

The cost of one watch encode is not measured. Size the budget against a real document before you pick a number.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions