Fixes and New Features...

This commit is contained in:
Adam Matthiesen 2024-01-20 04:52:55 -08:00
parent 6585fcebb8
commit 2d73445518
12 changed files with 186 additions and 67 deletions

108
index.ts
View File

@ -1,8 +1,17 @@
import type { AstroIntegration } from "astro"
import { ZodError, type SafeParseError, type SafeParseSuccess } from "astro/zod"
import { UserConfigSchema, type UserConfig } from "./src/utils/UserConfigSchema"
import type { AstroIntegration } from "astro";
import type { SafeParseError, SafeParseSuccess } from "astro/zod";
import { UserConfigSchema, type UserConfig } from "./src/utils/UserConfigSchema";
import { ghostSitemap, ghostRobots } from "./src/integrations";
import { loadEnv } from 'vite';
import { fromZodError } from "zod-validation-error";
const pkg = '@matthiesenxyz/astro-ghostcms'
// LOAD ENVIRONMENT VARIABLES
const mode = 'all';
const prefixes = 'CONTENT_API';
const env = loadEnv(mode, process.cwd(), prefixes);
// SET LOCAL PACKAGE NAME
const pkg = '@matthiesenxyz/astro-ghostcms';
export default function GhostCMS(options: UserConfig): AstroIntegration {
return {
@ -10,77 +19,108 @@ export default function GhostCMS(options: UserConfig): AstroIntegration {
hooks: {
'astro:config:setup': async ({
injectRoute,
config,
logger,
}) => {
const o = UserConfigSchema.safeParse(options || {}) as SafeParseSuccess<UserConfig>
// Check For ENV Variables
logger.info("Checking for Environment Variables...")
// CHECK FOR API KEY
if(env.CONTENT_API_KEY === undefined){
logger.error("CONTENT_API_KEY Missing from .env")
}
// CHECK FOR API URL
if(env.CONTENT_API_URL === undefined){
logger.error("CONTENT_API_URL Missing from .env")
}
// CHECK USER CONFIG
logger.info("Checking Config...")
const o = UserConfigSchema.safeParse(options || {}) as SafeParseSuccess<UserConfig>;
if (!o.success) {
const validationError = fromZodError((o as unknown as SafeParseError<UserConfig>).error)
logger.error(`Config Error - ${ validationError }`)
throw validationError
const validationError = fromZodError((o as unknown as SafeParseError<UserConfig>).error);
logger.error(`Config Error - ${ validationError }`);
throw validationError;
}
const entry = o.data.theme;
const entry = o.data.theme
// THEME SELECTOR
if (entry === pkg) {
logger.info("Injecting Theme: astro-ghostcms-basetheme")
logger.info("Injecting Theme: astro-ghostcms-basetheme");
} else {
logger.info(`Injecting Theme: ${entry}`)
logger.info(`Injecting Theme: ${entry}`);
}
// INJECT ROUTES
logger.info("Injecting Routes...");
logger.info("Injecting Route: /")
injectRoute({
pattern: '/',
entrypoint: `${entry}/index.astro`
})
});
logger.info("Injecting Route: /[slug]")
injectRoute({
pattern: '/[slug]',
entrypoint: `${entry}/[slug].astro`
})
});
logger.info("Injecting Route: /tags")
injectRoute({
pattern: '/tags',
entrypoint: `${entry}/tags.astro`
})
});
logger.info("Injecting Route: /authors")
injectRoute({
pattern: '/authors',
entrypoint: `${entry}/authors.astro`
})
});
logger.info("Injecting Route: /tag/[slug]")
injectRoute({
pattern: '/tag/[slug]',
entrypoint: `${entry}/tag/[slug].astro`
})
});
logger.info("Injecting Route: /author/[slug]")
injectRoute({
pattern: '/author/[slug]',
entrypoint: `${entry}/author/[slug].astro`
})
logger.info("Injecting Route: /archives/[...page]")
});
injectRoute({
pattern: '/archives/[...page]',
entrypoint: `${entry}/archives/[...page].astro`
})
});
// IMPORT INTEGRATIONS & INTEGRATION ROUTES
const int = [...config.integrations];
// IMPORT INTEGRATION: @ASTROJS/RSS
logger.info("Injecting Integration Route: @astrojs/rss");
injectRoute({
pattern: '/rss.xml',
entrypoint: `${pkg}/rss.xml.js`
});
// IMPORT INTEGRATION: @ASTROJS/SITEMAP
logger.info("Checking for @astrojs/sitemap");
if (!int.find(({ name }) => name === '@astrojs/sitemap')) {
logger.info("Injecting Integration: @astrojs/sitemap");
int.push(ghostSitemap());
} else {
logger.info("Already Imported by User: @astrojs/sitemap");
}
// IMPORT INTEGRATION: ASTRO-ROBOTS-TXT
logger.info("Checking for astro-robots-txt");
if (!int.find(({ name }) => name === 'astro-robots-txt')) {
logger.info("Injecting Integration: astro-robots-txt");
int.push(ghostRobots());
} else {
logger.info("Already Imported by User: astro-robots-txt");
}
},
'astro:config:done': async ({ logger }) => {
logger.info('GhostCMS Routes Injected. Integration is now ready.')
logger.info('GhostCMS Injection Complete. Integration is now ready.');
}
}
}
}
function fromZodError(error: ZodError<{ theme: string }>) {
throw new Error("Function not implemented.")
}

