{"id":48115155,"url":"https://github.com/flo-bit/contrail","last_synced_at":"2026-06-07T21:00:44.348Z","repository":{"id":345127502,"uuid":"1184302876","full_name":"flo-bit/contrail","owner":"flo-bit","description":"atproto backend in a bottle","archived":false,"fork":false,"pushed_at":"2026-05-28T03:42:15.000Z","size":1771,"stargazers_count":46,"open_issues_count":8,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-05-31T21:09:13.638Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://flo-bit.dev/contrail/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flo-bit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-17T13:07:50.000Z","updated_at":"2026-05-29T14:16:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"799059b3-3402-4d25-9d75-898336b7cb3e","html_url":"https://github.com/flo-bit/contrail","commit_stats":null,"previous_names":["flo-bit/contrail"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/flo-bit/contrail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flo-bit%2Fcontrail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flo-bit%2Fcontrail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flo-bit%2Fcontrail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flo-bit%2Fcontrail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flo-bit","download_url":"https://codeload.github.com/flo-bit/contrail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flo-bit%2Fcontrail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34037777,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-07T02:00:07.652Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T16:14:50.468Z","updated_at":"2026-06-07T21:00:44.324Z","avatar_url":"https://github.com/flo-bit.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Contrail\n\n\u003e **pre-alpha.** Expect breaking changes.\n\na library for easily creating (serverless) atproto backends/appviews.\n\n- declare collections\n- get automatic jetstream backfill and ingestion, typed XRPC endpoints\n- optional: permissioned spaces and group-controlled communities\n\nmostly tested on cloudflare workers with d1 but should run in any node env too \n(+ has adapters for node:sqlite and postgres for the db).\n\n## Install\n\n```bash\npnpm add @atmo-dev/contrail\n```\n\n## Minimal example\n\na complete cloudflare worker that indexes public calendar events from the atproto network and serves them over a typed XRPC endpoint. two files + config. a runnable version lives in [`apps/cloudflare-workers`](https://github.com/flo-bit/contrail/tree/main/apps/cloudflare-workers) — clone, deploy, `pnpm contrail backfill --remote`, done.\n\n**`src/contrail.config.ts`** — picked up automatically by the `contrail` CLI:\n\n```ts\nimport type { ContrailConfig } from \"@atmo-dev/contrail\";\n\nexport const config: ContrailConfig = {\n  namespace: \"com.example\",\n  collections: {\n    event: {\n      collection: \"community.lexicon.calendar.event\", // NSID to index\n      queryable: { startsAt: { type: \"range\" } },     // ?startsAtMin=...\n      searchable: [\"name\", \"description\"],            // ?search=...\n    },\n  },\n};\n```\n\n**`src/worker.ts`** — four lines. `createWorker` wires up fetch + scheduled + lazy init:\n\n```ts\nimport { createWorker } from \"@atmo-dev/contrail/worker\";\nimport { config } from \"./contrail.config\";\nimport { lexicons } from \"../lexicons/generated\";\n\nexport default createWorker(config, { lexicons });\n```\n\n`lexicons/generated/` is produced by `contrail-lex generate`; passing `{ lexicons }` exposes them at `/lexicons` so consumer apps can typegen against your deployed service. Drop it if you don't need that.\n\nand a d1 binding + cron in `wrangler.jsonc`:\n\n```jsonc\n{\n  \"main\": \"src/worker.ts\",\n  \"d1_databases\": [{ \"binding\": \"DB\", \"database_name\": \"contrail\", \"database_id\": \"...\" }],\n  \"triggers\": { \"crons\": [\"*/1 * * * *\"] }\n}\n```\n\nthen:\n\n```bash\nnpx wrangler d1 create contrail   # copy the id into wrangler.jsonc\npnpm wrangler deploy              # deploy the worker\npnpm contrail backfill --remote   # one-shot historical backfill\n```\n\nthe worker keeps itself fresh from now on via the cron. hit:\n\n```\nGET https://\u003cyour-worker\u003e.workers.dev/xrpc/com.example.event.listRecords?startsAtMin=2026-01-01\u0026limit=10\n```\n\nreturns every `community.lexicon.calendar.event` record published anywhere on atproto that matches, as JSON. that's it — no PDS setup, no lexicon publishing, no relay configuration. everything scales from there: add filters, add full-text search, add more collections, turn on [spaces](https://github.com/flo-bit/contrail/blob/main/docs/06-spaces.md) for private records, mount the handler in sveltekit instead, swap the adapter for postgres.\n\n**not using workers?** same library, different `db`. see [adapters](https://github.com/flo-bit/contrail/blob/main/docs/01-indexing.md#adapters) for node:sqlite and postgres.\n\n## Docs\n\n- [Indexing](https://github.com/flo-bit/contrail/blob/main/docs/01-indexing.md) — the core: collections, ingestion, adapters\n- [Querying](https://github.com/flo-bit/contrail/blob/main/docs/02-querying.md) — filters, sorts, hydration, search, pagination\n- [Lexicons](https://github.com/flo-bit/contrail/blob/main/docs/03-lexicons.md) — `contrail-lex` CLI, codegen, publishing\n- [Feeds](https://github.com/flo-bit/contrail/blob/main/docs/04-feeds.md) — personalized timelines via follow + target collections\n- [Auth](https://github.com/flo-bit/contrail/blob/main/docs/05-auth.md) — service-auth JWTs, invite tokens, watch tickets, OAuth permission sets\n- [Spaces](https://github.com/flo-bit/contrail/blob/main/docs/06-spaces.md) — permissioned records stored by the appview\n- [Communities](https://github.com/flo-bit/contrail/blob/main/docs/07-communities.md) — group-controlled atproto DIDs\n- [Sync](https://github.com/flo-bit/contrail/blob/main/docs/08-sync.md) — reactive client-side store over `watchRecords`\n- [Labels](https://github.com/flo-bit/contrail/blob/main/docs/09-labels.md) — atproto-native moderation hydration from external labelers\n- [Deployment shapes](https://github.com/flo-bit/contrail/blob/main/docs/10-deployment-shapes.md) — all-in-one vs split-authority vs split-host configurations\n- Frameworks: [SvelteKit + Cloudflare](https://github.com/flo-bit/contrail/blob/main/docs/frameworks/sveltekit-cloudflare.md)\n\n## Packages\n\n| Package | |\n|---|---|\n| `@atmo-dev/contrail` | Core library — indexing, XRPC server, spaces, realtime |\n| `@atmo-dev/contrail-community` | Community module — group-controlled DIDs, access-level ladder. Plugs into core via an integration |\n| `@atmo-dev/contrail-sync` | Client-side reactive watch-store with optional IndexedDB cache |\n| `@atmo-dev/contrail-lexicons` | Codegen + `contrail-lex` CLI |\n\nWorking in this repo? See [development.md](https://github.com/flo-bit/contrail/blob/main/development.md) for the monorepo layout and commands.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflo-bit%2Fcontrail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflo-bit%2Fcontrail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflo-bit%2Fcontrail/lists"}