From 400ea899491d493f3e5d1b202ce1a765f7164695 Mon Sep 17 00:00:00 2001 From: "Eliott C." Date: Mon, 23 Sep 2024 10:51:05 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A5=20Simpler=20credentials=20passing?= =?UTF-8?q?=20around=20(#918)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix https://github.com/huggingface/huggingface.js/issues/149 Should have backwards compatibilty, just marked as deprecated --- README.md | 12 +- packages/hub/README.md | 17 ++- packages/hub/src/lib/commit.spec.ts | 16 +-- packages/hub/src/lib/commit.ts | 16 +-- packages/hub/src/lib/count-commits.ts | 27 ++-- packages/hub/src/lib/create-repo.spec.ts | 12 +- packages/hub/src/lib/create-repo.ts | 41 ++++--- packages/hub/src/lib/delete-file.spec.ts | 9 +- packages/hub/src/lib/delete-file.ts | 29 ++--- packages/hub/src/lib/delete-files.spec.ts | 9 +- packages/hub/src/lib/delete-files.ts | 29 ++--- packages/hub/src/lib/delete-repo.ts | 25 ++-- packages/hub/src/lib/download-file.ts | 61 +++++----- packages/hub/src/lib/file-download-info.ts | 49 ++++---- packages/hub/src/lib/file-exists.ts | 29 ++--- packages/hub/src/lib/list-commits.ts | 41 ++++--- packages/hub/src/lib/list-datasets.ts | 45 +++---- packages/hub/src/lib/list-files.ts | 53 ++++---- packages/hub/src/lib/list-models.ts | 47 +++---- packages/hub/src/lib/list-spaces.ts | 43 +++---- .../hub/src/lib/parse-safetensors-metadata.ts | 115 +++++++++--------- packages/hub/src/lib/upload-file.spec.ts | 11 +- packages/hub/src/lib/upload-file.ts | 33 ++--- .../lib/upload-files-with-progress.spec.ts | 9 +- .../hub/src/lib/upload-files-with-progress.ts | 36 +++--- packages/hub/src/lib/upload-files.spec.ts | 9 +- packages/hub/src/lib/upload-files.ts | 32 ++--- packages/hub/src/lib/who-am-i.spec.ts | 2 +- packages/hub/src/lib/who-am-i.ts | 23 ++-- packages/hub/src/types/public.ts | 19 +++ packages/hub/src/utils/checkCredentials.ts | 19 ++- 31 files changed, 466 insertions(+), 452 deletions(-) diff --git a/README.md b/README.md index 769843751..86fb22159 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,12 @@ await createRepo({ repo: {type: "model", name: "my-user/nlp-model"}, - credentials: {accessToken: HF_TOKEN} + accessToken: HF_TOKEN }); await uploadFile({ repo: "my-user/nlp-model", - credentials: {accessToken: HF_TOKEN}, + accessToken: HF_TOKEN, // Can work with native File in browsers file: { path: "pytorch_model.bin", @@ -79,7 +79,7 @@ Then import the libraries in your code: import { HfInference } from "@huggingface/inference"; import { HfAgent } from "@huggingface/agents"; import { createRepo, commit, deleteRepo, listFiles } from "@huggingface/hub"; -import type { RepoId, Credentials } from "@huggingface/hub"; +import type { RepoId } from "@huggingface/hub"; ``` ### From CDN or Static hosting @@ -182,12 +182,12 @@ const HF_TOKEN = "hf_..."; await createRepo({ repo: "my-user/nlp-model", // or {type: "model", name: "my-user/nlp-test"}, - credentials: {accessToken: HF_TOKEN} + accessToken: HF_TOKEN }); await uploadFile({ repo: "my-user/nlp-model", - credentials: {accessToken: HF_TOKEN}, + accessToken: HF_TOKEN, // Can work with native File in browsers file: { path: "pytorch_model.bin", @@ -197,7 +197,7 @@ await uploadFile({ await deleteFiles({ repo: {type: "space", name: "my-user/my-space"}, // or "spaces/my-user/my-space" - credentials: {accessToken: HF_TOKEN}, + accessToken: HF_TOKEN, paths: ["README.md", ".gitattributes"] }); ``` diff --git a/packages/hub/README.md b/packages/hub/README.md index 22a9db256..e51b778c4 100644 --- a/packages/hub/README.md +++ b/packages/hub/README.md @@ -31,22 +31,21 @@ Learn how to find free models using the hub package in this [interactive tutoria ```ts import { createRepo, uploadFiles, uploadFilesWithProgress, deleteFile, deleteRepo, listFiles, whoAmI } from "@huggingface/hub"; -import type { RepoDesignation, Credentials } from "@huggingface/hub"; +import type { RepoDesignation } from "@huggingface/hub"; const repo: RepoDesignation = { type: "model", name: "myname/some-model" }; -const credentials: Credentials = { accessToken: "hf_..." }; -const {name: username} = await whoAmI({credentials}); +const {name: username} = await whoAmI({accessToken: "hf_..."}); -for await (const model of listModels({search: {owner: username}, credentials})) { +for await (const model of listModels({search: {owner: username}, accessToken: "hf_..."})) { console.log("My model:", model); } -await createRepo({ repo, credentials, license: "mit" }); +await createRepo({ repo, accessToken: "hf_...", license: "mit" }); await uploadFiles({ repo, - credentials, + accessToken: "hf_...", files: [ // path + blob content { @@ -70,7 +69,7 @@ await uploadFiles({ for await (const progressEvent of await uploadFilesWithProgress({ repo, - credentials, + accessToken: "hf_...", files: [ ... ], @@ -78,7 +77,7 @@ for await (const progressEvent of await uploadFilesWithProgress({ console.log(progressEvent); } -await deleteFile({repo, credentials, path: "myfile.bin"}); +await deleteFile({repo, accessToken: "hf_...", path: "myfile.bin"}); await (await downloadFile({ repo, path: "README.md" })).text(); @@ -86,7 +85,7 @@ for await (const fileInfo of listFiles({repo})) { console.log(fileInfo); } -await deleteRepo({ repo, credentials }); +await deleteRepo({ repo, accessToken: "hf_..." }); ``` ## OAuth Login diff --git a/packages/hub/src/lib/commit.spec.ts b/packages/hub/src/lib/commit.spec.ts index 3315b7361..617be8ee8 100644 --- a/packages/hub/src/lib/commit.spec.ts +++ b/packages/hub/src/lib/commit.spec.ts @@ -25,9 +25,7 @@ describe("commit", () => { }; await createRepo({ - credentials: { - accessToken: TEST_ACCESS_TOKEN, - }, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, repo, license: "mit", @@ -50,9 +48,7 @@ describe("commit", () => { await commit({ repo, title: "Some commit", - credentials: { - accessToken: TEST_ACCESS_TOKEN, - }, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, operations: [ { @@ -135,9 +131,7 @@ size ${lfsContent.length} }; await createRepo({ - credentials: { - accessToken: TEST_ACCESS_TOKEN, - }, + accessToken: TEST_ACCESS_TOKEN, repo, hubUrl: TEST_HUB_URL, }); @@ -163,9 +157,7 @@ size ${lfsContent.length} ); await commit({ repo, - credentials: { - accessToken: TEST_ACCESS_TOKEN, - }, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, title: "upload model", operations, diff --git a/packages/hub/src/lib/commit.ts b/packages/hub/src/lib/commit.ts index a66af74c1..bd623a96c 100644 --- a/packages/hub/src/lib/commit.ts +++ b/packages/hub/src/lib/commit.ts @@ -10,7 +10,7 @@ import type { ApiPreuploadRequest, ApiPreuploadResponse, } from "../types/api/api-commit"; -import type { Credentials, RepoDesignation } from "../types/public"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { chunk } from "../utils/chunk"; import { promisesQueue } from "../utils/promisesQueue"; @@ -54,12 +54,11 @@ type CommitBlob = Omit & { content: Blob }; export type CommitOperation = CommitDeletedEntry | CommitFile /* | CommitRenameFile */; type CommitBlobOperation = Exclude | CommitBlob; -export interface CommitParams { +export type CommitParams = { title: string; description?: string; repo: RepoDesignation; operations: CommitOperation[]; - credentials?: Credentials; /** @default "main" */ branch?: string; /** @@ -82,7 +81,8 @@ export interface CommitParams { */ fetch?: typeof fetch; abortSignal?: AbortSignal; -} + // Credentials are optional due to custom fetch functions or cookie auth +} & Partial; export interface CommitOutput { pullRequestUrl?: string; @@ -121,7 +121,7 @@ export type CommitProgressEvent = * Can be exposed later to offer fine-tuned progress info */ export async function* commitIter(params: CommitParams): AsyncGenerator { - checkCredentials(params.credentials); + const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); yield { event: "phase", phase: "preuploading" }; @@ -189,7 +189,7 @@ export async function* commitIter(params: CommitParams): AsyncGenerator { - checkCredentials(params.credentials); +export async function countCommits( + params: { + repo: RepoDesignation; + /** + * Revision to list commits from. Defaults to the default branch. + */ + revision?: string; + hubUrl?: string; + fetch?: typeof fetch; + } & Partial +): Promise { + const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); // Could upgrade to 1000 commits per page @@ -23,7 +24,7 @@ export async function countCommits(params: { }?limit=1`; const res: Response = await (params.fetch ?? fetch)(url, { - headers: params.credentials ? { Authorization: `Bearer ${params.credentials.accessToken}` } : {}, + headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : {}, }); if (!res.ok) { diff --git a/packages/hub/src/lib/create-repo.spec.ts b/packages/hub/src/lib/create-repo.spec.ts index 3fba39a08..c1a39b9f8 100644 --- a/packages/hub/src/lib/create-repo.spec.ts +++ b/packages/hub/src/lib/create-repo.spec.ts @@ -11,9 +11,7 @@ describe("createRepo", () => { const repoName = `${TEST_USER}/TEST-${insecureRandomString()}`; const result = await createRepo({ - credentials: { - accessToken: TEST_ACCESS_TOKEN, - }, + accessToken: TEST_ACCESS_TOKEN, repo: { name: repoName, type: "model", @@ -62,9 +60,7 @@ describe("createRepo", () => { const repoName = `${TEST_USER}/TEST-${insecureRandomString()}`; const result = await createRepo({ - credentials: { - accessToken: TEST_ACCESS_TOKEN, - }, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, repo: repoName, files: [{ path: ".gitattributes", content: new Blob(["*.html filter=lfs diff=lfs merge=lfs -text"]) }], @@ -88,9 +84,7 @@ describe("createRepo", () => { const repoName = `datasets/${TEST_USER}/TEST-${insecureRandomString()}`; const result = await createRepo({ - credentials: { - accessToken: TEST_ACCESS_TOKEN, - }, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, repo: repoName, files: [{ path: ".gitattributes", content: new Blob(["*.html filter=lfs diff=lfs merge=lfs -text"]) }], diff --git a/packages/hub/src/lib/create-repo.ts b/packages/hub/src/lib/create-repo.ts index 2334037c3..4005844d6 100644 --- a/packages/hub/src/lib/create-repo.ts +++ b/packages/hub/src/lib/create-repo.ts @@ -1,29 +1,30 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; import type { ApiCreateRepoPayload } from "../types/api/api-create-repo"; -import type { Credentials, RepoDesignation, SpaceSdk } from "../types/public"; +import type { CredentialsParams, RepoDesignation, SpaceSdk } from "../types/public"; import { base64FromBytes } from "../utils/base64FromBytes"; import { checkCredentials } from "../utils/checkCredentials"; import { toRepoId } from "../utils/toRepoId"; -export async function createRepo(params: { - repo: RepoDesignation; - credentials: Credentials; - private?: boolean; - license?: string; - /** - * Only a few lightweight files are supported at repo creation - */ - files?: Array<{ content: ArrayBuffer | Blob; path: string }>; - /** @required for when {@link repo.type} === "space" */ - sdk?: SpaceSdk; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise<{ repoUrl: string }> { - checkCredentials(params.credentials); +export async function createRepo( + params: { + repo: RepoDesignation; + private?: boolean; + license?: string; + /** + * Only a few lightweight files are supported at repo creation + */ + files?: Array<{ content: ArrayBuffer | Blob; path: string }>; + /** @required for when {@link repo.type} === "space" */ + sdk?: SpaceSdk; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & CredentialsParams +): Promise<{ repoUrl: string }> { + const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); const [namespace, repoName] = repoId.name.split("/"); @@ -61,7 +62,7 @@ export async function createRepo(params: { : undefined, } satisfies ApiCreateRepoPayload), headers: { - Authorization: `Bearer ${params.credentials.accessToken}`, + Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, }); diff --git a/packages/hub/src/lib/delete-file.spec.ts b/packages/hub/src/lib/delete-file.spec.ts index 51d2defdd..ec38a916d 100644 --- a/packages/hub/src/lib/delete-file.spec.ts +++ b/packages/hub/src/lib/delete-file.spec.ts @@ -12,13 +12,10 @@ describe("deleteFile", () => { it("should delete a file", async () => { const repoName = `${TEST_USER}/TEST-${insecureRandomString()}`; const repo = { type: "model", name: repoName } satisfies RepoId; - const credentials = { - accessToken: TEST_ACCESS_TOKEN, - }; try { const result = await createRepo({ - credentials, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, repo, files: [ @@ -39,7 +36,7 @@ describe("deleteFile", () => { assert.strictEqual(await content?.text(), "file1"); - await deleteFile({ path: "file1", repo, credentials, hubUrl: TEST_HUB_URL }); + await deleteFile({ path: "file1", repo, accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL }); content = await downloadFile({ repo, @@ -59,7 +56,7 @@ describe("deleteFile", () => { } finally { await deleteRepo({ repo, - credentials, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, }); } diff --git a/packages/hub/src/lib/delete-file.ts b/packages/hub/src/lib/delete-file.ts index 6f5fb4b94..58b19f198 100644 --- a/packages/hub/src/lib/delete-file.ts +++ b/packages/hub/src/lib/delete-file.ts @@ -1,21 +1,22 @@ -import type { Credentials } from "../types/public"; +import type { CredentialsParams } from "../types/public"; import type { CommitOutput, CommitParams } from "./commit"; import { commit } from "./commit"; -export function deleteFile(params: { - credentials: Credentials; - repo: CommitParams["repo"]; - path: string; - commitTitle?: CommitParams["title"]; - commitDescription?: CommitParams["description"]; - hubUrl?: CommitParams["hubUrl"]; - fetch?: CommitParams["fetch"]; - branch?: CommitParams["branch"]; - isPullRequest?: CommitParams["isPullRequest"]; - parentCommit?: CommitParams["parentCommit"]; -}): Promise { +export function deleteFile( + params: { + repo: CommitParams["repo"]; + path: string; + commitTitle?: CommitParams["title"]; + commitDescription?: CommitParams["description"]; + hubUrl?: CommitParams["hubUrl"]; + fetch?: CommitParams["fetch"]; + branch?: CommitParams["branch"]; + isPullRequest?: CommitParams["isPullRequest"]; + parentCommit?: CommitParams["parentCommit"]; + } & CredentialsParams +): Promise { return commit({ - credentials: params.credentials, + ...(params.accessToken ? { accessToken: params.accessToken } : { credentials: params.credentials }), repo: params.repo, operations: [ { diff --git a/packages/hub/src/lib/delete-files.spec.ts b/packages/hub/src/lib/delete-files.spec.ts index 707cb0b57..558da6a6b 100644 --- a/packages/hub/src/lib/delete-files.spec.ts +++ b/packages/hub/src/lib/delete-files.spec.ts @@ -12,13 +12,10 @@ describe("deleteFiles", () => { it("should delete multiple files", async () => { const repoName = `${TEST_USER}/TEST-${insecureRandomString()}`; const repo = { type: "model", name: repoName } satisfies RepoId; - const credentials = { - accessToken: TEST_ACCESS_TOKEN, - }; try { const result = await createRepo({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, files: [ { path: "file1", content: new Blob(["file1"]) }, @@ -48,7 +45,7 @@ describe("deleteFiles", () => { assert.strictEqual(await content?.text(), "file2"); - await deleteFiles({ paths: ["file1", "file2"], repo, credentials, hubUrl: TEST_HUB_URL }); + await deleteFiles({ paths: ["file1", "file2"], repo, accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL }); content = await downloadFile({ repo, @@ -76,7 +73,7 @@ describe("deleteFiles", () => { } finally { await deleteRepo({ repo, - credentials, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, }); } diff --git a/packages/hub/src/lib/delete-files.ts b/packages/hub/src/lib/delete-files.ts index 69b4a337a..956bd473e 100644 --- a/packages/hub/src/lib/delete-files.ts +++ b/packages/hub/src/lib/delete-files.ts @@ -1,21 +1,22 @@ -import type { Credentials } from "../types/public"; +import type { CredentialsParams } from "../types/public"; import type { CommitOutput, CommitParams } from "./commit"; import { commit } from "./commit"; -export function deleteFiles(params: { - credentials: Credentials; - repo: CommitParams["repo"]; - paths: string[]; - commitTitle?: CommitParams["title"]; - commitDescription?: CommitParams["description"]; - hubUrl?: CommitParams["hubUrl"]; - branch?: CommitParams["branch"]; - isPullRequest?: CommitParams["isPullRequest"]; - parentCommit?: CommitParams["parentCommit"]; - fetch?: CommitParams["fetch"]; -}): Promise { +export function deleteFiles( + params: { + repo: CommitParams["repo"]; + paths: string[]; + commitTitle?: CommitParams["title"]; + commitDescription?: CommitParams["description"]; + hubUrl?: CommitParams["hubUrl"]; + branch?: CommitParams["branch"]; + isPullRequest?: CommitParams["isPullRequest"]; + parentCommit?: CommitParams["parentCommit"]; + fetch?: CommitParams["fetch"]; + } & CredentialsParams +): Promise { return commit({ - credentials: params.credentials, + ...(params.accessToken ? { accessToken: params.accessToken } : { credentials: params.credentials }), repo: params.repo, operations: params.paths.map((path) => ({ operation: "delete", diff --git a/packages/hub/src/lib/delete-repo.ts b/packages/hub/src/lib/delete-repo.ts index 1c0b59ef4..7b34d1b8e 100644 --- a/packages/hub/src/lib/delete-repo.ts +++ b/packages/hub/src/lib/delete-repo.ts @@ -1,19 +1,20 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; -import type { Credentials, RepoDesignation } from "../types/public"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { toRepoId } from "../utils/toRepoId"; -export async function deleteRepo(params: { - repo: RepoDesignation; - credentials: Credentials; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise { - checkCredentials(params.credentials); +export async function deleteRepo( + params: { + repo: RepoDesignation; + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & CredentialsParams +): Promise { + const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); const [namespace, repoName] = repoId.name.split("/"); @@ -25,7 +26,7 @@ export async function deleteRepo(params: { type: repoId.type, }), headers: { - Authorization: `Bearer ${params.credentials.accessToken}`, + Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, }); diff --git a/packages/hub/src/lib/download-file.ts b/packages/hub/src/lib/download-file.ts index 1675cd112..4f6ebde2e 100644 --- a/packages/hub/src/lib/download-file.ts +++ b/packages/hub/src/lib/download-file.ts @@ -1,39 +1,40 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; -import type { Credentials, RepoDesignation } from "../types/public"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { toRepoId } from "../utils/toRepoId"; /** * @returns null when the file doesn't exist */ -export async function downloadFile(params: { - repo: RepoDesignation; - path: string; - /** - * If true, will download the raw git file. - * - * For example, when calling on a file stored with Git LFS, the pointer file will be downloaded instead. - */ - raw?: boolean; - /** - * An optional Git revision id which can be a branch name, a tag, or a commit hash. - * - * @default "main" - */ - revision?: string; - /** - * Fetch only a specific part of the file - */ - range?: [number, number]; - credentials?: Credentials; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise { - checkCredentials(params.credentials); +export async function downloadFile( + params: { + repo: RepoDesignation; + path: string; + /** + * If true, will download the raw git file. + * + * For example, when calling on a file stored with Git LFS, the pointer file will be downloaded instead. + */ + raw?: boolean; + /** + * An optional Git revision id which can be a branch name, a tag, or a commit hash. + * + * @default "main" + */ + revision?: string; + /** + * Fetch only a specific part of the file + */ + range?: [number, number]; + 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 repoId = toRepoId(params.repo); const url = `${params.hubUrl ?? HUB_URL}/${repoId.type === "model" ? "" : `${repoId.type}s/`}${repoId.name}/${ params.raw ? "raw" : "resolve" @@ -41,9 +42,9 @@ export async function downloadFile(params: { const resp = await (params.fetch ?? fetch)(url, { headers: { - ...(params.credentials + ...(accessToken ? { - Authorization: `Bearer ${params.credentials.accessToken}`, + Authorization: `Bearer ${accessToken}`, } : {}), ...(params.range diff --git a/packages/hub/src/lib/file-download-info.ts b/packages/hub/src/lib/file-download-info.ts index f5daaca8b..210bd11e7 100644 --- a/packages/hub/src/lib/file-download-info.ts +++ b/packages/hub/src/lib/file-download-info.ts @@ -1,6 +1,6 @@ import { HUB_URL } from "../consts"; import { createApiError, InvalidApiResponseFormatError } from "../error"; -import type { Credentials, RepoDesignation } from "../types/public"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { toRepoId } from "../utils/toRepoId"; @@ -15,28 +15,29 @@ export interface FileDownloadInfoOutput { /** * @returns null when the file doesn't exist */ -export async function fileDownloadInfo(params: { - repo: RepoDesignation; - path: string; - revision?: string; - credentials?: Credentials; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; - /** - * To get the raw pointer file behind a LFS file - */ - raw?: boolean; - /** - * To avoid the content-disposition header in the `downloadLink` for LFS files - * - * So that on browsers you can use the URL in an iframe for example - */ - noContentDisposition?: boolean; -}): Promise { - checkCredentials(params.credentials); +export async function fileDownloadInfo( + params: { + repo: RepoDesignation; + path: string; + revision?: 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; + /** + * To get the raw pointer file behind a LFS file + */ + raw?: boolean; + /** + * To avoid the content-disposition header in the `downloadLink` for LFS files + * + * So that on browsers you can use the URL in an iframe for example + */ + noContentDisposition?: boolean; + } & Partial +): Promise { + const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); const hubUrl = params.hubUrl ?? HUB_URL; @@ -50,7 +51,7 @@ export async function fileDownloadInfo(params: { method: "GET", headers: { ...(params.credentials && { - Authorization: `Bearer ${params.credentials.accessToken}`, + Authorization: `Bearer ${accessToken}`, }), Range: "bytes=0-0", }, diff --git a/packages/hub/src/lib/file-exists.ts b/packages/hub/src/lib/file-exists.ts index 47e371287..64acf1dd3 100644 --- a/packages/hub/src/lib/file-exists.ts +++ b/packages/hub/src/lib/file-exists.ts @@ -1,21 +1,22 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; -import type { Credentials, RepoDesignation } from "../types/public"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { toRepoId } from "../utils/toRepoId"; -export async function fileExists(params: { - repo: RepoDesignation; - path: string; - revision?: string; - credentials?: Credentials; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise { - checkCredentials(params.credentials); +export async function fileExists( + params: { + repo: RepoDesignation; + path: string; + revision?: 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 repoId = toRepoId(params.repo); const hubUrl = params.hubUrl ?? HUB_URL; @@ -25,7 +26,7 @@ export async function fileExists(params: { const resp = await (params.fetch ?? fetch)(url, { method: "HEAD", - headers: params.credentials ? { Authorization: `Bearer ${params.credentials.accessToken}` } : {}, + headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : {}, }); if (resp.status === 404) { diff --git a/packages/hub/src/lib/list-commits.ts b/packages/hub/src/lib/list-commits.ts index 42c9ab765..2bbcc99f7 100644 --- a/packages/hub/src/lib/list-commits.ts +++ b/packages/hub/src/lib/list-commits.ts @@ -1,7 +1,7 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; import type { ApiCommitData } from "../types/api/api-commit"; -import type { Credentials, RepoDesignation } from "../types/public"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { parseLinkHeader } from "../utils/parseLinkHeader"; import { toRepoId } from "../utils/toRepoId"; @@ -14,24 +14,25 @@ export interface CommitData { date: Date; } -export async function* listCommits(params: { - credentials?: Credentials; - repo: RepoDesignation; - /** - * Revision to list commits from. Defaults to the default branch. - */ - revision?: string; - hubUrl?: string; - /** - * Number of commits to fetch from the hub each http call. Defaults to 100. Can be set to 1000. - */ - batchSize?: number; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): AsyncGenerator { - checkCredentials(params.credentials); +export async function* listCommits( + params: { + repo: RepoDesignation; + /** + * Revision to list commits from. Defaults to the default branch. + */ + revision?: string; + hubUrl?: string; + /** + * Number of commits to fetch from the hub each http call. Defaults to 100. Can be set to 1000. + */ + batchSize?: number; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): AsyncGenerator { + const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); // Could upgrade to 1000 commits per page @@ -41,7 +42,7 @@ export async function* listCommits(params: { while (url) { const res: Response = await (params.fetch ?? fetch)(url, { - headers: params.credentials ? { Authorization: `Bearer ${params.credentials.accessToken}` } : {}, + headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : {}, }); if (!res.ok) { diff --git a/packages/hub/src/lib/list-datasets.ts b/packages/hub/src/lib/list-datasets.ts index 32b59f27a..2b9524d10 100644 --- a/packages/hub/src/lib/list-datasets.ts +++ b/packages/hub/src/lib/list-datasets.ts @@ -1,7 +1,7 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; import type { ApiDatasetInfo } from "../types/api/api-dataset"; -import type { Credentials } from "../types/public"; +import type { CredentialsParams } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { parseLinkHeader } from "../utils/parseLinkHeader"; import { pick } from "../utils/pick"; @@ -46,28 +46,29 @@ export interface DatasetEntry { export async function* listDatasets< const T extends Exclude<(typeof EXPANDABLE_KEYS)[number], (typeof EXPAND_KEYS)[number]> = never, ->(params?: { - search?: { +>( + params?: { + search?: { + /** + * Will search in the dataset name for matches + */ + query?: string; + owner?: string; + tags?: string[]; + }; + hubUrl?: string; + additionalFields?: T[]; /** - * Will search in the dataset name for matches + * Set to limit the number of models returned. */ - query?: string; - owner?: string; - tags?: string[]; - }; - credentials?: Credentials; - hubUrl?: string; - additionalFields?: T[]; - /** - * Set to limit the number of models returned. - */ - limit?: number; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): AsyncGenerator> { - checkCredentials(params?.credentials); + limit?: number; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): AsyncGenerator> { + const accessToken = params && checkCredentials(params); let totalToFetch = params?.limit ?? Infinity; const search = new URLSearchParams([ ...Object.entries({ @@ -85,7 +86,7 @@ export async function* listDatasets< const res: Response = await (params?.fetch ?? fetch)(url, { headers: { accept: "application/json", - ...(params?.credentials ? { Authorization: `Bearer ${params.credentials.accessToken}` } : undefined), + ...(params?.credentials ? { Authorization: `Bearer ${accessToken}` } : undefined), }, }); diff --git a/packages/hub/src/lib/list-files.ts b/packages/hub/src/lib/list-files.ts index fa4b306e3..3083e9587 100644 --- a/packages/hub/src/lib/list-files.ts +++ b/packages/hub/src/lib/list-files.ts @@ -1,7 +1,7 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; import type { ApiIndexTreeEntry } from "../types/api/api-index-tree"; -import type { Credentials, RepoDesignation } from "../types/public"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { parseLinkHeader } from "../utils/parseLinkHeader"; import { toRepoId } from "../utils/toRepoId"; @@ -35,30 +35,31 @@ export interface ListFileEntry { * List files in a folder. To list ALL files in the directory, call it * with {@link params.recursive} set to `true`. */ -export async function* listFiles(params: { - repo: RepoDesignation; - /** - * Do we want to list files in subdirectories? - */ - recursive?: boolean; - /** - * Eg 'data' for listing all files in the 'data' folder. Leave it empty to list all - * files in the repo. - */ - path?: string; - /** - * Fetch `lastCommit` and `securityStatus` for each file. - */ - expand?: boolean; - revision?: string; - credentials?: Credentials; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): AsyncGenerator { - checkCredentials(params.credentials); +export async function* listFiles( + params: { + repo: RepoDesignation; + /** + * Do we want to list files in subdirectories? + */ + recursive?: boolean; + /** + * Eg 'data' for listing all files in the 'data' folder. Leave it empty to list all + * files in the repo. + */ + path?: string; + /** + * Fetch `lastCommit` and `securityStatus` for each file. + */ + expand?: boolean; + revision?: 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 +): AsyncGenerator { + const accessToken = checkCredentials(params); const repoId = toRepoId(params.repo); let url: string | undefined = `${params.hubUrl || HUB_URL}/api/${repoId.type}s/${repoId.name}/tree/${ params.revision || "main" @@ -68,7 +69,7 @@ export async function* listFiles(params: { const res: Response = await (params.fetch ?? fetch)(url, { headers: { accept: "application/json", - ...(params.credentials ? { Authorization: `Bearer ${params.credentials.accessToken}` } : undefined), + ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined), }, }); diff --git a/packages/hub/src/lib/list-models.ts b/packages/hub/src/lib/list-models.ts index e5ebceb99..c4f0859c8 100644 --- a/packages/hub/src/lib/list-models.ts +++ b/packages/hub/src/lib/list-models.ts @@ -1,7 +1,7 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; import type { ApiModelInfo } from "../types/api/api-model"; -import type { Credentials, PipelineType } from "../types/public"; +import type { CredentialsParams, PipelineType } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { parseLinkHeader } from "../utils/parseLinkHeader"; import { pick } from "../utils/pick"; @@ -52,29 +52,30 @@ export interface ModelEntry { export async function* listModels< const T extends Exclude<(typeof EXPANDABLE_KEYS)[number], (typeof EXPAND_KEYS)[number]> = never, ->(params?: { - search?: { +>( + params?: { + search?: { + /** + * Will search in the model name for matches + */ + query?: string; + owner?: string; + task?: PipelineType; + tags?: string[]; + }; + hubUrl?: string; + additionalFields?: T[]; /** - * Will search in the model name for matches + * Set to limit the number of models returned. */ - query?: string; - owner?: string; - task?: PipelineType; - tags?: string[]; - }; - credentials?: Credentials; - hubUrl?: string; - additionalFields?: T[]; - /** - * Set to limit the number of models returned. - */ - limit?: number; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): AsyncGenerator> { - checkCredentials(params?.credentials); + limit?: number; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & Partial +): AsyncGenerator> { + const accessToken = params && checkCredentials(params); let totalToFetch = params?.limit ?? Infinity; const search = new URLSearchParams([ ...Object.entries({ @@ -93,7 +94,7 @@ export async function* listModels< const res: Response = await (params?.fetch ?? fetch)(url, { headers: { accept: "application/json", - ...(params?.credentials ? { Authorization: `Bearer ${params.credentials.accessToken}` } : undefined), + ...(params?.credentials ? { Authorization: `Bearer ${accessToken}` } : undefined), }, }); diff --git a/packages/hub/src/lib/list-spaces.ts b/packages/hub/src/lib/list-spaces.ts index fada26cb2..11b890ef1 100644 --- a/packages/hub/src/lib/list-spaces.ts +++ b/packages/hub/src/lib/list-spaces.ts @@ -1,7 +1,7 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; import type { ApiSpaceInfo } from "../types/api/api-space"; -import type { Credentials, SpaceSdk } from "../types/public"; +import type { CredentialsParams, SpaceSdk } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; import { parseLinkHeader } from "../utils/parseLinkHeader"; import { pick } from "../utils/pick"; @@ -38,27 +38,28 @@ export interface SpaceEntry { export async function* listSpaces< const T extends Exclude<(typeof EXPANDABLE_KEYS)[number], (typeof EXPAND_KEYS)[number]> = never, ->(params?: { - search?: { +>( + params?: { + search?: { + /** + * Will search in the space name for matches + */ + query?: string; + owner?: string; + tags?: string[]; + }; + hubUrl?: string; /** - * Will search in the space name for matches + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. */ - query?: string; - owner?: string; - tags?: string[]; - }; - credentials?: Credentials; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; - /** - * Additional fields to fetch from huggingface.co. - */ - additionalFields?: T[]; -}): AsyncGenerator> { - checkCredentials(params?.credentials); + fetch?: typeof fetch; + /** + * Additional fields to fetch from huggingface.co. + */ + additionalFields?: T[]; + } & Partial +): AsyncGenerator> { + const accessToken = params && checkCredentials(params); const search = new URLSearchParams([ ...Object.entries({ limit: "500", @@ -74,7 +75,7 @@ export async function* listSpaces< const res: Response = await (params?.fetch ?? fetch)(url, { headers: { accept: "application/json", - ...(params?.credentials ? { Authorization: `Bearer ${params.credentials.accessToken}` } : undefined), + ...(params?.credentials ? { Authorization: `Bearer ${accessToken}` } : undefined), }, }); diff --git a/packages/hub/src/lib/parse-safetensors-metadata.ts b/packages/hub/src/lib/parse-safetensors-metadata.ts index 4044ece60..063a503c9 100644 --- a/packages/hub/src/lib/parse-safetensors-metadata.ts +++ b/packages/hub/src/lib/parse-safetensors-metadata.ts @@ -1,5 +1,4 @@ -import type { Credentials, RepoDesignation } from "../types/public"; -import { checkCredentials } from "../utils/checkCredentials"; +import type { CredentialsParams, RepoDesignation } from "../types/public"; import { omit } from "../utils/omit"; import { toRepoId } from "../utils/toRepoId"; import { typedEntries } from "../utils/typedEntries"; @@ -83,13 +82,12 @@ async function parseSingleFile( params: { repo: RepoDesignation; revision?: string; - credentials?: Credentials; 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 firstResp = await downloadFile({ ...params, @@ -133,13 +131,12 @@ async function parseShardedIndex( params: { repo: RepoDesignation; revision?: string; - credentials?: Credentials; 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<{ index: SafetensorsIndexJson; headers: SafetensorsShardedHeaders }> { const indexResp = await downloadFile({ ...params, @@ -177,58 +174,60 @@ async function parseShardedIndex( * Analyze model.safetensors.index.json or model.safetensors from a model hosted * on Hugging Face using smart range requests to extract its metadata. */ -export async function parseSafetensorsMetadata(params: { - /** Only models are supported */ - repo: RepoDesignation; - /** - * Relative file path to safetensors file inside `repo`. Defaults to `SAFETENSORS_FILE` or `SAFETENSORS_INDEX_FILE` (whichever one exists). - */ - path?: string; - /** - * Will include SafetensorsParseFromRepo["parameterCount"], an object containing the number of parameters for each DType - * - * @default false - */ - computeParametersCount: true; - hubUrl?: string; - credentials?: Credentials; - revision?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise>; -export async function parseSafetensorsMetadata(params: { - /** Only models are supported */ - repo: RepoDesignation; - /** - * Will include SafetensorsParseFromRepo["parameterCount"], an object containing the number of parameters for each DType - * - * @default false - */ - path?: string; - computeParametersCount?: boolean; - hubUrl?: string; - credentials?: Credentials; - revision?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise; -export async function parseSafetensorsMetadata(params: { - repo: RepoDesignation; - path?: string; - computeParametersCount?: boolean; - hubUrl?: string; - credentials?: Credentials; - revision?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise { - checkCredentials(params.credentials); +export async function parseSafetensorsMetadata( + params: { + /** Only models are supported */ + repo: RepoDesignation; + /** + * Relative file path to safetensors file inside `repo`. Defaults to `SAFETENSORS_FILE` or `SAFETENSORS_INDEX_FILE` (whichever one exists). + */ + path?: string; + /** + * Will include SafetensorsParseFromRepo["parameterCount"], an object containing the number of parameters for each DType + * + * @default false + */ + computeParametersCount: true; + hubUrl?: string; + revision?: 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>; +export async function parseSafetensorsMetadata( + params: { + /** Only models are supported */ + repo: RepoDesignation; + /** + * Will include SafetensorsParseFromRepo["parameterCount"], an object containing the number of parameters for each DType + * + * @default false + */ + path?: string; + computeParametersCount?: boolean; + hubUrl?: string; + revision?: 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; +export async function parseSafetensorsMetadata( + params: { + repo: RepoDesignation; + path?: string; + computeParametersCount?: boolean; + hubUrl?: string; + revision?: 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 repoId = toRepoId(params.repo); if (repoId.type !== "model") { diff --git a/packages/hub/src/lib/upload-file.spec.ts b/packages/hub/src/lib/upload-file.spec.ts index 0d202554f..af7534963 100644 --- a/packages/hub/src/lib/upload-file.spec.ts +++ b/packages/hub/src/lib/upload-file.spec.ts @@ -12,13 +12,10 @@ describe("uploadFile", () => { it("should upload a file", async () => { const repoName = `${TEST_USER}/TEST-${insecureRandomString()}`; const repo = { type: "model", name: repoName } satisfies RepoId; - const credentials = { - accessToken: TEST_ACCESS_TOKEN, - }; try { const result = await createRepo({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, hubUrl: TEST_HUB_URL, }); @@ -28,13 +25,13 @@ describe("uploadFile", () => { }); await uploadFile({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, file: { content: new Blob(["file1"]), path: "file1" }, hubUrl: TEST_HUB_URL, }); await uploadFile({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, file: new URL("https://huggingface.co/gpt2/raw/main/config.json"), hubUrl: TEST_HUB_URL, @@ -93,7 +90,7 @@ describe("uploadFile", () => { } finally { await deleteRepo({ repo, - credentials, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, }); } diff --git a/packages/hub/src/lib/upload-file.ts b/packages/hub/src/lib/upload-file.ts index f760932ab..290cfcb03 100644 --- a/packages/hub/src/lib/upload-file.ts +++ b/packages/hub/src/lib/upload-file.ts @@ -1,21 +1,22 @@ -import type { Credentials } from "../types/public"; +import type { CredentialsParams } from "../types/public"; import type { CommitOutput, CommitParams, ContentSource } from "./commit"; import { commit } from "./commit"; -export function uploadFile(params: { - credentials?: Credentials; - repo: CommitParams["repo"]; - file: URL | File | { path: string; content: ContentSource }; - commitTitle?: CommitParams["title"]; - commitDescription?: CommitParams["description"]; - hubUrl?: CommitParams["hubUrl"]; - branch?: CommitParams["branch"]; - isPullRequest?: CommitParams["isPullRequest"]; - parentCommit?: CommitParams["parentCommit"]; - fetch?: CommitParams["fetch"]; - useWebWorkers?: CommitParams["useWebWorkers"]; - abortSignal?: CommitParams["abortSignal"]; -}): Promise { +export function uploadFile( + params: { + repo: CommitParams["repo"]; + file: URL | File | { path: string; content: ContentSource }; + commitTitle?: CommitParams["title"]; + commitDescription?: CommitParams["description"]; + hubUrl?: CommitParams["hubUrl"]; + branch?: CommitParams["branch"]; + isPullRequest?: CommitParams["isPullRequest"]; + parentCommit?: CommitParams["parentCommit"]; + fetch?: CommitParams["fetch"]; + useWebWorkers?: CommitParams["useWebWorkers"]; + abortSignal?: CommitParams["abortSignal"]; + } & Partial +): Promise { const path = params.file instanceof URL ? params.file.pathname.split("/").at(-1) ?? "file" @@ -24,7 +25,7 @@ export function uploadFile(params: { : params.file.name; return commit({ - credentials: params.credentials, + ...(params.accessToken ? { accessToken: params.accessToken } : { credentials: params.credentials }), repo: params.repo, operations: [ { diff --git a/packages/hub/src/lib/upload-files-with-progress.spec.ts b/packages/hub/src/lib/upload-files-with-progress.spec.ts index bc082cd89..b088e5597 100644 --- a/packages/hub/src/lib/upload-files-with-progress.spec.ts +++ b/packages/hub/src/lib/upload-files-with-progress.spec.ts @@ -13,14 +13,11 @@ describe("uploadFilesWithProgress", () => { it("should upload files", async () => { const repoName = `${TEST_USER}/TEST-${insecureRandomString()}`; const repo = { type: "model", name: repoName } satisfies RepoId; - const credentials = { - accessToken: TEST_ACCESS_TOKEN, - }; const lfsContent = "O123456789".repeat(100_000); try { const result = await createRepo({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, hubUrl: TEST_HUB_URL, }); @@ -30,7 +27,7 @@ describe("uploadFilesWithProgress", () => { }); const it = uploadFilesWithProgress({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, files: [ { content: new Blob(["file1"]), path: "file1" }, @@ -163,7 +160,7 @@ describe("uploadFilesWithProgress", () => { } finally { await deleteRepo({ repo, - credentials, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, }); } diff --git a/packages/hub/src/lib/upload-files-with-progress.ts b/packages/hub/src/lib/upload-files-with-progress.ts index 277344d83..e0e4c9d7f 100644 --- a/packages/hub/src/lib/upload-files-with-progress.ts +++ b/packages/hub/src/lib/upload-files-with-progress.ts @@ -1,3 +1,4 @@ +import type { CredentialsParams } from "../types/public"; import { typedInclude } from "../utils/typedInclude"; import type { CommitOutput, CommitParams, CommitProgressEvent, ContentSource } from "./commit"; import { commitIter } from "./commit"; @@ -16,24 +17,25 @@ const multipartUploadTracking = new WeakMap< * Needs XMLHttpRequest to be available for progress events for uploads * Set useWebWorkers to true in order to have progress events for hashing */ -export async function* uploadFilesWithProgress(params: { - credentials?: CommitParams["credentials"]; - repo: CommitParams["repo"]; - files: Array; - commitTitle?: CommitParams["title"]; - commitDescription?: CommitParams["description"]; - hubUrl?: CommitParams["hubUrl"]; - branch?: CommitParams["branch"]; - isPullRequest?: CommitParams["isPullRequest"]; - parentCommit?: CommitParams["parentCommit"]; - abortSignal?: CommitParams["abortSignal"]; - /** - * Set this to true in order to have progress events for hashing - */ - useWebWorkers?: CommitParams["useWebWorkers"]; -}): AsyncGenerator { +export async function* uploadFilesWithProgress( + params: { + repo: CommitParams["repo"]; + files: Array; + commitTitle?: CommitParams["title"]; + commitDescription?: CommitParams["description"]; + hubUrl?: CommitParams["hubUrl"]; + branch?: CommitParams["branch"]; + isPullRequest?: CommitParams["isPullRequest"]; + parentCommit?: CommitParams["parentCommit"]; + abortSignal?: CommitParams["abortSignal"]; + /** + * Set this to true in order to have progress events for hashing + */ + useWebWorkers?: CommitParams["useWebWorkers"]; + } & Partial +): AsyncGenerator { return yield* commitIter({ - credentials: params.credentials, + ...(params.accessToken ? { accessToken: params.accessToken } : { credentials: params.credentials }), repo: params.repo, operations: params.files.map((file) => ({ operation: "addOrUpdate", diff --git a/packages/hub/src/lib/upload-files.spec.ts b/packages/hub/src/lib/upload-files.spec.ts index 78a4882f3..89206c99c 100644 --- a/packages/hub/src/lib/upload-files.spec.ts +++ b/packages/hub/src/lib/upload-files.spec.ts @@ -12,13 +12,10 @@ describe("uploadFiles", () => { it("should upload files", async () => { const repoName = `${TEST_USER}/TEST-${insecureRandomString()}`; const repo = { type: "model", name: repoName } satisfies RepoId; - const credentials = { - accessToken: TEST_ACCESS_TOKEN, - }; try { const result = await createRepo({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, hubUrl: TEST_HUB_URL, }); @@ -28,7 +25,7 @@ describe("uploadFiles", () => { }); await uploadFiles({ - credentials, + accessToken: TEST_ACCESS_TOKEN, repo, files: [ { content: new Blob(["file1"]), path: "file1" }, @@ -90,7 +87,7 @@ describe("uploadFiles", () => { } finally { await deleteRepo({ repo, - credentials, + accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL, }); } diff --git a/packages/hub/src/lib/upload-files.ts b/packages/hub/src/lib/upload-files.ts index 22b93508f..d205dba97 100644 --- a/packages/hub/src/lib/upload-files.ts +++ b/packages/hub/src/lib/upload-files.ts @@ -1,22 +1,24 @@ +import type { CredentialsParams } from "../types/public"; import type { CommitOutput, CommitParams, ContentSource } from "./commit"; import { commit } from "./commit"; -export function uploadFiles(params: { - credentials?: CommitParams["credentials"]; - repo: CommitParams["repo"]; - files: Array; - commitTitle?: CommitParams["title"]; - commitDescription?: CommitParams["description"]; - hubUrl?: CommitParams["hubUrl"]; - branch?: CommitParams["branch"]; - isPullRequest?: CommitParams["isPullRequest"]; - parentCommit?: CommitParams["parentCommit"]; - fetch?: CommitParams["fetch"]; - useWebWorkers?: CommitParams["useWebWorkers"]; - abortSignal?: CommitParams["abortSignal"]; -}): Promise { +export function uploadFiles( + params: { + repo: CommitParams["repo"]; + files: Array; + commitTitle?: CommitParams["title"]; + commitDescription?: CommitParams["description"]; + hubUrl?: CommitParams["hubUrl"]; + branch?: CommitParams["branch"]; + isPullRequest?: CommitParams["isPullRequest"]; + parentCommit?: CommitParams["parentCommit"]; + fetch?: CommitParams["fetch"]; + useWebWorkers?: CommitParams["useWebWorkers"]; + abortSignal?: CommitParams["abortSignal"]; + } & Partial +): Promise { return commit({ - credentials: params.credentials, + ...(params.accessToken ? { accessToken: params.accessToken } : { credentials: params.credentials }), repo: params.repo, operations: params.files.map((file) => ({ operation: "addOrUpdate", diff --git a/packages/hub/src/lib/who-am-i.spec.ts b/packages/hub/src/lib/who-am-i.spec.ts index 148be17ae..387373923 100644 --- a/packages/hub/src/lib/who-am-i.spec.ts +++ b/packages/hub/src/lib/who-am-i.spec.ts @@ -4,7 +4,7 @@ import { whoAmI } from "./who-am-i"; describe("whoAmI", () => { it("should fetch identity info", async () => { - const info = await whoAmI({ credentials: { accessToken: TEST_ACCESS_TOKEN }, hubUrl: TEST_HUB_URL }); + const info = await whoAmI({ accessToken: TEST_ACCESS_TOKEN, hubUrl: TEST_HUB_URL }); if (info.auth.accessToken?.createdAt instanceof Date) { info.auth.accessToken.createdAt = new Date(0); diff --git a/packages/hub/src/lib/who-am-i.ts b/packages/hub/src/lib/who-am-i.ts index d3851aa6d..5f4c1845b 100644 --- a/packages/hub/src/lib/who-am-i.ts +++ b/packages/hub/src/lib/who-am-i.ts @@ -1,7 +1,7 @@ import { HUB_URL } from "../consts"; import { createApiError } from "../error"; import type { ApiWhoAmIReponse } from "../types/api/api-who-am-i"; -import type { AccessTokenRole, AuthType, Credentials } from "../types/public"; +import type { AccessTokenRole, AuthType, CredentialsParams } from "../types/public"; import { checkCredentials } from "../utils/checkCredentials"; export interface WhoAmIUser { @@ -58,19 +58,20 @@ export interface AuthInfo { expiresAt?: Date; } -export async function whoAmI(params: { - credentials: Credentials; - hubUrl?: string; - /** - * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. - */ - fetch?: typeof fetch; -}): Promise { - checkCredentials(params.credentials); +export async function whoAmI( + params: { + hubUrl?: string; + /** + * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers. + */ + fetch?: typeof fetch; + } & CredentialsParams +): Promise { + const accessToken = checkCredentials(params); const res = await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/whoami-v2`, { headers: { - Authorization: `Bearer ${params.credentials.accessToken}`, + Authorization: `Bearer ${accessToken}`, }, }); diff --git a/packages/hub/src/types/public.ts b/packages/hub/src/types/public.ts index d29a89543..648f5a615 100644 --- a/packages/hub/src/types/public.ts +++ b/packages/hub/src/types/public.ts @@ -14,10 +14,29 @@ export type RepoDesignation = RepoId | RepoFullName; /** Actually `hf_${string}`, but for convenience, using the string type */ export type AccessToken = string; +/** + * @deprecated Use `AccessToken` instead. Pass { accessToken: "hf_..." } instead of { credentials: { accessToken: "hf_..." } } + */ export interface Credentials { accessToken: AccessToken; } +export type CredentialsParams = + | { + accessToken?: undefined; + /** + * @deprecated Use `accessToken` instead + */ + credentials: Credentials; + } + | { + accessToken: AccessToken; + /** + * @deprecated Use `accessToken` instead + */ + credentials?: undefined; + }; + export type SpaceHardwareFlavor = | "cpu-basic" | "cpu-upgrade" diff --git a/packages/hub/src/utils/checkCredentials.ts b/packages/hub/src/utils/checkCredentials.ts index 3180a0c16..0e1717054 100644 --- a/packages/hub/src/utils/checkCredentials.ts +++ b/packages/hub/src/utils/checkCredentials.ts @@ -1,11 +1,18 @@ -import type { Credentials } from "../types/public"; +import type { CredentialsParams } from "../types/public"; -export function checkCredentials(credentials?: Credentials): void { - if (!credentials || credentials.accessToken === undefined || credentials.accessToken === null) { - return; +export function checkAccessToken(accessToken: string): void { + if (!accessToken.startsWith("hf_")) { + throw new TypeError("Your access token must start with 'hf_'"); } +} - if (!credentials.accessToken.startsWith("hf_")) { - throw new TypeError("Your access token must start with 'hf_'"); +export function checkCredentials(params: Partial): string | undefined { + if (params.accessToken) { + checkAccessToken(params.accessToken); + return params.accessToken; + } + if (params.credentials?.accessToken) { + checkAccessToken(params.credentials.accessToken); + return params.credentials.accessToken; } }