### Install ts-ghost-content-api Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-content-api/README.md Command to install the library using pnpm. ```bash pnpm add @ts-ghost/content-api ``` -------------------------------- ### Clone and Install Project Dependencies Source: https://github.com/phildl/ts-ghost/blob/main/CONTRIBUTING.md Clone the repository, navigate to the project directory, install dependencies using pnpm, and build the project. ```bash git clone git@github.com:PhilDL/ts-ghost.git cd ts-ghost pnpm i pnpm build ``` -------------------------------- ### Install @ts-ghost/content-api Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/nextjs/page.mdx Install the necessary package using pnpm. ```bash pnpm add @ts-ghost/content-api ``` -------------------------------- ### Install @ts-ghost/admin-api Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/nextjs/page.mdx Install the necessary package using pnpm. ```bash pnpm add @ts-ghost/admin-api ``` -------------------------------- ### Develop Documentation Source: https://github.com/phildl/ts-ghost/blob/main/CONTRIBUTING.md Navigate to the documentation directory and start the development server for live preview of documentation changes. ```bash cd www/ && pnpm dev ``` -------------------------------- ### Install Dependencies Source: https://github.com/phildl/ts-ghost/blob/main/AGENTS.md Installs all project dependencies using pnpm. ```bash pnpm i ``` -------------------------------- ### Install and Run Ghost Blog Buster CLI Source: https://github.com/phildl/ts-ghost/blob/main/apps/ghost-blog-buster/README.md Install the CLI globally and run it in a new shell session. ```bash npm install -g @ts-ghost/ghost-blog-buster ghost-blog-buster ``` -------------------------------- ### Browse with Order Example Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/browse/page.mdx Example demonstrating how to order posts by title in descending order, utilizing TypeScript for field validation. ```APIDOC ## Ordered Browse Example ### Description This example shows how to order posts by their title in descending order. The `order` parameter uses the format `field direction`, and TypeScript provides compile-time checks for valid fields and directions. ### Method GET ### Endpoint `/posts` ### Parameters #### Query Parameters - **order** (string) - Required - Orders results by `title DESC`. ### Request Example ```ts let query = await api.posts .browse({ order: "title DESC", }) .fetch(); ``` ``` -------------------------------- ### Configure Environment Variables for Ghost API Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-content-api/README.md Example of setting up environment variables for Ghost URL and Content API Key. ```bash GHOST_URL="https://myblog.com" GHOST_CONTENT_API_KEY="e9b414c5d95a5436a647ff04ab" ``` -------------------------------- ### Install ts-ghost/core-api Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-core-api/README.md Install the core API package using pnpm. Ensure your Node.js version is 16 or higher and that global fetch is available. ```shell pnpm i @ts-ghost/core-api ``` -------------------------------- ### Install Ghost Blog Buster CLI Source: https://github.com/phildl/ts-ghost/blob/main/README.md Install the Ghost Blog Buster CLI globally to use its features for exporting blog content. ```shell npm install -g @ts-ghost/ghost-blog-buster ``` -------------------------------- ### Build Browse Query with All Options Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/core-api/page.mdx Shows a complete example of using the `browse` method with all available input parameters: page, limit, filter, and order. Ensures type safety for query parameters. ```typescript const composedAPI = new APIComposer( "posts", { schema: simplifiedSchema, identitySchema: identitySchema, include: simplifiedIncludeSchema }, httpClient, ); let query = composedAPI.browse({ page: 1, limit: 5, filter: "title:typescript+slug:-test", order: "title DESC", }); ``` -------------------------------- ### Browse Posts Example Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md Demonstrates how to browse blog posts using the @ts-ghost/admin-api client, specifying fields and formats to retrieve. ```APIDOC ## GET /posts ### Description Retrieves a list of blog posts, with options to filter, sort, and select specific fields and formats. ### Method GET ### Endpoint /posts ### Parameters #### Query Parameters - **limit** (number) - Optional - The maximum number of posts to return. ### Request Example ```typescript import { TSGhostAdminAPI } from "@ts-ghost/admin-api"; const api = new TSGhostAdminAPI( process.env.GHOST_URL || "", process.env.GHOST_ADMIN_API_KEY || "", "v5.47.0", ); await api.posts .browse({ limit: 10, }) .fields({ title: true, slug: true, id: true, html: true, plaintext: true, }) .formats({ html: true, plaintext: true, }) .fetch(); ``` ### Response #### Success Response (200) - **data** (Array) - An array of post objects, each containing the requested fields and formats. - **title** (string) - The title of the post. - **slug** (string) - The slug of the post. - **id** (string) - The unique identifier of the post. - **html** (string) - The HTML content of the post. - **plaintext** (string) - The plain text content of the post. #### Response Example ```json { "data": [ { "title": "Example Post Title", "slug": "example-post-slug", "id": "post-id-123", "html": "

This is the post content.

