TryGhost / SDK

Tools for working with Ghost's APIs
MIT License
116 stars 76 forks source link

TypeScript support for the admin api client #446

Open dsebastien opened 2 years ago

dsebastien commented 2 years ago

I saw that there are community-provided types for the content API, but couldn't find the equivalent for the admin API.

It would be great if TypeScript types could be provided for the Admin API client. More and more apps are being developed using TypeScript, as it makes for a much nicer developer experience. Is this something already on the product roadmap?

ErisDS commented 2 years ago

These typings are provided by the community over on the DefinitelyTyped repo, but I'm not aware of anyone actively working on them for admin.

dsebastien commented 2 years ago

I've just created my own. I'll try to make those available on DefinitelyTyped if I get the time.

Here they are, just I case I don't and someone else cares enough. It's very rough, but it's a start:

declare module "@tryghost/admin-api" {
  import type {AxiosResponse} from "axios";

  export interface GhostAdminAPIOptions {
    /**
     * URL of the Ghost instance
     */
    url: string;
    ghostPath?: string;
    /**
     * The Admin API key
     */
    key: string;
    /**
     * A version string like v3.2, v4.1, v5.8 or boolean value identifying presence of Accept-Version header
     */
    version: string;
    /**
     * Flag controlling if the 'User-Agent' header should be sent with a request
     */
    userAgent?: string | boolean;
    /**
     * Customize the Accept-Version header sent with requests
     */
    acceptVersionHeader?: string;
    /**
     * Replace the function used to send HTTP requests
     */
    makeRequest?: (options: GhostAdminApiMakeRequestOptions) => Promise<unknown>; // TODO refine
    /**
     * Replace the function used to generate tokens
     * @param key the key
     * @param audience the audience of the token
     */
    generateToken?: (key: string, audience: string) => string;
  }

  export interface GhostAdminApiMakeRequestOptions {
    url: string;
    method: string;
    data: unknown;
    params: Record<unknown>;
    headers: Record<unknown>
  }

  export interface GhostAdminApiMediaUploadData {
    /**
     * File path to a media file
     **/
    file: string;
    /**
     * File path to a thumbnail file
     */
    thumbnail?: string;
    /**
     * Purpose of the file
     */
    purpose?: string;
  }

  export type GhostAdminApiImageUploadData = GhostAdminApiMediaUploadData;

  export interface GhostAdminApiFileUploadData {
    /**
     * File path to a file
     **/
    file: string;
    /**
     * Reference field returned in the response
     */
    ref?: string;
  }

  // export interface GhostAdminApiInstance {
  //
  // }

  declare class GhostAdminAPI implements GhostAdminApiInstance {
    constructor(options: GhostAdminAPIOptions);

    posts: {
      read: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      browse: (options: Record<unknown>) => Promise<AxiosResponse<unknown>>;
      add: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      edit: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      del: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
    };

    pages: {
      read: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      browse: (options: Record<unknown>) => Promise<AxiosResponse<unknown>>;
      add: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      edit: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      del: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
    };

    tags: {
      read: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      browse: (options: Record<unknown>) => Promise<AxiosResponse<unknown>>;
      add: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      edit: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      del: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
    };

    members: {
      read: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      browse: (options: Record<unknown>) => Promise<AxiosResponse<unknown>>;
      add: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      edit: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      del: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
    };

    users: {
      read: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      browse: (options: Record<unknown>) => Promise<AxiosResponse<unknown>>;
      add: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      edit: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      del: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
    };

    newsletters: {
      read: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      browse: (options: Record<unknown>) => Promise<AxiosResponse<unknown>>;
      add: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      edit: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      del: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
    };

    webhooks: {
      add: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      edit: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
      del: (data: Record<unknown>, queryParams: Record<unknown> = {}) => Promise<AxiosResponse<unknown>>;
    };

    images: {
      upload: (data: GhostAdminApiImageUploadData | FormData) => Promise<AxiosResponse<unknown>>;
    }

    media: {
      upload: (data: GhostAdminApiMediaUploadData | FormData) => Promise<AxiosResponse<unknown>>;
    }

    files: {
      upload: (data: GhostAdminApiFileUploadData | FormData) => Promise<AxiosResponse<unknown>>;
    }

    config: {
      read: () => Promise<AxiosResponse<unknown>>;
    }

    site: {
      read: () => Promise<AxiosResponse<unknown>>;
    }

    themes: {
      upload: (data) => Promise<AxiosResponse<unknown>>;
      activate: (name: string) => Promise<AxiosResponse<unknown>>;
    }
  }

  export = GhostAdminAPI;
}
newTomas commented 1 year ago

Code generated by chat gpt. Needs review:

declare module "@tryghost/admin-api" {
  export interface ClientOptions {
    url: string;
    key: string;
    version?: string;
  }

  export interface Page {
    id: string;
    title: string;
    slug: string;
    html: string;
    markdown: string;
    feature_image: string;
    featured: boolean;
    page: boolean;
    status: string;
    language: string;
    visibility: string;
    meta_title: string;
    meta_description: string;
    author_id: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
    published_at: string;
    published_by: string;
  }

