diff --git a/packages/hub/src/lib/collection-info.spec.ts b/packages/hub/src/lib/collection-info.spec.ts index e152f31a2f..a128eb0c13 100644 --- a/packages/hub/src/lib/collection-info.spec.ts +++ b/packages/hub/src/lib/collection-info.spec.ts @@ -5,7 +5,7 @@ import { collectionInfo } from "./collection-info"; describe("collectionInfo", () => { it("should return the collection info", async () => { const collection = await collectionInfo({ - collectionSlug: "quanghuynt14/test-collection-6866ff686ca2d2e0a1931507", + slug: "quanghuynt14/test-collection-6866ff686ca2d2e0a1931507", hubUrl: TEST_HUB_URL, }); diff --git a/packages/hub/src/lib/collection-info.ts b/packages/hub/src/lib/collection-info.ts index 398d32ff3e..376c18ad8b 100644 --- a/packages/hub/src/lib/collection-info.ts +++ b/packages/hub/src/lib/collection-info.ts @@ -9,7 +9,7 @@ export async function collectionInfo( /** * The slug of the collection. */ - collectionSlug: string; + slug: string; hubUrl?: string; /** * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. @@ -19,7 +19,7 @@ export async function collectionInfo( ): Promise { const accessToken = checkCredentials(params); - const res = await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/collections/${params.collectionSlug}`, { + const res = await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/collections/${params.slug}`, { headers: { "Content-Type": "application/json", ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined), diff --git a/packages/hub/src/lib/create-collection.spec.ts b/packages/hub/src/lib/create-collection.spec.ts new file mode 100644 index 0000000000..6b62c79d9d --- /dev/null +++ b/packages/hub/src/lib/create-collection.spec.ts @@ -0,0 +1,40 @@ +import { it, describe, expect } from "vitest"; + +import { TEST_HUB_URL, TEST_ACCESS_TOKEN } from "../test/consts"; +import { createCollection } from "./create-collection"; +import { whoAmI } from "./who-am-i"; +import { deleteCollection } from "./delete-collection"; + +describe("createCollection", () => { + it("should create a collection", async () => { + let slug: string = ""; + + try { + const user = await whoAmI({ + hubUrl: TEST_HUB_URL, + accessToken: TEST_ACCESS_TOKEN, + }); + + const result = await createCollection({ + collection: { + title: "Test Collection", + namespace: user.name, + description: "This is a test collection", + private: false, + }, + accessToken: TEST_ACCESS_TOKEN, + hubUrl: TEST_HUB_URL, + }); + + expect(result.slug.startsWith(`${user.name}/test-collection`)).toBe(true); + + slug = result.slug; + } finally { + await deleteCollection({ + slug, + accessToken: TEST_ACCESS_TOKEN, + hubUrl: TEST_HUB_URL, + }); + } + }); +}); diff --git a/packages/hub/src/lib/create-collection.ts b/packages/hub/src/lib/create-collection.ts new file mode 100644 index 0000000000..7cbe41fb65 --- /dev/null +++ b/packages/hub/src/lib/create-collection.ts @@ -0,0 +1,35 @@ +import { HUB_URL } from "../consts"; +import { createApiError } from "../error"; +import type { ApiCreateCollectionPayload } from "../types/api/api-create-collection"; +import type { CredentialsParams } from "../types/public"; +import { checkCredentials } from "../utils/checkCredentials"; + +export async function createCollection( + params: { + collection: ApiCreateCollectionPayload; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): Promise<{ slug: string }> { + const accessToken = checkCredentials(params); + + const res = await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/collections`, { + method: "POST", + body: JSON.stringify(params.collection), + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + + if (!res.ok) { + throw await createApiError(res); + } + + const output = await res.json(); + + return { slug: output.slug }; +} diff --git a/packages/hub/src/lib/delete-collection.ts b/packages/hub/src/lib/delete-collection.ts new file mode 100644 index 0000000000..efbe7d9f30 --- /dev/null +++ b/packages/hub/src/lib/delete-collection.ts @@ -0,0 +1,32 @@ +import { HUB_URL } from "../consts"; +import { createApiError } from "../error"; +import type { CredentialsParams } from "../types/public"; +import { checkCredentials } from "../utils/checkCredentials"; + +export async function deleteCollection( + params: { + /** + * The slug of the collection to delete. + */ + slug: string; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): Promise { + const accessToken = checkCredentials(params); + + const res = await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/collections/${params.slug}`, { + method: "DELETE", + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + + if (!res.ok) { + throw await createApiError(res); + } +} diff --git a/packages/hub/src/lib/index.ts b/packages/hub/src/lib/index.ts index 19c933a759..0d19b7e826 100644 --- a/packages/hub/src/lib/index.ts +++ b/packages/hub/src/lib/index.ts @@ -4,11 +4,13 @@ export * from "./commit"; export * from "./count-commits"; export * from "./create-repo"; export * from "./create-branch"; +export * from "./create-collection"; export * from "./dataset-info"; export * from "./delete-branch"; export * from "./delete-file"; export * from "./delete-files"; export * from "./delete-repo"; +export * from "./delete-collection"; export * from "./download-file"; export * from "./download-file-to-cache-dir"; export * from "./file-download-info"; diff --git a/packages/hub/src/types/api/api-create-collection.ts b/packages/hub/src/types/api/api-create-collection.ts new file mode 100644 index 0000000000..9d246b7561 --- /dev/null +++ b/packages/hub/src/types/api/api-create-collection.ts @@ -0,0 +1,19 @@ +export interface ApiCreateCollectionPayload { + /** + * Title of the collection to create. + */ + title: string; + /** + * Namespace of the collection to create (username or org). + */ + namespace: string; + /** + * Description of the collection to create. + */ + description?: string; + /** + * Whether the collection should be private or not. Defaults to False (i.e. public collection). + * @default false + */ + private?: boolean; +}