From 5a238661f2c8e73ac875be094c716e311ad670c5 Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:27:57 +0200 Subject: [PATCH] bump packages --- .changeset/config.json | 12 ++- .changeset/spaces-host-authority-split.md | 101 ------------------ packages/contrail-appview/CHANGELOG.md | 9 ++ packages/contrail-appview/package.json | 2 +- packages/contrail-authority/CHANGELOG.md | 7 ++ packages/contrail-authority/package.json | 2 +- packages/contrail-base/CHANGELOG.md | 3 + packages/contrail-base/package.json | 2 +- packages/contrail-community/CHANGELOG.md | 109 +++++++++++++++++++ packages/contrail-community/package.json | 2 +- packages/contrail-record-host/CHANGELOG.md | 7 ++ packages/contrail-record-host/package.json | 2 +- packages/contrail/CHANGELOG.md | 115 +++++++++++++++++++-- packages/contrail/package.json | 2 +- packages/lexicons/CHANGELOG.md | 10 +- packages/lexicons/package.json | 2 +- packages/sync/CHANGELOG.md | 104 ++++++++++++++++++- packages/sync/package.json | 2 +- 18 files changed, 371 insertions(+), 122 deletions(-) delete mode 100644 .changeset/spaces-host-authority-split.md create mode 100644 packages/contrail-appview/CHANGELOG.md create mode 100644 packages/contrail-authority/CHANGELOG.md create mode 100644 packages/contrail-base/CHANGELOG.md create mode 100644 packages/contrail-community/CHANGELOG.md create mode 100644 packages/contrail-record-host/CHANGELOG.md diff --git a/.changeset/config.json b/.changeset/config.json index 745d87f..070c0d5 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -2,8 +2,16 @@ "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", "changelog": "@changesets/cli/changelog", "commit": false, - "fixed": [], - "linked": [["@atmo-dev/contrail", "@atmo-dev/contrail-sync", "@atmo-dev/contrail-community"]], + "fixed": [[ + "@atmo-dev/contrail", + "@atmo-dev/contrail-community", + "@atmo-dev/contrail-sync", + "@atmo-dev/contrail-base", + "@atmo-dev/contrail-authority", + "@atmo-dev/contrail-record-host", + "@atmo-dev/contrail-appview" + ]], + "linked": [], "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", diff --git a/.changeset/spaces-host-authority-split.md b/.changeset/spaces-host-authority-split.md deleted file mode 100644 index e14e46c..0000000 --- a/.changeset/spaces-host-authority-split.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -"@atmo-dev/contrail": minor -"@atmo-dev/contrail-community": minor -"@atmo-dev/contrail-sync": minor ---- - -Spaces refactor: split authority + record host into independently runnable -roles, add space credentials, extract community into its own package. - -**Breaking — config shape** - -`spaces` is no longer flat — split into `authority` and `recordHost`: - -```ts -// before -spaces: { - type: "com.example.event.space", - serviceDid: "did:web:example.com", - blobs: { adapter, maxSize }, -} - -// after -spaces: { - authority: { - type: "com.example.event.space", - serviceDid: "did:web:example.com", - signing: await generateAuthoritySigningKey(), - }, - recordHost: { - blobs: { adapter, maxSize }, - }, -} -``` - -**Breaking — community moved to its own package** - -Community has been extracted to `@atmo-dev/contrail-community`. Wire it via -`createCommunityIntegration`: - -```ts -import { Contrail, resolveConfig } from "@atmo-dev/contrail"; -import { createCommunityIntegration } from "@atmo-dev/contrail-community"; - -const resolved = resolveConfig(config); -const communityIntegration = createCommunityIntegration({ db, config: resolved }); -const contrail = new Contrail({ ...config, communityIntegration }); -``` - -The community config (`config.community`) stays the same; only the wiring -moves. Imports of `CommunityAdapter`, `registerCommunityRoutes`, -`reconcile`, etc. now come from `@atmo-dev/contrail-community` instead of -`@atmo-dev/contrail`. - -**New — space credentials (`X-Space-Credential`)** - -The space authority issues short-lived ES256 JWTs (default 2h TTL) via -`.space.getCredential` and `refreshCredential`. The record host accepts -them on read/write paths in lieu of per-request service-auth JWTs. Skips -DID-doc fetches and member checks; the credential's signature is the proof. - -Generate a signing key once at deploy time: - -```ts -import { generateAuthoritySigningKey } from "@atmo-dev/contrail"; -const signing = await generateAuthoritySigningKey(); -// Store the JWK; pass to spaces.authority.signing. -``` - -**New — binding resolution** - -Verifiers can resolve "which authority signs for this space?" from three -sources, in order: local enrollment table, PDS records at -`at:////`, DID-doc `#atproto_space_authority` service -entry, owner-self fallback. Lets user-owned DIDs authorize a third-party -authority via a normal PDS write — no DID-doc surgery. - -**New — independent deployments + enrollment** - -The authority and record host can run as separate processes/operators. -A new `.recordHost.enroll` endpoint lets owners (or authorities) -register a space onto a host. In-process deployments auto-enroll on -`createSpace`; nothing changes for single-instance setups. - -See `docs/10-deployment-shapes.md` for all-in-one / authority-only / -host-only configurations and when to choose each. - -**Migration** - -For most deployments running spaces today, the migration is: - -1. Update the config: split `spaces.{type, serviceDid, blobs}` into - `spaces.authority.{type, serviceDid}` and `spaces.recordHost.{blobs}`. -2. Generate and store an authority signing key - (`generateAuthoritySigningKey()`); add to `spaces.authority.signing`. -3. If using community: install `@atmo-dev/contrail-community`, build - `createCommunityIntegration({ db, config })`, pass via - `new Contrail({ communityIntegration })` (or `createApp({ community })`). - -Existing service-auth JWT clients keep working as a fallback path. -Migrate to space credentials when convenient — exchange a JWT for a -credential once via `getCredential`, then reuse it. diff --git a/packages/contrail-appview/CHANGELOG.md b/packages/contrail-appview/CHANGELOG.md new file mode 100644 index 0000000..cd18649 --- /dev/null +++ b/packages/contrail-appview/CHANGELOG.md @@ -0,0 +1,9 @@ +# @atmo-dev/contrail-appview + +## 0.7.0 + +### Patch Changes + +- @atmo-dev/contrail-base@0.7.0 +- @atmo-dev/contrail-authority@0.7.0 +- @atmo-dev/contrail-record-host@0.7.0 diff --git a/packages/contrail-appview/package.json b/packages/contrail-appview/package.json index c76172b..f2627dd 100644 --- a/packages/contrail-appview/package.json +++ b/packages/contrail-appview/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail-appview", - "version": "0.6.0", + "version": "0.7.0", "description": "Public-records appview for contrail — jetstream ingestion, backfill, query layer, feeds, labels, profiles, per-collection XRPC routes.", "type": "module", "sideEffects": false, diff --git a/packages/contrail-authority/CHANGELOG.md b/packages/contrail-authority/CHANGELOG.md new file mode 100644 index 0000000..de82f64 --- /dev/null +++ b/packages/contrail-authority/CHANGELOG.md @@ -0,0 +1,7 @@ +# @atmo-dev/contrail-authority + +## 0.7.0 + +### Patch Changes + +- @atmo-dev/contrail-base@0.7.0 diff --git a/packages/contrail-authority/package.json b/packages/contrail-authority/package.json index 07c0477..a088146 100644 --- a/packages/contrail-authority/package.json +++ b/packages/contrail-authority/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail-authority", - "version": "0.6.0", + "version": "0.7.0", "description": "Default space-authority implementation for contrail — member list, invites, app policy, credential issuance. Contrail's binary-membership ACL flavor; for ladder-style access levels see @atmo-dev/contrail-community.", "type": "module", "sideEffects": false, diff --git a/packages/contrail-base/CHANGELOG.md b/packages/contrail-base/CHANGELOG.md new file mode 100644 index 0000000..e6ed047 --- /dev/null +++ b/packages/contrail-base/CHANGELOG.md @@ -0,0 +1,3 @@ +# @atmo-dev/contrail-base + +## 0.7.0 diff --git a/packages/contrail-base/package.json b/packages/contrail-base/package.json index e72201a..5535411 100644 --- a/packages/contrail-base/package.json +++ b/packages/contrail-base/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail-base", - "version": "0.6.0", + "version": "0.7.0", "description": "Shared infrastructure for the contrail family of packages — interfaces (SpaceAuthority, RecordHost, CommunityIntegration), credential primitives, binding resolvers, realtime infra, schema scaffolding. No routes, no tables of its own.", "type": "module", "sideEffects": false, diff --git a/packages/contrail-community/CHANGELOG.md b/packages/contrail-community/CHANGELOG.md new file mode 100644 index 0000000..163f0e5 --- /dev/null +++ b/packages/contrail-community/CHANGELOG.md @@ -0,0 +1,109 @@ +# @atmo-dev/contrail-community + +## 0.7.0 + +### Minor Changes + +- 7e3145b: Spaces refactor: split authority + record host into independently runnable + roles, add space credentials, extract community into its own package. + + **Breaking — config shape** + + `spaces` is no longer flat — split into `authority` and `recordHost`: + + ```ts + // before + spaces: { + type: "com.example.event.space", + serviceDid: "did:web:example.com", + blobs: { adapter, maxSize }, + } + + // after + spaces: { + authority: { + type: "com.example.event.space", + serviceDid: "did:web:example.com", + signing: await generateAuthoritySigningKey(), + }, + recordHost: { + blobs: { adapter, maxSize }, + }, + } + ``` + + **Breaking — community moved to its own package** + + Community has been extracted to `@atmo-dev/contrail-community`. Wire it via + `createCommunityIntegration`: + + ```ts + import { Contrail, resolveConfig } from "@atmo-dev/contrail"; + import { createCommunityIntegration } from "@atmo-dev/contrail-community"; + + const resolved = resolveConfig(config); + const communityIntegration = createCommunityIntegration({ + db, + config: resolved, + }); + const contrail = new Contrail({ ...config, communityIntegration }); + ``` + + The community config (`config.community`) stays the same; only the wiring + moves. Imports of `CommunityAdapter`, `registerCommunityRoutes`, + `reconcile`, etc. now come from `@atmo-dev/contrail-community` instead of + `@atmo-dev/contrail`. + + **New — space credentials (`X-Space-Credential`)** + + The space authority issues short-lived ES256 JWTs (default 2h TTL) via + `.space.getCredential` and `refreshCredential`. The record host accepts + them on read/write paths in lieu of per-request service-auth JWTs. Skips + DID-doc fetches and member checks; the credential's signature is the proof. + + Generate a signing key once at deploy time: + + ```ts + import { generateAuthoritySigningKey } from "@atmo-dev/contrail"; + const signing = await generateAuthoritySigningKey(); + // Store the JWK; pass to spaces.authority.signing. + ``` + + **New — binding resolution** + + Verifiers can resolve "which authority signs for this space?" from three + sources, in order: local enrollment table, PDS records at + `at:////`, DID-doc `#atproto_space_authority` service + entry, owner-self fallback. Lets user-owned DIDs authorize a third-party + authority via a normal PDS write — no DID-doc surgery. + + **New — independent deployments + enrollment** + + The authority and record host can run as separate processes/operators. + A new `.recordHost.enroll` endpoint lets owners (or authorities) + register a space onto a host. In-process deployments auto-enroll on + `createSpace`; nothing changes for single-instance setups. + + See `docs/10-deployment-shapes.md` for all-in-one / authority-only / + host-only configurations and when to choose each. + + **Migration** + + For most deployments running spaces today, the migration is: + 1. Update the config: split `spaces.{type, serviceDid, blobs}` into + `spaces.authority.{type, serviceDid}` and `spaces.recordHost.{blobs}`. + 2. Generate and store an authority signing key + (`generateAuthoritySigningKey()`); add to `spaces.authority.signing`. + 3. If using community: install `@atmo-dev/contrail-community`, build + `createCommunityIntegration({ db, config })`, pass via + `new Contrail({ communityIntegration })` (or `createApp({ community })`). + + Existing service-auth JWT clients keep working as a fallback path. + Migrate to space credentials when convenient — exchange a JWT for a + credential once via `getCredential`, then reuse it. + +### Patch Changes + +- Updated dependencies [7e3145b] + - @atmo-dev/contrail@0.7.0 + - @atmo-dev/contrail-base@0.7.0 diff --git a/packages/contrail-community/package.json b/packages/contrail-community/package.json index c6abcb2..ac7bc8a 100644 --- a/packages/contrail-community/package.json +++ b/packages/contrail-community/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail-community", - "version": "0.4.2", + "version": "0.7.0", "description": "Community module for contrail — community-owned spaces with tiered access levels (member → moderator → admin), invite tokens, DID provisioning, and the access-level reconciler that keeps spaces_members in sync.", "type": "module", "sideEffects": false, diff --git a/packages/contrail-record-host/CHANGELOG.md b/packages/contrail-record-host/CHANGELOG.md new file mode 100644 index 0000000..bbc13ac --- /dev/null +++ b/packages/contrail-record-host/CHANGELOG.md @@ -0,0 +1,7 @@ +# @atmo-dev/contrail-record-host + +## 0.7.0 + +### Patch Changes + +- @atmo-dev/contrail-base@0.7.0 diff --git a/packages/contrail-record-host/package.json b/packages/contrail-record-host/package.json index 2182f37..b0f50f9 100644 --- a/packages/contrail-record-host/package.json +++ b/packages/contrail-record-host/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail-record-host", - "version": "0.6.0", + "version": "0.7.0", "description": "Default record-host implementation for contrail — stores records and blobs for permissioned spaces, enforces local enrollment as the host's consent layer.", "type": "module", "sideEffects": false, diff --git a/packages/contrail/CHANGELOG.md b/packages/contrail/CHANGELOG.md index 63e68f6..d404678 100644 --- a/packages/contrail/CHANGELOG.md +++ b/packages/contrail/CHANGELOG.md @@ -1,11 +1,119 @@ # @atmo-dev/contrail +## 0.7.0 + +### Minor Changes + +- 7e3145b: Spaces refactor: split authority + record host into independently runnable + roles, add space credentials, extract community into its own package. + + **Breaking — config shape** + + `spaces` is no longer flat — split into `authority` and `recordHost`: + + ```ts + // before + spaces: { + type: "com.example.event.space", + serviceDid: "did:web:example.com", + blobs: { adapter, maxSize }, + } + + // after + spaces: { + authority: { + type: "com.example.event.space", + serviceDid: "did:web:example.com", + signing: await generateAuthoritySigningKey(), + }, + recordHost: { + blobs: { adapter, maxSize }, + }, + } + ``` + + **Breaking — community moved to its own package** + + Community has been extracted to `@atmo-dev/contrail-community`. Wire it via + `createCommunityIntegration`: + + ```ts + import { Contrail, resolveConfig } from "@atmo-dev/contrail"; + import { createCommunityIntegration } from "@atmo-dev/contrail-community"; + + const resolved = resolveConfig(config); + const communityIntegration = createCommunityIntegration({ + db, + config: resolved, + }); + const contrail = new Contrail({ ...config, communityIntegration }); + ``` + + The community config (`config.community`) stays the same; only the wiring + moves. Imports of `CommunityAdapter`, `registerCommunityRoutes`, + `reconcile`, etc. now come from `@atmo-dev/contrail-community` instead of + `@atmo-dev/contrail`. + + **New — space credentials (`X-Space-Credential`)** + + The space authority issues short-lived ES256 JWTs (default 2h TTL) via + `.space.getCredential` and `refreshCredential`. The record host accepts + them on read/write paths in lieu of per-request service-auth JWTs. Skips + DID-doc fetches and member checks; the credential's signature is the proof. + + Generate a signing key once at deploy time: + + ```ts + import { generateAuthoritySigningKey } from "@atmo-dev/contrail"; + const signing = await generateAuthoritySigningKey(); + // Store the JWK; pass to spaces.authority.signing. + ``` + + **New — binding resolution** + + Verifiers can resolve "which authority signs for this space?" from three + sources, in order: local enrollment table, PDS records at + `at:////`, DID-doc `#atproto_space_authority` service + entry, owner-self fallback. Lets user-owned DIDs authorize a third-party + authority via a normal PDS write — no DID-doc surgery. + + **New — independent deployments + enrollment** + + The authority and record host can run as separate processes/operators. + A new `.recordHost.enroll` endpoint lets owners (or authorities) + register a space onto a host. In-process deployments auto-enroll on + `createSpace`; nothing changes for single-instance setups. + + See `docs/10-deployment-shapes.md` for all-in-one / authority-only / + host-only configurations and when to choose each. + + **Migration** + + For most deployments running spaces today, the migration is: + 1. Update the config: split `spaces.{type, serviceDid, blobs}` into + `spaces.authority.{type, serviceDid}` and `spaces.recordHost.{blobs}`. + 2. Generate and store an authority signing key + (`generateAuthoritySigningKey()`); add to `spaces.authority.signing`. + 3. If using community: install `@atmo-dev/contrail-community`, build + `createCommunityIntegration({ db, config })`, pass via + `new Contrail({ communityIntegration })` (or `createApp({ community })`). + + Existing service-auth JWT clients keep working as a fallback path. + Migrate to space credentials when convenient — exchange a JWT for a + credential once via `getCredential`, then reuse it. + +### Patch Changes + +- @atmo-dev/contrail-base@0.7.0 +- @atmo-dev/contrail-authority@0.7.0 +- @atmo-dev/contrail-record-host@0.7.0 +- @atmo-dev/contrail-appview@0.7.0 + ## 0.6.0 ### Minor Changes - af24714: Add per-collection `recordFilter` and apply Jetstream `#identity` handle changes during ingest. - - `CollectionConfig.recordFilter?: (record) => boolean` runs against each create/update during ingest; returning false drops the record before it reaches the DB. Useful for narrowing high-volume collections to just the records you care about (e.g. only `app.bsky.feed.post` records mentioning a particular URL). Deletes are not filtered, so they still tear down any record the filter previously let through. Throws are caught, logged, and treated as drops. - Jetstream `#identity` events (handle changes) now flow through to the `identities` table via a new `applyIdentityEvent` helper. UPDATE-only — unknown DIDs are no-ops so we don't materialize partial rows lacking PDS. @@ -71,7 +179,6 @@ ``` what changed: - - `buildSpaceUri` / `parseSpaceUri` (`@atmo-dev/contrail`) emit / accept `ats://`. anything else returns `null` from `parseSpaceUri`. - generated lexicons no longer claim `format: "at-uri"` on `spaceUri` params, on the `space` record-output field, or on `spaceView.uri` — they're plain `string`. (atproto's `at-uri` format would reject `ats://`.) regenerate committed `lexicons/generated/*` with `contrail-lex generate`; downstream `lex-cli generate` then emits `v.string()` instead of `v.resourceUriString()` for those fields. - realtime topics are unchanged in shape (`space:`), but `` is now an `ats://` URI. @@ -98,7 +205,6 @@ ``` changes: - - `#record` def now requires `["uri", "cid", "value"]` (matches atproto's standard `com.atproto.repo.listRecords#record`). `did`/`collection`/`rkey`/`time_us` remain in the response but are optional. - `getRecord` top-level output requires `["uri", "value"]` (matches atproto's `com.atproto.repo.getRecord`). - profile entries in `?profiles=true` responses use `value` instead of `record` for the profile record body. @@ -138,7 +244,6 @@ - ad3a61d: add `contrail dev` — local dev wrapper for cloudflare workers deployments. replaces `wrangler dev --test-scheduled` + a separate cron-trigger script with one command. on start it: - 1. connects to your local D1 via wrangler's `getPlatformProxy`, inspects state 2. prompts to run `backfillAll` if no completed backfills exist yet 3. prompts to run `refresh` if the ingest cursor is older than 60 minutes (configurable with `--stale-after`) @@ -166,7 +271,6 @@ options: `binding` (D1 binding name, default `"DB"`), `lexicons` (see below), `onInit` (one-shot app-specific setup). **`/xrpc/.lexicons` endpoint + `contrail-lex pull-service`** lets consumer apps typegen against a deployed contrail over HTTP, no PDS or DNS required: - - `contrail-lex generate` now emits a barrel `lexicons/generated/index.ts` that imports every lexicon the deployment speaks: generated + pulled + custom. The pulled lexicons are needed so consumer typegen can resolve `$ref`s out of the generated schemas. - Pass `{ lexicons }` to `createWorker` (or `createHandler(contrail, { lexicons })`) and the service exposes them at `GET /xrpc/.lexicons`. - From a consumer app: @@ -184,7 +288,6 @@ unlike `backfillAll`, it ignores the `backfills` state table and sweeps fresh. useful after jetstream outages or after leaving a dev deployment idle for days. each record in each configured collection is classified as: - - **missing** — PDS has it, DB doesn't - **stale update** — DB has it with a different CID, _and_ the DB row was written before the ignore window (default 60s, configurable) - **in sync** — same CID, or DB row is within the ignore window diff --git a/packages/contrail/package.json b/packages/contrail/package.json index 0eec411..0219561 100644 --- a/packages/contrail/package.json +++ b/packages/contrail/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail", - "version": "0.6.0", + "version": "0.7.0", "description": "Index AT Protocol records with typed XRPC endpoints. Cloudflare Workers + D1, SvelteKit, Node.js.", "type": "module", "sideEffects": false, diff --git a/packages/lexicons/CHANGELOG.md b/packages/lexicons/CHANGELOG.md index d5f674f..ab5abd0 100644 --- a/packages/lexicons/CHANGELOG.md +++ b/packages/lexicons/CHANGELOG.md @@ -1,5 +1,12 @@ # @atmo-dev/contrail-lexicons +## 0.4.7 + +### Patch Changes + +- Updated dependencies [7e3145b] + - @atmo-dev/contrail@0.7.0 + ## 0.4.6 ### Patch Changes @@ -53,7 +60,6 @@ ``` what changed: - - `buildSpaceUri` / `parseSpaceUri` (`@atmo-dev/contrail`) emit / accept `ats://`. anything else returns `null` from `parseSpaceUri`. - generated lexicons no longer claim `format: "at-uri"` on `spaceUri` params, on the `space` record-output field, or on `spaceView.uri` — they're plain `string`. (atproto's `at-uri` format would reject `ats://`.) regenerate committed `lexicons/generated/*` with `contrail-lex generate`; downstream `lex-cli generate` then emits `v.string()` instead of `v.resourceUriString()` for those fields. - realtime topics are unchanged in shape (`space:`), but `` is now an `ats://` URI. @@ -86,7 +92,6 @@ ``` changes: - - `#record` def now requires `["uri", "cid", "value"]` (matches atproto's standard `com.atproto.repo.listRecords#record`). `did`/`collection`/`rkey`/`time_us` remain in the response but are optional. - `getRecord` top-level output requires `["uri", "value"]` (matches atproto's `com.atproto.repo.getRecord`). - profile entries in `?profiles=true` responses use `value` instead of `record` for the profile record body. @@ -110,7 +115,6 @@ options: `binding` (D1 binding name, default `"DB"`), `lexicons` (see below), `onInit` (one-shot app-specific setup). **`/xrpc/.lexicons` endpoint + `contrail-lex pull-service`** lets consumer apps typegen against a deployed contrail over HTTP, no PDS or DNS required: - - `contrail-lex generate` now emits a barrel `lexicons/generated/index.ts` that imports every lexicon the deployment speaks: generated + pulled + custom. The pulled lexicons are needed so consumer typegen can resolve `$ref`s out of the generated schemas. - Pass `{ lexicons }` to `createWorker` (or `createHandler(contrail, { lexicons })`) and the service exposes them at `GET /xrpc/.lexicons`. - From a consumer app: diff --git a/packages/lexicons/package.json b/packages/lexicons/package.json index 9cc3ea4..066e06c 100644 --- a/packages/lexicons/package.json +++ b/packages/lexicons/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail-lexicons", - "version": "0.4.6", + "version": "0.4.7", "description": "Generate atproto lexicon JSON (and optionally TypeScript types via @atcute/lex-cli) from a Contrail config.", "type": "module", "files": [ diff --git a/packages/sync/CHANGELOG.md b/packages/sync/CHANGELOG.md index f570219..aa4b041 100644 --- a/packages/sync/CHANGELOG.md +++ b/packages/sync/CHANGELOG.md @@ -1,5 +1,107 @@ # @atmo-dev/contrail-sync +## 0.7.0 + +### Minor Changes + +- 7e3145b: Spaces refactor: split authority + record host into independently runnable + roles, add space credentials, extract community into its own package. + + **Breaking — config shape** + + `spaces` is no longer flat — split into `authority` and `recordHost`: + + ```ts + // before + spaces: { + type: "com.example.event.space", + serviceDid: "did:web:example.com", + blobs: { adapter, maxSize }, + } + + // after + spaces: { + authority: { + type: "com.example.event.space", + serviceDid: "did:web:example.com", + signing: await generateAuthoritySigningKey(), + }, + recordHost: { + blobs: { adapter, maxSize }, + }, + } + ``` + + **Breaking — community moved to its own package** + + Community has been extracted to `@atmo-dev/contrail-community`. Wire it via + `createCommunityIntegration`: + + ```ts + import { Contrail, resolveConfig } from "@atmo-dev/contrail"; + import { createCommunityIntegration } from "@atmo-dev/contrail-community"; + + const resolved = resolveConfig(config); + const communityIntegration = createCommunityIntegration({ + db, + config: resolved, + }); + const contrail = new Contrail({ ...config, communityIntegration }); + ``` + + The community config (`config.community`) stays the same; only the wiring + moves. Imports of `CommunityAdapter`, `registerCommunityRoutes`, + `reconcile`, etc. now come from `@atmo-dev/contrail-community` instead of + `@atmo-dev/contrail`. + + **New — space credentials (`X-Space-Credential`)** + + The space authority issues short-lived ES256 JWTs (default 2h TTL) via + `.space.getCredential` and `refreshCredential`. The record host accepts + them on read/write paths in lieu of per-request service-auth JWTs. Skips + DID-doc fetches and member checks; the credential's signature is the proof. + + Generate a signing key once at deploy time: + + ```ts + import { generateAuthoritySigningKey } from "@atmo-dev/contrail"; + const signing = await generateAuthoritySigningKey(); + // Store the JWK; pass to spaces.authority.signing. + ``` + + **New — binding resolution** + + Verifiers can resolve "which authority signs for this space?" from three + sources, in order: local enrollment table, PDS records at + `at:////`, DID-doc `#atproto_space_authority` service + entry, owner-self fallback. Lets user-owned DIDs authorize a third-party + authority via a normal PDS write — no DID-doc surgery. + + **New — independent deployments + enrollment** + + The authority and record host can run as separate processes/operators. + A new `.recordHost.enroll` endpoint lets owners (or authorities) + register a space onto a host. In-process deployments auto-enroll on + `createSpace`; nothing changes for single-instance setups. + + See `docs/10-deployment-shapes.md` for all-in-one / authority-only / + host-only configurations and when to choose each. + + **Migration** + + For most deployments running spaces today, the migration is: + 1. Update the config: split `spaces.{type, serviceDid, blobs}` into + `spaces.authority.{type, serviceDid}` and `spaces.recordHost.{blobs}`. + 2. Generate and store an authority signing key + (`generateAuthoritySigningKey()`); add to `spaces.authority.signing`. + 3. If using community: install `@atmo-dev/contrail-community`, build + `createCommunityIntegration({ db, config })`, pass via + `new Contrail({ communityIntegration })` (or `createApp({ community })`). + + Existing service-auth JWT clients keep working as a fallback path. + Migrate to space credentials when convenient — exchange a JWT for a + credential once via `getCredential`, then reuse it. + ## 0.4.0 ### Minor Changes @@ -26,7 +128,6 @@ ``` what changed: - - `buildSpaceUri` / `parseSpaceUri` (`@atmo-dev/contrail`) emit / accept `ats://`. anything else returns `null` from `parseSpaceUri`. - generated lexicons no longer claim `format: "at-uri"` on `spaceUri` params, on the `space` record-output field, or on `spaceView.uri` — they're plain `string`. (atproto's `at-uri` format would reject `ats://`.) regenerate committed `lexicons/generated/*` with `contrail-lex generate`; downstream `lex-cli generate` then emits `v.string()` instead of `v.resourceUriString()` for those fields. - realtime topics are unchanged in shape (`space:`), but `` is now an `ats://` URI. @@ -53,7 +154,6 @@ ``` changes: - - `#record` def now requires `["uri", "cid", "value"]` (matches atproto's standard `com.atproto.repo.listRecords#record`). `did`/`collection`/`rkey`/`time_us` remain in the response but are optional. - `getRecord` top-level output requires `["uri", "value"]` (matches atproto's `com.atproto.repo.getRecord`). - profile entries in `?profiles=true` responses use `value` instead of `record` for the profile record body. diff --git a/packages/sync/package.json b/packages/sync/package.json index ef9e485..9bd77e4 100644 --- a/packages/sync/package.json +++ b/packages/sync/package.json @@ -1,6 +1,6 @@ { "name": "@atmo-dev/contrail-sync", - "version": "0.4.0", + "version": "0.7.0", "description": "Client-side reactive watch-store over contrail's watchRecords endpoints. SSE + WebSocket transports, optimistic updates, optional IndexedDB cache.", "type": "module", "sideEffects": false, -- 2.51.2