@gradio/client 2.5.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -281,11 +281,11 @@ export interface ClientOptions {
281
281
  */
282
282
  oauth_token?: string;
283
283
  /**
284
- * Whether to save each call's inputs and outputs in this browser's local
285
- * storage, so they can be reviewed on the app's run history page. Defaults
286
- * to true, and only ever applies in a browser: in Node there is no storage
287
- * to write to and nothing is recorded. The app can turn it off for everyone
288
- * with `run_history=False` on `launch()`, which takes precedence over this.
284
+ * Whether to save each call's inputs and outputs to the history destination
285
+ * selected in this browser (local storage by default, or a connected bucket).
286
+ * Defaults to true, and only ever applies in a browser: in Node there is no
287
+ * selected destination and nothing is recorded. The app can turn it off for
288
+ * everyone with `run_history=False` on `launch()`, which takes precedence.
289
289
  */
290
290
  record_history?: boolean;
291
291
  }
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,wBAAsB,MAAM,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAsCrC;AAED,wBAAsB,aAAa,CAClC,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,CAAC,EAAE,OAAO,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAYrB;AAED,qBAAa,QAAQ;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,IAAI;;MAAgC;gBAEjC,EACX,IAAI,EACJ,GAAG,EACH,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,SAAS,EACT,QAAQ,EACR,GAAG,EACH,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,IAAI,CAAC;QACZ,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;KACb;CAWD"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,wBAAsB,MAAM,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CA0CrC;AAED,wBAAsB,aAAa,CAClC,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,CAAC,EAAE,OAAO,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAYrB;AAED,qBAAa,QAAQ;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,IAAI;;MAAgC;gBAEjC,EACX,IAAI,EACJ,GAAG,EACH,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,SAAS,EACT,QAAQ,EACR,GAAG,EACH,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,IAAI,CAAC;QACZ,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;KACb;CAWD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Client for the durable run history in an HF Hub bucket
3
+ * (`/gradio_api/run-history/*`).
4
+ *
5
+ * Read-only by design. Records are written by the server from the run it
6
+ * actually executed — there is no push function here, and nothing in this
7
+ * module can create a record.
8
+ *
9
+ * Every call names the bucket it is talking about. The server holds no
10
+ * per-session binding, so two tabs (or two apps on one origin) cannot end up
11
+ * reading each other's history.
12
+ */
13
+ export declare function is_valid_bucket_id(id: string): boolean;
14
+ /** Mirrors `HistoryRecord` in `gradio/history.py`. */
15
+ export interface HistoryRecord {
16
+ record_id: string;
17
+ endpoint: string;
18
+ inputs: unknown;
19
+ outputs: unknown;
20
+ started_at: string;
21
+ schema_version: number;
22
+ }
23
+ export interface HistoryResult<T> {
24
+ ok: boolean;
25
+ status: number;
26
+ data: T;
27
+ detail?: string;
28
+ }
29
+ /**
30
+ * Create the bucket if it does not exist and confirm it is writable. Stores
31
+ * nothing server-side — the caller keeps its own choice and names it on every
32
+ * later request.
33
+ */
34
+ export declare function connect_bucket(root: string, bucket_id: string): Promise<HistoryResult<null>>;
35
+ export declare function list_user_buckets(root: string): Promise<HistoryResult<string[]>>;
36
+ export declare function list_bucket_records(root: string, bucket: string): Promise<HistoryResult<HistoryRecord[]>>;
37
+ export declare function asset_url(root: string, bucket: string, endpoint: string, record_id: string, filename: string): string;
38
+ //# sourceMappingURL=bucket_sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bucket_sync.d.ts","sourceRoot":"","sources":["../../src/utils/bucket_sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAKtD;AAED,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAuDD;;;;GAIG;AACH,wBAAsB,cAAc,CACnC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAmB9B;AAED,wBAAsB,iBAAiB,CACtC,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAIlC;AAED,wBAAsB,mBAAmB,CACxC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,aAAa,CAAC,aAAa,EAAE,CAAC,CAAC,CAIzC;AAED,wBAAgB,SAAS,CACxB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACd,MAAM,CAQR"}
@@ -9,6 +9,13 @@ export interface RunHistoryScope {
9
9
  /** The authenticated user, when the app uses `auth`. */
10
10
  username?: string | null;
11
11
  }
