Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

149 lines
5.5 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "emdash-aggregator",
"main": "./src/index.ts",
"compatibility_date": "2026-02-24",
"compatibility_flags": ["nodejs_compat"],
// Production routes are configured at deploy time. The CDN
// (`cdn.emdashcms.com`) is a separate Worker that we'll add later
// alongside R2. Local development (`wrangler dev`) doesn't need a route
// binding.
"d1_databases": [
{
"binding": "DB",
"database_name": "emdash-aggregator",
// `database_id` intentionally omitted — wrangler auto-provisions
// the D1 instance on first deploy. A placeholder ID would make
// wrangler think the binding is already configured and skip
// provisioning.
"migrations_dir": "./migrations",
},
],
"queues": {
"producers": [
{
"binding": "RECORDS_QUEUE",
"queue": "emdash-aggregator-records",
},
{
// Backfill orchestrator (POST /_admin/backfill) fans
// (DID, collection) pairs onto this queue. Per-pair work
// (resolve PDS → listRecords → sendBatch onto RECORDS_QUEUE)
// fits well within a single consumer invocation's waitUntil,
// solving the 30s wall-clock cap that would otherwise limit
// us to ~1525 DIDs per backfill POST.
"binding": "BACKFILL_QUEUE",
"queue": "emdash-aggregator-backfill",
},
],
"consumers": [
{
"queue": "emdash-aggregator-records",
"max_batch_size": 25,
"max_batch_timeout": 5,
"max_retries": 5,
"dead_letter_queue": "emdash-aggregator-records-dlq",
},
{
// Drains the DLQ. Today the consumer logs each dead-lettered
// job to Workers logs and writes a `dead_letters` row, then
// acks. On D1 failure the handler calls `message.retry()`
// (configured `max_retries: 3` per below); after that, the
// DLQ has no DLQ-of-DLQ so workerd drops the message. Once
// the reconciliation pass lands it'll replace this with
// retry-from-listRecords.
"queue": "emdash-aggregator-records-dlq",
"max_batch_size": 25,
"max_batch_timeout": 30,
"max_retries": 3,
},
{
// Backfill (DID, collection) consumer. Each job: resolve
// PDS, paginate listRecords for one collection, batch
// results onto RECORDS_QUEUE. `max_batch_size: 1` so each
// pair gets its own consumer invocation — listRecords can
// chain ~15s per page × `MAX_PAGES_PER_COLLECTION`, so
// batching multiple pairs per invocation risks blowing
// the consumer wall-clock budget. Throughput is fine
// because backfill is operator-triggered, not steady-state.
"queue": "emdash-aggregator-backfill",
"max_batch_size": 1,
"max_batch_timeout": 5,
"max_retries": 3,
"dead_letter_queue": "emdash-aggregator-backfill-dlq",
},
{
// Drains the backfill DLQ. Logs each dead-lettered pair
// loud enough that operators tailing logs see it, then
// acks so the DLQ doesn't accumulate unbounded. We don't
// write a forensics row to D1 here (no `backfill_dead_letters`
// table) because the operator's recovery action is
// "re-trigger backfill for the affected DID" — they don't
// need the per-pair payload, just the (did, collection)
// pair, which is on the log line.
"queue": "emdash-aggregator-backfill-dlq",
"max_batch_size": 25,
"max_batch_timeout": 30,
"max_retries": 3,
},
],
},
"durable_objects": {
"bindings": [
{
"name": "RECORDS_DO",
"class_name": "RecordsJetstreamDO",
},
],
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["RecordsJetstreamDO"],
},
],
"triggers": {
// Liveness ping for the records DO. The DO holds Jetstream open and
// stays alive while the WebSocket is up, but during a Jetstream
// outage it spends time in backoff sleeps with no active connection
// — that's when CF can evict it. The 5-minute cron wakes it back up
// quickly; constructor-time `ingestor.run()` resumes from the
// persisted cursor. Reconciliation work will share this trigger when
// it lands.
"crons": ["*/5 * * * *"],
},
"vars": {
"NODE_OPTIONS": "--max-old-space-size=6144",
// Jetstream endpoint. Override per environment for self-hosted relays
// or staging backends.
"JETSTREAM_URL": "wss://jetstream2.us-east.bsky.network/subscribe",
// Relay base URL implementing `com.atproto.sync.listReposByCollection`,
// used by `/_admin/backfill` to enumerate publishers of our NSIDs at
// cold-start time. Defaults to Bluesky's main relay (the canonical
// atproto relay; same trust orbit as our Jetstream endpoint).
// Override for self-hosted indexers (e.g. Microcosm's Lightrail)
// if/when we want a non-bsky.network discovery path.
"RELAY_URL": "https://bsky.network",
},
// Required secrets, declared in config so `wrangler types` generates the
// typed binding and `wrangler deploy` validates the secret is set on the
// target Worker before publishing. `wrangler dev` warns at startup when a
// required secret isn't in `.env`.
//
// Set in production with `wrangler secret put ADMIN_TOKEN`. Tests bind
// a stub via miniflare in vitest.config.ts. Local dev pulls from
// `.env` (gitignored; see `.env.example`).
//
// The `requireAdminAuth` runtime guard fails closed (503) if the binding
// is somehow empty at request time, so even a misconfigured deploy can't
// leave the admin routes unauth-passable. NOTE: this `secrets` block is
// not inherited by named environments — repeat it under each `env.<name>`
// you add or that env's deploys won't enforce the secret.
"secrets": {
"required": ["ADMIN_TOKEN"],
},
"observability": {
"enabled": true,
},
}