diff --git a/packages/pl-api/lib/client.ts b/packages/pl-api/lib/client.ts index e3ad10512..088639e1f 100644 --- a/packages/pl-api/lib/client.ts +++ b/packages/pl-api/lib/client.ts @@ -35,6 +35,8 @@ import { credentialApplicationSchema, customEmojiSchema, domainBlockSchema, + driveFileSchema, + driveFolderSchema, emojiReactionSchema, extendedDescriptionSchema, familiarFollowersSchema, @@ -159,6 +161,7 @@ import type { GetChatsParams, } from './params/chats'; import type { GetCircleStatusesParams } from './params/circles'; +import type { UpdateFileParams } from './params/drive'; import type { CreateEventParams, EditEventParams, @@ -5596,6 +5599,119 @@ class PlApiClient { }, }; + public readonly drive = { + getDrive: async () => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request('/api/iceshrimp/drive/folder'); + + return v.parse(driveFolderSchema, response.json); + }, + + getFolder: async (id: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request(`/api/iceshrimp/drive/folder/${id}`); + + return v.parse(driveFolderSchema, response.json); + }, + + createFolder: async (name: string, parentId: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request('/api/iceshrimp/drive/folder', { + method: 'POST', + body: { name, parentId }, + }); + + return v.parse(driveFolderSchema, response.json); + }, + + updateFolder: async (id: string, name: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request(`/api/iceshrimp/drive/folder/${id}`, { + method: 'PUT', + body: name, + }); + + return v.parse(driveFolderSchema, response.json); + }, + + deleteFolder: async (id: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request<{}>(`/api/iceshrimp/drive/folder/${id}`, { + method: 'DELETE', + }); + + return response; + }, + + moveFolder: async (id: string, targetFolderId: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request(`/api/iceshrimp/drive/folder/${id}/move`, { + method: 'POST', + body: { folderId: targetFolderId }, + }); + + return v.parse(driveFolderSchema, response.json); + }, + + getFile: async (id: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request(`/api/iceshrimp/drive/${id}`); + + return v.parse(driveFileSchema, response.json); + }, + + createFile: async (file: File, folderId: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request('/api/iceshrimp/drive', { + method: 'POST', + body: { file, folderId }, + contentType: '', + }); + + return v.parse(driveFileSchema, response.json); + }, + + updateFile: async (id: string, params: UpdateFileParams) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request(`/api/iceshrimp/drive/${id}`, { + method: 'PUT', + body: params, + }); + + return v.parse(driveFileSchema, response.json); + }, + + deleteFile: async (id: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request<{}>(`/api/iceshrimp/drive/${id}`, { + method: 'DELETE', + }); + + return response; + }, + + moveFile: async (id: string, targetFolderId: string) => { + await this.#getIceshrimpAccessToken(); + + const response = await this.request(`/api/iceshrimp/drive/${id}/move`, { + method: 'POST', + body: { folderId: targetFolderId }, + }); + + return v.parse(driveFolderSchema, response.json); + }, + }; + /** Routes that are not part of any stable release */ public readonly experimental = { admin: { diff --git a/packages/pl-api/lib/entities/drive-file.ts b/packages/pl-api/lib/entities/drive-file.ts new file mode 100644 index 000000000..9409adad9 --- /dev/null +++ b/packages/pl-api/lib/entities/drive-file.ts @@ -0,0 +1,29 @@ +import * as v from 'valibot'; + +/** + * @category Schemas +*/ +const driveFileSchema = v.pipe(v.any(), v.transform((file) => ({ + ...file, + thumbnail_url: file.thumbnailUrl, + content_type: file.contentType, + is_avatar: file.isAvatar, + is_banner: file.isBanner, +})), v.object({ + id: v.string(), + url: v.string(), + thumbnail_url: v.string(), + filename: v.string(), + content_type: v.string(), + sensitive: v.boolean(), + description: v.fallback(v.nullable(v.string()), null), + is_avatar: v.boolean(), + is_banner: v.boolean(), +})); + +/** + * @category Entity types + */ +type DriveFile = v.InferOutput; + +export { driveFileSchema, type DriveFile }; diff --git a/packages/pl-api/lib/entities/drive-folder.ts b/packages/pl-api/lib/entities/drive-folder.ts new file mode 100644 index 000000000..4953904d8 --- /dev/null +++ b/packages/pl-api/lib/entities/drive-folder.ts @@ -0,0 +1,26 @@ +import * as v from 'valibot'; + +import { bookmarkFolderSchema } from './bookmark-folder'; +import { driveFileSchema } from './drive-file'; +import { filteredArray } from './utils'; + +/** + * @category Schemas +*/ +const driveFolderSchema = v.pipe(v.any(), v.transform((folder) => ({ + ...folder, + parent_id: folder.parentId, +})), v.object({ + id: v.fallback(v.nullable(v.string()), null), + name: v.fallback(v.nullable(v.string()), null), + parent_id: v.fallback(v.nullable(v.string()), null), + files: filteredArray(driveFileSchema), + folders: filteredArray(bookmarkFolderSchema), +})); + +/** + * @category Entity types + */ +type DriveFolder = v.InferOutput; + +export { driveFolderSchema, type DriveFolder }; diff --git a/packages/pl-api/lib/entities/index.ts b/packages/pl-api/lib/entities/index.ts index 39a019778..d18355e4a 100644 --- a/packages/pl-api/lib/entities/index.ts +++ b/packages/pl-api/lib/entities/index.ts @@ -36,6 +36,8 @@ export * from './directory/language'; export * from './directory/server'; export * from './directory/statistics-period'; export * from './domain-block'; +export * from './drive-file'; +export * from './drive-folder'; export * from './emoji-reaction'; export * from './extended-description'; export * from './familiar-followers'; diff --git a/packages/pl-api/lib/params/drive.ts b/packages/pl-api/lib/params/drive.ts new file mode 100644 index 000000000..5f840e273 --- /dev/null +++ b/packages/pl-api/lib/params/drive.ts @@ -0,0 +1,7 @@ +interface UpdateFileParams { + filename: string; + sensitive: boolean; + description: string; +} + +export type { UpdateFileParams };