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.

Revert "publish docs to leaflet alongside site.standard"

This reverts commit f640677ae49e30dbcc3df8bd21a9b2b08b722b54.

zzstoatzz e35b6452 f640677a

-204
-8
.tangled/workflows/publish-docs.yml
··· 1 1 when: 2 2 - event: push 3 3 tag: "v*" 4 - - event: push 5 - branch: main 6 - path: 7 - - "README.md" 8 - - "CHANGELOG.md" 9 - - "docs/**" 10 - - "devlog/**" 11 4 12 5 engine: nixery 13 6 ··· 18 11 steps: 19 12 - name: build and publish docs to ATProto 20 13 command: | 21 - test -n "$ATPROTO_PASSWORD" 22 14 zig build 23 15 ./zig-out/bin/publish-docs
-196
scripts/publish-docs.zig
··· 82 82 83 83 try putRecord(&client, allocator, session.did, "site.standard.document", tid.str(), doc_record); 84 84 std.debug.print("published: {s} -> at://{s}/site.standard.document/{s}\n", .{ doc.file, session.did, tid.str() }); 85 - 86 - // also publish to leaflet 87 - const leaflet_blocks = try parseMarkdownToLeafletBlocks(allocator, content); 88 - const leaflet_page = LeafletPage{ .blocks = leaflet_blocks }; 89 - const leaflet_pages = try allocator.alloc(LeafletPage, 1); 90 - leaflet_pages[0] = leaflet_page; 91 - 92 - const leaflet_record = LeafletDocument{ 93 - .author = session.did, 94 - .title = title, 95 - .publishedAt = &now, 96 - .pages = leaflet_pages, 97 - }; 98 - try putRecord(&client, allocator, session.did, "pub.leaflet.document", tid.str(), leaflet_record); 99 - std.debug.print("published: {s} -> at://{s}/pub.leaflet.document/{s}\n", .{ doc.file, session.did, tid.str() }); 100 85 } 101 86 102 87 // devlog publication (clock_id 100 to separate from docs) ··· 136 121 137 122 try putRecord(&client, allocator, session.did, "site.standard.document", tid.str(), doc_record); 138 123 std.debug.print("published: {s} -> at://{s}/site.standard.document/{s}\n", .{ entry.file, session.did, tid.str() }); 139 - 140 - // also publish to leaflet 141 - const leaflet_blocks = try parseMarkdownToLeafletBlocks(allocator, content); 142 - const leaflet_page = LeafletPage{ .blocks = leaflet_blocks }; 143 - const leaflet_pages = try allocator.alloc(LeafletPage, 1); 144 - leaflet_pages[0] = leaflet_page; 145 - 146 - const leaflet_record = LeafletDocument{ 147 - .author = session.did, 148 - .title = title, 149 - .publishedAt = &now, 150 - .pages = leaflet_pages, 151 - }; 152 - try putRecord(&client, allocator, session.did, "pub.leaflet.document", tid.str(), leaflet_record); 153 - std.debug.print("published: {s} -> at://{s}/pub.leaflet.document/{s}\n", .{ entry.file, session.did, tid.str() }); 154 124 } 155 125 156 126 std.debug.print("done\n", .{}); ··· 172 142 publishedAt: []const u8, 173 143 }; 174 144 175 - // leaflet types 176 - const LeafletDocument = struct { 177 - @"$type": []const u8 = "pub.leaflet.document", 178 - author: []const u8, 179 - title: []const u8, 180 - publishedAt: ?[]const u8 = null, 181 - pages: []const LeafletPage, 182 - }; 183 - 184 - const LeafletPage = struct { 185 - @"$type": []const u8 = "pub.leaflet.pages.linearDocument", 186 - blocks: []const LeafletBlockWrapper, 187 - }; 188 - 189 - const LeafletBlockWrapper = struct { 190 - block: LeafletBlock, 191 - }; 192 - 193 - const LeafletBlock = union(enum) { 194 - header: HeaderBlock, 195 - text: TextBlock, 196 - code: CodeBlock, 197 - 198 - pub fn jsonStringify(self: @This(), jw: anytype) !void { 199 - switch (self) { 200 - .header => |h| try jw.write(h), 201 - .text => |t| try jw.write(t), 202 - .code => |c| try jw.write(c), 203 - } 204 - } 205 - }; 206 - 207 - const HeaderBlock = struct { 208 - @"$type": []const u8 = "pub.leaflet.blocks.header", 209 - plaintext: []const u8, 210 - level: u8, 211 - }; 212 - 213 - const TextBlock = struct { 214 - @"$type": []const u8 = "pub.leaflet.blocks.text", 215 - plaintext: []const u8, 216 - }; 217 - 218 - const CodeBlock = struct { 219 - @"$type": []const u8 = "pub.leaflet.blocks.code", 220 - plaintext: []const u8, 221 - language: ?[]const u8 = null, 222 - }; 223 - 224 145 const Session = struct { 225 146 did: []const u8, 226 147 access_token: []const u8, ··· 340 261 }) catch unreachable; 341 262 return buf; 342 263 } 343 - 344 - /// parse markdown into leaflet blocks (minimal: headers, code, paragraphs) 345 - fn parseMarkdownToLeafletBlocks(allocator: Allocator, markdown: []const u8) ![]LeafletBlockWrapper { 346 - var blocks: std.ArrayList(LeafletBlockWrapper) = .empty; 347 - errdefer blocks.deinit(allocator); 348 - 349 - var lines = std.mem.splitScalar(u8, markdown, '\n'); 350 - var in_code_block = false; 351 - var code_content: std.ArrayList(u8) = .empty; 352 - defer code_content.deinit(allocator); 353 - var code_lang: ?[]const u8 = null; 354 - var paragraph_lines: std.ArrayList([]const u8) = .empty; 355 - defer paragraph_lines.deinit(allocator); 356 - 357 - while (lines.next()) |line| { 358 - const trimmed = std.mem.trim(u8, line, " \t\r"); 359 - 360 - // handle code blocks 361 - if (std.mem.startsWith(u8, trimmed, "```")) { 362 - if (in_code_block) { 363 - // end code block 364 - try blocks.append(allocator, .{ .block = .{ .code = .{ 365 - .plaintext = try allocator.dupe(u8, code_content.items), 366 - .language = code_lang, 367 - } } }); 368 - code_content.clearRetainingCapacity(); 369 - code_lang = null; 370 - in_code_block = false; 371 - } else { 372 - // flush any pending paragraph first 373 - if (paragraph_lines.items.len > 0) { 374 - const para_text = try std.mem.join(allocator, " ", paragraph_lines.items); 375 - if (para_text.len > 0) { 376 - try blocks.append(allocator, .{ .block = .{ .text = .{ .plaintext = para_text } } }); 377 - } 378 - paragraph_lines.clearRetainingCapacity(); 379 - } 380 - // start code block 381 - in_code_block = true; 382 - const lang_part = trimmed[3..]; 383 - if (lang_part.len > 0) { 384 - code_lang = try allocator.dupe(u8, lang_part); 385 - } 386 - } 387 - continue; 388 - } 389 - 390 - if (in_code_block) { 391 - if (code_content.items.len > 0) { 392 - try code_content.append(allocator, '\n'); 393 - } 394 - try code_content.appendSlice(allocator, line); 395 - continue; 396 - } 397 - 398 - // handle headers 399 - if (trimmed.len > 0 and trimmed[0] == '#') { 400 - // flush any pending paragraph first 401 - if (paragraph_lines.items.len > 0) { 402 - const para_text = try std.mem.join(allocator, " ", paragraph_lines.items); 403 - if (para_text.len > 0) { 404 - try blocks.append(allocator, .{ .block = .{ .text = .{ .plaintext = para_text } } }); 405 - } 406 - paragraph_lines.clearRetainingCapacity(); 407 - } 408 - 409 - var level: u8 = 0; 410 - for (trimmed) |c| { 411 - if (c == '#') level += 1 else break; 412 - } 413 - if (level > 0 and level <= 6 and trimmed.len > level and trimmed[level] == ' ') { 414 - var header_text = trimmed[level + 1 ..]; 415 - // strip markdown link: [text](url) -> text 416 - if (std.mem.indexOf(u8, header_text, "](")) |bracket| { 417 - if (header_text[0] == '[') { 418 - header_text = header_text[1..bracket]; 419 - } 420 - } 421 - try blocks.append(allocator, .{ .block = .{ .header = .{ 422 - .plaintext = try allocator.dupe(u8, header_text), 423 - .level = level, 424 - } } }); 425 - continue; 426 - } 427 - } 428 - 429 - // blank line ends paragraph 430 - if (trimmed.len == 0) { 431 - if (paragraph_lines.items.len > 0) { 432 - const para_text = try std.mem.join(allocator, " ", paragraph_lines.items); 433 - if (para_text.len > 0) { 434 - try blocks.append(allocator, .{ .block = .{ .text = .{ .plaintext = para_text } } }); 435 - } 436 - paragraph_lines.clearRetainingCapacity(); 437 - } 438 - continue; 439 - } 440 - 441 - // accumulate paragraph lines 442 - try paragraph_lines.append(allocator, try allocator.dupe(u8, trimmed)); 443 - } 444 - 445 - // flush remaining content 446 - if (in_code_block and code_content.items.len > 0) { 447 - try blocks.append(allocator, .{ .block = .{ .code = .{ 448 - .plaintext = try allocator.dupe(u8, code_content.items), 449 - .language = code_lang, 450 - } } }); 451 - } else if (paragraph_lines.items.len > 0) { 452 - const para_text = try std.mem.join(allocator, " ", paragraph_lines.items); 453 - if (para_text.len > 0) { 454 - try blocks.append(allocator, .{ .block = .{ .text = .{ .plaintext = para_text } } }); 455 - } 456 - } 457 - 458 - return blocks.toOwnedSlice(allocator); 459 - }