////////////////////////////////////////////// // all types // https://yandex.com/dev/disk-api/doc/en/reference/response-objects ////////////////////////////////////////////// export interface Link { href: string; method: string; templated: boolean; } export interface Resource { antivirus_status?: string; public_key?: string; _embedded?: ResourceList; name?: string; created?: string; custom_properties?: Record; public_url?: string; origin_path?: string; modified?: string; path?: string; md5?: string; sha256?: string; file?: string; type?: "dir" | "file"; mime_type?: string; size?: number; exif?: Record; } type SortType = string; export interface ResourceList { sort?: SortType; public_key?: string; items?: Resource[]; path?: string; limit?: number; offset?: number; total?: number; } export interface FilesResourceList { items: Resource[]; limit: number; offset: number; } export interface LastUploadedResourceList { items: Resource[]; limit: number; } export interface PublicResourcesList { items: Resource[]; type: "dir" | "file"; limit: number; offset: number; } export interface Disk { trash_size: number; total_space: number; used_space: number; system_folders: { applications: string; downloads: string; }; } export interface Operation { status: "success" | "failed" | "in-progress"; } export interface ErrorResponse { error: string; description: string; message?: string; } ////////////////////////////////////////////// // api // https://yandex.com/dev/disk-api/doc/en/ ////////////////////////////////////////////// export class YandexApi { accessToken: string; apiVersion: number; host: string; constructor(accessToken: string) { this.accessToken = accessToken; this.apiVersion = 1; this.host = `https://cloud-api.yandex.net`; } async _api( method: string, endPoint: string, returnType: "json" | "arrayBuffer" | "raw", queryParams?: Record, body?: any, requestContentType?: string ) { let p = ""; if (queryParams !== undefined) { p = `?${new URLSearchParams(queryParams)}`; } const fullUrl = `${this.host}/v${this.apiVersion}/${endPoint}${p}`; // console.debug(`method: ${method}, fullUrl: ${fullUrl}`) const headers: HeadersInit = { Authorization: `OAuth ${this.accessToken}`, }; if (requestContentType !== undefined) { headers["Content-Type"] = requestContentType; } const r = await fetch(fullUrl, { method: method, headers: headers, body: body, }); // console.debug(r) if (r.status >= 200 && r.status < 300) { if (returnType === "json") { return await r.json(); } if (returnType === "arrayBuffer") { return await r.arrayBuffer(); } if (returnType === "raw") { return r; } } else { throw Error(JSON.stringify((await r.json()) as ErrorResponse)); } } async disk() { return (await this._api("GET", "disk/", "json")) as Disk; } async diskResources( path: string, fields?: string[], limit?: number, offset?: number ) { const params: Record = { path: path, }; if (fields !== undefined) { params["fields"] = fields.join(","); } if (limit !== undefined) { params["limit"] = `${limit}`; } if (offset !== undefined) { params["offset"] = `${offset}`; } return (await this._api( "GET", "disk/resources", "json", params )) as Resource; } async diskResourcesFiles(fields?: string[], limit?: number, offset?: number) { const params: Record = {}; if (fields !== undefined) { params["fields"] = fields.join(","); } if (limit !== undefined) { params["limit"] = `${limit}`; } if (offset !== undefined) { params["offset"] = `${offset}`; } return (await this._api( "GET", "disk/resources/files", "json", params )) as FilesResourceList; } async diskResourcesPatch( path: string, custom_properties: Record, fields?: string[] ) { const params: Record = { path: path, }; if (fields !== undefined) { params["fields"] = fields.join(","); } return (await this._api( "PATCH", "disk/resources", "json", params, JSON.stringify({ custom_properties: custom_properties, }), "application/json" )) as Resource; } async diskResoucesUpload( path: string, content: ArrayBuffer, overwrite?: boolean ) { const params: Record = { path: path, overwrite: `${overwrite ?? false}`, }; const link = (await this._api( "GET", "disk/resources/upload", "json", params )) as Link; if (link.templated) { throw Error( `do not know how to deal with upload link with templated: ${JSON.stringify( link )}` ); } const rsp = await fetch(link.href, { method: link.method, body: content, }); if (rsp.status === 200 || rsp.status === 201 || rsp.status === 202) { return true; } else { throw Error(`upload failed. status=${rsp.status}, link=${link.href}`); } } async diskResoucesDownload(path: string) { const params: Record = { path: path, }; const link = (await this._api( "GET", "disk/resources/download", "json", params )) as Link; if (link.templated) { throw Error( `do not know how to deal with download link with templated: ${JSON.stringify( link )}` ); } const rsp = await fetch(link.href, { method: link.method, }); if (rsp.status === 200 || rsp.status === 201 || rsp.status === 202) { return await rsp.arrayBuffer(); } else { throw Error(`download failed. status=${rsp.status}, link=${link.href}`); } } async diskResourcesDelete(path: string, permanently?: boolean) { const params: Record = { path: path, permanently: `${permanently ?? false}`, }; const rsp = (await this._api( "DELETE", "disk/resources", "raw", params )) as Response; if (rsp.status === 204) { return; } if (rsp.status === 202) { return (await rsp.json()) as Link; } throw Error(`do not know how to deal with delete response ${rsp}`); } async diskResourcesPut(path: string, fields?: string[]) { const params: Record = { path: path, }; if (fields !== undefined) { params["fields"] = fields.join(","); } return (await this._api("PUT", "disk/resources", "json", params)) as Link; } }