Skip to content

Worker Factory & Member API

createApp() (src/api/index.ts) is the factory that assembles the OpenAPIHono app — middleware chain, route registration, error envelope — and is reused everywhere the API runs: the Worker entry (src/worker.ts) and the test harness (tests/helpers/test-worker.ts) both build the app from the same factory, so tests exercise the real middleware/route wiring. See Worker API & Clerk Auth for the chain.

The same factory feeds production and tests, and registers the membership routes that back list sharing:

flowchart LR
  W["src/worker.ts"] --> APP["createApp()<br/>src/api/index.ts"]
  T["tests/helpers/test-worker.ts"] --> APP
  APP --> LM["registerListMembersRoutes<br/>src/api/routes/list-members.ts"]
  LM --> REPO["createListMembersRepository<br/>src/db/repositories/list-members.ts"]
  REPO --> D1[("D1: listMembers")]
  LM --> NM["notifyMembership()<br/>src/api/lib/notify.ts"]
  SS["ShareSurface.tsx<br/>island"] -->|"add / remove member"| LM

List sharing is the membership surface (src/api/routes/list-members.ts, registerListMembersRoutes) backed by createListMembersRepository (src/db/repositories/list-members.ts):

  • Add/remove Members of a List — owner-only; a List can only be shared with registered Users (Product Brief §5.2).
  • Membership changes drive notifyMembership(...) (signals the list’s users and the affected user) and, on removal, client-side evictRevoked(...) (see DB Schema & Notify-Affected, Sync-Core Reconcilers).
  • The ShareSurface.tsx island is the client UI for managing Members.
  • Assignment (spec 012) is membership-dependent: a Task may be assigned only to a Member; removing a Member clears their assignments.

A member removal commits to D1, then fans a signal to both the list’s users and the removed user so their client evicts the revoked list:

sequenceDiagram
  participant Owner
  participant LM as "registerListMembersRoutes"
  participant Repo as "listMembersRepository"
  participant D1 as "D1: listMembers"
  participant Notify as "notifyMembership()"
  Owner->>LM: DELETE member (owner-only)
  LM->>Repo: remove(listId, userId, now)
  Repo->>D1: soft-delete membership row
  D1-->>Repo: ok
  LM->>Notify: notifyMembership(c, listId, removedUserId)
  Notify-->>Owner: 2xx (fan-out off response path)
  Note over Notify: signals list users + removed user<br/>client evictRevoked drops the list

Related: Worker API & Clerk Auth, Idempotency & List-Members Repos, Group & List Context Menus (the share entry point).