Skip to content

Commit 186ab73

Browse files
authored
checkRepoAccess added (#947)
More helpers for #945 Introduces `checkRepoAccess` to check if user has read access to repo
1 parent 3f99361 commit 186ab73

File tree

7 files changed

+82
-26
lines changed

7 files changed

+82
-26
lines changed

packages/hub/README.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,23 @@ For some of the calls, you need to create an account and generate an [access tok
3030
Learn how to find free models using the hub package in this [interactive tutorial](https://scrimba.com/scrim/c7BbVPcd?pl=pkVnrP7uP).
3131

3232
```ts
33-
import { createRepo, uploadFiles, uploadFilesWithProgress, deleteFile, deleteRepo, listFiles, whoAmI, modelInfo, listModels } from "@huggingface/hub";
33+
import * as hub from "@huggingface/hub";
3434
import type { RepoDesignation } from "@huggingface/hub";
3535

3636
const repo: RepoDesignation = { type: "model", name: "myname/some-model" };
3737

38-
const {name: username} = await whoAmI({accessToken: "hf_..."});
38+
const {name: username} = await hub.whoAmI({accessToken: "hf_..."});
3939

40-
for await (const model of listModels({search: {owner: username}, accessToken: "hf_..."})) {
40+
for await (const model of hub.listModels({search: {owner: username}, accessToken: "hf_..."})) {
4141
console.log("My model:", model);
4242
}
4343

44-
const specificModel = await modelInfo({name: "openai-community/gpt2"});
44+
const specificModel = await hub.modelInfo({name: "openai-community/gpt2"});
45+
await hub.checkRepoAccess({repo, accessToken: "hf_..."});
4546

46-
await createRepo({ repo, accessToken: "hf_...", license: "mit" });
47+
await hub.createRepo({ repo, accessToken: "hf_...", license: "mit" });
4748

48-
await uploadFiles({
49+
await hub.uploadFiles({
4950
repo,
5051
accessToken: "hf_...",
5152
files: [
@@ -69,7 +70,7 @@ await uploadFiles({
6970

7071
// or
7172

72-
for await (const progressEvent of await uploadFilesWithProgress({
73+
for await (const progressEvent of await hub.uploadFilesWithProgress({
7374
repo,
7475
accessToken: "hf_...",
7576
files: [
@@ -79,15 +80,15 @@ for await (const progressEvent of await uploadFilesWithProgress({
7980
console.log(progressEvent);
8081
}
8182

82-
await deleteFile({repo, accessToken: "hf_...", path: "myfile.bin"});
83+
await hub.deleteFile({repo, accessToken: "hf_...", path: "myfile.bin"});
8384

84-
await (await downloadFile({ repo, path: "README.md" })).text();
85+
await (await hub.downloadFile({ repo, path: "README.md" })).text();
8586

86-
for await (const fileInfo of listFiles({repo})) {
87+
for await (const fileInfo of hub.listFiles({repo})) {
8788
console.log(fileInfo);
8889
}
8990

90-
await deleteRepo({ repo, accessToken: "hf_..." });
91+
await hub.deleteRepo({ repo, accessToken: "hf_..." });
9192
```
9293

9394
## OAuth Login
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { assert, describe, expect, it } from "vitest";
2+
import { checkRepoAccess } from "./check-repo-access";
3+
import { HubApiError } from "../error";
4+
import { TEST_ACCESS_TOKEN, TEST_HUB_URL } from "../test/consts";
5+
6+
describe("checkRepoAccess", () => {
7+
it("should throw 401 when accessing unexisting repo unauthenticated", async () => {
8+
try {
9+
await checkRepoAccess({ repo: { name: "i--d/dont", type: "model" } });
10+
assert(false, "should have thrown");
11+
} catch (err) {
12+
expect(err).toBeInstanceOf(HubApiError);
13+
expect((err as HubApiError).statusCode).toBe(401);
14+
}
15+
});
16+
17+
it("should throw 404 when accessing unexisting repo authenticated", async () => {
18+
try {
19+
await checkRepoAccess({
20+
repo: { name: "i--d/dont", type: "model" },
21+
hubUrl: TEST_HUB_URL,
22+
accessToken: TEST_ACCESS_TOKEN,
23+
});
24+
assert(false, "should have thrown");
25+
} catch (err) {
26+
expect(err).toBeInstanceOf(HubApiError);
27+
expect((err as HubApiError).statusCode).toBe(404);
28+
}
29+
});
30+
31+
it("should not throw when accessing public repo", async () => {
32+
await checkRepoAccess({ repo: { name: "openai-community/gpt2", type: "model" } });
33+
});
34+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { HUB_URL } from "../consts";
2+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
3+
import { createApiError, type HubApiError } from "../error";
4+
import type { CredentialsParams, RepoDesignation } from "../types/public";
5+
import { checkCredentials } from "../utils/checkCredentials";
6+
import { toRepoId } from "../utils/toRepoId";
7+
8+
/**
9+
* Check if we have read access to a repository.
10+
*
11+
* Throw a {@link HubApiError} error if we don't have access. HubApiError.statusCode will be 401, 403 or 404.
12+
*/
13+
export async function checkRepoAccess(
14+
params: {
15+
repo: RepoDesignation;
16+
hubUrl?: string;
17+
fetch?: typeof fetch;
18+
} & Partial<CredentialsParams>
19+
): Promise<void> {
20+
const accessToken = params && checkCredentials(params);
21+
const repoId = toRepoId(params.repo);
22+
23+
const response = await (params.fetch || fetch)(`${params?.hubUrl || HUB_URL}/api/${repoId.type}s/${repoId.name}`, {
24+
headers: {
25+
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
26+
},
27+
});
28+
29+
if (!response.ok) {
30+
throw await createApiError(response);
31+
}
32+
}

packages/hub/src/lib/dataset-info.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ export async function datasetInfo<
1313
name: string;
1414
hubUrl?: string;
1515
additionalFields?: T[];
16-
/**
17-
* Set to limit the number of models returned.
18-
*/
19-
limit?: number;
2016
/**
2117
* Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
2218
*/
@@ -41,7 +37,7 @@ export async function datasetInfo<
4137
);
4238

4339
if (!response.ok) {
44-
createApiError(response);
40+
throw await createApiError(response);
4541
}
4642

4743
const data = await response.json();

packages/hub/src/lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from "./cache-management";
2+
export * from "./check-repo-access";
23
export * from "./commit";
34
export * from "./count-commits";
45
export * from "./create-repo";

packages/hub/src/lib/model-info.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ export async function modelInfo<
1313
name: string;
1414
hubUrl?: string;
1515
additionalFields?: T[];
16-
/**
17-
* Set to limit the number of models returned.
18-
*/
19-
limit?: number;
2016
/**
2117
* Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
2218
*/
@@ -41,7 +37,7 @@ export async function modelInfo<
4137
);
4238

4339
if (!response.ok) {
44-
createApiError(response);
40+
throw await createApiError(response);
4541
}
4642

4743
const data = await response.json();

packages/hub/src/lib/space-info.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ export async function spaceInfo<
1414
name: string;
1515
hubUrl?: string;
1616
additionalFields?: T[];
17-
/**
18-
* Set to limit the number of models returned.
19-
*/
20-
limit?: number;
2117
/**
2218
* Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
2319
*/
@@ -42,7 +38,7 @@ export async function spaceInfo<
4238
);
4339

4440
if (!response.ok) {
45-
createApiError(response);
41+
throw await createApiError(response);
4642
}
4743

4844
const data = await response.json();

0 commit comments

Comments
 (0)