atproto utils for zig zat.dev
atproto sdk zig
26
fork

Configure Feed

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

add sync types for firehose consumption

new enums from com.atproto.sync.subscribeRepos lexicon:
- CommitAction: create, update, delete
- EventKind: commit, sync, identity, account, info
- AccountStatus: takendown, suspended, deleted, etc.

these work with std.json automatic enum parsing, enabling
exhaustive switches instead of mem.eql string comparisons.

bumps version to 0.1.0 (new feature, backwards compatible).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

zzstoatzz 5011ae25 58d29ba0

+129 -1
+32
README.md
··· 93 93 </details> 94 94 95 95 <details> 96 + <summary><strong>sync types</strong> - enums for firehose/event stream consumption</summary> 97 + 98 + ```zig 99 + // use in struct definitions for automatic json parsing: 100 + const RepoOp = struct { 101 + action: zat.CommitAction, // .create, .update, .delete 102 + path: []const u8, 103 + cid: ?[]const u8, 104 + }; 105 + 106 + // then exhaustive switch: 107 + switch (op.action) { 108 + .create, .update => processUpsert(op), 109 + .delete => processDelete(op), 110 + } 111 + ``` 112 + 113 + - **CommitAction** - `.create`, `.update`, `.delete` 114 + - **EventKind** - `.commit`, `.sync`, `.identity`, `.account`, `.info` 115 + - **AccountStatus** - `.takendown`, `.suspended`, `.deleted`, `.deactivated`, `.desynchronized`, `.throttled` 116 + 117 + </details> 118 + 119 + <details> 96 120 <summary><strong>json helpers</strong> - navigate nested json without verbose if-chains</summary> 97 121 98 122 ```zig ··· 149 173 ## specs 150 174 151 175 validation follows [atproto.com/specs](https://atproto.com/specs/atp). 176 + 177 + ## versioning 178 + 179 + pre-1.0 semver: 180 + - `0.x.0` - new features (backwards compatible) 181 + - `0.x.y` - bug fixes 182 + 183 + breaking changes bump the minor version and are documented in commit messages. 152 184 153 185 ## license 154 186
+1 -1
build.zig.zon
··· 1 1 .{ 2 2 .name = .zat, 3 - .version = "0.0.2", 3 + .version = "0.1.0", 4 4 .fingerprint = 0x8da9db57ee82fbe4, 5 5 .minimum_zig_version = "0.15.0", 6 6 .paths = .{
+90
src/internal/sync.zig
··· 1 + //! sync types - com.atproto.sync.subscribeRepos 2 + //! 3 + //! enums for firehose/event stream consumption. 4 + //! see: https://atproto.com/specs/event-stream 5 + 6 + const std = @import("std"); 7 + 8 + /// repo operation action (create/update/delete) 9 + /// 10 + /// from com.atproto.sync.subscribeRepos#repoOp 11 + /// used in firehose commit messages to indicate what happened to a record. 12 + pub const CommitAction = enum { 13 + create, 14 + update, 15 + delete, 16 + 17 + /// parse from string (for manual parsing) 18 + pub fn parse(s: []const u8) ?CommitAction { 19 + return std.meta.stringToEnum(CommitAction, s); 20 + } 21 + }; 22 + 23 + /// event stream message types 24 + /// 25 + /// from com.atproto.sync.subscribeRepos message union 26 + /// the top-level discriminator for firehose messages. 27 + pub const EventKind = enum { 28 + commit, 29 + sync, 30 + identity, 31 + account, 32 + info, 33 + 34 + pub fn parse(s: []const u8) ?EventKind { 35 + return std.meta.stringToEnum(EventKind, s); 36 + } 37 + }; 38 + 39 + /// account status reasons 40 + /// 41 + /// from com.atproto.sync.subscribeRepos#account status field 42 + /// indicates why an account is inactive. 43 + pub const AccountStatus = enum { 44 + takendown, 45 + suspended, 46 + deleted, 47 + deactivated, 48 + desynchronized, 49 + throttled, 50 + 51 + pub fn parse(s: []const u8) ?AccountStatus { 52 + return std.meta.stringToEnum(AccountStatus, s); 53 + } 54 + }; 55 + 56 + // === tests === 57 + 58 + test "CommitAction parse" { 59 + try std.testing.expectEqual(CommitAction.create, CommitAction.parse("create").?); 60 + try std.testing.expectEqual(CommitAction.update, CommitAction.parse("update").?); 61 + try std.testing.expectEqual(CommitAction.delete, CommitAction.parse("delete").?); 62 + try std.testing.expect(CommitAction.parse("invalid") == null); 63 + } 64 + 65 + test "CommitAction json parsing" { 66 + const json_str = 67 + \\{"action": "create", "path": "app.bsky.feed.post/abc"} 68 + ; 69 + 70 + const Op = struct { 71 + action: CommitAction, 72 + path: []const u8, 73 + }; 74 + 75 + const parsed = try std.json.parseFromSlice(Op, std.testing.allocator, json_str, .{}); 76 + defer parsed.deinit(); 77 + 78 + try std.testing.expectEqual(CommitAction.create, parsed.value.action); 79 + } 80 + 81 + test "EventKind parse" { 82 + try std.testing.expectEqual(EventKind.commit, EventKind.parse("commit").?); 83 + try std.testing.expectEqual(EventKind.identity, EventKind.parse("identity").?); 84 + try std.testing.expect(EventKind.parse("unknown") == null); 85 + } 86 + 87 + test "AccountStatus parse" { 88 + try std.testing.expectEqual(AccountStatus.takendown, AccountStatus.parse("takendown").?); 89 + try std.testing.expectEqual(AccountStatus.suspended, AccountStatus.parse("suspended").?); 90 + }
+6
src/root.zig
··· 26 26 pub const Jwt = @import("internal/jwt.zig").Jwt; 27 27 pub const multibase = @import("internal/multibase.zig"); 28 28 pub const multicodec = @import("internal/multicodec.zig"); 29 + 30 + // sync / firehose 31 + const sync = @import("internal/sync.zig"); 32 + pub const CommitAction = sync.CommitAction; 33 + pub const EventKind = sync.EventKind; 34 + pub const AccountStatus = sync.AccountStatus;