Skip to content

Runner

entrypoints/patreon.content.ts operates on *://*.patreon.com/*. It is the only component that calls Patreon. It does nothing until it receives a message from the service worker. Thus the extension adds no requests when the user reads Patreon.

  • All calls to fetch() are here, with credentials: 'include'. The calls must not move to the service worker. A context in the extension origin does not reliably send the session cookies of a different origin.
  • The runner normalizes the data before it replies (lib/patreon/normalize.ts). It finds each entity in included by type and id, connects the entities to their relationships, and makes the entity graph in lib/patreon/types.ts. The service worker never sees the JSON:API data.
  • The runner classifies each failure. classify() changes the HTTP result into a code that the panel can explain. HTTP 401 becomes signed-out. HTTP 429 becomes rate-limited, and the runner also sends the Retry-After header. A body that is not JSON becomes challenge. HTTP 403 becomes forbidden. HTTP 400 becomes api-shape.
  • The runner gets one page at a time. Each page has 20 posts (POSTS_PAGE_SIZE). Gopher gets the next page only when the user comes to the end of the list. Gopher never reads the full history of a creator automatically. See request limits.
  • The runner can use a smaller query. The full include list is verified against the live API. If Patreon refuses it with HTTP 400, the runner sends the query again without include. The API then sends its default includes. The service worker keeps this decision in browser.storage.session. Post attributes also contain media URLs, thus the smaller query still shows images, text, and embedded players.
  • The runner replies but does not write. It sends the normalized data in a message. It never writes the cache.

Read the data layer for the endpoints the runner calls and the shape of the answers it normalizes.