begin embedded pds with xrpc endpoints and well-known

This commit is contained in:
Evan Jarrett
2025-10-14 20:25:08 -05:00
parent 2ee8bd8786
commit 18fe0684d3
17 changed files with 1252 additions and 29 deletions

View File

@@ -510,40 +510,58 @@ With embedded PDS:
## Implementation Plan
### Phase 1: Basic PDS with Carstore (Current)
### Phase 1: Basic PDS with Carstore ✅ COMPLETED
**Decision: Use indigo's carstore with SQLite backend**
**Implementation: Using indigo's carstore with SQLite + DeltaSession**
```go
import (
"github.com/bluesky-social/indigo/carstore"
"github.com/bluesky-social/indigo/models"
"github.com/bluesky-social/indigo/repo"
)
type HoldPDS struct {
did string
carstore carstore.CarStore
repo *repo.Repo
did string
carstore carstore.CarStore
session *carstore.DeltaSession // Provides blockstore interface
repo *repo.Repo
dbPath string
uid models.Uid // User ID for carstore (fixed: 1)
}
func NewHoldPDS(did, dbPath string) (*HoldPDS, error) {
func NewHoldPDS(ctx context.Context, did, dbPath string) (*HoldPDS, error) {
// Create SQLite-backed carstore
sqlStore, err := carstore.NewSqliteStore(dbPath)
sqlStore.Open(dbPath)
cs := sqlStore.CarStore()
// Get or create repo
head, err := cs.GetUserRepoHead(ctx, did)
var r *repo.Repo
if err == carstore.ErrRepoNotFound {
r, err = repo.NewRepo(ctx, did, cs.Blockstore())
} else {
r, err = repo.OpenRepo(ctx, cs.Blockstore(), head)
}
// For single-hold use, fixed UID
uid := models.Uid(1)
return &HoldPDS{did: did, carstore: cs, repo: r}, nil
// Create DeltaSession (provides blockstore interface)
session, err := cs.NewDeltaSession(ctx, uid, nil)
// Create repo with session as blockstore
r := repo.NewRepo(ctx, did, session)
return &HoldPDS{
did: did,
carstore: cs,
session: session,
repo: r,
dbPath: dbPath,
uid: uid,
}, nil
}
```
**Key learnings:**
- ✅ Carstore provides blockstore via `DeltaSession` (not direct access)
-`models.Uid` is the user ID type (we use fixed UID(1))
- ✅ DeltaSession needs to be a pointer (`*carstore.DeltaSession`)
-`repo.NewRepo()` accepts the session directly as blockstore
**Storage:**
- Single file: `/var/lib/atcr-hold/hold.db` (SQLite)
- Contains MST nodes, records, commits in carstore tables
@@ -552,10 +570,10 @@ func NewHoldPDS(did, dbPath string) (*HoldPDS, error) {
**Why SQLite carstore:**
- ✅ Single file persistence (like appview's SQLite)
- ✅ Official indigo storage backend
- ✅ No custom blockstore implementation needed
- ✅ Handles compaction/cleanup automatically
- ✅ Migration path to Postgres/Scylla if needed
- ✅ Easy to replicate (Litestream, LiteFS, rsync)
- ✅ CAR import/export support built-in
**Scale considerations:**
- SQLite carstore marked "experimental" but suitable for single-hold use
@@ -564,6 +582,27 @@ func NewHoldPDS(did, dbPath string) (*HoldPDS, error) {
- Bluesky PDSs use carstore for millions of records
- If needed: migrate to Postgres-backed carstore (same API)
### Hold as Proper ATProto User
**Decision:** Make holds full ATProto actors for discoverability and ecosystem integration.
**What this enables:**
- Hold becomes discoverable via ATProto directory
- Can have profile (`app.bsky.actor.profile`)
- Can post status updates (`app.bsky.feed.post`)
- Users can follow holds
- Social proof/reputation via ATProto social graph
**MVP Scope:**
We're building the minimal PDS needed for discoverability, not a full social client:
- ✅ Signing keys (ES256K via `atproto/atcrypto`)
- ✅ DID document (did:web at `/.well-known/did.json`)
- ✅ Standard XRPC endpoints (`describeRepo`, `getRecord`, `listRecords`)
- ✅ Profile record (`app.bsky.actor.profile`)
- ⏸️ Posting functionality (later - other services can read our records)
**Key insight:** Other ATProto services will "just work" as long as they can retrieve records from the hold's PDS. We don't need to implement full social features for the hold to participate in the ecosystem.
### Crew Management: Individual Records
**Decision: Individual crew record per user (remove wildcard logic)**