View File

@ -1,7 +1,7 @@
{
"name": "@matthiesenxyz/astro-ghostcms",
"description": "Astro GhostCMS integration to allow easier importing of GhostCMS Content",
"version": "2.0.9",
"version": "2.1.0",
"author": "MatthiesenXYZ (https://matthiesen.xyz)",
"type": "module",
"license": "MIT",
@ -10,7 +10,8 @@
"url": "git+https://github.com/MatthiesenXYZ/astro-ghostcms.git"
},
"bugs": {
"url": "https://github.com/MatthiesenXYZ/astro-ghostcms/issues"
"url": "https://github.com/MatthiesenXYZ/astro-ghostcms/issues",
"email": "issues@astro-ghostcms.xyz"
},
"homepage": "https://astro-ghostcms.xyz/",
"exports": {
@ -23,10 +24,10 @@
"./tag/[slug].astro": "./src/routes/tag/[slug].astro",
"./author/[slug].astro": "./src/routes/author/[slug].astro",
"./archives/[...page].astro": "./src/routes/archives/[...page].astro",
"./DefaultLayout": "./src/layouts/default.astro"
"./rss.xml.js": "./src/routes/rss.xml.js"
},
"main": "index.ts",
"types": "src/api/ghosttypes.ts",
"types": "src/api/tryghost-content-api.d.ts",
"files": [
"src",
"index.ts"
@ -56,11 +57,13 @@
"dependencies": {
"@astrojs/check": "^0.3.4",
"typescript": "^5.3.3",
"zod-validation-error": "^3.0.0",
"axios": "^1.0.0",
"astro-font": "^0.0.72",
"@astrojs/renderer-svelte": "0.5.2",
"@astrojs/rss": "^4.0.2",
"@astrojs/sitemap": "^3.0.4",
"astro-robots-txt": "^1.0.0",
"@snowpack/plugin-dotenv": "^2.2.0",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",

View File

@ -1,8 +1,26 @@
// IMPORT Ghost Types
import type { PostOrPage, PostsOrPages, Authors, Tag, Tags, ArrayOrValue, IncludeParam, LimitParam, Settings, Nullable } from './ghosttypes';
// IMPORT Ghost Types & Content-API
import type {
PostOrPage, PostsOrPages, Authors,
Tag, Tags, ArrayOrValue, IncludeParam,
LimitParam, Settings, Nullable
} from './tryghost-content-api';
import GhostContentAPI from './tryghost-content-api';
// IMPORT Ghost API Client
import api from './interface';
// LOAD ENVIRONMENT VARIABLES
import { loadEnv } from 'vite';
const {CONTENT_API_KEY, CONTENT_API_URL} = loadEnv(
'all',
process.cwd(),
'CONTENT_'
);
let key = CONTENT_API_KEY;
let url = CONTENT_API_URL;
// SETUP API
const version = "v5.0";
const api = GhostContentAPI({ key, url, version });
// SET Include params
const include:ArrayOrValue<IncludeParam> = ['authors', 'tags'];
@ -10,54 +28,54 @@ const include:ArrayOrValue<IncludeParam> = ['authors', 'tags'];
// Get Posts (General "ALL")
export const getGhostPosts = async () => {
const ghostPosts:PostsOrPages = await api.posts.browse({include,filter:'visibility:public'})
return ghostPosts; }
return ghostPosts; };
// Get Posts (Recent "setLimit?")
export const getGhostRecentPosts = async (setLimit?:ArrayOrValue<LimitParam>) => {
const ghostRecentPosts:PostsOrPages = await api.posts.browse({limit:setLimit?setLimit:"6",include,filter:'visibility:public'});
return ghostRecentPosts; }
return ghostRecentPosts; };
// Get Posts (Featured "setLimit?")
export const getGhostFeaturedPosts = async (setLimit?:ArrayOrValue<LimitParam>) => {
const ghostFeaturedPosts:PostsOrPages = await api.posts.browse({limit:setLimit?setLimit:"1",include,filter:'featured:true'});
return ghostFeaturedPosts; }
return ghostFeaturedPosts; };
// Get Post (By Slug)
export const getGhostPostbySlug = async (slug:Nullable<string>) => {
const ghostPostbySlug:PostOrPage = await api.posts.read({slug},{include});
return ghostPostbySlug; }
return ghostPostbySlug; };
// Get Post (By Tag)
export const getGhostPostsbyTag = async (slug:Nullable<string>) => {
const ghostPostsbyTag:PostsOrPages = await api.posts.browse({filter:`tag:${slug}`,include});
return ghostPostsbyTag; }
return ghostPostsbyTag; };
// Get Tags (General "ALL")
export const getGhostTags = async () => {
const ghostTags:Tags = await api.tags.browse({include:`count.posts`});
return ghostTags; }
return ghostTags; };
// Get Tag (By Slug)
export const getGhostTagbySlug = async (slug:Nullable<string>) => {
const ghostTagbySlug:Tag = await api.tags.read({slug},{include:`count.posts`});
return ghostTagbySlug; }
return ghostTagbySlug; };
// Get Authors (General "ALL")
export const getGhostAuthors = async () => {
const ghostAuthors:Authors = await api.authors.browse({include:`count.posts`});
return ghostAuthors; }
return ghostAuthors; };
// Get Pages (ALL)
export const getGhostPages = async () => {
const ghostPages:PostsOrPages = await api.pages.browse();
return ghostPages; }
return ghostPages; };
// Get Page (by Slug)
export const getGhostPage = async (slug:Nullable<string>) => {
const ghostPage:PostOrPage = await api.pages.read({slug});
return ghostPage; }
return ghostPage; };
// Get Settings
export const getGhostSettings = async () => {
const ghostSettings:Settings = await api.settings.browse();
return ghostSettings; }
return ghostSettings; };