", "plaintext": "This is the post content." } ], "meta": {} } ``` #### Error Handling - **errors** (Array) - An array of error messages if the request fails. ``` -------------------------------- ### Install TS Ghost Core API Source: https://github.com/phildl/ts-ghost/blob/main/README.md Install the TS Ghost Core API package, the foundational library for API interactions with Zod schema support. ```shell npm install @ts-ghost/core-api ``` -------------------------------- ### Browse with Filter Example Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/browse/page.mdx Example showing how to filter posts to get only featured posts, excluding a specific slug, leveraging TypeScript's compile-time checks. ```APIDOC ## Filtered Browse Example ### Description This example demonstrates filtering posts to retrieve only those that are featured and exclude a post with a specific slug. The `filter` parameter uses the Ghost API syntax, and TypeScript helps ensure that only valid fields are used. ### Method GET ### Endpoint `/posts` ### Parameters #### Query Parameters - **filter** (string) - Required - Filters results by `featured:true` and `slug:-{slugToExclude}`. ### Request Example ```ts const slugToExclude = "test-slug"; let query = await api.posts .browse({ filter: `featured:true+slug:-${slugToExclude}`, }) .fetch(); ``` ``` -------------------------------- ### Browse Posts with All Options Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/browse/page.mdx Demonstrates using the browse method with all available query parameters: page, limit, filter, and order. This example shows how to construct a query with multiple filtering and ordering criteria. ```typescript import { TSGhostAdminAPI } from "@ts-ghost/admin-api"; const api = new TSGhostAdminAPI( "https://demo.ghost.io", "1efedd9db174adee2d23d982:4b74dca0219bad629852191af326a45037346c2231240e0f7aec1f9371cc14e8", "v6.0", ); let query = api.posts.browse({ page: 1, limit: 5, filter: "name:bar+slug:-test", // ^? the text here will throw a TypeScript lint error if you use unknown fields. order: "title DESC", // ^? the text here will throw a TypeScript lint error if you use unknown fields. }); ``` -------------------------------- ### Fetch All Posts Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md A basic example of fetching all posts without any specific modifiers, demonstrating the default behavior. ```typescript // example for the browse query (the data is an array of objects) const result: { success: true; data: Post[]; meta: { pagination: { pages: number; limit: number; page: number; total: number; prev: number | null; next: number | null; }; }; } | { success: false; errors: { message: string; type: string; }[]; } ``` -------------------------------- ### Install TS Ghost Content API Source: https://github.com/phildl/ts-ghost/blob/main/README.md Install the TS Ghost Content API package to interact with your Ghost Blog's content via TypeScript. ```shell npm install @ts-ghost/content-api ``` -------------------------------- ### Read Method Example Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/read/page.mdx Demonstrates how to use the `read` method to fetch a single post using either its ID or slug. It also shows how to handle the response, checking for success and accessing the data or errors. ```APIDOC ## Read Method ### Description Fetches a single item from a Ghost Content API resource. This is equivalent to making a `GET` request to an endpoint like `/posts/slug/this-is-a-slug`. ### Method `api..read(options)` ### Parameters #### Options - **id** (string) - Optional - The unique identifier of the resource to fetch. - **slug** (string) - Optional - The slug of the resource to fetch. *Note: Providing both `id` and `slug` is possible, but the `id` will be prioritized for the URL query.* ### Fetching the Data After calling the `read` method, you receive a `ReadFetcher` instance. You can then use the `fetch` method to execute the request. ```ts let result = await api.posts.read({ slug: "this-is-a-slug" }).fetch(); if (result.success) { const data = result.data; // Process the fetched data } else { // Handle errors console.log(result.errors.map((e) => e.message).join("\n")); } ``` ### Response #### Success Response - **success** (boolean) - `true` if the request was successful. - **data** (object) - The fetched resource object. The structure depends on the resource and any applied output modifiers. #### Error Response - **success** (boolean) - `false` if the request failed. - **errors** (array) - An array of error objects, each containing a `message` and `type`. ### Result Type Example ```typescript { success: true; data: Post; // The fetched Post object, potentially modified by output modifiers } | { success: false; errors: { message: string; type: string; }[]; } ``` ``` -------------------------------- ### Install TS Ghost Admin API Source: https://github.com/phildl/ts-ghost/blob/main/README.md Install the TS Ghost Admin API package to manage your Ghost Blog's content and members using TypeScript. ```shell npm install @ts-ghost/admin-api ``` -------------------------------- ### Instantiate BrowseFetcher in Isolation Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-core-api/README.md Example of instantiating a `BrowseFetcher` directly, outside of an `APIComposer`. This requires providing schemas and necessary parameters to construct the API URL. ```typescript import { BrowseFetcher } from "@ts-ghost/core-api"; // Example of instantiating a Fetcher, even though you will probably not do it const browseFetcher = new BrowseFetcher( { schema: simplifiedSchema, output: simplifiedSchema, include: simplifiedIncludeSchema, }, { browseParams: { limit: 1, }, }, api, ); ``` -------------------------------- ### Use Browse Fetcher with Include Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-core-api/README.md Shows how to use the `.include()` method on a BrowseFetcher to add additional data not provided by default by the Ghost API. TypeScript guides available include options. ```typescript const bf = new BrowseFetcher( { schema: simplifiedSchema, output: simplifiedSchema, include: simplifiedIncludeSchema }, {}, api, ); let result = await bf .include({ count: true, }) .fetch(); ``` -------------------------------- ### Fetching Data with fetch() and paginate() Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-content-api/README.md Explains how to execute the built queries using the asynchronous .fetch() method for a single result or .paginate() for browse queries to get cursor-based pagination. ```APIDOC ## Fetching Data Execute your built queries using the `.fetch()` or `.paginate()` methods. ### `fetch()` Method An asynchronous method that executes the query and returns a `Promise` resolving to a parsed result object. **Example:** ```ts // Fetching posts with specific fields let result = await api.posts .browse({ limit: 5 }) .fields({ id: true, slug: true, title: true }) .fetch(); // Fetching posts without specific fields let result2 = await api.posts .browse({ limit: 5 }) .fetch(); // Fetching a single post by slug let postResult = await api.posts.read({ slug: "my-post-slug" }).fetch(); ``` ### `paginate()` Method Available for `browse` queries, this method returns a cursor and a `next` fetcher for cursor-based pagination. **Example:** ```ts // Usage example for paginate would be detailed in Common Recipes section. // It provides a cursor and a next fetcher for subsequent pages. ``` ### Response Structure The result is a discriminated union based on the `success` boolean field. **Success Response:** ```json { "success": true, "data": [Post] | Post, // Shape depends on resource, browse/read, and fields modifiers // Additional metadata for browse queries } ``` **Error Response:** ```json { "success": false, "errors": [ { "message": "string", "type": "string" } ] } ``` ``` -------------------------------- ### Add a New Member Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md Create a new member with basic information like name and email. This example also shows how to optionally disable sending an email notification upon creation. ```typescript import { TSGhostAdminAPI } from "@ts-ghost/admin-api"; const api = new TSGhostAdminAPI(env.GHOST_URL, env.GHOST_ADMIN_API_KEY, "v6.0"); const membersAdd = await api.members.add( { name: "Philippe", email: "philippe@ts-ghost.com" }, { send_email: false }, ); ``` -------------------------------- ### Run Integration Tests in Watch Mode Source: https://github.com/phildl/ts-ghost/blob/main/CONTRIBUTING.md Start integration tests in watch mode. Note that these tests require specific `.env` variables for a real Ghost instance and may fail locally without them. ```bash # From the project root directory # This will fail as it is expecting specific values from a specific Ghost Instance pnpm test:integration:watch ``` -------------------------------- ### Configure Environment Variables Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/nextjs/page.mdx Set up your Ghost blog URL and Content API key in your .env file. ```bash GHOST_URL="https://myblog.com" GHOST_CONTENT_API_KEY="e9b414c5d95a5436a647ff04ab" ``` -------------------------------- ### Configure Environment Variables Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/nextjs/page.mdx Set up your Ghost blog URL and Admin API key in your .env file. ```bash GHOST_URL="https://myblog.com" GHOST_ADMIN_API_KEY="1efedd9db174adee2d23d982:4b74dca0219bad629852191af326a45037346c2231240e0f7aec1f9371cc14e8" ``` -------------------------------- ### Initialize TSGhostAdminAPI and Fetch Blog Posts Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/quickstart/page.mdx Instantiate the TSGhostAdminAPI client with your blog's URL, Admin API Key, and version. Then, fetch a list of blog posts with specified fields and formats. ```typescript import { TSGhostAdminAPI } from "@ts-ghost/admin-api"; const api = new TSGhostAdminAPI( process.env.GHOST_URL || "", process.env.GHOST_ADMIN_API_KEY || "", "v5.47.0" ); export async function getBlogPosts() { const response = await api.posts .browse({ limit: 10, }) .fields({ title: true, slug: true, id: true, html: true, plaintext: true, }) .formats({ html: true, plaintext: true, }) .fetch(); if (!response.success) { throw new Error(response.errors.join(", ")); } // Response data is typed correctly with only the requested fields // { // title: string; // slug: string; // id: string; // html: string; // plaintext: string; // }[] return response.data; } ``` -------------------------------- ### Fetching Data with Browse and Fetch Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md Demonstrates how to fetch a list of resources using the `browse` method with optional fields selection and ordering. It also shows how to use the `fetch` method to retrieve the data and the structure of the returned result, including success and error states. ```APIDOC ## Fetching Data ### Description Use the `browse` method to get a list of items from a Ghost Admin API resource. You can optionally specify fields to include, and control pagination, filtering, and ordering. ### Method `browse` followed by `fetch` or `paginate`. ### Parameters for `browse` #### Query Parameters (Optional) - **page** (number) - Optional - Queries a specific page of results. Defaults to 1. - **limit** (number) - Optional - Sets the number of items per page. - **filter** (string) - Optional - Filters the results based on specified criteria. - **order** (string) - Optional - Orders the results. Example: `title DESC`. ### Fetching Data #### Method `fetch()` #### Description Executes the query built with `browse` and returns a `Promise` that resolves to a result object. #### Response - **success** (boolean) - Discriminator to check if the query was successful. - **data** (object) - The fetched data. Its shape depends on the resource and query modifiers. - **errors** (array) - An array of error objects if `success` is false. - **message** (string) - The error message. - **type** (string) - The type of error. ### Example ```ts let query = await api.members.browse({ limit: 5, order: "email ASC", }).fields({ id: true, email: true, name: true, }).fetch(); // or without fields selection let query2 = await api.members.browse({ limit: 5, order: "email ASC", }).fetch(); ``` ``` -------------------------------- ### Reading a Post by Slug Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/read/page.mdx Example of how to read a post resource using its slug as the identity field. ```APIDOC ## GET /posts/slug/:slug ### Description Fetches a single post resource using its slug. ### Method GET ### Endpoint /posts/slug/ ### Parameters #### Query Parameters - **slug** (string) - Required - The slug of the post to fetch. ### Request Example ```ts let query = api.posts.read({ slug: "this-is-a-slug" }); ``` ### Response #### Success Response (200) - **data** (Post) - The fetched post object. #### Response Example ```json { "success": true, "data": { "id": "somePostId", "title": "This is a Post", "slug": "this-is-a-slug" // ... other post fields } } ``` ``` -------------------------------- ### Reading a User by ID Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/read/page.mdx Example of how to read a user resource using their ID as the identity field. ```APIDOC ## GET /users/:id ### Description Fetches a single user resource using their unique ID. ### Method GET ### Endpoint /users/ ### Parameters #### Query Parameters - **id** (string) - Required - The unique identifier of the user to fetch. ### Request Example ```ts let query = api.users.read({ id: "edHks74hdKqhs34izzahd45" }); ``` ### Response #### Success Response (200) - **data** (User) - The fetched user object. #### Response Example ```json { "success": true, "data": { "id": "edHks74hdKqhs34izzahd45", "name": "Philippe", "email": "philippe@ts-ghost.com" // ... other user fields } } ``` ``` -------------------------------- ### Build All Packages Source: https://github.com/phildl/ts-ghost/blob/main/CONTRIBUTING.md Run the build command from the project root to compile all packages in the monorepo. ```bash # From the project root directory pnpm build ``` -------------------------------- ### Reading a User by Email Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/read/page.mdx Example of how to read a user resource using their email address as the identity field. ```APIDOC ## GET /users/:id ### Description Fetches a single user resource using their email address. ### Method GET ### Endpoint /users/ ### Parameters #### Query Parameters - **email** (string) - Required - The email address of the user to fetch. ### Request Example ```ts let query = api.users.read({ email: "philippe@ts-ghost.com" }); ``` ### Response #### Success Response (200) - **data** (User) - The fetched user object. #### Response Example ```json { "success": true, "data": { "id": "someUserId", "name": "Philippe", "email": "philippe@ts-ghost.com" // ... other user fields } } ``` ``` -------------------------------- ### APIComposer Initialization and Browse Method Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-core-api/README.md Demonstrates how to initialize the APIComposer with custom schemas and use the `browse` method to fetch a list of resources. It highlights the available parameters for filtering and ordering. ```APIDOC ## APIComposer.browse ### Description Fetches a list of resources based on the provided configuration and parameters. Allows for filtering, ordering, pagination, and limiting the results. ### Method `browse(config?: BrowseConfig)` ### Parameters #### Input Parameters for `browse` method: - `page` (number) - Optional - The current page requested for pagination. - `limit` (number) - Optional - The number of results per page. Must be between 0 and 15. - `filter` (string) - Optional - Filters the results using the [Ghost API filter syntax](https://ghost.org/docs/content-api/#filtering). - `order` (string) - Optional - Orders the results by a specified field and direction (ASC or DESC). ### Request Example ```typescript const api = { url: "https://your-ghost-site.com", key: "your-api-key", version: "v6.0", resource: "posts", }; const simplifiedSchema = z.object({ title: z.string(), slug: z.string(), count: z.number().optional(), }); const identitySchema = z.union([z.object({ slug: z.string() }), z.object({ id: z.string() })]); const simplifiedIncludeSchema = z.object({ count: z.literal(true).optional(), }); const composedAPI = new APIComposer( { schema: simplifiedSchema, identitySchema: identitySchema, include: simplifiedIncludeSchema }, api, ); let query = composedAPI.browse({ page: 1, limit: 5, filter: "title:typescript+slug:-test", order: "title DESC", }); ``` ### Response Returns a `BrowseFetcher` instance which can be used to execute the query. ``` -------------------------------- ### Initialize and Query Ghost Content API Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/quickstart/page.mdx Initialize the TSGhostContentAPI with your blog URL, API key, and Ghost version. Then, fetch blog posts with specific fields. ```typescript import { TSGhostContentAPI } from "@ts-ghost/content-api"; const api = new TSGhostContentAPI( process.env.GHOST_URL || "", process.env.GHOST_CONTENT_API_KEY || "", "v5.47.0" ); export async function getBlogPosts() { const response = await api.posts .browse({ limit: 10, }) .fields({ title: true, slug: true, id: true, }) .fetch(); if (!response.success) { throw new Error(response.errors.join(", ")); } // Response data is typed correctly with only the requested fields // { // title: string; // slug: string; // id: string; // }[] return response.data; } ``` -------------------------------- ### Apply Fields Modifier to Read Query Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md Example of applying the `.fields({ title: true })` modifier to a `read` query. ```typescript // Example with read... let result = await api.posts.read({ slug: "slug"}).fields({ title: true }).fetch(); ``` -------------------------------- ### Instantiate APIComposer and Build Browse Query Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/core-api/page.mdx Demonstrates how to set up HTTP client credentials, define simplified and identity schemas, and use the APIComposer to build a browse query for posts with type safety. ```typescript import { z } from "zod"; import { APIComposer, HTTPClient, type HTTPClientOptions } from "@ts-ghost/core-api"; const credentials: HTTPClientOptions = { url: "https://ghost.org", key: "7d2d15d7338526d43c2fadc47c", version: "v6.0", endpoint: "content", }; const httpClient = new HTTPClient(credentials); const simplifiedSchema = z.object({ title: z.string(), slug: z.string(), count: z.number().optional(), }); const identitySchema = z.union([z.object({ slug: z.string() }), z.object({ id: z.string() })]); const simplifiedIncludeSchema = z.object({ count: z.literal(true).optional(), }); const composedAPI = new APIComposer( "posts", { schema: simplifiedSchema, identitySchema: identitySchema, include: simplifiedIncludeSchema }, httpClient, ); let query = composedAPI.browse({ limit: 5, order: "title DESC", // ^? the text here will throw a TypeScript lint error if you use unknown field. // In that case `title` is correctly defined in the `simplifiedSchema }); ``` -------------------------------- ### Fetch Members Data Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md Fetches a list of members with specified fields. Includes an alternative example without explicit field selection. ```typescript let query = await api.members .browse({ limit: 5, order: "email ASC", }) .fields({ id: true, email: true, name: true, }) .fetch(); // or without fields selection let query2 = await api.members .browse({ limit: 5, order: "email ASC", }) .fetch(); ``` -------------------------------- ### Browse All Available Options Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/browse/page.mdx Demonstrates using all available options for the `browse` method, including pagination, limit, filter, and order. ```typescript let query = api.posts.browse({ page: 1, limit: 5, filter: "name:bar+slug:-test", // ^? the text here will throw a TypeScript lint error if you use unknown fields. order: "title DESC", // ^? the text here will throw a TypeScript lint error if you use unknown fields. }); ``` -------------------------------- ### Example Usage of .fields() with read and browse Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/output-modifiers/page.mdx Demonstrates the basic syntax for applying the .fields() modifier to both the .read() and .browse() methods to select only the 'title' field. ```typescript // Example with read... let result = await api.posts.read({ slug: "slug"}).fields({ title: true }).fetch(); // ... and with browse let result = await api.posts.browse({limit: 2}).fields({ title: true }).fetch(); ``` -------------------------------- ### Build Browse Query with All Available Parameters Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-core-api/README.md Shows how to use the `browse` method with all optional input parameters including page, limit, filter, and order. The parameters are validated against a Zod schema. ```typescript const composedAPI = new APIComposer( { schema: simplifiedSchema, identitySchema: identitySchema, include: simplifiedIncludeSchema }, api, ); let query = composedAPI.browse({ page: 1, limit: 5, filter: "title:typescript+slug:-test", order: "title DESC", }); ``` -------------------------------- ### Include Additional Data with .include() Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/core-api/page.mdx The `.include()` method allows fetching supplementary data not returned by default. The available keys are resource-specific and guided by TypeScript. ```typescript const bf = new BrowseFetcher( "posts", { schema: simplifiedSchema, output: simplifiedSchema, include: simplifiedIncludeSchema }, {}, httpClient, ); let result = await bf .include({ count: true, }) .fetch(); ``` -------------------------------- ### Outputting Content in Different Formats Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/output-modifiers/page.mdx Use the `.formats()` method for Post and Page resources to get content in `plaintext` or `html` formats, in addition to the default. ```APIDOC ## Output page/post content into different `.formats()` In the Admin API, the `formats` method lets you add alternative content formats on the output of `Post` or `Page` resource to get the content in `plaintext` or `html`. Available options are `plaintext | html | mobiledoc`. In the Admin API the `html` is not the default format given back when calling `read` or `browse` on the `Post` or `Page` resource. You have to use the `formats` method to get it. ```ts let result = await api.posts .read({ slug: "this-is-a-post-slug", }) .formats({ plaintext: true, html: true, }) .fetch(); ``` The output type will be modified to make the formatted fields you include **non-optionals**. ``` -------------------------------- ### Instantiate the Content API Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/overview/page.mdx Initialize the TSGhostContentAPI with your Ghost blog URL, API key, and API version. This object is the entry point for all API interactions. ```typescript import { TSGhostContentAPI } from "@ts-ghost/content-api"; const api = new TSGhostContentAPI("https://demo.ghost.io", "22444f78447824223cefc48062", "v6.0"); ``` -------------------------------- ### Get Member Active Subscriptions Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/members-recipes/page.mdx Retrieve a member's subscriptions and filter them to return only those with an 'active' status. This function requires the member's ID. ```typescript import { TSGhostAdminAPI } from "@ts-ghost/admin-api"; export const getMemberActiveSubscriptions = async (memberId: string) => { const api = new TSGhostAdminAPI(env.GHOST_URL, env.GHOST_ADMIN_API_KEY, "v6.0"); const subscriptions = await api.members.read({ id: memberId }).fields({ subscriptions: true }).fetch(); if (!subscriptions.success) { throw new Error(subscriptions.errors.join(", ")); } return subscriptions.data.subscriptions.filter((sub) => sub.status === "active"); }; ``` -------------------------------- ### Instantiate the Content API Client Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/content-api/nextjs/page.mdx Create an API instance in a dedicated file, using environment variables for configuration. Ensure to specify the API version. ```typescript import { TSGhostContentAPI } from "@ts-ghost/content-api"; export const api = new TSGhostContentAPI( process.env.GHOST_URL || "", process.env.GHOST_CONTENT_API_KEY || "", "v6.0", ); ``` -------------------------------- ### Instantiate and Use Browse Fetcher with Fields Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-core-api/README.md Demonstrates how to instantiate a BrowseFetcher and use the `.fields()` method to select specific properties for the output. TypeScript enforces the selected fields. ```typescript import { BrowseFetcher } from "@ts-ghost/core-api"; // Example of instantiating a Fetcher, even though you will probably not do it const browseFetcher = new BrowseFetcher( { schema: simplifiedSchema, output: simplifiedSchema, include: simplifiedIncludeSchema, }, { browseParams: { limit: 1, }, }, api, ); let result = await browseFetcher .fields({ slug: true, title: true, // ^? available fields come form the `simplifiedSchema` passed in the constructor }) .fetch(); if (result.success) { const post = result.data; // ^? type {"slug":string; "title": string} } ``` -------------------------------- ### Browse Tags with Nested Order and Filter Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/browse/page.mdx Example demonstrating fetching tags, ordered by the count of their associated posts in descending order, and filtering for public tags. ```APIDOC ## Browse Tags with Nested Order and Filter ### Description This example demonstrates fetching tags, ordered by the count of their associated posts in descending order, and filtering for public tags. It also shows how to use the `.include()` modifier to fetch the count of posts. ### Method GET ### Endpoint `/tags` ### Parameters #### Query Parameters - **order** (string) - Required - Orders results by `count.posts DESC`. - **filter** (string) - Required - Filters results by `visibility:public`. - **limit** (number) - Required - Limits the number of results to 3. ### Request Example ```ts api.tags .browse({ order: "count.posts DESC", filter: "visibility:public", limit: 3, }) .include({ "count.posts": true }) .fetch() ``` ``` -------------------------------- ### Get All Active Paid Tiers Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/members-recipes/page.mdx Browse all tiers from your Ghost Blog, filtering for those that are active and paid. The `include` option can fetch associated benefits and pricing details. ```typescript import { TSGhostAdminAPI } from "@ts-ghost/admin-api"; const api = new TSGhostAdminAPI(env.GHOST_URL, env.GHOST_ADMIN_API_KEY, "v6.0"); const tiers = await api.tiers .browse({ filter: "active:true+type:paid", }) .include({ benefits: true, monthly_price: true, yearly_price: true }) .fetch(); if (!tiers.success) { throw new Error(tiers.errors.join(", ")); } console.log(tiers); ``` -------------------------------- ### Remix Route Loader with Ghost API Integration Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-content-api/README.md Example of a Remix route loader that fetches site settings and posts from the Ghost API using environment variables. ```typescript import { json, type LoaderArgs, type V2_MetaFunction } from "@remix-run/node"; import { Link, useLoaderData } from "@remix-run/react"; import { TSGhostContentAPI } from "@ts-ghost/content-api"; export const meta: V2_MetaFunction = () => { return [{ title: "New Remix App" }]; }; export async function loader({ request }: LoaderArgs) { const api = new TSGhostContentAPI( process.env.GHOST_URL || "", process.env.GHOST_CONTENT_API_KEY || "", "v6.0", ); const [settings, posts] = await Promise.all([api.settings.fetch(), api.posts.browse().fetch()]); if (!settings.success) { throw new Error(settings.errors.join(", ")); } if (!posts.success) { throw new Error(posts.errors.join(", ")); } return json({ settings: settings.data, posts: posts.data }); } export default function Index() { const { settings, posts } = useLoaderData(); return (

