From 544483ba5a41c65e025bc10908351fcf840a89d1 Mon Sep 17 00:00:00 2001 From: Steve Date: Wed, 28 Jan 2026 23:57:11 -0500 Subject: [PATCH] chore: cleaned up commands and libs --- packages/cli/src/commands/init.ts | 127 +++++++++++---------------- packages/cli/src/commands/publish.ts | 7 +- packages/cli/src/commands/sync.ts | 2 +- packages/cli/src/lib/atproto.ts | 17 +--- packages/cli/src/lib/config.ts | 5 -- packages/cli/src/lib/markdown.ts | 12 +-- packages/cli/src/lib/tid.ts | 41 --------- packages/cli/src/lib/types.ts | 99 ++++++++++----------- 8 files changed, 100 insertions(+), 210 deletions(-) delete mode 100644 packages/cli/src/lib/tid.ts diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 38aa425..1d02c51 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -53,26 +53,14 @@ export const initCommand = command({ }, ); - const hasImages = await consola.prompt( - "Do you have a separate directory for cover images?", + const imagesDir = await consola.prompt( + "Cover images directory (where cover/og images are stored, leave empty to skip):", { - type: "confirm", - initial: false, + type: "text", + placeholder: "./public/images", }, ); - let imagesDir: string | undefined; - if (hasImages) { - const imgDir = await consola.prompt( - "Cover images directory (where cover/og images are stored):", - { - type: "text", - placeholder: "./public/images", - }, - ); - imagesDir = imgDir as string; - } - // Public/static directory for .well-known files const publicDir = await consola.prompt( "Public/static directory (for .well-known files):", @@ -104,63 +92,52 @@ export const initCommand = command({ ); // Frontmatter mapping configuration - const customFrontmatter = await consola.prompt( - "Do you use custom frontmatter field names?", - { - type: "confirm", - initial: false, - }, + consola.info( + "Configure your frontmatter field mappings (press Enter to use defaults):", ); - let frontmatterMapping: FrontmatterMapping | undefined; - if (customFrontmatter) { - consola.info( - "Configure your frontmatter field mappings (press Enter to use defaults):", - ); - - const titleField = await consola.prompt("Field name for title:", { - type: "text", - default: "title", - placeholder: "title", - }); + const titleField = await consola.prompt("Field name for title:", { + type: "text", + default: "title", + placeholder: "title", + }); - const descField = await consola.prompt("Field name for description:", { - type: "text", - default: "description", - placeholder: "description", - }); + const descField = await consola.prompt("Field name for description:", { + type: "text", + default: "description", + placeholder: "description", + }); - const dateField = await consola.prompt("Field name for publish date:", { - type: "text", - default: "publishDate", - placeholder: "publishDate, pubDate, date, etc.", - }); + const dateField = await consola.prompt("Field name for publish date:", { + type: "text", + default: "publishDate", + placeholder: "publishDate, pubDate, date, etc.", + }); - const coverField = await consola.prompt("Field name for cover image:", { - type: "text", - default: "ogImage", - placeholder: "ogImage, coverImage, image, hero, etc.", - }); + const coverField = await consola.prompt("Field name for cover image:", { + type: "text", + default: "ogImage", + placeholder: "ogImage, coverImage, image, hero, etc.", + }); - frontmatterMapping = {}; + let frontmatterMapping: FrontmatterMapping | undefined = {}; - if (titleField && titleField !== "title") { - frontmatterMapping.title = titleField as string; - } - if (descField && descField !== "description") { - frontmatterMapping.description = descField as string; - } - if (dateField && dateField !== "publishDate") { - frontmatterMapping.publishDate = dateField as string; - } - if (coverField && coverField !== "ogImage") { - frontmatterMapping.coverImage = coverField as string; - } + if (titleField && titleField !== "title") { + frontmatterMapping.title = titleField as string; + } + if (descField && descField !== "description") { + frontmatterMapping.description = descField as string; + } + if (dateField && dateField !== "publishDate") { + frontmatterMapping.publishDate = dateField as string; + } + if (coverField && coverField !== "ogImage") { + frontmatterMapping.coverImage = coverField as string; + } - // Only keep frontmatterMapping if it has any custom fields - if (Object.keys(frontmatterMapping).length === 0) { - frontmatterMapping = undefined; - } + // Only keep frontmatterMapping if it has any custom fields + if (Object.keys(frontmatterMapping).length === 0) { + frontmatterMapping = undefined; } // Publication setup @@ -214,19 +191,13 @@ export const initCommand = command({ }, ); - const hasIcon = await consola.prompt("Add an icon image?", { - type: "confirm", - initial: false, - }); - - let iconPath: string | undefined; - if (hasIcon) { - const icon = await consola.prompt("Icon image path:", { + const iconPath = await consola.prompt( + "Icon image path (leave empty to skip):", + { type: "text", placeholder: "./icon.png", - }); - iconPath = icon as string; - } + }, + ); const showInDiscover = await consola.prompt("Show in Discover feed?", { type: "confirm", @@ -239,7 +210,7 @@ export const initCommand = command({ url: siteUrl as string, name: pubName as string, description: (pubDescription as string) || undefined, - iconPath, + iconPath: (iconPath as string) || undefined, showInDiscover, }); consola.success(`Publication created: ${publicationUri}`); @@ -267,7 +238,7 @@ export const initCommand = command({ const configContent = generateConfigTemplate({ siteUrl: siteUrl as string, contentDir: contentDir as string, - imagesDir, + imagesDir: imagesDir || undefined, publicDir: publicDir as string, outputDir: outputDir as string, pathPrefix: pathPrefix as string, diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index 16f0415..4215b3d 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -84,7 +84,7 @@ export const publishCommand = command({ // Scan for posts consola.start("Scanning for posts..."); - const posts = await scanContentDirectory(contentDir, config.include, config.exclude, config.frontmatter); + const posts = await scanContentDirectory(contentDir, config.frontmatter); consola.info(`Found ${posts.length} posts`); // Determine which posts need publishing @@ -95,11 +95,6 @@ export const publishCommand = command({ }> = []; for (const post of posts) { - // Skip hidden posts - if (post.frontmatter.hidden) { - continue; - } - const contentHash = await getContentHash(post.rawContent); const relativeFilePath = path.relative(configDir, post.filePath); const postState = state.posts[relativeFilePath]; diff --git a/packages/cli/src/commands/sync.ts b/packages/cli/src/commands/sync.ts index 628ff84..589be54 100644 --- a/packages/cli/src/commands/sync.ts +++ b/packages/cli/src/commands/sync.ts @@ -86,7 +86,7 @@ export const syncCommand = command({ // Scan local posts consola.start("Scanning local content..."); - const localPosts = await scanContentDirectory(contentDir, config.include, config.exclude, config.frontmatter); + const localPosts = await scanContentDirectory(contentDir, config.frontmatter); consola.info(`Found ${localPosts.length} local posts`); // Build a map of path -> local post for matching diff --git a/packages/cli/src/lib/atproto.ts b/packages/cli/src/lib/atproto.ts index cf08f64..50a9af3 100644 --- a/packages/cli/src/lib/atproto.ts +++ b/packages/cli/src/lib/atproto.ts @@ -1,7 +1,6 @@ import { AtpAgent } from "@atproto/api"; import * as path from "path"; -import type { Credentials, BlogPost, BlobObject, PublisherConfig, PublicationRecord } from "./types"; -import { generateTid } from "./tid"; +import type { Credentials, BlogPost, BlobObject, PublisherConfig } from "./types"; import { stripMarkdownForText } from "./markdown"; export async function resolveHandleToPDS(handle: string): Promise { @@ -184,16 +183,9 @@ export async function createDocument( record.coverImage = coverImage; } - if (config.location) { - record.location = config.location; - } - - const rkey = generateTid(); - const response = await agent.com.atproto.repo.createRecord({ repo: agent.session!.did, collection: "site.standard.document", - rkey, record, }); @@ -235,10 +227,6 @@ export async function updateDocument( record.coverImage = coverImage; } - if (config.location) { - record.location = config.location; - } - await agent.com.atproto.repo.putRecord({ repo: agent.session!.did, collection: collection!, @@ -342,12 +330,9 @@ export async function createPublication( }; } - const rkey = generateTid(); - const response = await agent.com.atproto.repo.createRecord({ repo: agent.session!.did, collection: "site.standard.publication", - rkey, record, }); diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index ede1186..13481c7 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -66,7 +66,6 @@ export function generateConfigTemplate(options: { pathPrefix?: string; publicationUri: string; pdsUrl?: string; - location?: string; frontmatter?: FrontmatterMapping; }): string { const config: Record = { @@ -96,10 +95,6 @@ export function generateConfigTemplate(options: { config.pdsUrl = options.pdsUrl; } - if (options.location) { - config.location = options.location; - } - if (options.frontmatter && Object.keys(options.frontmatter).length > 0) { config.frontmatter = options.frontmatter; } diff --git a/packages/cli/src/lib/markdown.ts b/packages/cli/src/lib/markdown.ts index 5300094..6ba0596 100644 --- a/packages/cli/src/lib/markdown.ts +++ b/packages/cli/src/lib/markdown.ts @@ -82,10 +82,6 @@ export function parseFrontmatter(content: string, mapping?: FrontmatterMapping): const coverField = mapping?.coverImage || "ogImage"; frontmatter.ogImage = raw[coverField] || raw.ogImage; - // Hidden mapping - const hiddenField = mapping?.hidden || "hidden"; - frontmatter.hidden = raw[hiddenField] || raw.hidden; - // Tags mapping const tagsField = mapping?.tags || "tags"; frontmatter.tags = raw[tagsField] || raw.tags; @@ -113,11 +109,9 @@ export async function getContentHash(content: string): Promise { export async function scanContentDirectory( contentDir: string, - include?: string[], - exclude?: string[], frontmatterMapping?: FrontmatterMapping ): Promise { - const patterns = include || ["**/*.md", "**/*.mdx"]; + const patterns = ["**/*.md", "**/*.mdx"]; const posts: BlogPost[] = []; for (const pattern of patterns) { @@ -127,10 +121,6 @@ export async function scanContentDirectory( cwd: contentDir, absolute: false, })) { - // Check exclusions - if (exclude?.some((ex) => relativePath.includes(ex))) { - continue; - } const filePath = path.join(contentDir, relativePath); const file = Bun.file(filePath); diff --git a/packages/cli/src/lib/tid.ts b/packages/cli/src/lib/tid.ts deleted file mode 100644 index b9ccb5d..0000000 --- a/packages/cli/src/lib/tid.ts +++ /dev/null @@ -1,41 +0,0 @@ -// TID (Timestamp Identifier) generation per ATProto spec -// Format: base32-sortable encoded, 13 characters -// Structure: 53 bits of timestamp (microseconds since epoch) + 10 bits of clock ID - -const S32_CHAR = "234567abcdefghijklmnopqrstuvwxyz"; - -let lastTimestamp = 0; -let clockId = Math.floor(Math.random() * 1024); - -export function generateTid(): string { - // Get current timestamp in microseconds - let timestamp = Date.now() * 1000; - - // Ensure monotonically increasing timestamps - if (timestamp <= lastTimestamp) { - timestamp = lastTimestamp + 1; - } - lastTimestamp = timestamp; - - // Combine timestamp (53 bits) and clock ID (10 bits) - // TID is a 63-bit integer encoded as 13 base32 characters - const tid = (BigInt(timestamp) << 10n) | BigInt(clockId); - - // Convert to base32-sortable - let result = ""; - let value = tid; - for (let i = 0; i < 13; i++) { - result = S32_CHAR[Number(value % 32n)] + result; - value = value / 32n; - } - - return result; -} - -export function isValidTid(tid: string): boolean { - if (tid.length !== 13) return false; - for (const char of tid) { - if (!S32_CHAR.includes(char)) return false; - } - return true; -} diff --git a/packages/cli/src/lib/types.ts b/packages/cli/src/lib/types.ts index 1649b5d..d3e6dd7 100644 --- a/packages/cli/src/lib/types.ts +++ b/packages/cli/src/lib/types.ts @@ -1,81 +1,76 @@ export interface FrontmatterMapping { - title?: string; // Field name for title (default: "title") - description?: string; // Field name for description (default: "description") - publishDate?: string; // Field name for publish date (default: "publishDate", also checks "pubDate", "date", "createdAt", "created_at") - coverImage?: string; // Field name for cover image (default: "ogImage") - hidden?: string; // Field name for hidden flag (default: "hidden") - tags?: string; // Field name for tags (default: "tags") + title?: string; // Field name for title (default: "title") + description?: string; // Field name for description (default: "description") + publishDate?: string; // Field name for publish date (default: "publishDate", also checks "pubDate", "date", "createdAt", "created_at") + coverImage?: string; // Field name for cover image (default: "ogImage") + tags?: string; // Field name for tags (default: "tags") } export interface PublisherConfig { - siteUrl: string; - contentDir: string; - imagesDir?: string; // Directory containing cover images - publicDir?: string; // Static/public folder for .well-known files (default: public) - outputDir?: string; // Built output directory for inject command - pathPrefix?: string; // URL path prefix for posts (default: /posts) - publicationUri: string; - pdsUrl?: string; - location?: string; - include?: string[]; - exclude?: string[]; - identity?: string; // Which stored identity to use (matches identifier) - frontmatter?: FrontmatterMapping; // Custom frontmatter field mappings + siteUrl: string; + contentDir: string; + imagesDir?: string; // Directory containing cover images + publicDir?: string; // Static/public folder for .well-known files (default: public) + outputDir?: string; // Built output directory for inject command + pathPrefix?: string; // URL path prefix for posts (default: /posts) + publicationUri: string; + pdsUrl?: string; + identity?: string; // Which stored identity to use (matches identifier) + frontmatter?: FrontmatterMapping; // Custom frontmatter field mappings } export interface Credentials { - pdsUrl: string; - identifier: string; - password: string; + pdsUrl: string; + identifier: string; + password: string; } export interface PostFrontmatter { - title: string; - description?: string; - publishDate: string; - tags?: string[]; - ogImage?: string; - hidden?: boolean; - atUri?: string; + title: string; + description?: string; + publishDate: string; + tags?: string[]; + ogImage?: string; + atUri?: string; } export interface BlogPost { - filePath: string; - slug: string; - frontmatter: PostFrontmatter; - content: string; - rawContent: string; + filePath: string; + slug: string; + frontmatter: PostFrontmatter; + content: string; + rawContent: string; } export interface BlobRef { - $link: string; + $link: string; } export interface BlobObject { - $type: "blob"; - ref: BlobRef; - mimeType: string; - size: number; + $type: "blob"; + ref: BlobRef; + mimeType: string; + size: number; } export interface PublisherState { - posts: Record; + posts: Record; } export interface PostState { - contentHash: string; - atUri?: string; - lastPublished?: string; + contentHash: string; + atUri?: string; + lastPublished?: string; } export interface PublicationRecord { - $type: "site.standard.publication"; - url: string; - name: string; - description?: string; - icon?: BlobObject; - createdAt: string; - preferences?: { - showInDiscover?: boolean; - }; + $type: "site.standard.publication"; + url: string; + name: string; + description?: string; + icon?: BlobObject; + createdAt: string; + preferences?: { + showInDiscover?: boolean; + }; } -- 2.51.2