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

Migrate to standard.site

+56 -28
+2 -2
README.md
··· 14 14 export default defineConfig({ 15 15 glob: { pattern: "**/*.md", base: "./testing/posts" }, 16 16 frontmatter: { type: "yaml", titleKey: "title", descriptionKey: "description", uploadDateKey: "uploadedDate" }, 17 - publicationUri: "at://did:plc:irx36xprktslecsbopbwnh5w/pub.leaflet.publication/3m27dfyhhtk2a", 17 + publicationUri: "at://did:plc:irx36xprktslecsbopbwnh5w/site.standard.publication/3m27dfyhhtk2a", 18 18 codeblockTheme: "catppuccin-mocha", 19 19 prependDoc: { 20 20 path: "./testing/leaflet-prepend.md", ··· 37 37 "descriptionKey": "description", 38 38 "uploadDateKey": "uploadedDate" 39 39 }, 40 - "publicationUri": "at://did:plc:irx36xprktslecsbopbwnh5w/pub.leaflet.publication/3m27dfyhhtk2a", 40 + "publicationUri": "at://did:plc:irx36xprktslecsbopbwnh5w/site.standard.publication/3m27dfyhhtk2a", 41 41 "prependDoc": { 42 42 "path": "./testing/leaflet-prepend.md" 43 43 }
+3
bun.lock
··· 30 30 "@atcute/atproto": "^3.1.10", 31 31 "@atcute/leaflet": "^1.0.19", 32 32 "@atcute/microcosm": "^1.0.1", 33 + "@atcute/standard-site": "^1.0.1", 33 34 "@types/bun": "1.3.9", 34 35 "@types/mdast": "^4.0.4", 35 36 "tsdown": "^0.20.3", ··· 57 58 "@atcute/microcosm": ["@atcute/microcosm@1.0.1", "", { "dependencies": { "@atcute/lexicons": "^1.2.7" } }, "sha512-siyreLgOCZ6gT3x5tajTw1MrlR0s4SDNlUvaRYQZrAUZS1xuuLx1Ko/cwsf+/QQzEN6K1wgtTC0J6HqtRZwWVg=="], 58 59 59 60 "@atcute/multibase": ["@atcute/multibase@1.1.8", "", { "dependencies": { "@atcute/uint8array": "^1.1.1" } }, "sha512-pJgtImMZKCjqwRbu+2GzB+4xQjKBXDwdZOzeqe0u97zYKRGftpGYGvYv3+pMe2xXe+msDyu7Nv8iJp+U14otTA=="], 61 + 62 + "@atcute/standard-site": ["@atcute/standard-site@1.0.1", "", { "dependencies": { "@atcute/atproto": "^3.1.10", "@atcute/lexicons": "^1.2.7" } }, "sha512-wL4ZAvbe3p7NxC92rRgc6vbd+0feNDEAfEcBLA+68KDTUtmtEko5lr09R31P7AWlN4MVTMRj5iLb9UaTThIzWw=="], 60 63 61 64 "@atcute/tid": ["@atcute/tid@1.1.2", "", { "dependencies": { "@atcute/time-ms": "^1.2.2" } }, "sha512-bmPuOX/TOfcm/vsK9vM98spjkcx2wgd9S2PeK5oLgEr8IbNRPq7iMCAPzOL1nu5XAW3LlkOYQEbYRcw5vcQ37w=="], 62 65
+1
package.json
··· 27 27 "@atcute/atproto": "^3.1.10", 28 28 "@atcute/leaflet": "^1.0.19", 29 29 "@atcute/microcosm": "^1.0.1", 30 + "@atcute/standard-site": "^1.0.1", 30 31 "@types/bun": "1.3.9", 31 32 "@types/mdast": "^4.0.4", 32 33 "tsdown": "^0.20.3"
+11 -2
src/commands/config-cmd.ts
··· 4 4 import { exists, loadConfig } from "../utils.ts"; 5 5 import { Client, simpleFetchHandler } from "@atcute/client"; 6 6 import type { ActorIdentifier } from "@atcute/lexicons/syntax"; 7 + import type { SiteStandardPublication } from "@atcute/standard-site"; 7 8 8 9 export const configCmd = defineCommand({ 9 10 async run(context) { ··· 36 37 printConfigLine("Glob pattern", config.glob.pattern); 37 38 if (config.glob.base) printConfigLine("Search folder", config.glob.base); 38 39 if (config.publicationUri) { 39 - let publicationStatus: "HandleNotProvided" | "NotFound" | "Found" | "ServerError" = "ServerError"; 40 + let publicationStatus: "HandleNotProvided" | "NotFound" | "Found" | "NotLeafletPublication" | "ServerError" = 41 + "ServerError"; 40 42 41 43 try { 42 44 if (!process.env.BSKY_HANDLE) { ··· 49 51 const recordRes = await slingshot.get("com.atproto.repo.getRecord", { 50 52 params: { 51 53 repo: process.env.BSKY_HANDLE as ActorIdentifier, 52 - collection: "pub.leaflet.publication", 54 + collection: "site.standard.publication", 53 55 rkey: rkey, 54 56 }, 55 57 }); ··· 61 63 62 64 if (!recordRes.ok) { 63 65 publicationStatus = "ServerError"; 66 + throw new Error(); 67 + } 68 + 69 + const url = (recordRes.data.value as SiteStandardPublication.Main).url; 70 + 71 + if (!url.endsWith(".leaflet.pub")) { 72 + publicationStatus = "NotLeafletPublication"; 64 73 throw new Error(); 65 74 } 66 75
+20 -12
src/commands/sync-cmd.ts
··· 24 24 import { isBun } from "std-env"; 25 25 import { Entry } from "@napi-rs/keyring"; 26 26 import { noKeyring } from "../cli.ts"; 27 + import type { SiteStandardPublication } from "@atcute/standard-site"; 27 28 28 29 export const syncCmd = defineCommand({ 29 30 async run({ cmd, args }) { ··· 94 95 const res = await ok( 95 96 client.get("com.atproto.repo.listRecords", { 96 97 params: { 97 - collection: "pub.leaflet.document", 98 + collection: "site.standard.document", 98 99 repo: miniDoc.did, 99 100 limit: 100, 100 101 cursor: docCursor, ··· 120 121 const rkey = config.publicationUri.split("/").at(-1) as string; 121 122 122 123 const res = await client.get("com.atproto.repo.getRecord", { 123 - params: { collection: "pub.leaflet.publication", repo: miniDoc.did, rkey: rkey }, 124 + params: { collection: "site.standard.publication", repo: miniDoc.did, rkey: rkey }, 124 125 }); 125 126 126 127 if (!res.ok) throw new Error("Could not find publication from the config."); 128 + const publication = res.data.value as SiteStandardPublication.Main; 129 + if (!publication.url.endsWith(".leaflet.pub")) 130 + throw new Error("Publication specified in the config is not from leaflet.pub"); 127 131 publicationUri = config.publicationUri; 128 - publicationName = (res.data.value as PubLeafletPublication.Main).name; 132 + publicationName = publication.name; 129 133 } else { 130 134 const res = await ok( 131 135 client.get("com.atproto.repo.listRecords", { 132 - params: { collection: "pub.leaflet.publication", repo: miniDoc.did, limit: 3 }, 136 + params: { collection: "site.standard.publication", repo: miniDoc.did, limit: 3 }, 133 137 }) 134 138 ); 135 139 136 - if (res.records.length > 0) { 137 - if (res.records.length > 1) 140 + const leafletPublications = res.records.filter((val) => 141 + (val.value as SiteStandardPublication.Main).url.endsWith(".leaflet.pub") 142 + ); 143 + 144 + if (leafletPublications.length > 0) { 145 + if (leafletPublications.length > 1) 138 146 throw new Error( 139 147 "There are more then 1 publications in your repo.\nPlease specify which one to use in your config." 140 148 ); 141 149 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; 150 + publicationUri = `at://${miniDoc.did}/site.standard.publication/${leafletPublications[0]!.uri.split("/").at(-1)}`; 151 + publicationName = (leafletPublications[0]!.value as SiteStandardPublication.Main).name; 144 152 } else { 145 153 throw new Error("Could not find any publications in your repo."); 146 154 } ··· 330 338 331 339 uploadDate ??= new Date(Date.now()).toISOString(); 332 340 341 + const tid = rkey ? rkey : TID.now(); 342 + 333 343 const doc = generateDoc( 334 - miniDoc.did, 344 + tid, 335 345 publicationUri, 336 346 [...prependBlocks, ...generateBlocks(ast.children, uploadedImages, codeblockTheme), ...appendBlocks], 337 347 title, ··· 346 356 continue; 347 357 } 348 358 349 - const tid = rkey ? rkey : TID.now(); 350 - 351 359 const res = await client.post("com.atproto.repo.putRecord", { 352 360 input: { 353 - collection: "pub.leaflet.document", 361 + collection: "site.standard.document", 354 362 repo: miniDoc.did, 355 363 rkey: tid, 356 364 record: doc,
+1 -1
src/config.ts
··· 24 24 25 25 export function defineConfig(config: Config) { 26 26 if (config.publicationUri) { 27 - if (!config.publicationUri.includes("/pub.leaflet.publication/")) 27 + if (!config.publicationUri.includes("/site.standard.publication/")) 28 28 throw new Error("Invalid publicationUri inside of the config."); 29 29 } 30 30
+17 -11
src/doc.ts
··· 1 - import type { PubLeafletDocument, PubLeafletPagesLinearDocument } from "@atcute/leaflet"; 2 - import type { ActorIdentifier, ResourceUri } from "@atcute/lexicons"; 1 + import type { PubLeafletContent, PubLeafletPagesLinearDocument } from "@atcute/leaflet"; 2 + import type { ResourceUri } from "@atcute/lexicons"; 3 + import type { SiteStandardDocument } from "@atcute/standard-site"; 3 4 4 5 export function generateDoc( 5 - author: ActorIdentifier, 6 + tid: string, 6 7 publicationUri: ResourceUri, 7 8 blocks: PubLeafletPagesLinearDocument.Block[], 8 9 title?: string, 9 10 description?: string, 10 11 uploadDate?: Date 11 - ): PubLeafletDocument.Main { 12 - return { 13 - $type: "pub.leaflet.document", 14 - author: author, 15 - title: title ? title : "Testing", 16 - description: description ? description : "test", 17 - publishedAt: uploadDate ? uploadDate.toISOString() : new Date().toISOString(), 18 - publication: publicationUri, 12 + ): SiteStandardDocument.Main { 13 + const content: PubLeafletContent.Main = { 14 + $type: "pub.leaflet.content", 19 15 pages: [ 20 16 { 21 17 $type: "pub.leaflet.pages.linearDocument", 22 18 blocks: blocks, 23 19 }, 24 20 ], 21 + }; 22 + 23 + return { 24 + $type: "site.standard.document", 25 + path: "/" + tid, 26 + site: publicationUri, 27 + title: title ? title : "Testing", 28 + description: description ? description : "test", 29 + publishedAt: uploadDate ? uploadDate.toISOString() : new Date().toISOString(), 30 + content: content as any, 25 31 }; 26 32 }
+1
tsconfig.json
··· 29 29 "@atcute/leaflet", 30 30 "@atcute/atproto", 31 31 "@atcute/microcosm", 32 + "@atcute/standard-site", 32 33 "@types/bun" 33 34 ], 34 35 "noImplicitAny": false