UNPKG

picgo

Version:

A tool for image uploading

983 lines (982 loc) 31.1 kB
import { Command } from 'commander'; import { Inquirer } from 'inquirer'; import { IRequestPromiseOptions } from './oldRequest'; import type { Env, Handler, Hono, MiddlewareHandler } from 'hono'; /** * Type definition for the plugin router setup callback. * The plugin receives a Hono instance created by the Host. */ export type PluginRouterSetup = (router: Hono<any, any, any>) => void; export interface IServerManager<E extends Env = any> { /** * * @param port * @param host * @param ignoreExistingExternalServer PicGo GUI may start a server instance already, if you want to start a new one, set this to true * @param secret shared secret for server authentication * @returns */ listen: (port?: number, host?: string, ignoreExistingExternalServer?: boolean, secret?: string) => Promise<number | void>; shutdown: () => void; isListening: () => boolean; /** * Get current server listening address if running. * e.g. "http://127.0.0.1:36677/" */ getServerInfo: () => string; registerGet<P extends string>(path: P, handler: Handler<E, P>): void; registerPost<P extends string>(path: P, handler: Handler<E, P>): void; registerPut<P extends string>(path: P, handler: Handler<E, P>): void; registerDelete<P extends string>(path: P, handler: Handler<E, P>): void; registerMiddleware<P extends string>(path: P, handler: MiddlewareHandler<E, P>): void; /** * Register a static file server route. * @param path - The URL prefix (e.g. '/static') * @param root - The local file system path */ registerStatic: (path: string, root: string) => void; /** * Mount a sub-router for plugins. * * PicGo creates a new Hono instance (to ensure version consistency) * and passes it to the setup callback for the plugin to configure. */ mount: (path: string, setup: PluginRouterSetup) => void; } export interface ICloudManager { login: (token?: string) => Promise<void>; logout: () => void; disposeLoginFlow: () => void; album: ICloudAlbumManager; uploader: ICloudUploaderManager; getUserInfo: () => Promise<ICloudUserInfo | null>; refreshUserInfo: () => Promise<ICloudUserInfo | null>; setAutoImport: (autoImport: boolean) => Promise<ICloudUserInfo>; getUsage: () => Promise<CloudUsage | null>; getBillingOverview: () => Promise<CloudBillingOverview | null>; } /** * Entry point picgo-gui and external plugins use to manage pending multipart upload sessions. * The state machine itself (runMultipartUpload) is intentionally not exposed here — uploads * should always go through FileService's size dispatch, not bypass it. */ export interface ICloudUploaderManager { /** Abort a remote multipart upload; fire-and-forget, errors swallowed (R2 lifecycle backstop). */ abort: (uploadId: string, objectKey: string) => Promise<void>; /** List every pending multipart session for the current user (local state only). */ listPending: () => MultipartSession[]; /** Delete only the local entry (use abort() to also notify the remote). */ removePending: (fingerprint: string) => void; } export interface ICloudUserInfo { user: string | null; avatar?: string | null; plan?: number; autoImport?: boolean; } export type CloudUsageDimension = { used: number; limit: number | null; }; export type CloudUsagePeriodInfo = { used: number; periodStart: string | null; periodEnd: string | null; }; export type CloudUsageConfigHistory = { used: number; limit: number; appType: 'gui' | 'cli'; }; export type CloudUsage = { /** Paid plan code(用于展示)。 */ plan: string; /** * 当前生效配额对应的 plan code(capabilityPlan)。grace/frozen/pending_cleanup * 阶段会降级为 'free',此时 effectiveQuotaPlan !== plan。 */ effectiveQuotaPlan: string; storage: CloudUsageDimension; mediaCount: CloudUsageDimension; monthlyServes: CloudUsagePeriodInfo; configHistory: CloudUsageConfigHistory; }; export type CloudBillingPlanInfo = { /** 来自 entitlement 的付费 plan code,用于展示 / billing portal。 */ paid: string; /** 用于 capability / 配额检查的 plan code(admin grant + entitlement 合并结果)。 */ capability: string; /** 订阅计费周期类型:'monthly' / 'yearly' / null(免费用户)。 */ billingPeriod: string | null; source: 'entitlement' | 'admin_grant' | 'both' | 'free'; }; export type CloudLifecyclePhase = 'active' | 'grace' | 'frozen' | 'pending_cleanup'; export type CloudLifecycleFlags = { customDomainDisabledByLifecycle: boolean; autoImportDisabledByLifecycle: boolean; }; export type CloudLifecycleInfo = { phase: CloudLifecyclePhase; daysRemaining: number | null; graceEndsAt: string | null; freezeEndsAt: string | null; /** * 当前 lifecycle phase 结束时间。客户端用此字段统一展示套餐到期: * - active → max(activeEnt.validUntil, grant.validUntil);永久 entitlement 为 null * - grace → 等同 graceEndsAt * - frozen → 等同 freezeEndsAt * - pending_cleanup → null */ currentPhaseEndsAt: string | null; flags: CloudLifecycleFlags; }; export type CloudSubscriptionInfo = { status: string; currentPeriodEnd: string | null; }; export type CloudBillingOverview = { plan: CloudBillingPlanInfo; lifecycle: CloudLifecycleInfo; subscription: CloudSubscriptionInfo | null; }; export type ImportResult = { total: number; created: number; skipped: number; invalid: number; failed: number; pending: number; items: IImgInfo[]; }; /** * Generic progress base — the minimal common fields shared by every progress event payload. * Consumers that only care about the ratio (CLI progress bar, future GUI progress widget) can * read these three fields directly without having to discriminate on event type. */ export type IProgress = { /** * Current progress count. Unit depends on the event: * - `FILE_UPLOAD_PROGRESS` → bytes uploaded so far * - `CLOUD_IMPORT_PROGRESS` → items processed so far */ current: number; /** Target total, same unit as current. */ total: number; /** current / total clipped to [0, 1]. Provided so consumers don't have to divide. 0 when total is 0. */ fraction: number; }; /** * Per-file byte-level upload progress for the `FILE_UPLOAD_PROGRESS` event. * current / total are bytes; multipart uploads also fill partsCompleted / totalParts, * non-multipart paths use -1 to signal N/A. */ export type IFileUploadProgress = IProgress & { /** The file name currently being uploaded (= IImgInfo.fileName; lets consumers disambiguate multi-file flows). */ fileName: string; /** Multipart: number of parts already completed. Non-multipart path uses -1. */ partsCompleted: number; /** Multipart: total part count. Non-multipart path uses -1. */ totalParts: number; /** Whether this is a resumed upload (multipart only). Always false on the non-resume path. */ resumed: boolean; }; export type CloudImportProgress = IProgress & { batchIndex: number; batchTotal: number; created: number; skipped: number; failed: number; }; /** * Metadata for a single multipart part. partNumber is 1-based; url is a server-presigned * R2 endpoint the client PUTs the part bytes to. */ export type MultipartPartInfo = { partNumber: number; url: string; method: 'PUT'; headers: Record<string, string>; }; /** * Minimal record the client keeps after a single part finishes uploading. * partNumber is 1-based; etag comes from the part PUT response header. */ export type MultipartCompletedPart = { partNumber: number; etag: string; }; /** * Locally persisted multipart upload session. Drives resume across process crashes / restarts. * `v` is a schema version field for future migrations. */ export type MultipartSession = { /** Schema version, currently 1. */ v: 1; uploadId: string; objectKey: string; publicId: string; url: string; filename: string; /** Total bytes. */ size: number; contentType: string; /** Per-part size (the last part may be smaller). */ partSize: number; /** Total part count = Math.ceil(size / partSize). */ partCount: number; /** Parts already finished, with their server-returned ETag, ready to submit at complete time. */ completedParts: MultipartCompletedPart[]; /** Epoch ms used for the 7-day TTL sweep. */ createdAt: number; }; export declare enum AlbumListOrder { ASC = "asc", DESC = "desc" } export declare enum AlbumListSort { NEWEST = "newest", OLDEST = "oldest", FILE_NAME = "fileName" } export type AlbumListQuery = { contentType?: string; type?: string; ext?: string; search?: string; fileName?: string; limit?: number; offset?: number; sort?: AlbumListSort | string; order?: AlbumListOrder; }; export type AlbumListResponse<T = IImgInfo> = { success: boolean; items: T[]; total: number; limit: number; offset: number; }; export type AlbumFiltersResponse = { success: boolean; contentTypes: string[]; exts: string[]; }; export type BatchUpdateResult = { updated: number; skipped: number; items: IImgInfo[]; }; export type AlbumStatsResponse = { total: number; types: { type: string; count: number; }[]; }; export interface ICloudAlbumManager { import: (items: IImgInfo[]) => Promise<ImportResult>; list: (query?: AlbumListQuery) => Promise<AlbumListResponse>; get: (id: string) => Promise<IImgInfo>; update: (id: string, data: Partial<IImgInfo>) => Promise<IImgInfo>; batchUpdate: (items: { id: string; data: Partial<IImgInfo>; }[]) => Promise<BatchUpdateResult>; delete: (id: string | string[]) => Promise<void>; getStats: () => Promise<AlbumStatsResponse>; getFilters: () => Promise<AlbumFiltersResponse>; getPending: () => Promise<IImgInfo[]>; addToPending: (items: IImgInfo[]) => Promise<IImgInfo[]>; retryPending: () => Promise<ImportResult>; } export interface IPicGo extends NodeJS.EventEmitter { /** * picgo configPath * * if do not provide, then it will use default configPath */ configPath: string; /** * the picgo configPath's baseDir */ baseDir: string; /** * picgo logger factory */ log: ILogger; /** * picgo commander, for cli */ cmd: ICommander; /** * picgo server manager */ server: IServerManager; /** * picgo cloud manager */ cloud: ICloudManager; /** * after transformer, the input will be output */ output: IImgInfo[]; /** * the origin input */ input: any[]; /** * register\unregister\get picgo's plugin */ pluginLoader: IPluginLoader; /** * install\uninstall\update picgo's plugin via npm */ pluginHandler: IPluginHandler; /** * @deprecated will be removed in v1.5.0+ * * use request instead. * * http request tool */ Request: IRequest; /** * plugin system core part transformer\uploader\beforeTransformPlugins... */ helper: IHelper; /** * uploader multi-config manager */ uploaderConfig: IUploaderConfigManager; /** * picgo-core version */ VERSION: string; /** * electron picgo's version */ GUI_VERSION?: string; /** * will be released in v1.5.0+ * * replace old Request * * http request tool */ request: IRequest['request']; /** * Opens a URL in the default browser. * * Default implementation uses the `open` package in Node.js. * Consumers (Electron/VSCode extensions) can overwrite this method. */ openUrl: (url: string) => Promise<void>; i18n: II18nManager; /** * get picgo config */ getConfig: <T = unknown>(name?: string) => T; /** * save picgo config to configPath */ saveConfig: (config: IStringKeyMap<any>) => void; /** * remove some [propName] in config[key] && save config to configPath */ removeConfig: (key: string, propName: string) => void; /** * set picgo config to ctx && will not save to configPath */ setConfig: (config: IStringKeyMap<any>) => void; /** * unset picgo config to ctx && will not save to configPath */ unsetConfig: (key: string, propName: string) => void; /** * upload gogogo */ upload: (input?: any[], options?: UploadOptions) => Promise<IImgInfo[] | Error>; } export declare enum OutputFormat { PRETTY = "pretty", JSON = "json" } export interface UploadOptions { /** Output format for the success message. Defaults to 'pretty'. */ outputFormat?: OutputFormat; } export interface IUploaderConfigItem { _id: string; _configName: string; _createdAt: number; _updatedAt: number; [key: string]: unknown; } export interface IUploaderTypeConfigs { configList: IUploaderConfigItem[]; defaultId: string; } export interface IUploaderConfigManager { listUploaderTypes: () => string[]; getConfigList: (type: string) => IUploaderConfigItem[]; getActiveConfig: (type: string) => IUploaderConfigItem | undefined; use: (type: string, configName?: string) => IUploaderConfigItem; createOrUpdate: (type: string, configName?: string, configPatch?: IStringKeyMap<unknown>) => IUploaderConfigItem; copy: (type: string, configName: string, newConfigName: string) => IUploaderConfigItem; rename: (type: string, oldName: string, newName: string) => IUploaderConfigItem; remove: (type: string, configName: string) => void; } /** * Snapshot of the currently displayed values for all fields in a plugin config form. * * Passed to function-form `choices` / `default` so reactive fields can derive * their value space from other fields. In the GUI this is the form's merged * view (stored config + schema defaults + user edits); in the CLI this is * inquirer's accumulated `answers`. */ export type PluginConfigAnswers = Record<string, unknown>; /** * One choice for a `list` / `checkbox` field. May be a bare string (used as * both label and value) or an object form. */ export type IPluginConfigChoice = string | { name?: string; value: unknown; checked?: boolean; }; /** * for plugin config * * @example Reactive cascading dropdown * const config = (ctx) => [ * { name: 'uploader', type: 'list', required: true, choices: ['github', 'gitee'] }, * { * name: 'repo', * type: 'list', * required: true, * dependsOn: ['uploader'], * choices: (answers) => { * return answers.uploader === 'github' * ? ['my-org/repo-a', 'my-org/repo-b'] * : ['gitee-org/repo-c'] * } * } * ] * * @example Multi-line text via `type: 'editor'` (3.0.0+) * const config = (ctx) => [ * { * name: 'script', * type: 'editor', * alias: 'Compression script', * required: true, * message: 'Enter your compression script (multi-line supported)' * } * ] */ export interface IPluginConfig { name: string; /** * Field widget kind. The string is forwarded to inquirer in the CLI path and * used by the GUI renderer to pick a control. Kept as `string` so plugin * authors can pass through any inquirer-supported value PicGo has not * documented. PicGo guarantees behavior for these known values: * * - `'input'` single-line text. CLI: inquirer text prompt; GUI: text input. * - `'password'` single-line text rendered masked. CLI: inquirer password * prompt; GUI: password input with show/hide toggle. * - `'list'` pick one from `choices`. CLI: inquirer list prompt; GUI: * single-select dropdown. * - `'checkbox'` pick many from `choices`. CLI: inquirer checkbox prompt; * GUI: multi-select combobox. * - `'confirm'` boolean. CLI: inquirer confirm prompt; GUI: switch. * - `'editor'` multi-line text (3.0.0+). Value is a `string` and MAY * contain `\n`. CLI: inquirer editor prompt — spawns the * user's external editor via `VISUAL` / `EDITOR` env vars * (falls back to platform default: `vi` / `nano` on Unix, * `notepad` on Windows); GUI: shadcn `<Textarea>` with * user-resizable height. */ type: string; required: boolean; /** * Default value for the field. May be a plain value or a function that * receives the current `answers` snapshot and returns the value. */ default?: any | ((answers: PluginConfigAnswers) => any); /** * Available options for `list` / `checkbox` fields. May be a static array * or a function that receives the current `answers` snapshot and returns * the array. */ choices?: IPluginConfigChoice[] | ((answers: PluginConfigAnswers) => IPluginConfigChoice[]); /** * Names of other fields in the same schema this field's `choices` / * `default` depends on. When any listed field's value changes, the GUI * will re-evaluate this field. Has no effect in the CLI path (inquirer * already passes the latest `answers` to every prompt). */ dependsOn?: string[]; alias?: string; message?: string; prefix?: string; [propName: string]: any; } /** * for lifecycle plugins */ export interface ILifecyclePlugins { register: (id: string, plugin: IPlugin) => void; unregister: (id: string) => void; getName: () => string; get: (id: string) => IPlugin | undefined; getList: () => IPlugin[]; getIdList: () => string[]; } export interface IHelper { transformer: ILifecyclePlugins; uploader: ILifecyclePlugins; beforeTransformPlugins: ILifecyclePlugins; beforeUploadPlugins: ILifecyclePlugins; afterUploadPlugins: ILifecyclePlugins; afterFinishPlugins: ILifecyclePlugins; } export interface ICommander extends ILifecyclePlugins { program: Command; inquirer: Inquirer; } export interface IPluginLoader { /** * register [local plugin] or [provided plugin] * * if the second param (plugin) is provided * * then picgo will register this plugin and enable it by default * * but picgo won't write any config to config file * * you should use ctx.setConfig to change the config context */ registerPlugin: (name: string, plugin?: IPicGoPlugin) => void; unregisterPlugin: (name: string) => void; getPlugin: (name: string) => IPicGoPluginInterface | undefined; /** * get enabled plugin list */ getList: () => string[]; /** * get all plugin list (enabled or not) */ getFullList: () => string[]; hasPlugin: (name: string) => boolean; } export interface IRequestOld { request: import('axios').AxiosInstance; } export type IOldReqOptions = Omit<IRequestPromiseOptions & { url: string; }, 'auth'>; export type IOldReqOptionsWithFullResponse = IOldReqOptions & { resolveWithFullResponse: true; }; export type IOldReqOptionsWithJSON = IOldReqOptions & { json: true; }; /** * for PicGo new request api, the response will be json format */ export type IReqOptions<T = any> = AxiosRequestConfig<T> & { resolveWithFullResponse: true; }; /** * for PicGo new request api, the response will be Buffer */ export type IReqOptionsWithArrayBufferRes<T = any> = IReqOptions<T> & { responseType: 'arraybuffer'; }; /** * for PicGo new request api, the response will be just response data. (not statusCode, headers, etc.) */ export type IReqOptionsWithBodyResOnly<T = any> = AxiosRequestConfig<T>; export type IFullResponse<T = any, U = any> = AxiosResponse<T, U> & { statusCode: number; body: T; }; type AxiosResponse<T = any, U = any> = import('axios').AxiosResponse<T, U>; type AxiosRequestConfig<T = any> = import('axios').AxiosRequestConfig<T>; interface IRequestOptionsWithFullResponse { resolveWithFullResponse: true; } interface IRequestOptionsWithJSON { json: true; } interface IRequestOptionsWithResponseTypeArrayBuffer { responseType: 'arraybuffer'; } /** * T is the response data type * U is the config type */ export type IResponse<T, U> = U extends IRequestOptionsWithFullResponse ? IFullResponse<T, U> : U extends IRequestOptionsWithJSON ? T : U extends IRequestOptionsWithResponseTypeArrayBuffer ? Buffer : U extends IOldReqOptionsWithFullResponse ? IFullResponse<T, U> : U extends IOldReqOptionsWithJSON ? T : U extends IOldReqOptions ? string : U extends IReqOptionsWithBodyResOnly ? T : string; /** * the old request lib will be removed in v1.5.0+ * the request options have the following properties */ export interface IRequestLibOnlyOptions { proxy?: string; body?: any; formData?: { [key: string]: any; } | undefined; form?: { [key: string]: any; } | string | undefined; } export type IRequestConfig<T> = T extends IRequestLibOnlyOptions ? IOldReqOptions : AxiosRequestConfig; export interface IRequest { request: <T, U extends (IRequestConfig<U> extends IOldReqOptions ? IOldReqOptions : IRequestConfig<U> extends AxiosRequestConfig ? AxiosRequestConfig : never)>(config: U) => Promise<IResponse<T, U>>; } export type ILogColor = 'blue' | 'green' | 'yellow' | 'red'; /** * for uploading image info */ export interface IImgInfo { id?: string; buffer?: Buffer; base64Image?: string; fileName?: string; width?: number; height?: number; extname?: string; imgUrl?: string; /** * if the imgUrl has been overwrite by url rewrite rule, then originImgUrl is the original url before rewrite */ originImgUrl?: string; /** @deprecated use `contentType` */ mimeType?: string; _importToPicGoCloud?: boolean; contentType?: string; filePath?: string; size?: number; createdAt?: number | string | Date; updatedAt?: number | string | Date; /** the origin input of the image, before any processing or uploading */ origin?: string; [propName: string]: any; } export interface IUrlRewriteRule { match: string; replace: string; enable?: boolean; global?: boolean; ignoreCase?: boolean; } export interface IPathTransformedImgInfo extends IImgInfo { success: boolean; } export interface IStringKeyMap<T> { [key: string]: T extends T ? T : any; } export interface ICLIConfigs { [module: string]: IStringKeyMap<any>; } /** SM.MS 图床配置项 */ export interface ISmmsConfig { token: string; backupDomain?: string; } /** 七牛云图床配置项 */ export interface IQiniuConfig { accessKey: string; secretKey: string; /** 存储空间名 */ bucket: string; /** 自定义域名 */ url: string; /** 存储区域编号 */ area: 'z0' | 'z1' | 'z2' | 'na0' | 'as0' | string; /** 网址后缀,比如使用 `?imageslim` 可进行[图片瘦身](https://developer.qiniu.com/dora/api/1271/image-thin-body-imageslim) */ options: string; /** 自定义存储路径,比如 `img/` */ path: string; } /** 又拍云图床配置项 */ export interface IUpyunConfig { /** 存储空间名,及你的服务名 */ bucket: string; /** 操作员 */ operator: string; /** 密码 */ password: string; /** 针对图片的一些后缀处理参数 */ options: string; /** 自定义存储路径,比如 `img/` */ path: string; /** 加速域名,注意要加 `http://` 或者 `https://` */ url: string; } /** 腾讯云图床配置项 */ export interface ITcyunConfig { secretId: string; secretKey: string; /** 存储桶名,v4 和 v5 版本不一样 */ bucket: string; appId: string; /** 存储区域,例如 ap-beijing-1 */ area: string; /** 请求的 ENDPOINT,设置后 `area` 字段会失效 */ endpoint: string; /** 自定义存储路径,比如 img/ */ path: string; /** 自定义域名,注意要加 `http://` 或者 `https://` */ customUrl: string; /** COS 版本,v4 或者 v5 */ version: 'v5' | 'v4'; /** 针对图片的一些后缀处理参数 PicGo 2.4.0+ PicGo-Core 1.5.0+ */ options: string; /** 是否支持极智压缩 */ slim: boolean; } /** GitHub 图床配置项 */ export interface IGithubConfig { /** 仓库名,格式是 `username/reponame` */ repo: string; /** github token */ token: string; /** 自定义存储路径,比如 `img/` */ path: string; /** 自定义域名,注意要加 `http://` 或者 `https://` */ customUrl: string; /** 分支名,默认是 `main` */ branch: string; } /** 阿里云图床配置项 */ export interface IAliyunConfig { accessKeyId: string; accessKeySecret: string; /** 存储空间名 */ bucket: string; /** 存储区域代号 */ area: string; /** 自定义存储路径 */ path: string; /** 自定义域名,注意要加 `http://` 或者 `https://` */ customUrl: string; /** 针对图片的一些后缀处理参数 PicGo 2.2.0+ PicGo-Core 1.4.0+ */ options: string; } /** Imgur 图床配置项 */ export interface IImgurConfig { /** imgur 的 `clientId` */ clientId: string; /** 代理地址,仅支持 http 代理 */ proxy: string; } /** PicGo 配置文件类型定义 */ export interface IConfig { picBed: { uploader: string; current?: string; smms?: ISmmsConfig; qiniu?: IQiniuConfig; upyun?: IUpyunConfig; tcyun?: ITcyunConfig; github?: IGithubConfig; aliyun?: IAliyunConfig; imgur?: IImgurConfig; transformer?: string; /** for uploader */ proxy?: string; [others: string]: any; }; picgoPlugins: { [pluginName: string]: boolean; }; debug?: boolean; silent?: boolean; settings?: { logLevel?: string[]; logPath?: string; /** for npm */ npmRegistry?: string; /** for npm */ npmProxy?: string; picgoCloud?: { token?: string; [others: string]: any; }; server?: { port?: number; host?: string; enable?: boolean; secret?: string; [others: string]: any; }; [others: string]: any; }; [configOptions: string]: any; } /** * for an uploader/transformer/beforeTransformHandler/beforeUploadHandler/afterUploadHandler */ export interface IPlugin { handle: ((ctx: IPicGo) => Promise<any>) | ((ctx: IPicGo) => void); /** The name of this handler */ name?: string; /** The config of this handler */ config?: (ctx: IPicGo) => IPluginConfig[]; [propName: string]: any; } export type IPluginNameType = 'simple' | 'scope' | 'normal' | 'unknown'; export interface IPluginProcessResult { success: boolean; /** * the package.json's name filed */ pkgName: string; /** * the plugin name or the fs absolute path */ fullName: string; } export interface IPluginHandler { install: (plugins: string[], options: IPluginHandlerOptions, env?: IProcessEnv) => Promise<IPluginHandlerResult<boolean>>; update: (plugins: string[], options: IPluginHandlerOptions, env?: IProcessEnv) => Promise<IPluginHandlerResult<boolean>>; uninstall: (plugins: string[], env?: IProcessEnv) => Promise<IPluginHandlerResult<boolean>>; } export interface IPluginHandlerResult<T> { success: T; body: T extends true ? string[] : string; } export interface IPluginHandlerOptions { npmProxy?: string; npmRegistry?: string; } /** * for picgo npm plugins */ export type IPicGoPlugin = (ctx: IPicGo) => IPicGoPluginInterface; /** * interfaces for PicGo plugin */ export interface IPicGoPluginInterface { /** * since PicGo-Core v1.5, register will inject ctx */ register: (ctx: IPicGo) => void; /** * this plugin's config */ config?: (ctx: IPicGo) => IPluginConfig[]; /** * register uploader name */ uploader?: string; /** * register transformer name */ transformer?: string; /** * for picgo gui plugins */ guiMenu?: (ctx: IPicGo) => IGuiMenuItem[]; /** * for picgo gui plugins * short key -> command */ commands?: (ctx: IPicGo) => ICommandItem[]; [propName: string]: any; } export interface IGuiMenuItem { label: string; handle: (ctx: IPicGo, guiApi: any) => Promise<void>; } export interface ICommandItem { label: string; name: string; key: string; handle: (ctx: IPicGo, guiApi: any) => Promise<void>; } /** * for spawn output */ export interface IResult { code: number; data: string; } /** * for transformer - path */ export interface IImgSize { width: number; height: number; real?: boolean; extname?: string; } /** * for clipboard image */ export interface IClipboardImage { imgPath: string; /** * if the path is generate by picgo -> false * if the path is a real file path in system -> true */ shouldKeepAfterUploading: boolean; } /** * for install command environment variable */ export interface IProcessEnv { [propName: string]: Undefinable<string>; } export type ILogArgvType = string | number; export type ILogArgvTypeWithError = ILogArgvType | Error | unknown; export type Nullable<T> = T | null; export type Undefinable<T> = T | undefined; export interface ILogger { success: (...msg: ILogArgvType[]) => void; info: (...msg: ILogArgvType[]) => void; error: (...msg: ILogArgvTypeWithError[]) => void; warn: (...msg: ILogArgvType[]) => void; debug: (...msg: ILogArgvType[]) => void; createLogger?: (options?: { logPath?: string; consoleOutput?: boolean; respectSilent?: boolean; }) => ILogger; } export interface IConfigChangePayload<T> { configName: string; value: T; } export interface ILocale { [key: string]: any; } export interface II18nManager { /** * translate text */ translate: <T extends string>(key: T, args?: IStringKeyMap<string>) => string; /** * add locale to current i18n language * default locale list * - zh-CN * - en */ addLocale: (language: string, locales: ILocale) => boolean; /** * set current language */ setLanguage: (language: string) => void; /** * dynamic add new language & locales */ addLanguage: (language: string, locales: ILocale) => boolean; /** * get language list */ getLanguageList: () => string[]; } export {};