ATProto Personal Data Server storage for OCaml
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

OCaml 94.8%
Dune 1.7%
Other 3.6%
35 1 0

Clone this repository

https://tangled.org/gazagnaire.org/ocaml-pds https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-pds
git@git.recoil.org:gazagnaire.org/ocaml-pds git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-pds

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

pds#

ATProto Personal Data Server storage for OCaml.

Overview#

A library for reading and writing ATProto PDS (Personal Data Server) storage format. This enables:

  • Local PDS-compatible repositories without running a full PDS
  • Offline repository manipulation (backup, migration, inspection)
  • CAR import/export for interoperability

Installation#

Install with opam:

$ opam install nox-pds

If opam cannot find the package, it may not yet be released in the public opam-repository. Add the overlay repository, then install it:

$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install nox-pds

Usage#

Create a repo, put and get records#

let put_and_get ~record_bytes =
  Eio_main.run @@ fun env ->
  Eio.Switch.run @@ fun sw ->
  let fs = Eio.Stdenv.fs env in
  let repo =
    Pds.v ~sw
      Eio.Path.(fs / "my-repo")
      ~did:(Atp.Did.of_string_exn "did:web:example.com")
  in
  Pds.put repo ~collection:"app.bsky.feed.post" ~rkey:"abc123" record_bytes;
  (match Pds.find repo ~collection:"app.bsky.feed.post" ~rkey:"abc123" with
  | Some data -> Fmt.pr "record: %d bytes@." (String.length data)
  | None -> Fmt.pr "not found@.");
  Pds.close repo

List a collection#

let list_posts repo =
  Pds.list repo ~collection:"app.bsky.feed.post"
  |> List.iter (fun (rkey, cid) ->
         Fmt.pr "%s -> %a@." rkey Atp.Cid.pp cid)

Blobs#

let store_image repo image_bytes =
  Pds.put_blob repo ~mime_type:"image/png" image_bytes

Import / export#

let backup repo = Pds.export_car repo
let restore repo car = Pds.import_car repo car

API#

Repository#

  • Pds.v ~sw path ~did -- create a new repository
  • Pds.open_ ~sw path -- open an existing repository
  • Pds.did t
  • Pds.close t

Records#

  • Pds.put t ~collection ~rkey data
  • Pds.find t ~collection ~rkey -- returns string option
  • Pds.delete t ~collection ~rkey
  • Pds.list t ~collection -- returns (rkey * cid) list

Blobs#

  • Pds.put_blob t ~mime_type data -- returns Atp.Blob_ref.t
  • Pds.blob t cid -- returns string option

Repository state#

  • Pds.head t -- current commit CID
  • Pds.set_head t cid
  • Pds.checkout t -- MST at HEAD
  • Pds.blockstore t -- underlying blockstore

Named refs#

  • Pds.ref t name / set_ref t name cid / delete_ref t name
  • Pds.list_refs t

CAR#

  • Pds.import_car t data -- returns number of imported blocks
  • Pds.export_car t

Storage layout#

<repo>/
├── pds.db              # SQLite database
│   ├── blocks table    # CID → DAG-CBOR bytes
│   ├── refs table      # name → CID (branches)
│   └── meta table      # did, version, etc.
└── blobs/              # Large binary data
    ├── ba/             # First 2 chars of CID
    │   └── bafyrei...  # Full CID as filename
    └── ...
  • ocaml-atp -- ATProto primitives (MST, CID, DAG-CBOR, CAR)
  • ocaml-sqlite -- SQLite key-value store (used internally)
  • Bluesky PDS -- Reference TypeScript implementation

Licence#

MIT License. See LICENSE.md for details.