diff --git a/package.json b/package.json index 6ed77ce..edea4c2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "lemmy-js-client", "description": "A javascript / typescript client for Lemmy", - "version": "0.20.0-reports-combined.3", + "version": "0.20.0-image-api-rework.8", "author": "Dessalines ", "license": "AGPL-3.0", "main": "./dist/index.js", @@ -35,7 +35,7 @@ "typescript": "^5.5.4", "typescript-eslint": "^8.7.0" }, - "packageManager": "pnpm@9.15.2", + "packageManager": "pnpm@9.15.3", "types": "./dist/index.d.ts", "lint-staged": { "*.{ts,tsx,js}": [ diff --git a/putTypesInIndex.js b/putTypesInIndex.js index 8d41ef8..4a30b48 100644 --- a/putTypesInIndex.js +++ b/putTypesInIndex.js @@ -5,7 +5,7 @@ const exportRegex = /export\s+(?:enum|interface|type)\s+([A-Za-z0-9_]+)/g; const baseExports = [ 'export * from "./http";', - 'export {UploadImage,UploadImageResponse,ImageFile,DeleteImage} from "./other_types";', + 'export {UploadImage} from "./other_types";', ]; async function putTypesInIndex() { diff --git a/src/http.ts b/src/http.ts index ddeb49b..cb4d36e 100644 --- a/src/http.ts +++ b/src/http.ts @@ -117,12 +117,7 @@ import { SearchResponse } from "./types/SearchResponse"; import { SiteResponse } from "./types/SiteResponse"; import { TransferCommunity } from "./types/TransferCommunity"; import { VerifyEmail } from "./types/VerifyEmail"; -import { - DeleteImage, - UploadImage, - UploadImageResponse, - VERSION, -} from "./other_types"; +import { UploadImage, VERSION } from "./other_types"; import { HideCommunity } from "./types/HideCommunity"; import { GenerateTotpSecretResponse } from "./types/GenerateTotpSecretResponse"; import { UpdateTotp } from "./types/UpdateTotp"; @@ -163,11 +158,14 @@ import { ListPersonContent } from "./types/ListPersonContent"; import { ListPersonContentResponse } from "./types/ListPersonContentResponse"; import { ListPersonSaved } from "./types/ListPersonSaved"; import { ListPersonSavedResponse } from "./types/ListPersonSavedResponse"; +import { DeleteImageParams } from "./types/DeleteImageParams"; +import { UploadImageResponse } from "./types/UploadImageResponse"; enum HttpType { Get = "GET", Post = "POST", Put = "PUT", + Delete = "DELETE", } type RequestOptions = Pick; @@ -178,7 +176,6 @@ type RequestOptions = Pick; export class LemmyHttp { #apiUrl: string; #headers: { [key: string]: string } = {}; - #pictrsUrl: string; #fetchFunction: typeof fetch = fetch.bind(globalThis); /** @@ -194,7 +191,6 @@ export class LemmyHttp { }, ) { this.#apiUrl = `${baseUrl.replace(/\/+$/, "")}/api/${VERSION}`; - this.#pictrsUrl = `${baseUrl}/pictrs/image`; if (options?.headers) { this.#headers = options.headers; @@ -1871,64 +1867,224 @@ export class LemmyHttp { ); } + /** + * Upload new user avatar. + * + * `HTTP.Post /account/avatar` + */ + async uploadUserAvatar( + image: UploadImage, + options?: RequestOptions, + ): Promise { + return this.#upload("/account/avatar", image, options); + } + + /** + * Delete the user avatar. + * + * `HTTP.Delete /account/avatar` + */ + async deleteUserAvatar(options?: RequestOptions): Promise { + return this.#wrapper( + HttpType.Delete, + "/account/avatar", + {}, + options, + ); + } + + /** + * Upload new user banner. + * + * `HTTP.Post /account/banner` + */ + async uploadUserBanner( + image: UploadImage, + options?: RequestOptions, + ): Promise { + return this.#upload("/account/banner", image, options); + } + + /** + * Delete the user banner. + * + * `HTTP.Delete /account/banner` + */ + async deleteUserBanner(options?: RequestOptions): Promise { + return this.#wrapper( + HttpType.Delete, + "/account/banner", + {}, + options, + ); + } + + /** + * Upload new community icon. + * + * `HTTP.Post /community/icon` + */ + async uploadCommunityIcon( + image: UploadImage, + options?: RequestOptions, + ): Promise { + return this.#upload("/community/icon", image, options); + } + + /** + * Delete the community icon. + * + * `HTTP.Delete /community/icon` + */ + async deleteCommunityIcon( + options?: RequestOptions, + ): Promise { + return this.#wrapper( + HttpType.Delete, + "/community/icon", + {}, + options, + ); + } + + /** + * Upload new community banner. + * + * `HTTP.Post /community/banner` + */ + async uploadCommunityBanner( + image: UploadImage, + options?: RequestOptions, + ): Promise { + return this.#upload("/community/banner", image, options); + } + + /** + * Delete the community banner. + * + * `HTTP.Delete /community/banner` + */ + async deleteCommunityBanner( + options?: RequestOptions, + ): Promise { + return this.#wrapper( + HttpType.Delete, + "/community/banner", + {}, + options, + ); + } + + /** + * Upload new site icon. + * + * `HTTP.Post /site/icon` + */ + async uploadSiteIcon( + image: UploadImage, + options?: RequestOptions, + ): Promise { + return this.#upload("/site/icon", image, options); + } + + /** + * Delete the site icon. + * + * `HTTP.Delete /site/icon` + */ + async deleteSiteIcon(options?: RequestOptions): Promise { + return this.#wrapper( + HttpType.Delete, + "/site/icon", + {}, + options, + ); + } + + /** + * Upload new site banner. + * + * `HTTP.Post /site/banner` + */ + async uploadSiteBanner( + image: UploadImage, + options?: RequestOptions, + ): Promise { + return this.#upload("/site/banner", image, options); + } + + /** + * Delete the site banner. + * + * `HTTP.Delete /site/banner` + */ + async deleteSiteBanner(options?: RequestOptions): Promise { + return this.#wrapper( + HttpType.Delete, + "/site/banner", + {}, + options, + ); + } + /** * Upload an image to the server. + * + * `HTTP.Post /image` */ async uploadImage( - { image }: UploadImage, + image: UploadImage, options?: RequestOptions, ): Promise { + return this.#upload("/image", image, options); + } + + /** + * Delete a pictrs image + * + * `HTTP.Delete /image` + */ + async deleteImage(form: DeleteImageParams, options?: RequestOptions) { + return this.#wrapper( + HttpType.Delete, + "/image", + form, + options, + ); + } + + /** + * Health check for image functionality + * + * `HTTP.Get /image/health` + */ + async imageHealth(options?: RequestOptions) { + return this.#wrapper( + HttpType.Get, + "/image/health", + {}, + options, + ); + } + + #buildFullUrl(endpoint: string) { + return `${this.#apiUrl}${endpoint}`; + } + + async #upload( + path: string, + { image }: UploadImage, + options?: RequestOptions, + ): Promise { const formData = createFormData(image); - let url: string | undefined = undefined; - let delete_url: string | undefined = undefined; - - const response = await this.#fetchFunction(this.#pictrsUrl, { + const response = await this.#fetchFunction(this.#buildFullUrl(path), { ...options, method: HttpType.Post, body: formData as unknown as BodyInit, headers: this.#headers, }); - - if (response.status === 413) { - return { msg: "too_large" }; - } - - const responseJson = await response.json(); - - if (responseJson.msg === "ok") { - const { file: hash, delete_token: deleteToken } = responseJson.files[0]; - delete_url = `${this.#pictrsUrl}/delete/${deleteToken}/${hash}`; - url = `${this.#pictrsUrl}/${hash}`; - } - - return { - ...responseJson, - url, - delete_url, - }; - } - - /** - * Delete a pictrs image - */ - async deleteImage( - { token, filename }: DeleteImage, - options?: RequestOptions, - ): Promise { - const deleteUrl = `${this.#pictrsUrl}/delete/${token}/${filename}`; - - const response = await this.#fetchFunction(deleteUrl, { - ...options, - method: HttpType.Get, - headers: this.#headers, - }); - - return response.status == 204; - } - - #buildFullUrl(endpoint: string) { - return `${this.#apiUrl}${endpoint}`; + return response.json(); } async #wrapper( diff --git a/src/index.ts b/src/index.ts index d09d732..1f7e62c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,5 @@ export * from "./http"; -export { - UploadImage, - UploadImageResponse, - ImageFile, - DeleteImage, -} from "./other_types"; +export { UploadImage } from "./other_types"; export { ActivityId } from "./types/ActivityId"; export { AddAdmin } from "./types/AddAdmin"; export { AddAdminResponse } from "./types/AddAdminResponse"; @@ -91,6 +86,7 @@ export { DeleteAccount } from "./types/DeleteAccount"; export { DeleteComment } from "./types/DeleteComment"; export { DeleteCommunity } from "./types/DeleteCommunity"; export { DeleteCustomEmoji } from "./types/DeleteCustomEmoji"; +export { DeleteImageParams } from "./types/DeleteImageParams"; export { DeleteOAuthProvider } from "./types/DeleteOAuthProvider"; export { DeletePost } from "./types/DeletePost"; export { DeletePrivateMessage } from "./types/DeletePrivateMessage"; @@ -144,6 +140,8 @@ export { GetUnreadRegistrationApplicationCountResponse } from "./types/GetUnread export { HideCommunity } from "./types/HideCommunity"; export { HidePost } from "./types/HidePost"; export { ImageDetails } from "./types/ImageDetails"; +export { ImageGetParams } from "./types/ImageGetParams"; +export { ImageProxyParams } from "./types/ImageProxyParams"; export { Instance } from "./types/Instance"; export { InstanceId } from "./types/InstanceId"; export { InstanceWithFederationState } from "./types/InstanceWithFederationState"; @@ -318,6 +316,7 @@ export { TransferCommunity } from "./types/TransferCommunity"; export { UpdateTagline } from "./types/UpdateTagline"; export { UpdateTotp } from "./types/UpdateTotp"; export { UpdateTotpResponse } from "./types/UpdateTotpResponse"; +export { UploadImageResponse } from "./types/UploadImageResponse"; export { UserBlockInstanceParams } from "./types/UserBlockInstanceParams"; export { VerifyEmail } from "./types/VerifyEmail"; export { VoteView } from "./types/VoteView"; diff --git a/src/other_types.ts b/src/other_types.ts index 27e2e33..b3be06c 100644 --- a/src/other_types.ts +++ b/src/other_types.ts @@ -3,23 +3,3 @@ export const VERSION = "v4"; export interface UploadImage { image: File | Buffer; } - -export interface UploadImageResponse { - /** - * Is "ok" if the upload was successful; is something else otherwise. - */ - msg: string; - files?: ImageFile[]; - url?: string; - delete_url?: string; -} - -export interface ImageFile { - file: string; - delete_token: string; -} - -export interface DeleteImage { - token: string; - filename: string; -} diff --git a/src/types/CreateSite.ts b/src/types/CreateSite.ts index f36bfde..a7c9de6 100644 --- a/src/types/CreateSite.ts +++ b/src/types/CreateSite.ts @@ -14,8 +14,6 @@ export type CreateSite = { name: string; sidebar?: string; description?: string; - icon?: string; - banner?: string; enable_nsfw?: boolean; community_creation_admin_only?: boolean; require_email_verification?: boolean; diff --git a/src/types/DeleteImageParams.ts b/src/types/DeleteImageParams.ts new file mode 100644 index 0000000..626a45a --- /dev/null +++ b/src/types/DeleteImageParams.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type DeleteImageParams = { filename: string; token: string }; diff --git a/src/types/EditCommunity.ts b/src/types/EditCommunity.ts index 8fb1b52..627fb52 100644 --- a/src/types/EditCommunity.ts +++ b/src/types/EditCommunity.ts @@ -20,14 +20,6 @@ export type EditCommunity = { * A shorter, one line description of your community. */ description?: string; - /** - * An icon URL. - */ - icon?: string; - /** - * A banner URL. - */ - banner?: string; /** * Whether its an NSFW community. */ diff --git a/src/types/EditSite.ts b/src/types/EditSite.ts index 82a0b1e..75b4fb1 100644 --- a/src/types/EditSite.ts +++ b/src/types/EditSite.ts @@ -20,14 +20,6 @@ export type EditSite = { * A shorter, one line description of your site. */ description?: string; - /** - * A url for your site's icon. - */ - icon?: string; - /** - * A url for your site's banner. - */ - banner?: string; /** * Whether to enable NSFW. */ diff --git a/src/types/GetSiteResponse.ts b/src/types/GetSiteResponse.ts index 4d36090..8a3f8a9 100644 --- a/src/types/GetSiteResponse.ts +++ b/src/types/GetSiteResponse.ts @@ -27,4 +27,5 @@ export type GetSiteResponse = { oauth_providers?: Array; admin_oauth_providers?: Array; blocked_urls: Array; + image_upload_disabled: boolean; }; diff --git a/src/types/ImageGetParams.ts b/src/types/ImageGetParams.ts new file mode 100644 index 0000000..5dab275 --- /dev/null +++ b/src/types/ImageGetParams.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ImageGetParams = { file_type?: string; max_size?: number }; diff --git a/src/types/ImageProxyParams.ts b/src/types/ImageProxyParams.ts new file mode 100644 index 0000000..1d74299 --- /dev/null +++ b/src/types/ImageProxyParams.ts @@ -0,0 +1,7 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ImageProxyParams = { + url: string; + file_type?: string; + max_size?: number; +}; diff --git a/src/types/LemmyErrorType.ts b/src/types/LemmyErrorType.ts index a6a582b..5b9e0df 100644 --- a/src/types/LemmyErrorType.ts +++ b/src/types/LemmyErrorType.ts @@ -22,6 +22,8 @@ export type LemmyErrorType = | { error: "pictrs_api_key_not_provided" } | { error: "no_content_type_header" } | { error: "not_an_image_type" } + | { error: "invalid_image_upload" } + | { error: "image_upload_disabled" } | { error: "not_a_mod_or_admin" } | { error: "not_top_mod" } | { error: "not_logged_in" } diff --git a/src/types/SaveUserSettings.ts b/src/types/SaveUserSettings.ts index 431a8dd..78a3769 100644 --- a/src/types/SaveUserSettings.ts +++ b/src/types/SaveUserSettings.ts @@ -42,14 +42,6 @@ export type SaveUserSettings = { * The language of the lemmy interface */ interface_language?: string; - /** - * A URL for your avatar. - */ - avatar?: string; - /** - * A URL for your banner. - */ - banner?: string; /** * Your display name, which can contain strange characters, and does not need to be unique. */ diff --git a/src/types/UploadImageResponse.ts b/src/types/UploadImageResponse.ts new file mode 100644 index 0000000..afc7d98 --- /dev/null +++ b/src/types/UploadImageResponse.ts @@ -0,0 +1,7 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type UploadImageResponse = { + image_url: string; + filename: string; + delete_token: string; +};