@gradio/client 2.3.1 → 2.5.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +4 -2
  3. package/dist/__vite-browser-external-Cgmn0awE.js +7 -0
  4. package/dist/browser.js +1949 -1963
  5. package/dist/client.d.ts +5 -0
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/constants.d.ts +4 -0
  8. package/dist/constants.d.ts.map +1 -1
  9. package/dist/helpers/api_info.d.ts.map +1 -1
  10. package/dist/helpers/data.d.ts.map +1 -1
  11. package/dist/helpers/init_helpers.d.ts +11 -2
  12. package/dist/helpers/init_helpers.d.ts.map +1 -1
  13. package/dist/index.cjs +2584 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2471 -2466
  17. package/dist/index.min.js +1962 -0
  18. package/dist/types.d.ts +29 -0
  19. package/dist/types.d.ts.map +1 -1
  20. package/dist/utils/duplicate.d.ts.map +1 -1
  21. package/dist/utils/predict.d.ts.map +1 -1
  22. package/dist/utils/run_history.d.ts +64 -0
  23. package/dist/utils/run_history.d.ts.map +1 -0
  24. package/dist/utils/stream.d.ts.map +1 -1
  25. package/dist/utils/submit.d.ts.map +1 -1
  26. package/package.json +11 -4
  27. package/scripts/verify_dist.mjs +46 -0
  28. package/src/client.ts +54 -5
  29. package/src/constants.ts +10 -0
  30. package/src/helpers/api_info.ts +46 -19
  31. package/src/helpers/data.ts +8 -3
  32. package/src/helpers/init_helpers.ts +54 -7
  33. package/src/index.ts +12 -0
  34. package/src/test/api_info.test.ts +77 -12
  35. package/src/test/data.test.ts +26 -3
  36. package/src/test/init.test.ts +21 -3
  37. package/src/test/init_helpers.test.ts +67 -1
  38. package/src/test/refresh.test.ts +31 -0
  39. package/src/test/run_history.test.ts +345 -0
  40. package/src/test/submit.test.ts +1 -3
  41. package/src/types.ts +29 -0
  42. package/src/utils/duplicate.ts +2 -0
  43. package/src/utils/predict.ts +14 -1
  44. package/src/utils/run_history.ts +520 -0
  45. package/src/utils/stream.ts +17 -4
  46. package/src/utils/submit.ts +105 -12
  47. package/vite.config.ts +20 -4
  48. package/dist/__vite-browser-external-DYxpcVy9.js +0 -4
@@ -19,14 +19,21 @@ import {
19
19
  } from "../helpers/api_info";
20
20
  import {
21
21
  BROKEN_CONNECTION_MSG,
22
+ NO_API_INFO_MSG,
22
23
  QUEUE_FULL_MSG,
23
24
  SSE_URL,
24
25
  SSE_DATA_URL,
25
26
  RESET_URL,
26
- CANCEL_URL
27
+ CANCEL_URL,
28
+ WS_PROTOCOL_MSG
27
29
  } from "../constants";
28
30
  import { apply_diff_stream, close_stream } from "./stream";
29
31
  import { Client } from "../client";
32
+ import {
33
+ start_run_history,
34
+ update_run_history,
35
+ update_run_inputs
36
+ } from "./run_history";
30
37
 