This is a list of posts for {settings.title}:

    {posts.map((post) => (
  • {post.title}
  • ))}
); } ``` -------------------------------- ### Instantiate APIComposer and Build Browse Query Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-core-api/README.md Demonstrates how to instantiate the APIComposer with custom schemas and build a browse query with basic parameters. The TypeScript linting helps ensure correct field usage. ```typescript import { z } from "zod"; import { APIComposer, type ContentAPICredentials } from "@ts-ghost/core-api"; const api: ContentAPICredentials = { url: "https://ghost.org", key: "7d2d15d7338526d43c2fadc47c", version: "v6.0", resource: "posts", }; const simplifiedSchema = z.object({ title: z.string(), slug: z.string(), count: z.number().optional(), }); const identitySchema = z.union([z.object({ slug: z.string() }), z.object({ id: z.string() })]); const simplifiedIncludeSchema = z.object({ count: z.literal(true).optional(), }); const composedAPI = new APIComposer( { schema: simplifiedSchema, identitySchema: identitySchema, include: simplifiedIncludeSchema }, api, ); let query = composedAPI.browse({ limit: 5, order: "title DESC", // ^? the text here will throw a TypeScript lint error if you use unknown field. // In that case `title` is correctly defined in the `simplifiedSchema }); ``` -------------------------------- ### Run Integration Tests Source: https://github.com/phildl/ts-ghost/blob/main/AGENTS.md Executes integration tests, which require a configured .env file with real Ghost instance credentials. ```bash pnpm test:integration ``` -------------------------------- ### Type-Safe Query Building Example Source: https://github.com/phildl/ts-ghost/blob/main/AGENTS.md Demonstrates building a type-safe query using the builder pattern. The `.fields()` method modifies the output type by selecting specific fields. ```typescript const posts = await contentApi.posts .fields({ title: true, slug: true }) .fetch() // posts.data[0].title // posts.data[0].slug // posts.data[0].id // Error: Property 'id' does not exist on type '{ title: string; slug: string; }' ``` -------------------------------- ### Including Relations with .include() Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/output-modifiers/page.mdx The .include() method allows fetching additional related data not returned by default. TypeScript guides you on available include keys specific to each resource. ```typescript let result = await api.authors .read({ slug: "phildl", }) .include({ "count.posts": true }) .fetch(); ``` -------------------------------- ### Browsing Resources Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md Demonstrates how to browse resources like posts, allowing for filtering, ordering, and limiting results. It also shows how to fetch the data and handle success or error responses. ```APIDOC ## Browsing Resources This section covers the `browse` method for fetching collections of resources. ### Parameters - **limit** (`number` | `"all"`) - Optional - Limits the number of results per page. Defaults to `15`. Can be set to `"all"` to retrieve all results. - **filter** (`string`) - Optional - Filters results using Ghost API filter syntax. Provides TypeScript linting for unknown fields. - **order** (`string`) - Optional - Orders results by a specified field and direction (ASC/DESC). Provides TypeScript linting for unknown fields. ### Output Modifiers After calling `browse`, a `Fetcher` instance is returned, which can be used with methods like `include`, `fields`, and `formats` to alter the output. Refer to the [output modifiers documentation](/docs/admin-api/output-modifiers) for details. ### Fetching Data The `Fetcher` instance provides two methods to retrieve data: - `fetch()`: Asynchronously fetches the data. - `paginate()`: Asynchronously fetches data and returns a cursor for the next page. ### Fetch Example ```ts let result = await api.posts.browse().fetch(); if (result.success) { const posts = result.data; // posts is of type Post[] } else { console.log(result.errors.map((e) => e.message).join("\n")); } ``` ### Result Type of `.fetch()` The result of `fetch()` is a discriminated union. On success, it contains `data` (an array of resource objects) and `meta` (pagination information). On failure, it contains an `errors` array. ```ts // Example structure for a successful fetch of posts { success: true, data: Post[]; meta: { pagination: { pages: number; limit: number; page: number; total: number; prev: number | null; next: number | null; }; } } | { success: false; errors: { message: string; type: string; }[]; } ``` ### Result Type of `.paginate()` The `paginate()` method returns a similar structure to `fetch()`, but includes a `next` property which is a `Fetcher` instance for the subsequent page, if available. ```ts // Example structure for a successful paginate of posts { success: true, data: Post[]; meta: { pagination: { pages: number; limit: number | "all"; page: number; total: number; prev: number | null; next: number | null; }; }, next: BrowseFetcher | undefined; // Fetcher for the next page } | { success: false; errors: { message: string; type: string; }[]; next: undefined; } ``` ``` -------------------------------- ### Configure Environment Variables Source: https://github.com/phildl/ts-ghost/blob/main/AGENTS.md Sets up environment variables required for integration testing and playground scripts. Ensure to replace placeholder values with your actual Ghost instance credentials. ```dotenv GHOST_URL=https://your-ghost-instance.com GHOST_CONTENT_API_KEY=your-content-api-key GHOST_ADMIN_API_KEY=your-admin-api-key GHOST_VERSION=v5.x ``` -------------------------------- ### Get All Posts with Authors and Tags using Pagination Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-content-api/README.md Retrieves all posts, including their authors and tags, by iteratively fetching pages using the paginate function. Requires TSGhostContentAPI initialization. ```typescript import { TSGhostContentAPI, type Post } from "@ts-ghost/content-api"; let url = "https://demo.ghost.io"; let key = "22444f78447824223cefc48062"; // Content API KEY const api = new TSGhostContentAPI(url, key, "v6.0"); const posts: Post[] = []; let cursor = await api.posts .browse() .include({ authors: true, tags: true }) .paginate(); if (cursor.current.success) posts.push(...cursor.current.data); while (cursor.next) { cursor = await cursor.next.paginate(); if (cursor.current.success) posts.push(...cursor.current.data); } return posts; ``` -------------------------------- ### fetch() with Options Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/core-api/page.mdx The `fetch` method accepts an optional `options` object, which corresponds to the standard `RequestInit` object from the Fetch API. This allows for advanced fetch configurations, such as setting caching strategies. ```APIDOC ## fetch() with Options ### Description Allows passing standard `RequestInit` options to the `fetch` call, enabling customization of request behavior like caching. ### Method Instance method of a Fetcher object. ### Parameters #### Request Body - **options** (object) - Optional - A `RequestInit` object. - **cache** (string) - Optional - Specifies the cache mode (e.g., `no-store`). ### Request Example ```ts let result = await api.posts.read({ slug: "typescript-is-cool" }).fetch({ cache: "no-store" }); ``` ``` -------------------------------- ### Add a New Post Source: https://github.com/phildl/ts-ghost/blob/main/packages/ts-ghost-admin-api/README.md Provides an example of how to create a new post using the `add` method on the `posts` resource. It requires at least a `title` and returns the newly created post data. ```APIDOC ## POST /posts/ ### Description Creates a new post with the minimum required field `title`. ### Method POST ### Endpoint `/posts/ ### Parameters #### Request Body - **title** (string) - Required - The title of the new post. ### Request Example ```ts const postAdd = await api.posts.add({ title: "My New Post Title", }); ``` ### Response #### Success Response (201) - **success** (boolean) - Indicates if the operation was successful. - **data** (object) - The newly created post object, parsed and typed. #### Response Example ```json { "success": true, "data": { "id": "65a4b1f3a1b2c3d4e5f6a7b9", "title": "My New Post Title", "slug": "my-new-post-title" } } ``` ``` -------------------------------- ### Instantiate HTTPClient and APIComposer Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/core-api/page.mdx Demonstrates the instantiation of HTTPClient with credentials and APIComposer with resource schemas and the HTTPClient. The APIComposer handles type-safety for query parameters and returns appropriate fetchers. ```typescript import { z } from "zod"; import { APIComposer, HTTPClient, type HTTPClientOptions } from "@ts-ghost/core-api"; const credentials: HTTPClientOptions = { url: "https://ghost.org", key: "7d2d15d7338526d43c2fadc47c", version: "v6.0", endpoint: "content", }; const httpClient = new HTTPClient(credentials); const simplifiedSchema = z.object({ title: z.string(), slug: z.string(), count: z.number().optional(), }); // the "identity" schema is used to validate the inputs of the `read`method of the APIComposer const identitySchema = z.union([z.object({ slug: z.string() }), z.object({ id: z.string() })]); // the "include" schema is used to validate the "include" parameters of the API call // it is specific to the Ghost API resource targeted. // The format is always { 'name_of_the_field': true } const simplifiedIncludeSchema = z.object({ count: z.literal(true).optional(), }); const createSchema = z.object({ foo: z.string(), bar: z.string().nullish(), baz: z.boolean().nullish(), }); const composedAPI = new APIComposer( "posts", { schema: simplifiedSchema, identitySchema: identitySchema, include: simplifiedIncludeSchema, createSchema: createSchema, createOptionsSchema: z.object({ option_1: z.boolean(), }), }, HTTPClient, ); ``` -------------------------------- ### Instantiate TSGhostAdminAPI Source: https://github.com/phildl/ts-ghost/blob/main/docs/src/app/docs/admin-api/overview/page.mdx Import and instantiate the TSGhostAdminAPI with your Ghost blog URL, Admin API Key, and API version. This is the entry point for all admin API interactions. ```typescript import { TSGhostAdminAPI } from "@ts-ghost/admin-api"; const api = new TSGhostAdminAPI( "https://demo.ghost.io", "1efedd9db174adee2d23d982:4b74dca0219bad629852191af326a45037346c2231240e0f7aec1f9371cc14e8", "v6.0", ); ```