View File

@ -1,5 +1,22 @@
// FUNCTION EXPORTS
export { getGhostPosts, getGhostRecentPosts, getGhostFeaturedPosts, getGhostPostbySlug, getGhostPostsbyTag, getGhostTags, getGhostTagbySlug, getGhostAuthors, getGhostPages, getGhostPage, getGhostSettings } from './functions';
export {
getGhostPosts, getGhostRecentPosts, getGhostFeaturedPosts,
getGhostPostbySlug, getGhostPostsbyTag, getGhostTags,
getGhostTagbySlug, getGhostAuthors, getGhostPages,
getGhostPage, getGhostSettings
} from './functions';
// TYPE EXPORTS
export type { PostOrPage, ArrayOrValue, Author, Authors, BrowseFunction, CodeInjection, Excerpt, Facebook, FieldParam, FilterParam, FormatParam, GhostAPI, GhostContentAPIOptions, GhostData, GhostError, Identification, IncludeParam, LimitParam, Metadata, Nullable, OrderParam, PageParam, Pagination, Params, PostsOrPages, ReadFunction, Settings, SettingsResponse, SocialMedia, Tag, TagVisibility, Tags, Twitter } from './ghosttypes';
export type {
PostOrPage, ArrayOrValue, Author,
Authors, BrowseFunction, CodeInjection,
Excerpt, Facebook, FieldParam,
FilterParam, FormatParam, GhostAPI,
GhostContentAPIOptions, GhostData, GhostError,
Identification, IncludeParam, LimitParam,
Metadata, Nullable, OrderParam,
PageParam, Pagination, Params,
PostsOrPages, ReadFunction, Settings,
SettingsResponse, SocialMedia, Tag,
TagVisibility, Tags, Twitter
} from './tryghost-content-api.d';

