CLI tool to sync your Markdown to Leaflet
leafletpub atproto cli markdown

Use listRecords instead of getRepo

Changed files
+43 -34
src
commands
-13
bun.lock
··· 8 8 "@atcute/cbor": "^2.2.7", 9 9 "@atcute/cid": "^2.2.6", 10 10 "@atcute/client": "^4.0.5", 11 - "@atcute/repo": "^0.1.0", 12 11 "@atcute/tid": "^1.0.3", 13 12 "@napi-rs/keyring": "^1.2.0", 14 13 "citty": "^0.1.6", ··· 43 42 "packages": { 44 43 "@atcute/atproto": ["@atcute/atproto@3.1.9", "", { "dependencies": { "@atcute/lexicons": "^1.2.2" } }, "sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w=="], 45 44 46 - "@atcute/car": ["@atcute/car@5.0.0", "", { "dependencies": { "@atcute/cbor": "^2.2.7", "@atcute/cid": "^2.2.6", "@atcute/uint8array": "^1.0.5", "@atcute/varint": "^1.0.3" } }, "sha512-OIY2xTXv8lSpZsDSn/UYQtJSMvDw5Hi4Q+uyvmiqSM+fht08QRAEq/nxa5YFciPZ3nfDFnZ3//EgJw7QhkSXLQ=="], 47 - 48 45 "@atcute/cbor": ["@atcute/cbor@2.2.7", "", { "dependencies": { "@atcute/cid": "^2.2.5", "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-/mwAF0gnokOphceZqFq3uzMGdd8sbw5y6bxF8CRutRkCCUcpjjpJc5fkLwhxyGgOveF3mZuHE6p7t/+IAqb7Aw=="], 49 46 50 47 "@atcute/cid": ["@atcute/cid@2.2.6", "", { "dependencies": { "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-bTAHHbJ24p+E//V4KCS4xdmd39o211jJswvqQOevj7vk+5IYcgDLx1ryZWZ1sEPOo9x875li/kj5gpKL14RDwQ=="], 51 48 52 49 "@atcute/client": ["@atcute/client@4.0.5", "", { "dependencies": { "@atcute/identity": "^1.1.1", "@atcute/lexicons": "^1.2.2" } }, "sha512-R8Qen8goGmEkynYGg2m6XFlVmz0GTDvQ+9w+4QqOob+XMk8/WDpF4aImev7WKEde/rV2gjcqW7zM8E6W9NShDA=="], 53 50 54 - "@atcute/crypto": ["@atcute/crypto@2.2.6", "", { "dependencies": { "@atcute/multibase": "^1.1.6", "@atcute/uint8array": "^1.0.5", "@noble/secp256k1": "^3.0.0" } }, "sha512-vkuexF+kmrKE1/Uqzub99Qi4QpnxA2jbu60E6PTgL4XypELQ6rb59MB/J1VbY2gs0kd3ET7+L3+NWpKD5nXyfA=="], 55 - 56 51 "@atcute/identity": ["@atcute/identity@1.1.2", "", { "dependencies": { "@atcute/lexicons": "^1.2.3", "@badrap/valita": "^0.4.6" } }, "sha512-vn0RN7SUF6N0sEPG9yyT6a0MzpfVS8BhsiLtB8OeS4qp2rLMQW33pelCpNitP1N+fq03MFlDGzs5p7K4qMs4cA=="], 57 52 58 53 "@atcute/leaflet": ["@atcute/leaflet@1.0.12", "", { "dependencies": { "@atcute/atproto": "^3.1.9", "@atcute/lexicons": "^1.2.2" } }, "sha512-T5laBTl8vwzy0eZXBy07IQSjsLqhbZmRJsffnNQ6XMSc+lnCZ/NHfuKy8TNJbDU6dc26Z7o5l0ELfWz5QESo+w=="], ··· 61 56 62 57 "@atcute/microcosm": ["@atcute/microcosm@1.0.0", "", { "dependencies": { "@atcute/lexicons": "^1.2.3" } }, "sha512-XJW+TMvdktH2maTkVcNU6wKmnHpmNwhmg0Xj4ZY36plHpqNHfxR4kAAcXGSJcjH9CS8I1+cTHiyUQykdeOPeGg=="], 63 58 64 - "@atcute/mst": ["@atcute/mst@0.1.0", "", { "dependencies": { "@atcute/cbor": "^2.2.7", "@atcute/cid": "^2.2.6", "@atcute/uint8array": "^1.0.5" } }, "sha512-h+iDToKEnBpigk2DOHjSqY63vJtjYKUIztqu1CZ0P+I54wV2SrgoqAXAT1xrW6A1Iup8cjTv+U2H5WVG4KxPLw=="], 65 - 66 59 "@atcute/multibase": ["@atcute/multibase@1.1.6", "", { "dependencies": { "@atcute/uint8array": "^1.0.5" } }, "sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg=="], 67 - 68 - "@atcute/repo": ["@atcute/repo@0.1.0", "", { "dependencies": { "@atcute/car": "^5.0.0", "@atcute/cbor": "^2.2.7", "@atcute/cid": "^2.2.6", "@atcute/crypto": "^2.2.5", "@atcute/lexicons": "^1.2.2", "@atcute/mst": "^0.1.0", "@atcute/uint8array": "^1.0.5" } }, "sha512-INiYAuma8dydBu7cqd2WVpcXh3mzhIepYBUqFWAK5MqMulPRLTRCc/9GW3G9pxYrOdlvLCVamG2Jf8XK0nuFEw=="], 69 60 70 61 "@atcute/tid": ["@atcute/tid@1.0.3", "", {}, "sha512-wfMJx1IMdnu0CZgWl0uR4JO2s6PGT1YPhpytD4ZHzEYKKQVuqV6Eb/7vieaVo1eYNMp2FrY67FZObeR7utRl2w=="], 71 62 72 63 "@atcute/uint8array": ["@atcute/uint8array@1.0.5", "", {}, "sha512-XLWWxoR2HNl2qU+FCr0rp1APwJXci7HnzbOQLxK55OaMNBXZ19+xNC5ii4QCsThsDxa4JS/JTzuiQLziITWf2Q=="], 73 - 74 - "@atcute/varint": ["@atcute/varint@1.0.3", "", {}, "sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog=="], 75 64 76 65 "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], 77 66 ··· 176 165 "@napi-rs/keyring-win32-x64-msvc": ["@napi-rs/keyring-win32-x64-msvc@1.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xFlx/TsmqmCwNU9v+AVnEJgoEAlBYgzFF5Ihz1rMpPAt4qQWWkMd4sCyM1gMJ1A/GnRqRegDiQpwaxGUHFtFbA=="], 177 166 178 167 "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], 179 - 180 - "@noble/secp256k1": ["@noble/secp256k1@3.0.0", "", {}, "sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg=="], 181 168 182 169 "@oxc-project/runtime": ["@oxc-project/runtime@0.97.0", "", {}, "sha512-yH0zw7z+jEws4dZ4IUKoix5Lh3yhqIJWF9Dc8PWvhpo7U7O+lJrv7ZZL4BeRO0la8LBQFwcCewtLBnVV7hPe/w=="], 183 170
-1
package.json
··· 38 38 "@atcute/cbor": "^2.2.7", 39 39 "@atcute/cid": "^2.2.6", 40 40 "@atcute/client": "^4.0.5", 41 - "@atcute/repo": "^0.1.0", 42 41 "@atcute/tid": "^1.0.3", 43 42 "@napi-rs/keyring": "^1.2.0", 44 43 "citty": "^0.1.6",
+40 -19
src/commands/sync-cmd.ts
··· 13 13 import { gatherImages, generateBlocks, replaceInAst } from "../conversion"; 14 14 import type { Blob, RecordKey, ResourceUri } from "@atcute/lexicons"; 15 15 import { glob, readFile, writeFile } from "node:fs/promises"; 16 - import { fromStream } from "@atcute/repo"; 17 16 import * as CID from "@atcute/cid"; 18 17 import * as CBOR from "@atcute/cbor"; 19 18 import { generateDoc } from "../doc.ts"; ··· 87 86 } 88 87 } 89 88 90 - const publications = new Map<RecordKey, string>(); 91 89 const uploadedDocuments = new Map<RecordKey, { cid: string; publishedAt?: string }>(); 92 90 93 - const carReq = await fetch(`${miniDoc.pds}/xrpc/com.atproto.sync.getRepo?did=${miniDoc.did}`); 94 - await using repo = fromStream(carReq.body!); 91 + let docCursor: string | undefined = undefined; 92 + 93 + do { 94 + const res = await ok( 95 + client.get("com.atproto.repo.listRecords", { 96 + params: { 97 + collection: "pub.leaflet.document", 98 + repo: miniDoc.did, 99 + limit: 100, 100 + cursor: docCursor, 101 + }, 102 + }) 103 + ); 95 104 96 - for await (const entry of repo) { 97 - if (entry.collection == "pub.leaflet.document") { 98 - uploadedDocuments.set(entry.rkey, { 99 - cid: entry.cid.$link, 100 - publishedAt: (entry.record as PubLeafletDocument.Main).publishedAt, 105 + for (const doc of res.records) { 106 + uploadedDocuments.set(doc.uri.split("/").at(-1)!, { 107 + cid: doc.cid, 108 + publishedAt: (doc.value as PubLeafletDocument.Main).publishedAt, 101 109 }); 102 - } else if (entry.collection == "pub.leaflet.publication") { 103 - publications.set(entry.rkey, (entry.record as PubLeafletPublication.Main).name); 104 110 } 105 - } 106 111 107 - repo.dispose(); 112 + docCursor = res.cursor; 113 + if (res.records.length == 0) docCursor = undefined; 114 + } while (docCursor); 108 115 109 116 let publicationUri: ResourceUri; 110 117 let publicationName: string; 111 118 112 119 if (config.publicationUri) { 113 120 const rkey = config.publicationUri.split("/").at(-1) as string; 114 - if (!publications.has(rkey)) throw new Error("Could not find publication from the config."); 121 + 122 + const res = await client.get("com.atproto.repo.getRecord", { 123 + params: { collection: "pub.leaflet.publication", repo: miniDoc.did, rkey: rkey }, 124 + }); 115 125 126 + if (!res.ok) throw new Error("Could not find publication from the config."); 116 127 publicationUri = config.publicationUri; 117 - publicationName = publications.get(rkey)!; 128 + publicationName = (res.data.value as PubLeafletPublication.Main).name; 118 129 } else { 119 - if (publications.size > 0) { 120 - const publication = publications.entries().next().value!; 121 - publicationUri = `at://${miniDoc.did}/pub.leaflet.publication/${publication[0]}`; 122 - publicationName = publication[1]; 130 + const res = await ok( 131 + client.get("com.atproto.repo.listRecords", { 132 + params: { collection: "pub.leaflet.publication", repo: miniDoc.did, limit: 3 }, 133 + }) 134 + ); 135 + 136 + if (res.records.length > 0) { 137 + if (res.records.length > 1) 138 + throw new Error( 139 + "There are more then 1 publications in your repo.\nPlease specify which one to use in your config." 140 + ); 141 + 142 + publicationUri = `at://${miniDoc.did}/pub.leaflet.publication/${res.records[0]!.uri.split("/").at(-1)}`; 143 + publicationName = (res.records[0]!.value as PubLeafletPublication.Main).name; 123 144 } else { 124 145 throw new Error("Could not find any publications in your repo."); 125 146 }
+3 -1
tsconfig.json
··· 1 1 { 2 + "$schema": "https://www.schemastore.org/tsconfig.json", 2 3 "compilerOptions": { 3 4 // Environment setup & latest features 4 5 "lib": [ ··· 29 30 "@atcute/atproto", 30 31 "@atcute/microcosm", 31 32 "@types/bun" 32 - ] 33 + ], 34 + "noImplicitAny": false 33 35 } 34 36 }