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

Configure Feed

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

Use listRecords instead of getRepo

SharpMars 8b380527 286b3bac

+43 -34
-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 }