  export interface Post {
    id: string;
    title: string;
    slug: string;
    html: string;
    markdown: string;
    feature_image: string;
    featured: boolean;
    page: boolean;
    status: string;
    language: string;
    visibility: string;
    meta_title: string;
    meta_description: string;
    author_id: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
    published_at: string;
    published_by: string;
  }

  export interface Member {
    id: string;
    name: string;
    email: string;
    status: string;
    note: string;
  }

  export interface Tag {
    id: string;
    name: string;
    slug: string;
    description: string;
    feature_image: string;
    visibility: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
  }

  export interface Webhook {
    id: string;
    event: string;
    target_url: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
  }

  export interface User {
    id: string;
    name: string;
    slug: string;
    profile_image: string;
    cover_image: string;
    bio: string;
    website: string;
    location: string;
    status: string;
    visibility: string;
    meta_title: string;
    meta_description: string;
    last_login: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
  }

  export interface Newsletter {
    id: string;
    name: string;
    slug: string;
    status: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
  }

  export interface Image {
    id: string;
    title: string;
    slug: string;
    type: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
    published_at: string;
    published_by: string;
  }

  export interface Media {
    id: string;
    title: string;
    slug: string;
    type: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
    published_at: string;
    published_by: string;
  }

  export interface File {
    id: string;
    title: string;
    slug: string;
    type: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
    published_at: string;
    published_by: string;
  }

  export interface Config {
    id: string;
    key: string;
    value: string;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
  }

  export interface Site {
    id: string;
    name: string;
    description: string;
    logo: string;
    icon: string;
    cover_image: string;
    facebook: string;
    twitter: string;
    lang: string;
    timezone: string;
    navigation: string[];
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
  }

  export interface Theme {
    id: string;
    name: string;
    package: {
      name: string;
      version: string;
    };
    active: boolean;
    created_at: string;
    created_by: string;
    updated_at: string;
    updated_by: string;
  }

  export default class Client {
    constructor(options: ClientOptions);

    pages: {
      browse(options?: object): Promise<Page[]>;
      read(options: { id: string }): Promise<Page>;
      edit(options: { id: string; data: Page }): Promise<Page>;
      add(options: Partial<Page>): Promise<Page>;
      delete(options: { id: string }): Promise<void>;
    };

    posts: {
      browse(options?: object): Promise<Post[]>;
      read(options: { id: string }): Promise<Post>;
      edit(options: { id: string; data: Post }): Promise<Post>;
      add(options: Partial<Post>): Promise<Post>;
      delete(options: { id: string }): Promise<void>;
    };

    members: {
      browse(options?: object): Promise<Member[]>;
      read(options: { id: string }): Promise<Member>;
      edit(options: { id: string; data: Member }): Promise<Member>;
      add(options: Partial<Member>): Promise<Member>;
      delete(options: { id: string }): Promise<void>;
    };

    tags: {
      browse(options?: object): Promise<Tag[]>;
      read(options: { id: string }): Promise<Tag>;
      edit(options: { id: string; data: Tag }): Promise<Tag>;
      add(options: Partial<Tag>): Promise<Tag>;
      delete(options: { id: string }): Promise<void>;
    };

    webhooks: {
      browse(options?: object): Promise<Webhook[]>;
      read(options: { id: string }): Promise<Webhook>;
      edit(options: { id: string; data: Webhook }): Promise<Webhook>;
      add(options: Partial<Webhook>): Promise<Webhook>;
      delete(options: { id: string }): Promise<void>;
    };

    users: {
      browse(options?: object): Promise<User[]>;
      read(options: { id: string }): Promise<User>;
      edit(options: { id: string; data: User }): Promise<User>;
      add(options: Partial<User>): Promise<User>;
      delete(options: { id: string }): Promise<void>;
    };

    newsletters: {
      browse(options?: object): Promise<Newsletter[]>;
      read(options: { id: string }): Promise<Newsletter>;
      edit(options: { id: string; data: Newsletter }): Promise<Newsletter>;
      add(options: Partial<Newsletter>): Promise<Newsletter>;
      delete(options: { id: string }): Promise<void>;
    };

    images: {
      upload(options: { file: any }): Promise<Image>;
    };

    media: {
      upload(options: { file: any }): Promise<Media>;
    };

    files: {
      upload(options: { file: any }): Promise<File>;
    };

    config: {
      read(options: { id: string }): Promise<Config>;
    };

    site: {
      read(options: { id: string }): Promise<Site>;
    };

    themes: {
      upload(options: { file: any }): Promise<Theme>;
      activate(options: { id: string }): Promise<Theme>;
    };
  }
}
maccman commented 1 year ago

It's honestly a bit embarrassing that this lib doesn't have typescript support. Is it maintained?

ivosabev commented 1 year ago

Would love to have TypeScript definitions for the Admin API. JSDoc is not a bad way to do it.

philkunz commented 4 months ago

How is non-TypeScript for npm still a thing in 2024?