atproto utils for zig zat.dev
atproto sdk zig
Zig 85.3%
JavaScript 8.7%
CSS 4.6%
HTML 1.3%
Just 0.1%
73 1 6

Clone this repository

https://tangled.org/zat.dev/zat
git@tangled.org:zat.dev/zat

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

README.md

zat#

AT Protocol building blocks for zig.

this readme is an ATProto record

view in zat.dev's repository

zat publishes these docs as site.standard.document records, signed by its DID.

install#

zig fetch --save https://tangled.sh/zat.dev/zat/archive/main

then in build.zig:

const zat = b.dependency("zat", .{}).module("zat");
exe.root_module.addImport("zat", zat);

what's here#

string primitives - parsing and validation for atproto identifiers
  • Tid - timestamp identifiers (base32-sortable)
  • Did - decentralized identifiers
  • Handle - domain-based handles
  • Nsid - namespaced identifiers (lexicon types)
  • Rkey - record keys
  • AtUri - at:// URIs
const zat = @import("zat");

if (zat.AtUri.parse(uri_string)) |uri| {
    const authority = uri.authority();
    const collection = uri.collection();
    const rkey = uri.rkey();
}
did resolution - resolve did:plc and did:web to documents
var resolver = zat.DidResolver.init(allocator);
defer resolver.deinit();

const did = zat.Did.parse("did:plc:z72i7hdynmk6r22z27h6tvur").?;
var doc = try resolver.resolve(did);
defer doc.deinit();

const handle = doc.handle();           // "bsky.app"
const pds = doc.pdsEndpoint();         // "https://..."
const key = doc.signingKey();          // verification method
handle resolution - resolve handles to DIDs via HTTP well-known
var resolver = zat.HandleResolver.init(allocator);
defer resolver.deinit();

const handle = zat.Handle.parse("bsky.app").?;
const did = try resolver.resolve(handle);
defer allocator.free(did);
// did = "did:plc:z72i7hdynmk6r22z27h6tvur"
xrpc client - call AT Protocol endpoints
var client = zat.XrpcClient.init(allocator, "https://bsky.social");
defer client.deinit();

const nsid = zat.Nsid.parse("app.bsky.actor.getProfile").?;
var response = try client.query(nsid, params);
defer response.deinit();

if (response.ok()) {
    var json = try response.json();
    defer json.deinit();
    // use json.value
}
sync types - enums for firehose/event stream consumption
// use in struct definitions for automatic json parsing:
const RepoOp = struct {
    action: zat.CommitAction,  // .create, .update, .delete
    path: []const u8,
    cid: ?[]const u8,
};

// then exhaustive switch:
switch (op.action) {
    .create, .update => processUpsert(op),
    .delete => processDelete(op),
}
  • CommitAction - .create, .update, .delete
  • EventKind - .commit, .sync, .identity, .account, .info
  • AccountStatus - .takendown, .suspended, .deleted, .deactivated, .desynchronized, .throttled
json helpers - navigate nested json without verbose if-chains
// runtime paths for one-offs:
const uri = zat.json.getString(value, "embed.external.uri");
const count = zat.json.getInt(value, "meta.count");

// comptime extraction for complex structures:
const FeedPost = struct {
    uri: []const u8,
    cid: []const u8,
    record: struct {
        text: []const u8 = "",
    },
};
const post = try zat.json.extractAt(FeedPost, allocator, value, .{"post"});
jwt verification - verify service auth tokens
var jwt = try zat.Jwt.parse(allocator, token_string);
defer jwt.deinit();

// check claims
if (jwt.isExpired()) return error.TokenExpired;
if (!std.mem.eql(u8, jwt.payload.aud, expected_audience)) return error.InvalidAudience;

// verify signature against issuer's public key (from DID document)
try jwt.verify(public_key_multibase);

supports ES256 (P-256) and ES256K (secp256k1) signing algorithms.

multibase decoding - decode public keys from DID documents
const key_bytes = try zat.multibase.decode(allocator, "zQ3sh...");
defer allocator.free(key_bytes);

const parsed = try zat.multicodec.parsePublicKey(key_bytes);
// parsed.key_type: .secp256k1 or .p256
// parsed.raw: 33-byte compressed public key

specs#

validation follows atproto.com/specs.

versioning#

pre-1.0 semver:

  • 0.x.0 - new features (backwards compatible)
  • 0.x.y - bug fixes

breaking changes bump the minor version and are documented in commit messages.

license#

MIT


roadmap · changelog