31
38
  export function submit(
32
39
  this: Client,
@@ -60,7 +67,7 @@ export function submit(
60
67
 
61
68
  const that = this;
62
69
 
63
- if (!api_info) throw new Error("No API found");
70
+ if (!api_info) throw new Error(NO_API_INFO_MSG);
64
71
  if (!config) throw new Error("Could not resolve app config");
65
72
 
66
73
  let { fn_index, endpoint_info, dependency } = get_endpoint_info(
@@ -71,12 +78,65 @@ export function submit(
71
78
  );
72
79
 
73
80
  let resolved_data = map_data_to_params(data, endpoint_info);
74
-
75
- let stream: EventSource | null;
76
81
  let protocol = config.protocol ?? "ws";
77
82
  if (protocol === "ws") {
78
- throw new Error("WebSocket protocol is not supported in this version");
83
+ throw new Error(WS_PROTOCOL_MSG);
79
84
  }
85
+ const history_endpoint =
86
+ typeof dependency.api_name === "string"
87
+ ? `/${dependency.api_name}`
88
+ : endpoint;
89
+ const history_api_name =
90
+ typeof dependency.api_name === "string"
91
+ ? `/${dependency.api_name}`
92
+ : `Function ${fn_index}`;
93
+ // Kept index-aligned with the stored payloads (null for components we
94
+ // cannot resolve) so every saved value stays matched to its component.
95
+ const component_metadata = (id: number) => {
96
+ const component = config.components.find((item) => item.id === id);
97
+ if (!component) return null;
98
+ return {
99
+ type: component.type,
100
+ component_class_id: component.component_class_id,
101
+ props: component.props
102
+ };
103
+ };
104
+ // The run history covers the same endpoints the API page documents, which
105
+ // it selects with exactly this predicate (see `ApiDocs.svelte`). That also
106
+ // keeps out the dependencies Gradio wires up for itself, since example
107
+ // loading, flagging and clear buttons are all "undocumented" or "private"
108
+ // and some of them fire on page load. The trade is that a component whose
109
+ // UI submits through an undocumented dependency — `gr.ChatInterface` does
110
+ // — records nothing for its in-app use.
111
+ const is_documented_endpoint = dependency.api_visibility === "public";
112
+ // Either side may opt out: the app for everyone who uses it, and this
113
+ // caller for itself.
114
+ const history_enabled =
115
+ config.run_history !== false && this.options.record_history !== false;
116
+ const history_scope = { app_id: config.app_id, username: config.username };
117
+ const history_run_id =
118
+ !history_enabled || !is_documented_endpoint
119
+ ? null
120
+ : start_run_history({
121
+ ...history_scope,
122
+ endpoint: history_endpoint,
123
+ api_name: history_api_name,
124
+ fn_index,
125
+ // Aligned to `dependency.inputs` the same way the submitted payload
126
+ // is, so this placeholder matches the components until the uploaded
127
+ // files are swapped in by `update_run_inputs` below.
128
+ inputs: handle_payload(
129
+ resolved_data,
130
+ dependency,
131
+ config.components,
132
+ "input",
133
+ true
134
+ ),
135
+ input_components: dependency.inputs.map(component_metadata),
136
+ output_components: dependency.outputs.map(component_metadata)
137
+ });
138
+
139
+ let stream: EventSource | null;
80
140
  let event_id_final = "";
81
141
  let event_id_cb: () => string = () => event_id_final;
82
142
 
@@ -101,6 +161,7 @@ export function submit(
101
161
 
102
162
  // event subscription methods
103
163
  function fire_event(event: GradioEvent): void {
164
+ update_run_history(history_scope, history_run_id, event);
104
165
  if (all_events || events_to_publish[event.type]) {
105
166
  push_event(event);
106
167
  }
@@ -178,11 +239,15 @@ export function submit(
178
239
  "input",
179
240
  true
180
241
  );
242
+ update_run_inputs(history_scope, history_run_id, input_data || []);
181
243
  payload = {
182
244
  data: input_data || [],
183
245
  event_data,
184
246
  fn_index,
185
- trigger_id
247
+ trigger_id,
248
+ ...(options.oauth_token && endpoint_info?.oauth_token
249
+ ? { oauth_token: options.oauth_token }
250
+ : {})
186
251
  };
187
252
  if (skip_queue(fn_index, config)) {
188
253
  fire_event({
@@ -630,6 +695,22 @@ export function submit(
630
695
  }
631
696
  });
632
697
 
698
+ // Surface internal failures (e.g. malformed payloads or configs) as an
699
+ // error event instead of leaving the returned iterator hanging forever
700
+ // with an unhandled promise rejection.
701
+ job.catch((e) => {
702
+ fire_event({
703
+ type: "status",
704
+ stage: "error",
705
+ message: e instanceof Error ? e.message : String(e),
706
+ queue: !skip_queue(fn_index, config),
707
+ endpoint: _endpoint,
708
+ fn_index,
709
+ time: new Date()
710
+ });
711
+ close();
712
+ });
713
+
633
714
  let done = false;
634
715
  const values: (IteratorResult<GradioEvent> | PromiseLike<never>)[] = [];
635
716
  const resolvers: ((
@@ -735,25 +816,37 @@ function get_endpoint_info(
735
816
  } {
736
817
  let fn_index: number;
737
818
  let endpoint_info: EndpointInfo<JsApiData>;
738
- let dependency: Dependency;
819
+ let dependency: Dependency | undefined;
739
820
 
740
821
  if (typeof endpoint === "number") {
741
822
  fn_index = endpoint;
742
823
  endpoint_info = api_info.unnamed_endpoints[fn_index];
743
- dependency = config.dependencies.find((dep) => dep.id == endpoint)!;
824
+ dependency = config.dependencies.find((dep) => dep.id == endpoint);
744
825
  } else {
745
826
  const trimmed_endpoint = endpoint.replace(/^\//, "");
746
827
 
747
828
  fn_index = api_map[trimmed_endpoint];
748
- endpoint_info = api_info.named_endpoints[endpoint.trim()];
829
+ // named endpoints are keyed with a leading slash in the API info, but
830
+ // accept endpoint names passed without one (e.g. "predict")
831
+ endpoint_info =
832
+ api_info.named_endpoints[endpoint.trim()] ??
833
+ api_info.named_endpoints[`/${trimmed_endpoint}`];
749
834
  dependency = config.dependencies.find(
750
835
  (dep) => dep.id == api_map[trimmed_endpoint]
751
- )!;
836
+ );
752
837
  }
753
838
 
754
- if (typeof fn_index !== "number") {
839
+ if (typeof fn_index !== "number" || !dependency) {
840
+ const valid_endpoints = config.dependencies
841
+ .filter((dep) => dep.api_name)
842
+ .map((dep) => `"/${dep.api_name}"`)
843
+ .join(", ");
755
844
  throw new Error(
756
- "There is no endpoint matching that name of fn_index matching that number."
845
+ `No endpoint matching ${JSON.stringify(endpoint)} was found. ` +
846
+ (valid_endpoints
847
+ ? `Valid named endpoints are: ${valid_endpoints}. `
848
+ : "This app exposes no named endpoints. ") +
849
+ "An fn_index (number) of an existing dependency can also be used."
757
850
  );
758
851
  }
759
852
  return { fn_index, endpoint_info, dependency };
package/vite.config.ts CHANGED
@@ -38,7 +38,12 @@ logger.info = (log, options) => {
38
38
  };
39
39
  export default defineConfig(({ mode }) => {
40
40
  const production = mode === "production";
41
- const isBrowserBuild = process.env.BROWSER_BUILD === "true";
41
+ // Single-file, minified browser bundle served from CDNs at
42
+ // dist/index.min.js (see https://github.com/gradio-app/gradio/issues/10028)
43
+ const isCdnBuild = process.env.CDN_BUILD === "true";
44
+ // a CDN build is always a browser build (guards against CDN_BUILD=true
45
+ // without BROWSER_BUILD=true emitting es+cjs into the same file name)
46
+ const isBrowserBuild = process.env.BROWSER_BUILD === "true" || isCdnBuild;
42
47
 
43
48
  if (mode === "preview") {
44
49
  return {
@@ -50,15 +55,26 @@ export default defineConfig(({ mode }) => {
50
55
  customLogger: logger,
51
56
  build: {
52
57
  emptyOutDir: false,
58
+ ...(isCdnBuild ? { minify: true } : {}),
53
59
  lib: {
54
60
  entry: "src/index.ts",
55
- formats: ["es"],
56
- fileName: isBrowserBuild ? `browser` : `index`
61
+ // the node build also emits a CommonJS bundle (dist/index.cjs)
62
+ // so that require("@gradio/client") works on all supported
63
+ // node versions (see https://github.com/gradio-app/gradio/issues/9214)
64
+ formats: isBrowserBuild ? ["es"] : ["es", "cjs"],
65
+ fileName: (format) => {
66
+ if (isCdnBuild) return "index.min.js";
67
+ if (isBrowserBuild) return "browser.js";
68
+ return format === "cjs" ? "index.cjs" : "index.js";
69
+ }
57
70
  },
58
71
  rollupOptions: {
59
72
  input: "src/index.ts",
60
73
  output: {
61
- dir: "dist"
74
+ dir: "dist",
75
+ // keep the CDN bundle as a single file so the documented
76
+ // <script type="module"> import works without extra chunks
77
+ inlineDynamicImports: isCdnBuild
62
78
  }
63
79
  }
64
80
  },
@@ -1,4 +0,0 @@
1
- const e = {};
2
- export {
3
- e as default
4
- };