atproto utils for zig zat.dev
atproto sdk zig

Revert "publish docs to leaflet alongside site.standard"

This reverts commit f640677ae49e30dbcc3df8bd21a9b2b08b722b54.

Changed files
-204
.tangled
workflows
scripts
-8
.tangled/workflows/publish-docs.yml
··· 1 when: 2 - event: push 3 tag: "v*" 4 - - event: push 5 - branch: main 6 - path: 7 - - "README.md" 8 - - "CHANGELOG.md" 9 - - "docs/**" 10 - - "devlog/**" 11 12 engine: nixery 13 ··· 18 steps: 19 - name: build and publish docs to ATProto 20 command: | 21 - test -n "$ATPROTO_PASSWORD" 22 zig build 23 ./zig-out/bin/publish-docs
··· 1 when: 2 - event: push 3 tag: "v*" 4 5 engine: nixery 6 ··· 11 steps: 12 - name: build and publish docs to ATProto 13 command: | 14 zig build 15 ./zig-out/bin/publish-docs
-196
scripts/publish-docs.zig
··· 82 83 try putRecord(&client, allocator, session.did, "site.standard.document", tid.str(), doc_record); 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 } 101 102 // devlog publication (clock_id 100 to separate from docs) ··· 136 137 try putRecord(&client, allocator, session.did, "site.standard.document", tid.str(), doc_record); 138 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 } 155 156 std.debug.print("done\n", .{}); ··· 172 publishedAt: []const u8, 173 }; 174 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 const Session = struct { 225 did: []const u8, 226 access_token: []const u8, ··· 340 }) catch unreachable; 341 return buf; 342 } 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 - }
··· 82 83 try putRecord(&client, allocator, session.did, "site.standard.document", tid.str(), doc_record); 84 std.debug.print("published: {s} -> at://{s}/site.standard.document/{s}\n", .{ doc.file, session.did, tid.str() }); 85 } 86 87 // devlog publication (clock_id 100 to separate from docs) ··· 121 122 try putRecord(&client, allocator, session.did, "site.standard.document", tid.str(), doc_record); 123 std.debug.print("published: {s} -> at://{s}/site.standard.document/{s}\n", .{ entry.file, session.did, tid.str() }); 124 } 125 126 std.debug.print("done\n", .{}); ··· 142 publishedAt: []const u8, 143 }; 144 145 const Session = struct { 146 did: []const u8, 147 access_token: []const u8, ··· 261 }) catch unreachable; 262 return buf; 263 }