SDK icon indicating copy to clipboard operation
SDK copied to clipboard

TypeScript support for the admin api client

Open dsebastien opened this issue 2 years ago • 6 comments

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?

dsebastien avatar Sep 22 '22 08:09 dsebastien

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.

ErisDS avatar Sep 22 '22 11:09 ErisDS

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;
}

dsebastien avatar Sep 22 '22 12:09 dsebastien

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>;
    };
  }
}

newTomas avatar Jan 04 '23 06:01 newTomas

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

maccman avatar Aug 18 '23 14:08 maccman

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

ivosabev avatar Oct 06 '23 11:10 ivosabev

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

philkunz avatar May 29 '24 20:05 philkunz