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

Session restore

Changed files
+77 -2
src
commands
+30
bun.lock
··· 10 10 "@atcute/client": "^4.0.5", 11 11 "@atcute/repo": "^0.1.0", 12 12 "@atcute/tid": "^1.0.3", 13 + "@napi-rs/keyring": "^1.2.0", 13 14 "citty": "^0.1.6", 14 15 "consola": "^3.4.2", 15 16 "dotenv": "^17.2.3", ··· 19 20 "remark-parse": "^11.0.0", 20 21 "remark-squeeze-paragraphs": "^6.0.0", 21 22 "sharp": "^0.34.5", 23 + "std-env": "^3.10.0", 22 24 "unified": "^11.0.5", 23 25 "unist-util-remove-position": "^5.0.0", 24 26 "unist-util-visit": "^5.0.0", ··· 146 148 "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], 147 149 148 150 "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], 151 + 152 + "@napi-rs/keyring": ["@napi-rs/keyring@1.2.0", "", { "optionalDependencies": { "@napi-rs/keyring-darwin-arm64": "1.2.0", "@napi-rs/keyring-darwin-x64": "1.2.0", "@napi-rs/keyring-freebsd-x64": "1.2.0", "@napi-rs/keyring-linux-arm-gnueabihf": "1.2.0", "@napi-rs/keyring-linux-arm64-gnu": "1.2.0", "@napi-rs/keyring-linux-arm64-musl": "1.2.0", "@napi-rs/keyring-linux-riscv64-gnu": "1.2.0", "@napi-rs/keyring-linux-x64-gnu": "1.2.0", "@napi-rs/keyring-linux-x64-musl": "1.2.0", "@napi-rs/keyring-win32-arm64-msvc": "1.2.0", "@napi-rs/keyring-win32-ia32-msvc": "1.2.0", "@napi-rs/keyring-win32-x64-msvc": "1.2.0" } }, "sha512-d0d4Oyxm+v980PEq1ZH2PmS6cvpMIRc17eYpiU47KgW+lzxklMu6+HOEOPmxrpnF/XQZ0+Q78I2mgMhbIIo/dg=="], 153 + 154 + "@napi-rs/keyring-darwin-arm64": ["@napi-rs/keyring-darwin-arm64@1.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-CA83rDeyONDADO25JLZsh3eHY8yTEtm/RS6ecPsY+1v+dSawzT9GywBMu2r6uOp1IEhQs/xAfxgybGAFr17lSA=="], 155 + 156 + "@napi-rs/keyring-darwin-x64": ["@napi-rs/keyring-darwin-x64@1.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-dBHjtKRCj4ByfnfqIKIJLo3wueQNJhLRyuxtX/rR4K/XtcS7VLlRD01XXizjpre54vpmObj63w+ZpHG+mGM8uA=="], 157 + 158 + "@napi-rs/keyring-freebsd-x64": ["@napi-rs/keyring-freebsd-x64@1.2.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-DPZFr11pNJSnaoh0dzSUNF+T6ORhy3CkzUT3uGixbA71cAOPJ24iG8e8QrLOkuC/StWrAku3gBnth2XMWOcR3Q=="], 159 + 160 + "@napi-rs/keyring-linux-arm-gnueabihf": ["@napi-rs/keyring-linux-arm-gnueabihf@1.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-8xv6DyEMlvRdqJzp4F39RLUmmTQsLcGYYv/3eIfZNZN1O5257tHxTrFYqAsny659rJJK2EKeSa7PhrSibQqRWQ=="], 161 + 162 + "@napi-rs/keyring-linux-arm64-gnu": ["@napi-rs/keyring-linux-arm64-gnu@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Pu2V6Py+PBt7inryEecirl+t+ti8bhZphjP+W68iVaXHUxLdWmkgL9KI1VkbRHbx5k8K5Tew9OP218YfmVguIA=="], 163 + 164 + "@napi-rs/keyring-linux-arm64-musl": ["@napi-rs/keyring-linux-arm64-musl@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-8TDymrpC4P1a9iDEaegT7RnrkmrJN5eNZh3Im3UEV5PPYGtrb82CRxsuFohthCWQW81O483u1bu+25+XA4nKUw=="], 165 + 166 + "@napi-rs/keyring-linux-riscv64-gnu": ["@napi-rs/keyring-linux-riscv64-gnu@1.2.0", "", { "os": "linux", "cpu": "none" }, "sha512-awsB5XI1MYL7fwfjMDGmKOWvNgJEO7mM7iVEMS0fO39f0kVJnOSjlu7RHcXAF0LOx+0VfF3oxbWqJmZbvRCRHw=="], 167 + 168 + "@napi-rs/keyring-linux-x64-gnu": ["@napi-rs/keyring-linux-x64-gnu@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8E+7z4tbxSJXxIBqA+vfB1CGajpCDRyTyqXkBig5NtASrv4YXcntSo96Iah2QDR5zD3dSTsmbqJudcj9rKKuHQ=="], 169 + 170 + "@napi-rs/keyring-linux-x64-musl": ["@napi-rs/keyring-linux-x64-musl@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8RZ8yVEnmWr/3BxKgBSzmgntI7lNEsY7xouNfOsQkuVAiCNmxzJwETspzK3PQ2FHtDxgz5vHQDEBVGMyM4hUHA=="], 171 + 172 + "@napi-rs/keyring-win32-arm64-msvc": ["@napi-rs/keyring-win32-arm64-msvc@1.2.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-AoqaDZpQ6KPE19VBLpxyORcp+yWmHI9Xs9Oo0PJ4mfHma4nFSLVdhAubJCxdlNptHe5va7ghGCHj3L9Akiv4cQ=="], 173 + 174 + "@napi-rs/keyring-win32-ia32-msvc": ["@napi-rs/keyring-win32-ia32-msvc@1.2.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-EYL+EEI6bCsYi3LfwcQdnX3P/R76ENKNn+3PmpGheBsUFLuh0gQuP7aMVHM4rTw6UVe+L3vCLZSptq/oeacz0A=="], 175 + 176 + "@napi-rs/keyring-win32-x64-msvc": ["@napi-rs/keyring-win32-x64-msvc@1.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xFlx/TsmqmCwNU9v+AVnEJgoEAlBYgzFF5Ihz1rMpPAt4qQWWkMd4sCyM1gMJ1A/GnRqRegDiQpwaxGUHFtFbA=="], 149 177 150 178 "@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=="], 151 179 ··· 390 418 "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], 391 419 392 420 "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], 421 + 422 + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], 393 423 394 424 "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], 395 425
+2
package.json
··· 40 40 "@atcute/client": "^4.0.5", 41 41 "@atcute/repo": "^0.1.0", 42 42 "@atcute/tid": "^1.0.3", 43 + "@napi-rs/keyring": "^1.2.0", 43 44 "citty": "^0.1.6", 44 45 "consola": "^3.4.2", 45 46 "dotenv": "^17.2.3", ··· 49 50 "remark-parse": "^11.0.0", 50 51 "remark-squeeze-paragraphs": "^6.0.0", 51 52 "sharp": "^0.34.5", 53 + "std-env": "^3.10.0", 52 54 "unified": "^11.0.5", 53 55 "unist-util-remove-position": "^5.0.0", 54 56 "unist-util-visit": "^5.0.0",
+9
src/cli.ts
··· 7 7 import { version } from "../package.json" with { type: "json" }; 8 8 9 9 import dotenv from "dotenv"; 10 + import { isCI } from "std-env"; 10 11 if (!("Bun" in globalThis)) dotenv.config({ quiet: true }); 11 12 12 13 const consolaOptions = consola.options; 13 14 consolaOptions.formatOptions.date = false; 14 15 consola.options = consolaOptions; 16 + 17 + export let noKeyring = false; 15 18 16 19 const main = defineCommand({ 17 20 meta: { ··· 23 26 sync: syncCmd, 24 27 config: configCmd, 25 28 files: filesCmd, 29 + }, 30 + args: { 31 + nokeyring: { type: "boolean", description: "Disables saving and restoring of auth session." }, 32 + }, 33 + setup: (ctx) => { 34 + noKeyring = ctx.args.nokeyring || isCI; 26 35 }, 27 36 }); 28 37
+36 -2
src/commands/sync-cmd.ts
··· 1 1 import { defineCommand } from "citty"; 2 - import { Client, CredentialManager, ok, simpleFetchHandler } from "@atcute/client"; 2 + import { Client, CredentialManager, ok, simpleFetchHandler, type AtpSessionData } from "@atcute/client"; 3 3 import type { PubLeafletDocument, PubLeafletPagesLinearDocument, PubLeafletPublication } from "@atcute/leaflet"; 4 4 import * as TID from "@atcute/tid"; 5 5 import { unified } from "unified"; ··· 22 22 import { exists, readJson, loadConfig } from "../utils.ts"; 23 23 import { parse } from "yaml"; 24 24 import type { ActorIdentifier } from "@atcute/lexicons/syntax"; 25 + import { isBun } from "std-env"; 26 + import { Entry } from "@napi-rs/keyring"; 27 + import { noKeyring } from "../cli.ts"; 25 28 26 29 export const syncCmd = defineCommand({ 27 30 async run({ cmd, args }) { ··· 51 54 throw new Error("BSKY_PASSW not provided in .env"); 52 55 } 53 56 54 - await handler.login({ identifier: process.env.BSKY_HANDLE as string, password: process.env.BSKY_PASSW as string }); 57 + let sessionJson = noKeyring 58 + ? null 59 + : isBun 60 + ? await Bun.secrets.get({ 61 + service: "sharpmars.leaflet-md", 62 + name: "apppsw_session/" + process.env.BSKY_HANDLE, 63 + }) 64 + : new Entry("sharpmars.leaflet-md", "apppsw_session/" + process.env.BSKY_HANDLE).getPassword(); 65 + 66 + try { 67 + if (!sessionJson) throw new Error(); 68 + 69 + const session = JSON.parse(sessionJson) as AtpSessionData; 70 + await handler.resume(session); 71 + } catch (error) { 72 + await handler.login({ 73 + identifier: process.env.BSKY_HANDLE as string, 74 + password: process.env.BSKY_PASSW as string, 75 + }); 76 + 77 + if (!noKeyring) { 78 + isBun 79 + ? Bun.secrets.set({ 80 + service: "sharpmars.leaflet-md", 81 + name: "apppsw_session/" + process.env.BSKY_HANDLE, 82 + value: JSON.stringify(handler.session), 83 + }) 84 + : new Entry("sharpmars.leaflet-md", "apppsw_session/" + process.env.BSKY_HANDLE).setPassword( 85 + JSON.stringify(handler.session) 86 + ); 87 + } 88 + } 55 89 56 90 const publications = new Map<RecordKey, string>(); 57 91 const uploadedDocuments = new Map<RecordKey, { cid: string; publishedAt?: string }>();