12
+ export type RunHistoryStorage = {
13
+ type: "browser";
14
+ bucket_id?: string;
15
+ } | {
16
+ type: "bucket";
17
+ bucket_id: string;
18
+ };
12
19
  export type RunStatus = "running" | "completed" | "failed";
13
20
  export interface StoredRunComponent {
14
21
  type: string;
@@ -70,6 +77,8 @@ export interface ReplayTarget {
70
77
  }[];
71
78
  }
72
79
  export declare function read_run_history(scope: RunHistoryScope | null | undefined): StoredRun[];
80
+ export declare function read_run_history_storage(scope: RunHistoryScope | null | undefined): RunHistoryStorage;
81
+ export declare function set_run_history_storage(scope: RunHistoryScope | null | undefined, storage: RunHistoryStorage): void;
73
82
  export declare function clear_run_history(scope: RunHistoryScope | null | undefined): void;
74
83
  export declare function delete_run_history(scope: RunHistoryScope | null | undefined, id: string): void;
75
84
  export declare function stage_run_history_replay(scope: RunHistoryScope | null | undefined, run: StoredRun): void;
@@ -1 +1 @@
1
- {"version":3,"file":"run_history.d.ts","sourceRoot":"","sources":["../../src/utils/run_history.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run_history.d.ts","sourceRoot":"","sources":["../../src/utils/run_history.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/utils/submit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,WAAW,EAMX,cAAc,EACd,MAAM,UAAU,CAAC;AAoBlB,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAOnC,wBAAgB,MAAM,CACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,GAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAC9C,UAAU,CAAC,EAAE,OAAO,EACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,CAAC,EAAE,OAAO,EACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,cAAc,CAAC,WAAW,CAAC,CA8uB7B"}
1
+ {"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/utils/submit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,WAAW,EAMX,cAAc,EACd,MAAM,UAAU,CAAC;AAoBlB,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAQnC,wBAAgB,MAAM,CACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,GAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAC9C,UAAU,CAAC,EAAE,OAAO,EACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,CAAC,EAAE,OAAO,EACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,cAAc,CAAC,WAAW,CAAC,CAsvB7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/client",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "Gradio API client",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -83,10 +83,22 @@ export function map_names_to_ids(
83
83
 
84
84
  export function resolve_config_root(
85
85
  root: string,
86
- current_location: string
86
+ current_location: string,
87
+ prioritize_current_location = false
87
88
  ): string {
88
- const root_url = new URL(root, current_location);
89
89
  const current_url = new URL(current_location);
90
+ const root_url = new URL(root, current_url);
91
+ // Modern Colab configs can omit is_colab even though the backend root still
92
+ // uses one of Colab's internal-only hostname families.
93
+ const is_colab_runtime =
94
+ root_url.hostname.endsWith(".colab-user-runtimes.internal") ||
95
+ root_url.hostname.endsWith(".codatalab-user-runtimes.internal");
96
+ if (prioritize_current_location || is_colab_runtime) {
97
+ return new URL(new URL(root, current_url).pathname, current_url)
98
+ .toString()
99
+ .replace(/\/$/, "");
100
+ }
101
+
90
102
  if (root_url.hostname !== current_url.hostname) {
91
103
  return root;
92
104
  }
@@ -138,9 +150,14 @@ export async function resolve_config(
138
150
  // The page was rendered by this Gradio server, so a same-host root may
139
151
  // contain an internal protocol or port supplied by a reverse proxy. Keep
140
152
  // the configured path, but use the browser-visible origin for requests
141
- // made by the client itself (queue, upload, reset, etc.).
153
+ // made by the client itself (queue, upload, reset, etc.). Colab's public
154
+ // proxy uses a different hostname, so always prefer the browser origin.
142
155
  const config = { ...window.gradio_config } as unknown as Config;
143
- config.root = resolve_config_root(config.root, location.href);
156
+ config.root = resolve_config_root(
157
+ config.root,
158
+ location.href,
159
+ config.is_colab
160
+ );
144
161
  return config;
145
162
  } else if (endpoint) {
146
163
  let config_url = join_urls(
package/src/index.ts CHANGED
@@ -12,13 +12,25 @@ export {
12
12
  delete_run_history,
13
13
  on_run_history_change,
14
14
  read_run_history,
15
+ read_run_history_storage,
15
16
  run_history_url,
17
+ set_run_history_storage,
16
18
  stage_run_history_replay,
17
19
  type ReplayTarget,
20
+ type RunHistoryStorage,
18
21
  type RunHistoryScope,
19
22
  type StoredRunComponent,
20
23
  type StoredRun
21
24
  } from "./utils/run_history";
25
+ export {
26
+ asset_url,
27
+ connect_bucket,
28
+ is_valid_bucket_id,
29
+ list_bucket_records,
30
+ list_user_buckets,
31
+ type HistoryRecord,
32
+ type HistoryResult
33
+ } from "./utils/bucket_sync";
22
34
 
23
35
  export type {
24
36
  SpaceStatus,
@@ -0,0 +1,138 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import {
3
+ asset_url,
4
+ connect_bucket,
5
+ is_valid_bucket_id,
6
+ list_bucket_records,
7
+ list_user_buckets
8
+ } from "../utils/bucket_sync";
9
+
10
+ describe("is_valid_bucket_id", () => {
11
+ it("accepts user/name form", () => {
12
+ expect(is_valid_bucket_id("alice/my-history")).toBe(true);
13
+ });
14
+
15
+ it("rejects missing slash", () => {
16
+ expect(is_valid_bucket_id("alice")).toBe(false);
17
+ });
18
+
19
+ it("rejects path traversal", () => {
20
+ expect(is_valid_bucket_id("alice/..")).toBe(false);
21
+ expect(is_valid_bucket_id("../etc")).toBe(false);
22
+ expect(is_valid_bucket_id("alice/./x")).toBe(false);
23
+ });
24
+
25
+ it("rejects empty segments", () => {
26
+ expect(is_valid_bucket_id("alice/")).toBe(false);
27
+ expect(is_valid_bucket_id("/name")).toBe(false);
28
+ });
29
+ });
30
+
31
+ describe("list_bucket_records", () => {
32
+ const orig = globalThis.fetch;
33
+ afterEach(() => {
34
+ globalThis.fetch = orig;
35
+ });
36
+
37
+ it("reports a failed request instead of an empty history", async () => {
38
+ globalThis.fetch = vi.fn().mockResolvedValue({
39
+ ok: false,
40
+ status: 401,
41
+ json: async () => ({ detail: "oauth session required" })
42
+ }) as any;
43
+ const res = await list_bucket_records("http://x", "alice/h");
44
+ expect(res.ok).toBe(false);
45
+ expect(res.status).toBe(401);
46
+ expect(res.data).toEqual([]);
47
+ });
48
+
49
+ it("returns records on success", async () => {
50
+ globalThis.fetch = vi.fn().mockResolvedValue({
51
+ ok: true,
52
+ status: 200,
53
+ json: async () => ({ records: [{ record_id: "r1" }] })
54
+ }) as any;
55
+ const res = await list_bucket_records("http://x", "alice/h");
56
+ expect(res.ok).toBe(true);
57
+ expect(res.data).toHaveLength(1);
58
+ });
59
+
60
+ it("names the bucket on every request rather than relying on session state", async () => {
61
+ const spy = vi.fn().mockResolvedValue({
62
+ ok: true,
63
+ status: 200,
64
+ json: async () => ({ records: [] })
65
+ });
66
+ globalThis.fetch = spy as any;
67
+ await list_bucket_records("http://x", "alice/my-history");
68
+ const called = String(spy.mock.calls[0][0]);
69
+ expect(called).toContain("bucket=alice%2Fmy-history");
70
+ expect(called).not.toContain("endpoint=");
71
+ expect(called).not.toContain("limit=");
72
+ });
73
+
74
+ it("does not emit a root-absolute URL when root is empty", async () => {
75
+ const spy = vi.fn().mockResolvedValue({
76
+ ok: true,
77
+ status: 200,
78
+ json: async () => ({ records: [] })
79
+ });
80
+ globalThis.fetch = spy as any;
81
+ await list_bucket_records("", "alice/h");
82
+ const called = String(spy.mock.calls[0][0]);
83
+ // must resolve against the document base, not "/gradio_api/..."
84
+ expect(called.startsWith("/gradio_api/")).toBe(false);
85
+ expect(called).toContain("gradio_api/run-history/records");
86
+ });
87
+ });
88
+
89
+ describe("bucket setup", () => {
90
+ const orig = globalThis.fetch;
91
+ afterEach(() => {
92
+ globalThis.fetch = orig;
93
+ });
94
+
95
+ it("ignores the connect response body", async () => {
96
+ globalThis.fetch = vi.fn().mockResolvedValue({
97
+ ok: true,
98
+ status: 200,
99
+ json: async () => ({ ok: true })
100
+ }) as any;
101
+ const result = await connect_bucket("http://x", "alice/history");
102
+ expect(result).toMatchObject({ ok: true, data: null });
103
+ });
104
+
105
+ it("returns bucket ids as strings", async () => {
106
+ globalThis.fetch = vi.fn().mockResolvedValue({
107
+ ok: true,
108
+ status: 200,
109
+ json: async () => ({ buckets: ["alice/one", "alice/two"] })
110
+ }) as any;
111
+ expect(await list_user_buckets("http://x")).toMatchObject({
112
+ ok: true,
113
+ data: ["alice/one", "alice/two"]
114
+ });
115
+ });
116
+
117
+ it("preserves authentication errors for the connect UI", async () => {
118
+ globalThis.fetch = vi.fn().mockResolvedValue({
119
+ ok: false,
120
+ status: 401,
121
+ json: async () => ({ detail: "oauth session required" })
122
+ }) as any;
123
+ expect(await list_user_buckets("http://x")).toMatchObject({
124
+ ok: false,
125
+ status: 401,
126
+ data: [],
127
+ detail: "oauth session required"
128
+ });
129
+ });
130
+ });
131
+
132
+ describe("asset_url", () => {
133
+ it("addresses an asset by bucket, endpoint and record", () => {
134
+ const url = asset_url("http://x", "alice/h", "predict", "r1", "a001.png");
135
+ expect(url).toContain("/run-history/records/predict/r1/assets/a001.png");
136
+ expect(url).toContain("bucket=alice%2Fh");
137
+ });
138
+ });
@@ -7,7 +7,9 @@ import {
7
7
  delete_run_history,
8
8
  on_run_history_change,
9
9
  read_run_history,
10
+ read_run_history_storage,
10
11
  run_history_url,
12
+ set_run_history_storage,
11
13
  stage_run_history_replay,
12
14
  start_run_history,
13
15
  update_run_history,
@@ -25,6 +27,8 @@ const replacement_apps = Array.from(
25
27
  const in_browser = typeof window !== "undefined";
26
28
 
27
29
  afterEach(() => {
30
+ set_run_history_storage(scope, { type: "browser" });
31
+ set_run_history_storage(other_scope, { type: "browser" });
28
32
  clear_run_history(scope);
29
33
  clear_run_history(other_scope);
30
34
  for (const replacement_app of replacement_apps) {
@@ -34,6 +38,48 @@ afterEach(() => {
34
38
  });
35
39
 
36
40
  describe.skipIf(!in_browser)("run history", () => {
41
+ test("uses this browser as the default history storage", () => {
42
+ expect(read_run_history_storage(scope)).toEqual({ type: "browser" });
43
+ });
44
+
45
+ test("remembers a bucket while switching storage destinations", () => {
46
+ set_run_history_storage(scope, {
47
+ type: "bucket",
48
+ bucket_id: "alice/app-history"
49
+ });
50
+ expect(read_run_history_storage(scope)).toEqual({
51
+ type: "bucket",
52
+ bucket_id: "alice/app-history"
53
+ });
54
+
55
+ set_run_history_storage(scope, {
56
+ type: "browser",
57
+ bucket_id: "alice/app-history"
58
+ });
59
+ expect(read_run_history_storage(scope)).toEqual({
60
+ type: "browser",
61
+ bucket_id: "alice/app-history"
62
+ });
63
+ });
64
+
65
+ test("does not duplicate bucket runs in local storage", () => {
66
+ set_run_history_storage(scope, {
67
+ type: "bucket",
68
+ bucket_id: "alice/app-history"
69
+ });
70
+
71
+ const id = start_run_history({
72
+ app_id,
73
+ endpoint: "/predict",
74
+ api_name: "/predict",
75
+ fn_index: 0,
76
+ inputs: ["hello"]
77
+ });
78
+
79
+ expect(id).toBeNull();
80
+ expect(read_run_history(scope)).toEqual([]);
81
+ });
82
+
37
83
  test("stores runs per app id with the page and inputs", () => {
38
84
  const id = start_run_history({
39
85
  app_id,
@@ -1,6 +1,9 @@
1
1
  import { describe, beforeAll, afterEach, afterAll, test, expect } from "vitest";
2
+ import { HttpResponse, http } from "msw";
2
3
 
3
4
  import { Client } from "../client";
5
+ import { set_run_history_storage } from "../utils/run_history";
6
+ import { direct_space_url } from "./handlers";
4
7
  import { initialise_server } from "./server";
5
8
 
6
9
  let server: Awaited<ReturnType<typeof initialise_server>>;
@@ -9,7 +12,12 @@ beforeAll(async () => {
9
12
  server = await initialise_server();
10
13
  await server.start({ quiet: true });
11
14
  });
12
- afterEach(() => server.resetHandlers());
15
+ afterEach(() => {
16
+ server.resetHandlers();
17
+ if (typeof window !== "undefined") {
18
+ set_run_history_storage({ app_id: 123 }, { type: "browser" });
19
+ }
20
+ });
13
21
  afterAll(() => server.stop());
14
22
 
15
23
  async function race_with_timeout<T>(
@@ -29,6 +37,35 @@ async function race_with_timeout<T>(
29
37
  }
30
38
 
31
39
  describe("submit iterator", () => {
40
+ test.skipIf(typeof window === "undefined")(
41
+ "sends the selected history bucket with queued submissions",
42
+ async () => {
43
+ const app = await Client.connect("hmb/hello_world");
44
+ const scope = {
45
+ app_id: app.config?.app_id,
46
+ username: app.config?.username
47
+ };
48
+ set_run_history_storage(scope, {
49
+ type: "bucket",
50
+ bucket_id: "alice/app-history"
51
+ });
52
+
53
+ let header: string | null = null;
54
+ server.resetHandlers(
55
+ http.post(`${direct_space_url}/queue/join`, ({ request }) => {
56
+ header = request.headers.get("x-gradio-history-bucket");
57
+ return HttpResponse.json({ event_id: "bucket-event" });
58
+ })
59
+ );
60
+
61
+ const iterator = app.submit("/predict", ["hi"]);
62
+ await expect(iterator.wait_for_id()).resolves.toBe("bucket-event");
63
+ expect(header).toBe("alice/app-history");
64
+ await iterator.return();
65
+ set_run_history_storage(scope, { type: "browser" });
66
+ }
67
+ );
68
+
32
69
  test("next() after the iterator is closed resolves to {done: true}", async () => {
33
70
  const app = await Client.connect("hmb/hello_world");
34
71
  // Avoid opening a real SSE stream — the test does not need one.
@@ -0,0 +1,25 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+
3
+ import type { Client } from "../client";
4
+ import { FileData, upload } from "../upload";
5
+
6
+ describe("upload", () => {
7
+ it("encodes uploaded file paths in file URLs", async () => {
8
+ const path = "/tmp/computer%20vision#Huggy.png";
9
+ const client = {
10
+ api_prefix: "/gradio_api",
11
+ upload_files: vi.fn().mockResolvedValue({ files: [path] })
12
+ } as unknown as Client;
13
+ const input = new FileData({
14
+ path,
15
+ blob: new File([], "computer%20vision#Huggy.png")
16
+ });
17
+
18
+ const result = await upload.call(client, [input], "https://example.com");
19
+
20
+ expect(result?.[0]).toMatchObject({
21
+ path,
22
+ url: "https://example.com/gradio_api/file=/tmp/computer%2520vision%23Huggy.png"
23
+ });
24
+ });
25
+ });
package/src/types.ts CHANGED
@@ -354,11 +354,11 @@ export interface ClientOptions {
354
354
  */
355
355
  oauth_token?: string;
356
356
  /**
357
- * Whether to save each call's inputs and outputs in this browser's local
358
- * storage, so they can be reviewed on the app's run history page. Defaults
359
- * to true, and only ever applies in a browser: in Node there is no storage
360
- * to write to and nothing is recorded. The app can turn it off for everyone
361
- * with `run_history=False` on `launch()`, which takes precedence over this.
357
+ * Whether to save each call's inputs and outputs to the history destination
358
+ * selected in this browser (local storage by default, or a connected bucket).
359
+ * Defaults to true, and only ever applies in a browser: in Node there is no
360
+ * selected destination and nothing is recorded. The app can turn it off for
361
+ * everyone with `run_history=False` on `launch()`, which takes precedence.
362
362
  */
363
363
  record_history?: boolean;
364
364
  }
package/src/upload.ts CHANGED
@@ -30,10 +30,14 @@ export async function upload(
30
30
  } else {
31
31
  if (response.files) {
32
32
  return response.files.map((f, i) => {
33
+ const encoded_path = f
34
+ .split("/")
35
+ .map((segment) => encodeURIComponent(segment))
36
+ .join("/");
33
37
  const file = new FileData({
34
38
  ...file_data[i],
35
39
  path: f,
36
- url: `${root_url}${this.api_prefix}/file=${f}`
40
+ url: `${root_url}${this.api_prefix}/file=${encoded_path}`
37
41
  });
38
42
  return file;
39
43
  });
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Client for the durable run history in an HF Hub bucket
3
+ * (`/gradio_api/run-history/*`).
4
+ *
5
+ * Read-only by design. Records are written by the server from the run it
6
+ * actually executed — there is no push function here, and nothing in this
7
+ * module can create a record.
8
+ *
9
+ * Every call names the bucket it is talking about. The server holds no
10
+ * per-session binding, so two tabs (or two apps on one origin) cannot end up
11
+ * reading each other's history.
12
+ */
13
+
14
+ const BUCKET_ID_RE = /^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-][a-zA-Z0-9_./-]*$/;
15
+
16
+ export function is_valid_bucket_id(id: string): boolean {
17
+ if (!BUCKET_ID_RE.test(id)) return false;
18
+ return !id
19
+ .split("/")
20
+ .some((seg) => seg === "" || seg === "." || seg === "..");
21
+ }
22
+
23
+ /** Mirrors `HistoryRecord` in `gradio/history.py`. */
24
+ export interface HistoryRecord {
25
+ record_id: string;
26
+ endpoint: string;
27
+ inputs: unknown;
28
+ outputs: unknown;
29
+ started_at: string;
30
+ schema_version: number;
31
+ }
32
+
33
+ export interface HistoryResult<T> {
34
+ ok: boolean;
35
+ status: number;
36
+ data: T;
37
+ detail?: string;
38
+ }
39
+
40
+ function url(
41
+ root: string,
42
+ path: string,
43
+ params?: Record<string, string>
44
+ ): string {
45
+ const query = params ? `?${new URLSearchParams(params)}` : "";
46
+ const base = root.replace(/\/+$/, "");
47
+ if (base) return `${base}/gradio_api/run-history/${path}${query}`;
48
+ // No configured root. A leading slash would drop any mount subpath
49
+ // (`mount_gradio_app(app, path="/myapp")`), so resolve against the document
50
+ // base, which gradio sets via <base href> on the app shell.
51
+ if (typeof document !== "undefined" && document.baseURI) {
52
+ return new URL(
53
+ `gradio_api/run-history/${path}${query}`,
54
+ document.baseURI
55
+ ).toString();
56
+ }
57
+ return `gradio_api/run-history/${path}${query}`;
58
+ }
59
+
60
+ async function parse_error(res: Response): Promise<string> {
61
+ try {
62
+ const j = await res.json();
63
+ return typeof j?.detail === "string" ? j.detail : `${res.status}`;
64
+ } catch {
65
+ return `${res.status}`;
66
+ }
67
+ }
68
+
69
+ async function request<T>(
70
+ input: string,
71
+ init: RequestInit,
72
+ fallback: T,
73
+ pick: (body: any) => T
74
+ ): Promise<HistoryResult<T>> {
75
+ try {
76
+ const res = await fetch(input, { credentials: "include", ...init });
77
+ if (!res.ok) {
78
+ // An empty list and a failed request are different things: a 401 here
79
+ // means "sign in", not "no runs yet".
80
+ return {
81
+ ok: false,
82
+ status: res.status,
83
+ data: fallback,
84
+ detail: await parse_error(res)
85
+ };
86
+ }
87
+ return { ok: true, status: res.status, data: pick(await res.json()) };
88
+ } catch (e) {
89
+ return { ok: false, status: 0, data: fallback, detail: String(e) };
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Create the bucket if it does not exist and confirm it is writable. Stores
95
+ * nothing server-side — the caller keeps its own choice and names it on every
96
+ * later request.
97
+ */
98
+ export async function connect_bucket(
99
+ root: string,
100
+ bucket_id: string
101
+ ): Promise<HistoryResult<null>> {
102
+ if (!is_valid_bucket_id(bucket_id)) {
103
+ return {
104
+ ok: false,
105
+ status: 422,
106
+ data: null,
107
+ detail: "invalid bucket id"
108
+ };
109
+ }
110
+ return request(
111
+ url(root, "connect"),
112
+ {
113
+ method: "POST",
114
+ headers: { "Content-Type": "application/json" },
115
+ body: JSON.stringify({ bucket_id })
116
+ },
117
+ null,
118
+ () => null
119
+ );
120
+ }
121
+
122
+ export async function list_user_buckets(
123
+ root: string
124
+ ): Promise<HistoryResult<string[]>> {
125
+ return request<string[]>(url(root, "buckets"), {}, [], (b) =>
126
+ Array.isArray(b?.buckets) ? b.buckets : []
127
+ );
128
+ }
129
+
130
+ export async function list_bucket_records(
131
+ root: string,
132
+ bucket: string
133
+ ): Promise<HistoryResult<HistoryRecord[]>> {
134
+ return request(url(root, "records", { bucket }), {}, [], (b) =>
135
+ Array.isArray(b?.records) ? b.records : []
136
+ );
137
+ }
138
+
139
+ export function asset_url(
140
+ root: string,
141
+ bucket: string,
142
+ endpoint: string,
143
+ record_id: string,
144
+ filename: string
145
+ ): string {
146
+ return url(
147
+ root,
148
+ `records/${encodeURIComponent(endpoint)}/${encodeURIComponent(
149
+ record_id
150
+ )}/assets/${encodeURIComponent(filename)}`,
151
+ { bucket }
152
+ );
153
+ }