UNPKG

astro-loader-hashnode

Version:

Astro content loader for seamlessly integrating Hashnode blog posts into your Astro website using the Content Layer API

166 lines (165 loc) 5.58 kB
/** * Drafts Loader - Handles Hashnode draft posts (requires authentication) */ import { BaseHashnodeLoader } from './base.js'; import { draftSchema } from '../types/schema.js'; /** * Transform Hashnode draft to Astro content format */ function transformHashnodeDraft(draft) { // Generate ID for the draft const generateDraftId = (draft) => { // Try different ID fields since drafts might not have all fields const id = draft.id || draft.cuid || draft.slug; if (id) { return `draft-${id}`; } // Fallback: generate ID from title and updatedAt const title = draft.title || 'untitled'; const updatedAt = draft.updatedAt || new Date().toISOString(); const hash = simpleHash(`${title}-${updatedAt}`); return `draft-${hash}`; }; // Simple hash function for generating IDs const simpleHash = (str) => { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = (hash << 5) - hash + char; hash = hash & hash; // Convert to 32-bit integer } return Math.abs(hash).toString(36); }; return { // Include ID in the transformed data id: generateDraftId(draft), // Core content - handle null/undefined values title: draft.title || 'Untitled Draft', subtitle: draft.subtitle || '', content: draft.content?.markdown || draft.content?.html || '', canonicalUrl: draft.canonicalUrl || '', // Metadata updatedAt: draft.updatedAt ? new Date(draft.updatedAt) : new Date(), createdAt: draft.updatedAt ? new Date(draft.updatedAt) : new Date(), // Use updatedAt as fallback // Author information - handle potential missing author author: draft.author ? { id: draft.author.id || 'unknown', name: draft.author.name || 'Unknown Author', username: draft.author.username || 'unknown', profilePicture: draft.author.profilePicture || '', } : { id: 'unknown', name: 'Unknown Author', username: 'unknown', profilePicture: '', }, // Cover image coverImage: draft.coverImage ? { url: draft.coverImage.url, } : undefined, // Tags - handle null/undefined tags: (draft.tags || []).map(tag => ({ id: tag.id || 'unknown', name: tag.name || 'Unknown Tag', slug: tag.slug || 'unknown', })), // Table of contents (simplified for drafts) tableOfContents: [], // Draft-specific metadata isDraft: true, lastSaved: draft.updatedAt ? new Date(draft.updatedAt) : new Date(), // Raw data for advanced use cases raw: { id: draft.id || null, // Include any additional draft-specific fields }, }; } /** * Drafts Loader Class */ export class DraftsLoader extends BaseHashnodeLoader { options; constructor(options) { // Ensure authentication token is provided if (!options.token) { throw new Error('Authentication token is required for accessing drafts'); } super({ ...options, collection: 'drafts', schema: draftSchema, }); this.options = options; } /** * Fetch drafts data from Hashnode API */ async fetchData() { const { maxDrafts = 50, includeDraftById } = this.options; // If specific draft ID is provided, fetch only that draft if (includeDraftById) { const draft = await this.client.getDraft(includeDraftById); return draft ? [draft] : []; } // Fetch user's drafts const result = await this.client.getDrafts({ first: maxDrafts }); return result.me.drafts.edges.map(edge => edge.node); } /** * Transform Hashnode draft to Astro content format */ transformItem(draft) { return transformHashnodeDraft(draft); } /** * Generate ID for draft */ generateId(draft) { // Try different ID fields since drafts might not have all fields const id = draft.id || draft.cuid || draft.slug; if (id) { return `draft-${id}`; } // Fallback: generate ID from title and updatedAt const fallbackId = this.generateFallbackId(draft); return `draft-${fallbackId}`; } /** * Generate fallback ID when no proper ID is available */ generateFallbackId(draft) { const title = draft.title || 'untitled'; const updatedAt = draft.updatedAt || new Date().toISOString(); const hash = this.simpleHash(`${title}-${updatedAt}`); return hash; } /** * Simple hash function for generating IDs */ simpleHash(str) { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = (hash << 5) - hash + char; hash = hash & hash; // Convert to 32-bit integer } return Math.abs(hash).toString(36); } } /** * Create a drafts loader */ export function createDraftsLoader(options) { return new DraftsLoader(options); } /** * Create an Astro Loader for drafts */ export function draftsLoader(options) { return createDraftsLoader(options).createLoader(); }