View File

@ -1,10 +0,0 @@
import GhostContentAPI from './tryghost-content-api';
// CALL GHOST VARS AND CREATE CLIENT
const key = import.meta.env.CONTENT_API_KEY;
const url = import.meta.env.CONTENT_API_URL;
const version = "v5.0"
const api = new GhostContentAPI({ key, url, version })
export default api;

1
src/env.d.ts vendored
View File

@ -1 +0,0 @@
/// <reference types="astro/client" />

View File

@ -0,0 +1,2 @@
export { default as ghostSitemap } from "./sitemap"
export { default as ghostRobots } from "./robots-txt"

View File

@ -0,0 +1,13 @@
import robotsTxt, { type RobotsTxtOptions } from "astro-robots-txt";
export function getRobotsTxtConfig(): RobotsTxtOptions {
const robotsConfig: RobotsTxtOptions = {};
return robotsConfig;
}
/**
* A wrapped version of the `astro-robots-txt` integration for GhostCMS.
*/
export default function ghostRobots() {
return robotsTxt(getRobotsTxtConfig());
}

View File

@ -0,0 +1,13 @@
import sitemap, { type SitemapOptions } from '@astrojs/sitemap';
export function getSitemapConfig(): SitemapOptions {
const sitemapConfig: SitemapOptions = {};
return sitemapConfig;
}
/**
* A wrapped version of the `@astrojs/sitemap` integration for GhostCMS.
*/
export default function ghostSitemap() {
return sitemap(getSitemapConfig());
}

23
src/routes/rss.xml.js Normal file
View File

@ -0,0 +1,23 @@
import rss from "@astrojs/rss";
import { getGhostPosts, getGhostSettings } from '../api';
import invariant from "tiny-invariant";
export async function GET(context) {
const posts = await getGhostPosts();
const settings = await getGhostSettings();
invariant(settings, "Settings not found");
const title = settings.title;
const description = settings.description;
return rss({
title: title,
description: description,
site: context.site,
//stylesheet: '/rss/styles.xsl',
items: posts.map((post) => ({
title: post.title,
pubDate: post.published_at,
description: post.excerpt,
link: `/blog/${post.slug}/`,
})),
});
}

View File

@ -1,7 +1,8 @@
import { z } from 'astro/zod';
export const UserConfigSchema = z.object({
theme: z.string().default('@matthiesenxyz/astro-ghostcms')
theme: z.string().default('@matthiesenxyz/astro-ghostcms'),
rssStyle: z.string().optional()
});
export type UserConfig = z.infer<typeof UserConfigSchema>