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

Configure Feed

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

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