@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
package/dist/index.js CHANGED
@@ -1,2561 +1,2566 @@
1
- const HOST_URL = `host`;
2
- const SSE_URL = `queue/data`;
3
- const SSE_DATA_URL = `queue/join`;
4
- const UPLOAD_URL = `upload`;
5
- const LOGIN_URL = `login`;
6
- const CONFIG_URL = `config`;
7
- const API_INFO_URL = `info`;
8
- const RUNTIME_URL = `runtime`;
9
- const SLEEPTIME_URL = `sleeptime`;
10
- const HEARTBEAT_URL = `heartbeat`;
11
- const COMPONENT_SERVER_URL = `component_server`;
12
- const RESET_URL = `reset`;
13
- const CANCEL_URL = `cancel`;
14
- const APP_ID_URL = `app_id`;
15
- const QUEUE_FULL_MSG = "This application is currently busy. Please try again. ";
16
- const BROKEN_CONNECTION_MSG = "Connection errored out. ";
17
- const CONFIG_ERROR_MSG = "Could not resolve app config. ";
18
- const SPACE_STATUS_ERROR_MSG = "Could not get space status. ";
19
- const API_INFO_ERROR_MSG = "Could not get API info. ";
20
- const SPACE_METADATA_ERROR_MSG = "Space metadata could not be loaded. ";
21
- const INVALID_URL_MSG = "Invalid URL. A full URL path is required.";
22
- const UNAUTHORIZED_MSG = "Not authorized to access this space. ";
23
- const INVALID_CREDENTIALS_MSG = "Invalid credentials. Could not login. ";
24
- const MISSING_CREDENTIALS_MSG = "Login credentials are required to access this space.";
25
- const NODEJS_FS_ERROR_MSG = "File system access is only available in Node.js environments";
26
- const ROOT_URL_ERROR_MSG = "Root URL not found in client config";
27
- const FILE_PROCESSING_ERROR_MSG = "Error uploading file";
1
+ //#region src/constants.ts
2
+ var HOST_URL = `host`;
3
+ var SSE_URL = `queue/data`;
4
+ var SSE_DATA_URL = `queue/join`;
5
+ var UPLOAD_URL = `upload`;
6
+ var LOGIN_URL = `login`;
7
+ var CONFIG_URL = `config`;
8
+ var API_INFO_URL = `info`;
9
+ var RUNTIME_URL = `runtime`;
10
+ var SLEEPTIME_URL = `sleeptime`;
11
+ var HEARTBEAT_URL = `heartbeat`;
12
+ var COMPONENT_SERVER_URL = `component_server`;
13
+ var RESET_URL = `reset`;
14
+ var CANCEL_URL = `cancel`;
15
+ var APP_ID_URL = `app_id`;
16
+ var QUEUE_FULL_MSG = "This application is currently busy. Please try again. ";
17
+ var BROKEN_CONNECTION_MSG = "Connection errored out. ";
18
+ var CONFIG_ERROR_MSG = "Could not resolve app config. ";
19
+ var SPACE_STATUS_ERROR_MSG = "Could not get space status. ";
20
+ var API_INFO_ERROR_MSG = "Could not get API info. ";
21
+ var SPACE_METADATA_ERROR_MSG = "Space metadata could not be loaded. ";
22
+ var INVALID_URL_MSG = "Invalid URL. A full URL path is required.";
23
+ var UNAUTHORIZED_MSG = "Not authorized to access this space. ";
24
+ var INVALID_CREDENTIALS_MSG = "Invalid credentials. Could not login. ";
25
+ var MISSING_CREDENTIALS_MSG = "Login credentials are required to access this space.";
26
+ var PRIVATE_SPACE_MSG = "Could not access this app (received a 401 response). If it is a private Hugging Face Space, pass a valid Hugging Face token to the `token` option of `Client.connect`. You can generate a token at https://huggingface.co/settings/tokens.";
27
+ var SPACE_NOT_FOUND_MSG = (space, status) => `Space "${space}" could not be accessed (received a ${status} response from the Hugging Face API). Check that the Space name is spelled correctly and that the Space exists. If the Space is private, pass a valid Hugging Face token to the \`token\` option of \`Client.connect\`. You can generate a token at https://huggingface.co/settings/tokens.`;
28
+ var NO_API_INFO_MSG = "No API information is available for this app. This can happen when the app's `/info` endpoint cannot be reached, or when the app is running a legacy version of Gradio that is not supported by this client. ";
29
+ var WS_PROTOCOL_MSG = "This app appears to be running a legacy version of Gradio (3.x or earlier) that communicates over WebSockets, which is not supported by this version of @gradio/client. Please upgrade the app to a newer version of Gradio, or connect to it with @gradio/client version 0.x.";
30
+ var NODEJS_FS_ERROR_MSG = "File system access is only available in Node.js environments";
31
+ var ROOT_URL_ERROR_MSG = "Root URL not found in client config";
32
+ var FILE_PROCESSING_ERROR_MSG = "Error uploading file";
33
+ //#endregion
34
+ //#region src/helpers/init_helpers.ts
28
35
  async function get_jwt(space, token, cookies) {
29
- try {
30
- const r = await fetch(`https://huggingface.co/api/spaces/${space}/jwt`, {
31
- headers: {
32
- Authorization: `Bearer ${token}`,
33
- ...cookies ? { Cookie: cookies } : {}
34
- }
35
- });
36
- const jwt = (await r.json()).token;
37
- return jwt || false;
38
- } catch (e) {
39
- return false;
40
- }
36
+ try {
37
+ return (await (await fetch(`https://huggingface.co/api/spaces/${space}/jwt`, { headers: {
38
+ Authorization: `Bearer ${token}`,
39
+ ...cookies ? { Cookie: cookies } : {}
40
+ } })).json()).token || false;
41
+ } catch (e) {
42
+ return false;
43
+ }
44
+ }
45
+ /**
46
+ * The `hf_token` option was renamed to `token`, but a lot of existing code
47
+ * (and the Python client) still uses `hf_token`. Accept it as an alias so
48
+ * that authenticated requests are not silently sent without credentials,
49
+ * which previously surfaced as "Could not resolve app config" errors when
50
+ * connecting to private Spaces.
51
+ */
52
+ function normalise_token_option(options) {
53
+ if (options.hf_token && !options.token) {
54
+ options.token = options.hf_token;
55
+ console.warn("The `hf_token` option has been renamed to `token`. Support for `hf_token` will be removed in a future version of @gradio/client.");
56
+ }
41
57
  }
42
58
  function map_names_to_ids(fns) {
43
- let apis = {};
44
- fns.forEach(({ api_name, id }) => {
45
- if (api_name) apis[api_name] = id;
46
- });
47
- return apis;
48
- }
49
- async function resolve_config(endpoint) {
50
- const headers = this.options.token ? { Authorization: `Bearer ${this.options.token}` } : {};
51
- if (typeof window !== "undefined" && window.gradio_config && location.origin !== "http://localhost:9876") {
52
- if (window.gradio_config.current_page) {
53
- endpoint = endpoint.substring(0, endpoint.lastIndexOf("/"));
54
- }
55
- if (window.gradio_config.dev_mode || typeof window !== "undefined" && window?.BUILD_MODE === "dev") {
56
- let config_url = join_urls(
57
- endpoint,
58
- this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL
59
- );
60
- const response = await this.fetch(config_url, {
61
- headers,
62
- credentials: this.options.credentials ?? "same-origin"
63
- });
64
- const config = await handleConfigResponse(response, !!this.options.auth);
65
- config.root = endpoint || config.root;
66
- window.gradio_config = {
67
- ...config,
68
- current_page: window.gradio_config.current_page
69
- };
70
- }
71
- return { ...window.gradio_config };
72
- } else if (endpoint) {
73
- let config_url = join_urls(
74
- endpoint,
75
- this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL
76
- );
77
- const response = await this.fetch(config_url, {
78
- headers,
79
- credentials: this.options.credentials ?? "same-origin"
80
- });
81
- const config = await handleConfigResponse(response, !!this.options.auth);
82
- if (!config.root) {
83
- config.root = endpoint;
84
- }
85
- return config;
86
- }
87
- throw new Error(CONFIG_ERROR_MSG);
59
+ let apis = {};
60
+ fns.forEach(({ api_name, id }) => {
61
+ if (api_name) apis[api_name] = id;
62
+ });
63
+ return apis;
64
+ }
65
+ function resolve_config_root(root, current_location) {
66
+ const root_url = new URL(root, current_location);
67
+ const current_url = new URL(current_location);
68
+ if (root_url.hostname !== current_url.hostname) return root;
69
+ root_url.protocol = current_url.protocol;
70
+ root_url.host = current_url.host;
71
+ return root_url.toString().replace(/\/$/, "");
72
+ }
73
+ async function resolve_config(endpoint, strip_current_page = true) {
74
+ const headers = this.options.token ? { Authorization: `Bearer ${this.options.token}` } : {};
75
+ if (typeof window !== "undefined" && window.gradio_config && location.origin !== "http://localhost:9876") {
76
+ if (strip_current_page && window.gradio_config.current_page) endpoint = endpoint.substring(0, endpoint.lastIndexOf("/"));
77
+ if (window.gradio_config.dev_mode || typeof window !== "undefined" && window?.BUILD_MODE === "dev") {
78
+ let config_url = join_urls(endpoint, this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL);
79
+ const config = await handleConfigResponse(await this.fetch(config_url, {
80
+ headers,
81
+ credentials: this.options.credentials ?? "same-origin"
82
+ }), !!this.options.auth);
83
+ config.root = endpoint || config.root;
84
+ window.gradio_config = {
85
+ ...config,
86
+ current_page: window.gradio_config.current_page
87
+ };
88
+ }
89
+ const config = { ...window.gradio_config };
90
+ config.root = resolve_config_root(config.root, location.href);
91
+ return config;
92
+ } else if (endpoint) {
93
+ let config_url = join_urls(endpoint, this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL);
94
+ const config = await handleConfigResponse(await this.fetch(config_url, {
95
+ headers,
96
+ credentials: this.options.credentials ?? "same-origin"
97
+ }), !!this.options.auth);
98
+ if (!config.root) config.root = endpoint;
99
+ return config;
100
+ }
101
+ throw new Error(CONFIG_ERROR_MSG);
88
102
  }
89
103
  async function handleConfigResponse(response, authorized) {
90
- if (response?.status === 401 && !authorized) {
91
- const error_data = await response.json();
92
- const auth_message = error_data?.detail?.auth_message;
93
- throw new Error(auth_message || MISSING_CREDENTIALS_MSG);
94
- } else if (response?.status === 401 && authorized) {
95
- throw new Error(INVALID_CREDENTIALS_MSG);
96
- }
97
- if (response?.status === 200) {
98
- let config = await response.json();
99
- config.dependencies?.forEach((dep, i) => {
100
- if (dep.id === void 0) {
101
- dep.id = i;
102
- }
103
- });
104
- return config;
105
- } else if (response?.status === 401) {
106
- throw new Error(UNAUTHORIZED_MSG);
107
- }
108
- throw new Error(CONFIG_ERROR_MSG);
104
+ if (response?.status === 401 && !authorized) {
105
+ let error_data = null;
106
+ try {
107
+ error_data = await response.json();
108
+ } catch (e) {
109
+ throw new Error(PRIVATE_SPACE_MSG);
110
+ }
111
+ const auth_message = error_data?.detail?.auth_message;
112
+ throw new Error(auth_message || "Login credentials are required to access this space.");
113
+ } else if (response?.status === 401 && authorized) throw new Error(INVALID_CREDENTIALS_MSG);
114
+ if (response?.status === 200) {
115
+ let config = await response.json();
116
+ config.dependencies?.forEach((dep, i) => {
117
+ if (dep.id === void 0) dep.id = i;
118
+ });
119
+ return config;
120
+ } else if (response?.status === 401) throw new Error(UNAUTHORIZED_MSG);
121
+ throw new Error(`${CONFIG_ERROR_MSG}(received status ${response?.status} when fetching the app config)`);
109
122
  }
110
123
  async function resolve_cookies() {
111
- const { http_protocol, host } = await process_endpoint(
112
- this.app_reference,
113
- this.options.token
114
- );
115
- try {
116
- if (this.options.auth) {
117
- const cookie_header = await get_cookie_header(
118
- http_protocol,
119
- host,
120
- this.options.auth,
121
- this.fetch,
122
- this.options.token,
123
- this.options.credentials
124
- );
125
- if (cookie_header) this.set_cookies(cookie_header);
126
- }
127
- } catch (e) {
128
- throw Error(e.message);
129
- }
124
+ const { http_protocol, host } = await process_endpoint(this.app_reference, this.options.token);
125
+ try {
126
+ if (this.options.auth) {
127
+ const cookie_header = await get_cookie_header(http_protocol, host, this.options.auth, this.fetch, this.options.token, this.options.credentials);
128
+ if (cookie_header) this.set_cookies(cookie_header);
129
+ }
130
+ } catch (e) {
131
+ throw Error(e.message);
132
+ }
130
133
  }
131
134
  async function get_cookie_header(http_protocol, host, auth, _fetch, token, credentials) {
132
- const formData = new FormData();
133
- formData.append("username", auth?.[0]);
134
- formData.append("password", auth?.[1]);
135
- let headers = {};
136
- if (token) {
137
- headers.Authorization = `Bearer ${token}`;
138
- }
139
- const res = await _fetch(`${http_protocol}//${host}/${LOGIN_URL}`, {
140
- headers,
141
- method: "POST",
142
- body: formData,
143
- credentials: credentials ?? "same-origin"
144
- });
145
- if (res.status === 200) {
146
- return res.headers.get("set-cookie");
147
- } else if (res.status === 401) {
148
- throw new Error(INVALID_CREDENTIALS_MSG);
149
- } else {
150
- throw new Error(SPACE_METADATA_ERROR_MSG);
151
- }
135
+ const formData = new FormData();
136
+ formData.append("username", auth?.[0]);
137
+ formData.append("password", auth?.[1]);
138
+ let headers = {};
139
+ if (token) headers.Authorization = `Bearer ${token}`;
140
+ const res = await _fetch(`${http_protocol}//${host}/${LOGIN_URL}`, {
141
+ headers,
142
+ method: "POST",
143
+ body: formData,
144
+ credentials: credentials ?? "same-origin"
145
+ });
146
+ if (res.status === 200) return res.headers.get("set-cookie");
147
+ else if (res.status === 401) throw new Error(INVALID_CREDENTIALS_MSG);
148
+ else throw new Error(SPACE_METADATA_ERROR_MSG);
152
149
  }
153
150
  function determine_protocol(endpoint) {
154
- if (endpoint.startsWith("http")) {
155
- const { protocol, host, pathname } = new URL(endpoint);
156
- return {
157
- ws_protocol: protocol === "https:" ? "wss" : "ws",
158
- http_protocol: protocol,
159
- host: host + (pathname !== "/" ? pathname : "")
160
- };
161
- }
162
- return {
163
- ws_protocol: "wss",
164
- http_protocol: "https:",
165
- host: new URL(endpoint).host
166
- };
167
- }
168
- const parse_and_set_cookies = (cookie_header) => {
169
- let cookies = [];
170
- const parts = cookie_header.split(/,(?=\s*[^\s=;]+=[^\s=;]+)/);
171
- parts.forEach((cookie) => {
172
- const [cookie_name, cookie_value] = cookie.split(";")[0].split("=");
173
- if (cookie_name && cookie_value) {
174
- cookies.push(`${cookie_name.trim()}=${cookie_value.trim()}`);
175
- }
176
- });
177
- return cookies;
151
+ if (endpoint.startsWith("http")) {
152
+ const { protocol, host, pathname } = new URL(endpoint);
153
+ return {
154
+ ws_protocol: protocol === "https:" ? "wss" : "ws",
155
+ http_protocol: protocol,
156
+ host: host + (pathname !== "/" ? pathname : "")
157
+ };
158
+ }
159
+ return {
160
+ ws_protocol: "wss",
161
+ http_protocol: "https:",
162
+ host: new URL(endpoint).host
163
+ };
164
+ }
165
+ var parse_and_set_cookies = (cookie_header) => {
166
+ let cookies = [];
167
+ cookie_header.split(/,(?=\s*[^\s=;]+=[^\s=;]+)/).forEach((cookie) => {
168
+ const [cookie_name, cookie_value] = cookie.split(";")[0].split("=");
169
+ if (cookie_name && cookie_value) cookies.push(`${cookie_name.trim()}=${cookie_value.trim()}`);
170
+ });
171
+ return cookies;
178
172
  };
179
- const RE_SPACE_NAME = /^[a-zA-Z0-9_\-\.]+\/[a-zA-Z0-9_\-\.]+$/;
180
- const RE_SPACE_DOMAIN = /.*hf\.space\/{0,1}.*$/;
173
+ //#endregion
174
+ //#region src/helpers/api_info.ts
175
+ var RE_SPACE_NAME = /^[a-zA-Z0-9_\-\.]+\/[a-zA-Z0-9_\-\.]+$/;
176
+ var RE_SPACE_DOMAIN = /.*hf\.space\/{0,1}.*$/;
181
177
  async function process_endpoint(app_reference, token) {
182
- const headers = {};
183
- if (token) {
184
- headers.Authorization = `Bearer ${token}`;
185
- }
186
- const _app_reference = app_reference.trim().replace(/\/$/, "");
187
- if (RE_SPACE_NAME.test(_app_reference)) {
188
- try {
189
- const res = await fetch(
190
- `https://huggingface.co/api/spaces/${_app_reference}/${HOST_URL}`,
191
- { headers }
192
- );
193
- const _host = (await res.json()).host;
194
- return {
195
- space_id: app_reference,
196
- ...determine_protocol(_host)
197
- };
198
- } catch (e) {
199
- throw new Error(SPACE_METADATA_ERROR_MSG);
200
- }
201
- }
202
- if (RE_SPACE_DOMAIN.test(_app_reference)) {
203
- const { ws_protocol, http_protocol, host } = determine_protocol(_app_reference);
204
- return {
205
- space_id: host.split("/")[0].replace(".hf.space", ""),
206
- ws_protocol,
207
- http_protocol,
208
- host
209
- };
210
- }
211
- return {
212
- space_id: false,
213
- ...determine_protocol(_app_reference)
214
- };
215
- }
216
- const join_urls = (...urls) => {
217
- try {
218
- return urls.reduce((base_url, part) => {
219
- base_url = base_url.replace(/\/+$/, "");
220
- part = part.replace(/^\/+/, "");
221
- return new URL(part, base_url + "/").toString();
222
- });
223
- } catch (e) {
224
- throw new Error(INVALID_URL_MSG);
225
- }
178
+ const headers = {};
179
+ if (token) headers.Authorization = `Bearer ${token}`;
180
+ const _app_reference = app_reference.trim().replace(/\/$/, "");
181
+ if (RE_SPACE_NAME.test(_app_reference)) {
182
+ let res;
183
+ try {
184
+ res = await fetch(`https://huggingface.co/api/spaces/${_app_reference}/${HOST_URL}`, { headers });
185
+ } catch (e) {
186
+ throw new Error(SPACE_METADATA_ERROR_MSG);
187
+ }
188
+ if (res.status === 401 || res.status === 404) throw new Error(SPACE_NOT_FOUND_MSG(_app_reference, res.status));
189
+ let _host;
190
+ try {
191
+ _host = (await res.json()).host;
192
+ } catch (e) {
193
+ throw new Error(SPACE_METADATA_ERROR_MSG);
194
+ }
195
+ if (!_host) throw new Error(SPACE_METADATA_ERROR_MSG);
196
+ return {
197
+ space_id: _app_reference,
198
+ ...determine_protocol(_host)
199
+ };
200
+ }
201
+ if (RE_SPACE_DOMAIN.test(_app_reference)) {
202
+ const { ws_protocol, http_protocol, host } = determine_protocol(_app_reference);
203
+ return {
204
+ space_id: host.split("/")[0].replace(".hf.space", ""),
205
+ ws_protocol,
206
+ http_protocol,
207
+ host
208
+ };
209
+ }
210
+ return {
211
+ space_id: false,
212
+ ...determine_protocol(_app_reference)
213
+ };
214
+ }
215
+ var join_urls = (...urls) => {
216
+ try {
217
+ return urls.reduce((base_url, part) => {
218
+ base_url = base_url.replace(/\/+$/, "");
219
+ part = part.replace(/^\/+/, "");
220
+ return new URL(part, base_url + "/").toString();
221
+ });
222
+ } catch (e) {
223
+ throw new Error(INVALID_URL_MSG);
224
+ }
226
225
  };
227
226
  function transform_api_info(api_info, config, api_map) {
228
- const transformed_info = {
229
- named_endpoints: {},
230
- unnamed_endpoints: {}
231
- };
232
- Object.keys(api_info).forEach((category) => {
233
- if (category === "named_endpoints" || category === "unnamed_endpoints") {
234
- transformed_info[category] = {};
235
- Object.entries(api_info[category]).forEach(
236
- ([endpoint, { parameters, returns }]) => {
237
- const dependencyIndex = config.dependencies.find(
238
- (dep) => dep.api_name === endpoint || dep.api_name === endpoint.replace("/", "")
239
- )?.id || api_map[endpoint.replace("/", "")] || -1;
240
- const dependencyTypes = dependencyIndex !== -1 ? config.dependencies.find((dep) => dep.id == dependencyIndex)?.types : { generator: false, cancel: false };
241
- if (dependencyIndex !== -1 && config.dependencies.find((dep) => dep.id == dependencyIndex)?.inputs?.length !== parameters.length) {
242
- const components = config.dependencies.find((dep) => dep.id == dependencyIndex).inputs.map(
243
- (input) => config.components.find((c) => c.id === input)?.type
244
- );
245
- try {
246
- components.forEach((comp, idx) => {
247
- if (comp === "state") {
248
- const new_param = {
249
- component: "state",
250
- example: null,
251
- parameter_default: null,
252
- parameter_has_default: true,
253
- parameter_name: null,
254
- hidden: true
255
- };
256
- parameters.splice(idx, 0, new_param);
257
- }
258
- });
259
- } catch (e) {
260
- console.error(e);
261
- }
262
- }
263
- const transform_type = (data, component, serializer, signature_type) => ({
264
- ...data,
265
- description: get_description(data?.type, serializer),
266
- type: get_type(data?.type, component, serializer, signature_type) || ""
267
- });
268
- transformed_info[category][endpoint] = {
269
- parameters: parameters.map(
270
- (p) => transform_type(p, p?.component, p?.serializer, "parameter")
271
- ),
272
- returns: returns.map(
273
- (r) => transform_type(r, r?.component, r?.serializer, "return")
274
- ),
275
- type: dependencyTypes
276
- };
277
- }
278
- );
279
- }
280
- });
281
- return transformed_info;
227
+ const transformed_info = {
228
+ named_endpoints: {},
229
+ unnamed_endpoints: {}
230
+ };
231
+ Object.keys(api_info).forEach((category) => {
232
+ if (category === "named_endpoints" || category === "unnamed_endpoints") {
233
+ transformed_info[category] = {};
234
+ Object.entries(api_info[category]).forEach(([endpoint, endpoint_info]) => {
235
+ const parameters = endpoint_info?.parameters ?? [];
236
+ const returns = endpoint_info?.returns ?? [];
237
+ const dependencyIndex = config.dependencies.find((dep) => dep.api_name === endpoint || dep.api_name === endpoint.replace("/", ""))?.id || api_map[endpoint.replace("/", "")] || -1;
238
+ const dependency = dependencyIndex !== -1 ? config.dependencies.find((dep) => dep.id == dependencyIndex) : void 0;
239
+ const dependencyTypes = dependencyIndex !== -1 ? dependency?.types : {
240
+ generator: false,
241
+ cancel: false
242
+ };
243
+ if (dependency && Array.isArray(dependency.inputs) && dependency.inputs.length !== parameters.length) {
244
+ const components = dependency.inputs.map((input) => config.components.find((c) => c.id === input)?.type);
245
+ try {
246
+ components.forEach((comp, idx) => {
247
+ if (comp === "state") parameters.splice(idx, 0, {
248
+ component: "state",
249
+ example: null,
250
+ parameter_default: null,
251
+ parameter_has_default: true,
252
+ parameter_name: null,
253
+ hidden: true
254
+ });
255
+ });
256
+ } catch (e) {
257
+ console.error(e);
258
+ }
259
+ }
260
+ const transform_type = (data, component, serializer, signature_type) => ({
261
+ ...data,
262
+ description: get_description(data?.type, serializer),
263
+ type: get_type(data?.type, component, serializer, signature_type) || ""
264
+ });
265
+ transformed_info[category][endpoint] = {
266
+ parameters: parameters.map((p) => transform_type(p, p?.component, p?.serializer, "parameter")),
267
+ returns: returns.map((r) => transform_type(r, r?.component, r?.serializer, "return")),
268
+ type: dependencyTypes,
269
+ ...endpoint_info?.oauth_token ? { oauth_token: endpoint_info.oauth_token } : {}
270
+ };
271
+ });
272
+ }
273
+ });
274
+ return transformed_info;
282
275
  }
283
276
  function get_type(type, component, serializer, signature_type) {
284
- if (component === "Api") return type.type;
285
- switch (type?.type) {
286
- case "string":
287
- return "string";
288
- case "boolean":
289
- return "boolean";
290
- case "number":
291
- return "number";
292
- }
293
- if (serializer === "JSONSerializable" || serializer === "StringSerializable") {
294
- return "any";
295
- } else if (serializer === "ListStringSerializable") {
296
- return "string[]";
297
- } else if (component === "Image") {
298
- return signature_type === "parameter" ? "Blob | File | Buffer" : "string";
299
- } else if (serializer === "FileSerializable") {
300
- if (type?.type === "array") {
301
- return signature_type === "parameter" ? "(Blob | File | Buffer)[]" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`;
302
- }
303
- return signature_type === "parameter" ? "Blob | File | Buffer" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`;
304
- } else if (serializer === "GallerySerializable") {
305
- return signature_type === "parameter" ? "[(Blob | File | Buffer), (string | null)][]" : `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`;
306
- }
277
+ if (component === "Api") return type.type;
278
+ switch (type?.type) {
279
+ case "string": return "string";
280
+ case "boolean": return "boolean";
281
+ case "number": return "number";
282
+ }
283
+ if (serializer === "JSONSerializable" || serializer === "StringSerializable") return "any";
284
+ else if (serializer === "ListStringSerializable") return "string[]";
285
+ else if (component === "Image") return signature_type === "parameter" ? "Blob | File | Buffer" : "string";
286
+ else if (serializer === "FileSerializable") {
287
+ if (type?.type === "array") return signature_type === "parameter" ? "(Blob | File | Buffer)[]" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`;
288
+ return signature_type === "parameter" ? "Blob | File | Buffer" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`;
289
+ } else if (serializer === "GallerySerializable") return signature_type === "parameter" ? "[(Blob | File | Buffer), (string | null)][]" : `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`;
307
290
  }
308
291
  function get_description(type, serializer) {
309
- if (serializer === "GallerySerializable") {
310
- return "array of [file, label] tuples";
311
- } else if (serializer === "ListStringSerializable") {
312
- return "array of strings";
313
- } else if (serializer === "FileSerializable") {
314
- return "array of files or single file";
315
- }
316
- return type?.description;
292
+ if (serializer === "GallerySerializable") return "array of [file, label] tuples";
293
+ else if (serializer === "ListStringSerializable") return "array of strings";
294
+ else if (serializer === "FileSerializable") return "array of files or single file";
295
+ return type?.description;
317
296
  }
318
297
  function handle_message(data, last_status) {
319
- const queue = true;
320
- switch (data.msg) {
321
- case "send_data":
322
- return { type: "data" };
323
- case "send_hash":
324
- return { type: "hash" };
325
- case "queue_full":
326
- return {
327
- type: "update",
328
- status: {
329
- queue,
330
- message: QUEUE_FULL_MSG,
331
- stage: "error",
332
- code: data.code,
333
- success: data.success
334
- }
335
- };
336
- case "heartbeat":
337
- return {
338
- type: "heartbeat"
339
- };
340
- case "unexpected_error":
341
- return {
342
- type: "unexpected_error",
343
- status: {
344
- queue,
345
- message: data.message,
346
- session_not_found: data.session_not_found,
347
- stage: "error",
348
- success: false
349
- }
350
- };
351
- case "broken_connection":
352
- return {
353
- type: "broken_connection",
354
- status: {
355
- queue,
356
- message: data.message,
357
- stage: "error",
358
- success: false
359
- }
360
- };
361
- case "estimation":
362
- return {
363
- type: "update",
364
- status: {
365
- queue,
366
- stage: last_status || "pending",
367
- code: data.code,
368
- size: data.queue_size,
369
- position: data.rank,
370
- eta: data.rank_eta,
371
- success: data.success
372
- }
373
- };
374
- case "progress":
375
- return {
376
- type: "update",
377
- status: {
378
- queue,
379
- stage: "pending",
380
- code: data.code,
381
- progress_data: data.progress_data,
382
- success: data.success
383
- }
384
- };
385
- case "log":
386
- return { type: "log", data };
387
- case "process_generating":
388
- return {
389
- type: "generating",
390
- status: {
391
- queue,
392
- message: !data.success ? data.output.error : null,
393
- stage: data.success ? "generating" : "error",
394
- code: data.code,
395
- progress_data: data.progress_data,
396
- eta: data.average_duration,
397
- changed_state_ids: data.success ? data.output.changed_state_ids : void 0
398
- },
399
- data: data.success ? data.output : null
400
- };
401
- case "process_streaming":
402
- return {
403
- type: "streaming",
404
- status: {
405
- queue,
406
- message: data.output.error,
407
- stage: "streaming",
408
- time_limit: data.time_limit,
409
- code: data.code,
410
- progress_data: data.progress_data,
411
- changed_state_ids: data.output.changed_state_ids,
412
- eta: data.eta
413
- },
414
- data: data.output
415
- };
416
- case "process_completed":
417
- if ("error" in data.output) {
418
- return {
419
- type: "update",
420
- status: {
421
- queue,
422
- title: data.output.title ?? "Error",
423
- message: data.output.error ?? "An error occurred",
424
- visible: data.output.visible,
425
- duration: data.output.duration,
426
- stage: "error",
427
- code: data.code,
428
- success: data.success
429
- }
430
- };
431
- }
432
- return {
433
- type: "complete",
434
- status: {
435
- queue,
436
- message: !data.success ? data.output.error : void 0,
437
- stage: data.success ? "complete" : "error",
438
- code: data.code,
439
- progress_data: data.progress_data,
440
- changed_state_ids: data.success ? data.output.changed_state_ids : void 0,
441
- used_cache: data.used_cache,
442
- cache_duration: data.cache_duration,
443
- avg_time: data.avg_time
444
- },
445
- data: data.success ? data.output : null
446
- };
447
- case "process_starts":
448
- return {
449
- type: "update",
450
- status: {
451
- queue,
452
- stage: "pending",
453
- code: data.code,
454
- size: data.rank,
455
- position: 0,
456
- success: data.success,
457
- eta: data.eta
458
- },
459
- original_msg: "process_starts"
460
- };
461
- }
462
- return { type: "none", status: { stage: "error", queue } };
463
- }
464
- const map_data_to_params = (data = [], endpoint_info) => {
465
- const parameters = endpoint_info ? endpoint_info.parameters : [];
466
- if (Array.isArray(data)) {
467
- if (endpoint_info && parameters.length > 0 && data.length > parameters.length) {
468
- console.warn("Too many arguments provided for the endpoint.");
469
- }
470
- return data;
471
- }
472
- const resolved_data = [];
473
- const provided_keys = Object.keys(data);
474
- parameters.forEach((param, index) => {
475
- if (data.hasOwnProperty(param.parameter_name)) {
476
- resolved_data[index] = data[param.parameter_name];
477
- } else if (param.parameter_has_default) {
478
- resolved_data[index] = param.parameter_default;
479
- } else {
480
- throw new Error(
481
- `No value provided for required parameter: ${param.parameter_name}`
482
- );
483
- }
484
- });
485
- provided_keys.forEach((key) => {
486
- if (!parameters.some((param) => param.parameter_name === key)) {
487
- throw new Error(
488
- `Parameter \`${key}\` is not a valid keyword argument. Please refer to the API for usage.`
489
- );
490
- }
491
- });
492
- resolved_data.forEach((value, idx) => {
493
- if (value === void 0 && !parameters[idx].parameter_has_default) {
494
- throw new Error(
495
- `No value provided for required parameter: ${parameters[idx].parameter_name}`
496
- );
497
- }
498
- });
499
- return resolved_data;
298
+ const queue = true;
299
+ switch (data.msg) {
300
+ case "send_data": return { type: "data" };
301
+ case "send_hash": return { type: "hash" };
302
+ case "queue_full": return {
303
+ type: "update",
304
+ status: {
305
+ queue,
306
+ message: QUEUE_FULL_MSG,
307
+ stage: "error",
308
+ code: data.code,
309
+ success: data.success
310
+ }
311
+ };
312
+ case "heartbeat": return { type: "heartbeat" };
313
+ case "unexpected_error": return {
314
+ type: "unexpected_error",
315
+ status: {
316
+ queue,
317
+ message: data.message,
318
+ session_not_found: data.session_not_found,
319
+ stage: "error",
320
+ success: false
321
+ }
322
+ };
323
+ case "broken_connection": return {
324
+ type: "broken_connection",
325
+ status: {
326
+ queue,
327
+ message: data.message,
328
+ stage: "error",
329
+ success: false
330
+ }
331
+ };
332
+ case "estimation": return {
333
+ type: "update",
334
+ status: {
335
+ queue,
336
+ stage: last_status || "pending",
337
+ code: data.code,
338
+ size: data.queue_size,
339
+ position: data.rank,
340
+ eta: data.rank_eta,
341
+ success: data.success
342
+ }
343
+ };
344
+ case "progress": return {
345
+ type: "update",
346
+ status: {
347
+ queue,
348
+ stage: "pending",
349
+ code: data.code,
350
+ progress_data: data.progress_data,
351
+ success: data.success
352
+ }
353
+ };
354
+ case "log": return {
355
+ type: "log",
356
+ data
357
+ };
358
+ case "process_generating": return {
359
+ type: "generating",
360
+ status: {
361
+ queue,
362
+ message: !data.success ? data.output.error : null,
363
+ stage: data.success ? "generating" : "error",
364
+ code: data.code,
365
+ progress_data: data.progress_data,
366
+ eta: data.average_duration,
367
+ changed_state_ids: data.success ? data.output.changed_state_ids : void 0
368
+ },
369
+ data: data.success ? data.output : null
370
+ };
371
+ case "process_streaming": return {
372
+ type: "streaming",
373
+ status: {
374
+ queue,
375
+ message: data.output.error,
376
+ stage: "streaming",
377
+ time_limit: data.time_limit,
378
+ code: data.code,
379
+ progress_data: data.progress_data,
380
+ changed_state_ids: data.output.changed_state_ids,
381
+ eta: data.eta
382
+ },
383
+ data: data.output
384
+ };
385
+ case "process_completed":
386
+ if ("error" in data.output) return {
387
+ type: "update",
388
+ status: {
389
+ queue,
390
+ title: data.output.title ?? "Error",
391
+ message: data.output.error ?? "An error occurred",
392
+ visible: data.output.visible,
393
+ duration: data.output.duration,
394
+ stage: "error",
395
+ code: data.code,
396
+ success: data.success
397
+ }
398
+ };
399
+ return {
400
+ type: "complete",
401
+ status: {
402
+ queue,
403
+ message: !data.success ? data.output.error : void 0,
404
+ stage: data.success ? "complete" : "error",
405
+ code: data.code,
406
+ progress_data: data.progress_data,
407
+ changed_state_ids: data.success ? data.output.changed_state_ids : void 0,
408
+ used_cache: data.used_cache,
409
+ cache_duration: data.cache_duration,
410
+ avg_time: data.avg_time
411
+ },
412
+ data: data.success ? data.output : null
413
+ };
414
+ case "process_starts": return {
415
+ type: "update",
416
+ status: {
417
+ queue,
418
+ stage: "pending",
419
+ code: data.code,
420
+ size: data.rank,
421
+ position: 0,
422
+ success: data.success,
423
+ eta: data.eta
424
+ },
425
+ original_msg: "process_starts"
426
+ };
427
+ }
428
+ return {
429
+ type: "none",
430
+ status: {
431
+ stage: "error",
432
+ queue
433
+ }
434
+ };
435
+ }
436
+ /**
437
+ * Maps the provided `data` to the parameters defined by the `/info` endpoint response.
438
+ * This allows us to support both positional and keyword arguments passed to the client
439
+ * and ensures that all parameters are either directly provided or have default values assigned.
440
+ *
441
+ * @param {unknown[] | Record<string, unknown>} data - The input data for the function,
442
+ * which can be either an array of values for positional arguments or an object
443
+ * with key-value pairs for keyword arguments.
444
+ * @param {JsApiData[]} parameters - Array of parameter descriptions retrieved from the
445
+ * `/info` endpoint.
446
+ *
447
+ * @returns {unknown[]} - Returns an array of resolved data where each element corresponds
448
+ * to the expected parameter from the API. The `parameter_default` value is used where
449
+ * a value is not provided for a parameter, and optional parameters without defaults are
450
+ * set to `undefined`.
451
+ *
452
+ * @throws {Error} - Throws an error:
453
+ * - If more arguments are provided than are defined in the parameters.
454
+ * * - If no parameter value is provided for a required parameter and no default value is defined.
455
+ * - If an argument is provided that does not match any defined parameter.
456
+ */
457
+ var map_data_to_params = (data = [], endpoint_info) => {
458
+ const parameters = endpoint_info ? endpoint_info.parameters : [];
459
+ if (Array.isArray(data)) {
460
+ if (endpoint_info && parameters.length > 0 && data.length > parameters.length) console.warn("Too many arguments provided for the endpoint.");
461
+ return data;
462
+ }
463
+ const resolved_data = [];
464
+ const provided_keys = Object.keys(data);
465
+ parameters.forEach((param, index) => {
466
+ if (data.hasOwnProperty(param.parameter_name)) resolved_data[index] = data[param.parameter_name];
467
+ else if (param.parameter_has_default) resolved_data[index] = param.parameter_default;
468
+ else throw new Error(`No value provided for required parameter: ${param.parameter_name}`);
469
+ });
470
+ provided_keys.forEach((key) => {
471
+ if (!parameters.some((param) => param.parameter_name === key)) throw new Error(`Parameter \`${key}\` is not a valid keyword argument. Please refer to the API for usage.`);
472
+ });
473
+ resolved_data.forEach((value, idx) => {
474
+ if (value === void 0 && !parameters[idx].parameter_has_default) throw new Error(`No value provided for required parameter: ${parameters[idx].parameter_name}`);
475
+ });
476
+ return resolved_data;
500
477
  };
478
+ //#endregion
479
+ //#region src/utils/view_api.ts
501
480
  async function view_api() {
502
- if (this.api_info) return this.api_info;
503
- const { token } = this.options;
504
- const { config } = this;
505
- const headers = {};
506
- if (token) {
507
- headers.Authorization = `Bearer ${token}`;
508
- }
509
- if (!config) {
510
- return;
511
- }
512
- try {
513
- let response;
514
- let api_info;
515
- if (typeof window !== "undefined" && window.gradio_api_info) {
516
- api_info = window.gradio_api_info;
517
- } else {
518
- const url = join_urls(config.root, this.api_prefix, API_INFO_URL);
519
- response = await this.fetch(url, {
520
- headers,
521
- credentials: this.options.credentials ?? "same-origin"
522
- });
523
- if (!response.ok) {
524
- throw new Error(BROKEN_CONNECTION_MSG);
525
- }
526
- api_info = await response.json();
527
- }
528
- if ("api" in api_info) {
529
- api_info = api_info.api;
530
- }
531
- if (api_info.named_endpoints["/predict"] && !api_info.unnamed_endpoints["0"]) {
532
- api_info.unnamed_endpoints[0] = api_info.named_endpoints["/predict"];
533
- }
534
- return transform_api_info(api_info, config, this.api_map);
535
- } catch (e) {
536
- throw new Error("Could not get API info. " + e.message);
537
- }
481
+ if (this.api_info) return this.api_info;
482
+ const { token } = this.options;
483
+ const { config } = this;
484
+ const headers = {};
485
+ if (token) headers.Authorization = `Bearer ${token}`;
486
+ if (!config) return;
487
+ try {
488
+ let response;
489
+ let api_info;
490
+ if (typeof window !== "undefined" && window.gradio_api_info) api_info = window.gradio_api_info;
491
+ else {
492
+ const url = join_urls(config.root, this.api_prefix, API_INFO_URL);
493
+ response = await this.fetch(url, {
494
+ headers,
495
+ credentials: this.options.credentials ?? "same-origin"
496
+ });
497
+ if (!response.ok) throw new Error(BROKEN_CONNECTION_MSG);
498
+ api_info = await response.json();
499
+ }
500
+ if ("api" in api_info) api_info = api_info.api;
501
+ if (api_info.named_endpoints["/predict"] && !api_info.unnamed_endpoints["0"]) api_info.unnamed_endpoints[0] = api_info.named_endpoints["/predict"];
502
+ return transform_api_info(api_info, config, this.api_map);
503
+ } catch (e) {
504
+ throw new Error("Could not get API info. " + e.message);
505
+ }
538
506
  }
507
+ //#endregion
508
+ //#region src/utils/upload_files.ts
539
509
  async function upload_files(root_url, files, upload_id) {
540
- const headers = {};
541
- if (this?.options?.token) {
542
- headers.Authorization = `Bearer ${this.options.token}`;
543
- }
544
- const chunkSize = 1e3;
545
- const uploadResponses = [];
546
- let response;
547
- for (let i = 0; i < files.length; i += chunkSize) {
548
- const chunk = files.slice(i, i + chunkSize);
549
- const formData = new FormData();
550
- chunk.forEach((file) => {
551
- formData.append("files", file);
552
- });
553
- try {
554
- const upload_url = upload_id ? `${root_url}${this.api_prefix}/${UPLOAD_URL}?upload_id=${upload_id}` : `${root_url}${this.api_prefix}/${UPLOAD_URL}`;
555
- response = await this.fetch(upload_url, {
556
- method: "POST",
557
- body: formData,
558
- headers,
559
- credentials: this.options.credentials ?? "same-origin"
560
- });
561
- } catch (e) {
562
- throw new Error(BROKEN_CONNECTION_MSG + e.message);
563
- }
564
- if (!response.ok) {
565
- const error_text = await response.text();
566
- return { error: `HTTP ${response.status}: ${error_text}` };
567
- }
568
- const output = await response.json();
569
- if (output) {
570
- uploadResponses.push(...output);
571
- }
572
- }
573
- return { files: uploadResponses };
574
- }
575
- const si = {
576
- radix: 1e3,
577
- unit: ["b", "kb", "Mb", "Gb", "Tb", "Pb", "Eb", "Zb", "Yb"]
578
- };
579
- const iec = {
580
- radix: 1024,
581
- unit: ["b", "Kib", "Mib", "Gib", "Tib", "Pib", "Eib", "Zib", "Yib"]
582
- };
583
- const jedec = {
584
- radix: 1024,
585
- unit: ["b", "Kb", "Mb", "Gb", "Tb", "Pb", "Eb", "Zb", "Yb"]
586
- };
587
- const SPECS = {
588
- si,
589
- iec,
590
- jedec
510
+ const headers = {};
511
+ if (this?.options?.token) headers.Authorization = `Bearer ${this.options.token}`;
512
+ const chunkSize = 1e3;
513
+ const uploadResponses = [];
514
+ let response;
515
+ for (let i = 0; i < files.length; i += chunkSize) {
516
+ const chunk = files.slice(i, i + chunkSize);
517
+ const formData = new FormData();
518
+ chunk.forEach((file) => {
519
+ formData.append("files", file);
520
+ });
521
+ try {
522
+ const upload_url = upload_id ? `${root_url}${this.api_prefix}/${UPLOAD_URL}?upload_id=${upload_id}` : `${root_url}${this.api_prefix}/${UPLOAD_URL}`;
523
+ response = await this.fetch(upload_url, {
524
+ method: "POST",
525
+ body: formData,
526
+ headers,
527
+ credentials: this.options.credentials ?? "same-origin"
528
+ });
529
+ } catch (e) {
530
+ throw new Error(BROKEN_CONNECTION_MSG + e.message);
531
+ }
532
+ if (!response.ok) {
533
+ const error_text = await response.text();
534
+ return { error: `HTTP ${response.status}: ${error_text}` };
535
+ }
536
+ const output = await response.json();
537
+ if (output) uploadResponses.push(...output);
538
+ }
539
+ return { files: uploadResponses };
540
+ }
541
+ var SPECS = {
542
+ si: {
543
+ radix: 1e3,
544
+ unit: [
545
+ "b",
546
+ "kb",
547
+ "Mb",
548
+ "Gb",
549
+ "Tb",
550
+ "Pb",
551
+ "Eb",
552
+ "Zb",
553
+ "Yb"
554
+ ]
555
+ },
556
+ iec: {
557
+ radix: 1024,
558
+ unit: [
559
+ "b",
560
+ "Kib",
561
+ "Mib",
562
+ "Gib",
563
+ "Tib",
564
+ "Pib",
565
+ "Eib",
566
+ "Zib",
567
+ "Yib"
568
+ ]
569
+ },
570
+ jedec: {
571
+ radix: 1024,
572
+ unit: [
573
+ "b",
574
+ "Kb",
575
+ "Mb",
576
+ "Gb",
577
+ "Tb",
578
+ "Pb",
579
+ "Eb",
580
+ "Zb",
581
+ "Yb"
582
+ ]
583
+ }
591
584
  };
585
+ /**
586
+ * file size from https://github.com/hustcc/filesize.js
587
+ * @param bytes - The number of bytes to convert to human-readable format
588
+ * @param fixed - Number of decimal places to display (default: 1)
589
+ * @param spec - Size specification to use: "si", "iec", or "jedec" (default: "jedec")
590
+ * @returns Human-readable file size string
591
+ */
592
592
  function filesize(bytes, fixed = 1, spec = "jedec") {
593
- bytes = Math.abs(bytes);
594
- const { radix, unit } = SPECS[spec] || SPECS.jedec;
595
- let loop = 0;
596
- while (bytes >= radix) {
597
- bytes /= radix;
598
- ++loop;
599
- }
600
- return `${bytes.toFixed(fixed)} ${unit[loop]}`;
593
+ bytes = Math.abs(bytes);
594
+ const { radix, unit } = SPECS[spec] || SPECS.jedec;
595
+ let loop = 0;
596
+ while (bytes >= radix) {
597
+ bytes /= radix;
598
+ ++loop;
599
+ }
600
+ return `${bytes.toFixed(fixed)} ${unit[loop]}`;
601
601
  }
602
+ //#endregion
603
+ //#region src/upload.ts
602
604
  async function upload(file_data, root_url, upload_id, max_file_size) {
603
- let files = (Array.isArray(file_data) ? file_data : [file_data]).map(
604
- (file_data2) => file_data2.blob
605
- );
606
- const oversized_files = files.filter(
607
- (f) => f.size > (max_file_size ?? Infinity)
608
- );
609
- if (oversized_files.length) {
610
- throw new Error(
611
- `File(s) exceed the maximum allowed size of ${filesize(max_file_size || Infinity)}: ${oversized_files.map((f) => `"${f.name}"`).join(", ")}`
612
- );
613
- }
614
- return await Promise.all(
615
- await this.upload_files(root_url, files, upload_id).then(
616
- async (response) => {
617
- if (response.error) {
618
- throw new Error(response.error);
619
- } else {
620
- if (response.files) {
621
- return response.files.map((f, i) => {
622
- const file = new FileData({
623
- ...file_data[i],
624
- path: f,
625
- url: `${root_url}${this.api_prefix}/file=${f}`
626
- });
627
- return file;
628
- });
629
- }
630
- return [];
631
- }
632
- }
633
- )
634
- );
605
+ let files = (Array.isArray(file_data) ? file_data : [file_data]).map((file_data) => file_data.blob);
606
+ const oversized_files = files.filter((f) => f.size > (max_file_size ?? Infinity));
607
+ if (oversized_files.length) throw new Error(`File(s) exceed the maximum allowed size of ${filesize(max_file_size || Infinity)}: ${oversized_files.map((f) => `"${f.name}"`).join(", ")}`);
608
+ return await Promise.all(await this.upload_files(root_url, files, upload_id).then(async (response) => {
609
+ if (response.error) throw new Error(response.error);
610
+ else {
611
+ if (response.files) return response.files.map((f, i) => {
612
+ return new FileData({
613
+ ...file_data[i],
614
+ path: f,
615
+ url: `${root_url}${this.api_prefix}/file=${f}`
616
+ });
617
+ });
618
+ return [];
619
+ }
620
+ }));
635
621
  }
636
622
  async function prepare_files(files, is_stream) {
637
- return files.map(
638
- (f) => new FileData({
639
- path: f.name,
640
- orig_name: f.name,
641
- blob: f,
642
- size: f.size,
643
- mime_type: f.type,
644
- is_stream
645
- })
646
- );
647
- }
648
- class FileData {
649
- path;
650
- url;
651
- orig_name;
652
- size;
653
- blob;
654
- is_stream;
655
- mime_type;
656
- alt_text;
657
- b64;
658
- meta = { _type: "gradio.FileData" };
659
- constructor({
660
- path,
661
- url,
662
- orig_name,
663
- size,
664
- blob,
665
- is_stream,
666
- mime_type,
667
- alt_text,
668
- b64
669
- }) {
670
- this.path = path;
671
- this.url = url;
672
- this.orig_name = orig_name;
673
- this.size = size;
674
- this.blob = url ? void 0 : blob;
675
- this.is_stream = is_stream;
676
- this.mime_type = mime_type;
677
- this.alt_text = alt_text;
678
- this.b64 = b64;
679
- }
680
- }
681
- class Command {
682
- type;
683
- command;
684
- meta;
685
- fileData;
686
- constructor(command, meta) {
687
- this.type = "command";
688
- this.command = command;
689
- this.meta = meta;
690
- }
691
- }
692
- const is_node = typeof process !== "undefined" && process.versions && process.versions.node;
623
+ return files.map((f) => new FileData({
624
+ path: f.name,
625
+ orig_name: f.name,
626
+ blob: f,
627
+ size: f.size,
628
+ mime_type: f.type,
629
+ is_stream
630
+ }));
631
+ }
632
+ var FileData = class {
633
+ path;
634
+ url;
635
+ orig_name;
636
+ size;
637
+ blob;
638
+ is_stream;
639
+ mime_type;
640
+ alt_text;
641
+ b64;
642
+ meta = { _type: "gradio.FileData" };
643
+ constructor({ path, url, orig_name, size, blob, is_stream, mime_type, alt_text, b64 }) {
644
+ this.path = path;
645
+ this.url = url;
646
+ this.orig_name = orig_name;
647
+ this.size = size;
648
+ this.blob = url ? void 0 : blob;
649
+ this.is_stream = is_stream;
650
+ this.mime_type = mime_type;
651
+ this.alt_text = alt_text;
652
+ this.b64 = b64;
653
+ }
654
+ };
655
+ //#endregion
656
+ //#region src/types.ts
657
+ var Command = class {
658
+ type;
659
+ command;
660
+ meta;
661
+ fileData;
662
+ constructor(command, meta) {
663
+ this.type = "command";
664
+ this.command = command;
665
+ this.meta = meta;
666
+ }
667
+ };
668
+ //#endregion
669
+ //#region src/helpers/data.ts
670
+ var is_node = typeof process !== "undefined" && process.versions && process.versions.node;
693
671
  function update_object(object, newValue, stack) {
694
- while (stack.length > 1) {
695
- const key2 = stack.shift();
696
- if (typeof key2 === "string" || typeof key2 === "number") {
697
- object = object[key2];
698
- } else {
699
- throw new Error("Invalid key type");
700
- }
701
- }
702
- const key = stack.shift();
703
- if (typeof key === "string" || typeof key === "number") {
704
- object[key] = newValue;
705
- } else {
706
- throw new Error("Invalid key type");
707
- }
672
+ while (stack.length > 1) {
673
+ const key = stack.shift();
674
+ if (typeof key === "string" || typeof key === "number") object = object[key];
675
+ else throw new Error("Invalid key type");
676
+ }
677
+ const key = stack.shift();
678
+ if (typeof key === "string" || typeof key === "number") object[key] = newValue;
679
+ else throw new Error("Invalid key type");
708
680
  }
709
681
  async function walk_and_store_blobs(data, type = void 0, path = [], root = false, endpoint_info = void 0) {
710
- if (Array.isArray(data)) {
711
- let blob_refs = [];
712
- await Promise.all(
713
- data.map(async (_, index) => {
714
- let new_path = path.slice();
715
- new_path.push(String(index));
716
- const array_refs = await walk_and_store_blobs(
717
- data[index],
718
- root ? endpoint_info?.parameters[index]?.component || void 0 : type,
719
- new_path,
720
- false,
721
- endpoint_info
722
- );
723
- blob_refs = blob_refs.concat(array_refs);
724
- })
725
- );
726
- return blob_refs;
727
- } else if (globalThis.Buffer && data instanceof globalThis.Buffer || data instanceof Blob) {
728
- return [
729
- {
730
- path,
731
- blob: new Blob([data]),
732
- type
733
- }
734
- ];
735
- } else if (typeof data === "object" && data !== null) {
736
- let blob_refs = [];
737
- for (const key of Object.keys(data)) {
738
- const new_path = [...path, key];
739
- const value = data[key];
740
- blob_refs = blob_refs.concat(
741
- await walk_and_store_blobs(
742
- value,
743
- void 0,
744
- new_path,
745
- false,
746
- endpoint_info
747
- )
748
- );
749
- }
750
- return blob_refs;
751
- }
752
- return [];
682
+ if (Array.isArray(data)) {
683
+ let blob_refs = [];
684
+ await Promise.all(data.map(async (_, index) => {
685
+ let new_path = path.slice();
686
+ new_path.push(String(index));
687
+ const array_refs = await walk_and_store_blobs(data[index], root ? endpoint_info?.parameters[index]?.component || void 0 : type, new_path, false, endpoint_info);
688
+ blob_refs = blob_refs.concat(array_refs);
689
+ }));
690
+ return blob_refs;
691
+ } else if (globalThis.Buffer && data instanceof globalThis.Buffer || data instanceof Blob) return [{
692
+ path,
693
+ blob: data instanceof Blob ? data : new Blob([data]),
694
+ type
695
+ }];
696
+ else if (typeof data === "object" && data !== null) {
697
+ let blob_refs = [];
698
+ for (const key of Object.keys(data)) {
699
+ const new_path = [...path, key];
700
+ const value = data[key];
701
+ blob_refs = blob_refs.concat(await walk_and_store_blobs(value, void 0, new_path, false, endpoint_info));
702
+ }
703
+ return blob_refs;
704
+ }
705
+ return [];
753
706
  }
754
707
  function skip_queue(id, config) {
755
- let fn_queue = config?.dependencies?.find((dep) => dep.id == id)?.queue;
756
- if (fn_queue != null) {
757
- return !fn_queue;
758
- }
759
- return !config.enable_queue;
708
+ let fn_queue = config?.dependencies?.find((dep) => dep.id == id)?.queue;
709
+ if (fn_queue != null) return !fn_queue;
710
+ return !config.enable_queue;
760
711
  }
761
712
  function post_message(message, origin) {
762
- return new Promise((res, _rej) => {
763
- const channel = new MessageChannel();
764
- channel.port1.onmessage = (({ data }) => {
765
- channel.port1.close();
766
- res(data);
767
- });
768
- window.parent.postMessage(message, origin, [channel.port2]);
769
- });
713
+ return new Promise((res, _rej) => {
714
+ const channel = new MessageChannel();
715
+ channel.port1.onmessage = (({ data }) => {
716
+ channel.port1.close();
717
+ res(data);
718
+ });
719
+ window.parent.postMessage(message, origin, [channel.port2]);
720
+ });
770
721
  }
771
722
  function handle_file(file_or_url) {
772
- if (typeof file_or_url === "string") {
773
- if (file_or_url.startsWith("http://") || file_or_url.startsWith("https://")) {
774
- return {
775
- path: file_or_url,
776
- url: file_or_url,
777
- orig_name: file_or_url.split("/").pop() ?? "unknown",
778
- meta: { _type: "gradio.FileData" }
779
- };
780
- }
781
- if (is_node) {
782
- return new Command("upload_file", {
783
- path: file_or_url,
784
- name: file_or_url,
785
- orig_path: file_or_url
786
- });
787
- }
788
- } else if (typeof File !== "undefined" && file_or_url instanceof File) {
789
- return new Blob([file_or_url]);
790
- } else if (file_or_url instanceof Buffer) {
791
- return new Blob([file_or_url]);
792
- } else if (file_or_url instanceof Blob) {
793
- return file_or_url;
794
- }
795
- throw new Error(
796
- "Invalid input: must be a URL, File, Blob, or Buffer object."
797
- );
723
+ if (typeof file_or_url === "string") {
724
+ if (file_or_url.startsWith("http://") || file_or_url.startsWith("https://")) return {
725
+ path: file_or_url,
726
+ url: file_or_url,
727
+ orig_name: file_or_url.split("/").pop() ?? "unknown",
728
+ meta: { _type: "gradio.FileData" }
729
+ };
730
+ if (is_node) return new Command("upload_file", {
731
+ path: file_or_url,
732
+ name: file_or_url,
733
+ orig_path: file_or_url
734
+ });
735
+ } else if (typeof File !== "undefined" && file_or_url instanceof File) return file_or_url;
736
+ else if (globalThis.Buffer && file_or_url instanceof globalThis.Buffer) return new Blob([file_or_url]);
737
+ else if (file_or_url instanceof Blob) return file_or_url;
738
+ throw new Error("Invalid input: must be a URL, File, Blob, or Buffer object.");
798
739
  }
740
+ /**
741
+ * Handles the payload by filtering out state inputs and returning an array of resolved payload values.
742
+ * We send null values for state inputs to the server, but we don't want to include them in the resolved payload.
743
+ *
744
+ * @param resolved_payload - The resolved payload values received from the client or the server
745
+ * @param dependency - The dependency object.
746
+ * @param components - The array of component metadata.
747
+ * @param with_null_state - Optional. Specifies whether to include null values for state inputs. Default is false.
748
+ * @returns An array of resolved payload values, filtered based on the dependency and component metadata.
749
+ */
799
750
  function handle_payload(resolved_payload, dependency, components, type, with_null_state = false) {
800
- if (type === "input" && !with_null_state) {
801
- throw new Error("Invalid code path. Cannot skip state inputs for input.");
802
- }
803
- if (type === "output" && with_null_state) {
804
- return resolved_payload;
805
- }
806
- let updated_payload = [];
807
- let payload_index = 0;
808
- const deps = type === "input" ? dependency.inputs : dependency.outputs;
809
- for (let i = 0; i < deps.length; i++) {
810
- const input_id = deps[i];
811
- const component = components.find((c) => c.id === input_id);
812
- if (component?.type === "state") {
813
- if (with_null_state) {
814
- if (resolved_payload.length === deps.length) {
815
- const value = resolved_payload[payload_index];
816
- updated_payload.push(value);
817
- payload_index++;
818
- } else {
819
- updated_payload.push(null);
820
- }
821
- } else {
822
- payload_index++;
823
- continue;
824
- }
825
- continue;
826
- } else {
827
- const value = resolved_payload[payload_index];
828
- updated_payload.push(value);
829
- payload_index++;
830
- }
831
- }
832
- return updated_payload;
751
+ if (type === "input" && !with_null_state) throw new Error("Invalid code path. Cannot skip state inputs for input.");
752
+ if (type === "output" && with_null_state) return resolved_payload;
753
+ let updated_payload = [];
754
+ let payload_index = 0;
755
+ const deps = type === "input" ? dependency.inputs : dependency.outputs;
756
+ for (let i = 0; i < deps.length; i++) {
757
+ const input_id = deps[i];
758
+ if (components.find((c) => c.id === input_id)?.type === "state") {
759
+ if (with_null_state) if (resolved_payload.length === deps.length) {
760
+ const value = resolved_payload[payload_index];
761
+ updated_payload.push(value);
762
+ payload_index++;
763
+ } else updated_payload.push(null);
764
+ else {
765
+ payload_index++;
766
+ continue;
767
+ }
768
+ continue;
769
+ } else {
770
+ const value = resolved_payload[payload_index];
771
+ updated_payload.push(value);
772
+ payload_index++;
773
+ }
774
+ }
775
+ return updated_payload;
833
776
  }
777
+ //#endregion
778
+ //#region src/utils/handle_blob.ts
834
779
  async function handle_blob(endpoint, data, api_info) {
835
- const self = this;
836
- await process_local_file_commands(self, data);
837
- const blobRefs = await walk_and_store_blobs(
838
- data,
839
- void 0,
840
- [],
841
- true,
842
- api_info
843
- );
844
- const results = await Promise.all(
845
- blobRefs.map(async ({ path, blob, type }) => {
846
- if (!blob) return { path, type };
847
- const response = await self.upload_files(endpoint, [blob]);
848
- const file_url = response.files && response.files[0];
849
- return {
850
- path,
851
- file_url,
852
- type,
853
- name: typeof File !== "undefined" && blob instanceof File ? blob?.name : void 0
854
- };
855
- })
856
- );
857
- results.forEach(({ path, file_url, type, name }) => {
858
- if (type === "Gallery") {
859
- update_object(data, file_url, path);
860
- } else if (file_url) {
861
- const file = new FileData({ path: file_url, orig_name: name });
862
- update_object(data, file, path);
863
- }
864
- });
865
- return data;
866
- }
867
- async function process_local_file_commands(client2, data) {
868
- const root = client2.config?.root || client2.config?.root_url;
869
- if (!root) {
870
- throw new Error(ROOT_URL_ERROR_MSG);
871
- }
872
- await recursively_process_commands(client2, data);
873
- }
874
- async function recursively_process_commands(client2, data, path = []) {
875
- for (const key in data) {
876
- if (data[key] instanceof Command) {
877
- await process_single_command(client2, data, key);
878
- } else if (typeof data[key] === "object" && data[key] !== null) {
879
- await recursively_process_commands(client2, data[key], [...path, key]);
880
- }
881
- }
882
- }
883
- async function process_single_command(client2, data, key) {
884
- let cmd_item = data[key];
885
- const root = client2.config?.root || client2.config?.root_url;
886
- if (!root) {
887
- throw new Error(ROOT_URL_ERROR_MSG);
888
- }
889
- try {
890
- let fileBuffer;
891
- let fullPath;
892
- if (typeof process !== "undefined" && process.versions && process.versions.node) {
893
- const fs = await import("fs/promises");
894
- const path = await import("path");
895
- fullPath = path.resolve(process.cwd(), cmd_item.meta.path);
896
- fileBuffer = await fs.readFile(fullPath);
897
- } else {
898
- throw new Error(NODEJS_FS_ERROR_MSG);
899
- }
900
- const file = new Blob([fileBuffer], {
901
- type: "application/octet-stream"
902
- });
903
- const response = await client2.upload_files(root, [file]);
904
- const file_url = response.files && response.files[0];
905
- if (file_url) {
906
- const fileData = new FileData({
907
- path: file_url,
908
- orig_name: cmd_item.meta.name || ""
909
- });
910
- data[key] = fileData;
911
- }
912
- } catch (error) {
913
- console.error(FILE_PROCESSING_ERROR_MSG, error);
914
- }
780
+ const self = this;
781
+ await process_local_file_commands(self, data);
782
+ const blobRefs = await walk_and_store_blobs(data, void 0, [], true, api_info);
783
+ (await Promise.all(blobRefs.map(async ({ path, blob, type }) => {
784
+ if (!blob) return {
785
+ path,
786
+ type
787
+ };
788
+ const response = await self.upload_files(endpoint, [blob]);
789
+ return {
790
+ path,
791
+ file_url: response.files && response.files[0],
792
+ type,
793
+ name: typeof File !== "undefined" && blob instanceof File ? blob?.name : void 0
794
+ };
795
+ }))).forEach(({ path, file_url, type, name }) => {
796
+ if (type === "Gallery") update_object(data, file_url, path);
797
+ else if (file_url) update_object(data, new FileData({
798
+ path: file_url,
799
+ orig_name: name
800
+ }), path);
801
+ });
802
+ return data;
803
+ }
804
+ async function process_local_file_commands(client, data) {
805
+ if (!(client.config?.root || client.config?.root_url)) throw new Error(ROOT_URL_ERROR_MSG);
806
+ await recursively_process_commands(client, data);
915
807
  }
808
+ async function recursively_process_commands(client, data, path = []) {
809
+ for (const key in data) if (data[key] instanceof Command) await process_single_command(client, data, key);
810
+ else if (typeof data[key] === "object" && data[key] !== null) await recursively_process_commands(client, data[key], [...path, key]);
811
+ }
812
+ async function process_single_command(client, data, key) {
813
+ let cmd_item = data[key];
814
+ const root = client.config?.root || client.config?.root_url;
815
+ if (!root) throw new Error(ROOT_URL_ERROR_MSG);
816
+ try {
817
+ let fileBuffer;
818
+ let fullPath;
819
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
820
+ const fs = await import("fs/promises");
821
+ fullPath = (await import("path")).resolve(process.cwd(), cmd_item.meta.path);
822
+ fileBuffer = await fs.readFile(fullPath);
823
+ } else throw new Error(NODEJS_FS_ERROR_MSG);
824
+ const file = new Blob([fileBuffer], { type: "application/octet-stream" });
825
+ const response = await client.upload_files(root, [file]);
826
+ const file_url = response.files && response.files[0];
827
+ if (file_url) data[key] = new FileData({
828
+ path: file_url,
829
+ orig_name: cmd_item.meta.name || ""
830
+ });
831
+ } catch (error) {
832
+ console.error(FILE_PROCESSING_ERROR_MSG, error);
833
+ }
834
+ }
835
+ //#endregion
836
+ //#region src/utils/post_data.ts
916
837
  async function post_data(url, body, additional_headers) {
917
- const headers = { "Content-Type": "application/json" };
918
- if (this.options.token) {
919
- headers.Authorization = `Bearer ${this.options.token}`;
920
- }
921
- try {
922
- var response = await this.fetch(url, {
923
- method: "POST",
924
- body: JSON.stringify(body),
925
- headers: { ...headers, ...additional_headers },
926
- credentials: this.options.credentials ?? "same-origin"
927
- });
928
- } catch (e) {
929
- return [{ error: BROKEN_CONNECTION_MSG }, 500];
930
- }
931
- let output;
932
- let status;
933
- try {
934
- output = await response.json();
935
- status = response.status;
936
- } catch (e) {
937
- output = { error: `Could not parse server response: ${e}` };
938
- status = 500;
939
- }
940
- return [output, status];
838
+ const headers = { "Content-Type": "application/json" };
839
+ if (this.options.token) headers.Authorization = `Bearer ${this.options.token}`;
840
+ try {
841
+ var response = await this.fetch(url, {
842
+ method: "POST",
843
+ body: JSON.stringify(body),
844
+ headers: {
845
+ ...headers,
846
+ ...additional_headers
847
+ },
848
+ credentials: this.options.credentials ?? "same-origin"
849
+ });
850
+ } catch (e) {
851
+ return [{ error: BROKEN_CONNECTION_MSG }, 500];
852
+ }
853
+ let output;
854
+ let status;
855
+ try {
856
+ output = await response.json();
857
+ status = response.status;
858
+ } catch (e) {
859
+ output = { error: `Could not parse server response: ${e}` };
860
+ status = 500;
861
+ }
862
+ return [output, status];
941
863
  }
864
+ //#endregion
865
+ //#region src/utils/predict.ts
942
866
  async function predict(endpoint, data = {}) {
943
- let data_returned = false;
944
- let status_complete = false;
945
- if (!this.config) {
946
- throw new Error("Could not resolve app config");
947
- }
948
- if (typeof endpoint === "number") {
949
- this.config.dependencies.find((dep) => dep.id == endpoint);
950
- } else {
951
- const trimmed_endpoint = endpoint.replace(/^\//, "");
952
- this.config.dependencies.find(
953
- (dep) => dep.id == this.api_map[trimmed_endpoint]
954
- );
955
- }
956
- const app = this.submit(endpoint, data, null, null, true);
957
- let result;
958
- for await (const message of app) {
959
- if (message.type === "data") {
960
- data_returned = true;
961
- result = message;
962
- if (status_complete) {
963
- return result;
964
- }
965
- }
966
- if (message.type === "status") {
967
- if (message.stage === "error") {
968
- throw message;
969
- }
970
- if (message.stage === "complete") {
971
- status_complete = true;
972
- if (data_returned) {
973
- return result;
974
- }
975
- }
976
- }
977
- }
978
- return result;
867
+ let data_returned = false;
868
+ let status_complete = false;
869
+ if (!this.config) throw new Error("Could not resolve app config");
870
+ if (typeof endpoint === "number") this.config.dependencies.find((dep) => dep.id == endpoint);
871
+ else {
872
+ const trimmed_endpoint = endpoint.replace(/^\//, "");
873
+ this.config.dependencies.find((dep) => dep.id == this.api_map[trimmed_endpoint]);
874
+ }
875
+ const app = this.submit(endpoint, data, null, null, true);
876
+ let result;
877
+ for await (const message of app) {
878
+ if (message.type === "data") {
879
+ data_returned = true;
880
+ result = message;
881
+ if (status_complete) return result;
882
+ }
883
+ if (message.type === "status") {
884
+ if (message.stage === "error") {
885
+ const { message: error_message, ...status } = message;
886
+ const error = new Error((typeof error_message === "string" ? error_message : error_message && JSON.stringify(error_message)) || "An unknown error occurred while making a prediction.");
887
+ Object.assign(error, status);
888
+ throw error;
889
+ }
890
+ if (message.stage === "complete") {
891
+ status_complete = true;
892
+ if (data_returned) return result;
893
+ }
894
+ }
895
+ }
896
+ return result;
979
897
  }
898
+ //#endregion
899
+ //#region src/helpers/spaces.ts
980
900
  async function check_space_status(id, type, status_callback) {
981
- let endpoint = type === "subdomain" ? `https://huggingface.co/api/spaces/by-subdomain/${id}` : `https://huggingface.co/api/spaces/${id}`;
982
- let response;
983
- let _status;
984
- try {
985
- response = await fetch(endpoint);
986
- _status = response.status;
987
- if (_status !== 200) {
988
- throw new Error();
989
- }
990
- response = await response.json();
991
- } catch (e) {
992
- status_callback({
993
- status: "error",
994
- load_status: "error",
995
- message: SPACE_STATUS_ERROR_MSG,
996
- detail: "NOT_FOUND"
997
- });
998
- return;
999
- }
1000
- if (!response || _status !== 200) return;
1001
- const {
1002
- runtime: { stage },
1003
- id: space_name
1004
- } = response;
1005
- switch (stage) {
1006
- case "STOPPED":
1007
- case "SLEEPING":
1008
- status_callback({
1009
- status: "sleeping",
1010
- load_status: "pending",
1011
- message: "Space is asleep. Waking it up...",
1012
- detail: stage
1013
- });
1014
- setTimeout(() => {
1015
- check_space_status(id, type, status_callback);
1016
- }, 1e3);
1017
- break;
1018
- case "PAUSED":
1019
- status_callback({
1020
- status: "paused",
1021
- load_status: "error",
1022
- message: "This space has been paused by the author. If you would like to try this demo, consider duplicating the space.",
1023
- detail: stage,
1024
- discussions_enabled: await discussions_enabled(space_name)
1025
- });
1026
- break;
1027
- case "RUNNING":
1028
- case "RUNNING_BUILDING":
1029
- status_callback({
1030
- status: "running",
1031
- load_status: "complete",
1032
- message: "Space is running.",
1033
- detail: stage
1034
- });
1035
- break;
1036
- case "BUILDING":
1037
- status_callback({
1038
- status: "building",
1039
- load_status: "pending",
1040
- message: "Space is building...",
1041
- detail: stage
1042
- });
1043
- setTimeout(() => {
1044
- check_space_status(id, type, status_callback);
1045
- }, 1e3);
1046
- break;
1047
- case "APP_STARTING":
1048
- status_callback({
1049
- status: "starting",
1050
- load_status: "pending",
1051
- message: "Space is starting...",
1052
- detail: stage
1053
- });
1054
- setTimeout(() => {
1055
- check_space_status(id, type, status_callback);
1056
- }, 1e3);
1057
- break;
1058
- default:
1059
- status_callback({
1060
- status: "space_error",
1061
- load_status: "error",
1062
- message: "This space is experiencing an issue.",
1063
- detail: stage,
1064
- discussions_enabled: await discussions_enabled(space_name)
1065
- });
1066
- break;
1067
- }
1068
- }
1069
- const check_and_wake_space = async (space_id, status_callback) => {
1070
- let retries = 0;
1071
- const max_retries = 12;
1072
- const check_interval = 5e3;
1073
- return new Promise((resolve) => {
1074
- check_space_status(
1075
- space_id,
1076
- RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain",
1077
- (status) => {
1078
- status_callback(status);
1079
- if (status.status === "running") {
1080
- resolve();
1081
- } else if (status.status === "error" || status.status === "paused" || status.status === "space_error") {
1082
- resolve();
1083
- } else if (status.status === "sleeping" || status.status === "building") {
1084
- if (retries < max_retries) {
1085
- retries++;
1086
- setTimeout(() => {
1087
- check_and_wake_space(space_id, status_callback).then(resolve);
1088
- }, check_interval);
1089
- } else {
1090
- resolve();
1091
- }
1092
- }
1093
- }
1094
- );
1095
- });
901
+ let endpoint = type === "subdomain" ? `https://huggingface.co/api/spaces/by-subdomain/${id}` : `https://huggingface.co/api/spaces/${id}`;
902
+ let response;
903
+ let _status;
904
+ try {
905
+ response = await fetch(endpoint);
906
+ _status = response.status;
907
+ if (_status !== 200) throw new Error();
908
+ response = await response.json();
909
+ } catch (e) {
910
+ status_callback({
911
+ status: "error",
912
+ load_status: "error",
913
+ message: SPACE_STATUS_ERROR_MSG,
914
+ detail: "NOT_FOUND"
915
+ });
916
+ return;
917
+ }
918
+ if (!response || _status !== 200) return;
919
+ const { runtime: { stage }, id: space_name } = response;
920
+ switch (stage) {
921
+ case "STOPPED":
922
+ case "SLEEPING":
923
+ status_callback({
924
+ status: "sleeping",
925
+ load_status: "pending",
926
+ message: "Space is asleep. Waking it up...",
927
+ detail: stage
928
+ });
929
+ setTimeout(() => {
930
+ check_space_status(id, type, status_callback);
931
+ }, 1e3);
932
+ break;
933
+ case "PAUSED":
934
+ status_callback({
935
+ status: "paused",
936
+ load_status: "error",
937
+ message: "This space has been paused by the author. If you would like to try this demo, consider duplicating the space.",
938
+ detail: stage,
939
+ discussions_enabled: await discussions_enabled(space_name)
940
+ });
941
+ break;
942
+ case "RUNNING":
943
+ case "RUNNING_BUILDING":
944
+ status_callback({
945
+ status: "running",
946
+ load_status: "complete",
947
+ message: "Space is running.",
948
+ detail: stage
949
+ });
950
+ break;
951
+ case "BUILDING":
952
+ status_callback({
953
+ status: "building",
954
+ load_status: "pending",
955
+ message: "Space is building...",
956
+ detail: stage
957
+ });
958
+ setTimeout(() => {
959
+ check_space_status(id, type, status_callback);
960
+ }, 1e3);
961
+ break;
962
+ case "APP_STARTING":
963
+ status_callback({
964
+ status: "starting",
965
+ load_status: "pending",
966
+ message: "Space is starting...",
967
+ detail: stage
968
+ });
969
+ setTimeout(() => {
970
+ check_space_status(id, type, status_callback);
971
+ }, 1e3);
972
+ break;
973
+ default:
974
+ status_callback({
975
+ status: "space_error",
976
+ load_status: "error",
977
+ message: "This space is experiencing an issue.",
978
+ detail: stage,
979
+ discussions_enabled: await discussions_enabled(space_name)
980
+ });
981
+ break;
982
+ }
983
+ }
984
+ var check_and_wake_space = async (space_id, status_callback) => {
985
+ let retries = 0;
986
+ const max_retries = 12;
987
+ const check_interval = 5e3;
988
+ return new Promise((resolve) => {
989
+ check_space_status(space_id, RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", (status) => {
990
+ status_callback(status);
991
+ if (status.status === "running") resolve();
992
+ else if (status.status === "error" || status.status === "paused" || status.status === "space_error") resolve();
993
+ else if (status.status === "sleeping" || status.status === "building") if (retries < max_retries) {
994
+ retries++;
995
+ setTimeout(() => {
996
+ check_and_wake_space(space_id, status_callback).then(resolve);
997
+ }, check_interval);
998
+ } else resolve();
999
+ });
1000
+ });
1096
1001
  };
1097
- const RE_DISABLED_DISCUSSION = /^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/;
1002
+ var RE_DISABLED_DISCUSSION = /^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/;
1098
1003
  async function discussions_enabled(space_id) {
1099
- try {
1100
- const r = await fetch(
1101
- `https://huggingface.co/api/spaces/${space_id}/discussions`,
1102
- {
1103
- method: "HEAD"
1104
- }
1105
- );
1106
- const error = r.headers.get("x-error-message");
1107
- if (!r.ok || error && RE_DISABLED_DISCUSSION.test(error)) return false;
1108
- return true;
1109
- } catch (e) {
1110
- return false;
1111
- }
1004
+ try {
1005
+ const r = await fetch(`https://huggingface.co/api/spaces/${space_id}/discussions`, { method: "HEAD" });
1006
+ const error = r.headers.get("x-error-message");
1007
+ if (!r.ok || error && RE_DISABLED_DISCUSSION.test(error)) return false;
1008
+ return true;
1009
+ } catch (e) {
1010
+ return false;
1011
+ }
1112
1012
  }
1113
1013
  async function get_space_hardware(space_id, token) {
1114
- const headers = {};
1115
- if (token) {
1116
- headers.Authorization = `Bearer ${token}`;
1117
- }
1118
- try {
1119
- const res = await fetch(
1120
- `https://huggingface.co/api/spaces/${space_id}/${RUNTIME_URL}`,
1121
- { headers }
1122
- );
1123
- if (res.status !== 200)
1124
- throw new Error("Space hardware could not be obtained.");
1125
- const { hardware } = await res.json();
1126
- return hardware.current;
1127
- } catch (e) {
1128
- throw new Error(e.message);
1129
- }
1014
+ const headers = {};
1015
+ if (token) headers.Authorization = `Bearer ${token}`;
1016
+ try {
1017
+ const res = await fetch(`https://huggingface.co/api/spaces/${space_id}/${RUNTIME_URL}`, { headers });
1018
+ if (res.status !== 200) throw new Error("Space hardware could not be obtained.");
1019
+ const { hardware } = await res.json();
1020
+ return hardware.current;
1021
+ } catch (e) {
1022
+ throw new Error(e.message);
1023
+ }
1130
1024
  }
1131
1025
  async function set_space_timeout(space_id, timeout, token) {
1132
- const headers = {};
1133
- if (token) {
1134
- headers.Authorization = `Bearer ${token}`;
1135
- }
1136
- const body = {
1137
- seconds: timeout
1138
- };
1139
- try {
1140
- const res = await fetch(
1141
- `https://huggingface.co/api/spaces/${space_id}/${SLEEPTIME_URL}`,
1142
- {
1143
- method: "POST",
1144
- headers: { "Content-Type": "application/json", ...headers },
1145
- body: JSON.stringify(body)
1146
- }
1147
- );
1148
- if (res.status !== 200) {
1149
- throw new Error(
1150
- "Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges."
1151
- );
1152
- }
1153
- const response = await res.json();
1154
- return response;
1155
- } catch (e) {
1156
- throw new Error(e.message);
1157
- }
1158
- }
1159
- const hardware_types = [
1160
- "cpu-basic",
1161
- "cpu-upgrade",
1162
- "cpu-xl",
1163
- "t4-small",
1164
- "t4-medium",
1165
- "a10g-small",
1166
- "a10g-large",
1167
- "a10g-largex2",
1168
- "a10g-largex4",
1169
- "a100-large",
1170
- "zero-a10g",
1171
- "h100",
1172
- "h100x8"
1026
+ const headers = {};
1027
+ if (token) headers.Authorization = `Bearer ${token}`;
1028
+ const body = { seconds: timeout };
1029
+ try {
1030
+ const res = await fetch(`https://huggingface.co/api/spaces/${space_id}/${SLEEPTIME_URL}`, {
1031
+ method: "POST",
1032
+ headers: {
1033
+ "Content-Type": "application/json",
1034
+ ...headers
1035
+ },
1036
+ body: JSON.stringify(body)
1037
+ });
1038
+ if (res.status !== 200) throw new Error("Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges.");
1039
+ return await res.json();
1040
+ } catch (e) {
1041
+ throw new Error(e.message);
1042
+ }
1043
+ }
1044
+ var hardware_types = [
1045
+ "cpu-basic",
1046
+ "cpu-upgrade",
1047
+ "cpu-xl",
1048
+ "t4-small",
1049
+ "t4-medium",
1050
+ "a10g-small",
1051
+ "a10g-large",
1052
+ "a10g-largex2",
1053
+ "a10g-largex4",
1054
+ "a100-large",
1055
+ "zero-a10g",
1056
+ "h100",
1057
+ "h100x8"
1173
1058
  ];
1059
+ //#endregion
1060
+ //#region src/utils/duplicate.ts
1174
1061
  async function duplicate(app_reference, options) {
1175
- const { token, private: _private, hardware, timeout, auth } = options;
1176
- if (hardware && !hardware_types.includes(hardware)) {
1177
- throw new Error(
1178
- `Invalid hardware type provided. Valid types are: ${hardware_types.map((v) => `"${v}"`).join(",")}.`
1179
- );
1180
- }
1181
- const { http_protocol, host } = await process_endpoint(app_reference, token);
1182
- let cookies = null;
1183
- if (auth) {
1184
- const cookie_header = await get_cookie_header(
1185
- http_protocol,
1186
- host,
1187
- auth,
1188
- fetch,
1189
- void 0,
1190
- options.credentials
1191
- );
1192
- if (cookie_header) cookies = parse_and_set_cookies(cookie_header);
1193
- }
1194
- const headers = {
1195
- Authorization: `Bearer ${token}`,
1196
- "Content-Type": "application/json",
1197
- ...cookies ? { Cookie: cookies.join("; ") } : {}
1198
- };
1199
- const user = (await (await fetch(`https://huggingface.co/api/whoami-v2`, {
1200
- headers
1201
- })).json()).name;
1202
- const space_name = app_reference.split("/")[1];
1203
- const body = {
1204
- repository: `${user}/${space_name}`
1205
- };
1206
- if (_private) {
1207
- body.private = true;
1208
- }
1209
- let original_hardware;
1210
- try {
1211
- if (!hardware) {
1212
- original_hardware = await get_space_hardware(app_reference, token);
1213
- }
1214
- } catch (e) {
1215
- throw Error(SPACE_METADATA_ERROR_MSG + e.message);
1216
- }
1217
- const requested_hardware = hardware || original_hardware || "cpu-basic";
1218
- body.hardware = requested_hardware;
1219
- try {
1220
- const response = await fetch(
1221
- `https://huggingface.co/api/spaces/${app_reference}/duplicate`,
1222
- {
1223
- method: "POST",
1224
- headers,
1225
- body: JSON.stringify(body)
1226
- }
1227
- );
1228
- if (response.status === 409) {
1229
- try {
1230
- const client2 = await Client.connect(`${user}/${space_name}`, options);
1231
- return client2;
1232
- } catch (error) {
1233
- console.error("Failed to connect Client instance:", error);
1234
- throw error;
1235
- }
1236
- } else if (response.status !== 200) {
1237
- throw new Error(response.statusText);
1238
- }
1239
- const duplicated_space = await response.json();
1240
- await set_space_timeout(`${user}/${space_name}`, timeout || 300, token);
1241
- return await Client.connect(
1242
- get_space_reference(duplicated_space.url),
1243
- options
1244
- );
1245
- } catch (e) {
1246
- throw new Error(e);
1247
- }
1062
+ normalise_token_option(options);
1063
+ const { token, private: _private, hardware, timeout, auth } = options;
1064
+ if (hardware && !hardware_types.includes(hardware)) throw new Error(`Invalid hardware type provided. Valid types are: ${hardware_types.map((v) => `"${v}"`).join(",")}.`);
1065
+ const { http_protocol, host } = await process_endpoint(app_reference, token);
1066
+ let cookies = null;
1067
+ if (auth) {
1068
+ const cookie_header = await get_cookie_header(http_protocol, host, auth, fetch, void 0, options.credentials);
1069
+ if (cookie_header) cookies = parse_and_set_cookies(cookie_header);
1070
+ }
1071
+ const headers = {
1072
+ Authorization: `Bearer ${token}`,
1073
+ "Content-Type": "application/json",
1074
+ ...cookies ? { Cookie: cookies.join("; ") } : {}
1075
+ };
1076
+ const user = (await (await fetch(`https://huggingface.co/api/whoami-v2`, { headers })).json()).name;
1077
+ const space_name = app_reference.split("/")[1];
1078
+ const body = { repository: `${user}/${space_name}` };
1079
+ if (_private) body.private = true;
1080
+ let original_hardware;
1081
+ try {
1082
+ if (!hardware) original_hardware = await get_space_hardware(app_reference, token);
1083
+ } catch (e) {
1084
+ throw Error(SPACE_METADATA_ERROR_MSG + e.message);
1085
+ }
1086
+ body.hardware = hardware || original_hardware || "cpu-basic";
1087
+ try {
1088
+ const response = await fetch(`https://huggingface.co/api/spaces/${app_reference}/duplicate`, {
1089
+ method: "POST",
1090
+ headers,
1091
+ body: JSON.stringify(body)
1092
+ });
1093
+ if (response.status === 409) try {
1094
+ return await Client.connect(`${user}/${space_name}`, options);
1095
+ } catch (error) {
1096
+ console.error("Failed to connect Client instance:", error);
1097
+ throw error;
1098
+ }
1099
+ else if (response.status !== 200) throw new Error(response.statusText);
1100
+ const duplicated_space = await response.json();
1101
+ await set_space_timeout(`${user}/${space_name}`, timeout || 300, token);
1102
+ return await Client.connect(get_space_reference(duplicated_space.url), options);
1103
+ } catch (e) {
1104
+ throw new Error(e);
1105
+ }
1248
1106
  }
1249
1107
  function get_space_reference(url) {
1250
- const regex = /https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/;
1251
- const match = url.match(regex);
1252
- if (match) {
1253
- return match[1];
1254
- }
1255
- }
1256
- const ZEROGPU_HEADERS_MESSAGE = "supports-zerogpu-headers";
1257
- let zerogpu_handshake_initialized = false;
1108
+ const match = url.match(/https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/);
1109
+ if (match) return match[1];
1110
+ }
1111
+ //#endregion
1112
+ //#region src/helpers/zerogpu.ts
1113
+ var ZEROGPU_HEADERS_MESSAGE = "supports-zerogpu-headers";
1114
+ var zerogpu_handshake_initialized = false;
1258
1115
  function supports_browser_handshake() {
1259
- return typeof window !== "undefined" && typeof document !== "undefined" && typeof window.addEventListener === "function";
1116
+ return typeof window !== "undefined" && typeof document !== "undefined" && typeof window.addEventListener === "function";
1260
1117
  }
1261
1118
  function get_zerogpu_origin(hostname) {
1262
- if (hostname.includes(".dev.")) {
1263
- return `https://moon-${hostname.split(".")[1]}.dev.spaces.huggingface.tech`;
1264
- }
1265
- if (hostname.endsWith(".hf.space")) {
1266
- return "https://huggingface.co";
1267
- }
1268
- return null;
1119
+ if (hostname.includes(".dev.")) return `https://moon-${hostname.split(".")[1]}.dev.spaces.huggingface.tech`;
1120
+ if (hostname.endsWith(".hf.space")) return "https://huggingface.co";
1121
+ return null;
1269
1122
  }
1270
1123
  function initialize_zerogpu_handshake() {
1271
- if (!supports_browser_handshake() || zerogpu_handshake_initialized) {
1272
- return;
1273
- }
1274
- window.addEventListener("message", (event) => {
1275
- if (event.data === ZEROGPU_HEADERS_MESSAGE) {
1276
- window.supports_zerogpu_headers = true;
1277
- }
1278
- });
1279
- zerogpu_handshake_initialized = true;
1280
- const origin = get_zerogpu_origin(window.location.hostname);
1281
- if (origin && window.parent !== window) {
1282
- window.parent.postMessage(ZEROGPU_HEADERS_MESSAGE, origin);
1283
- }
1284
- }
1285
- class TextLineStream extends TransformStream {
1286
- #currentLine = "";
1287
- /** Constructs a new instance. */
1288
- constructor(options = { allowCR: false }) {
1289
- super({
1290
- transform: (chars, controller) => {
1291
- chars = this.#currentLine + chars;
1292
- while (true) {
1293
- const lfIndex = chars.indexOf("\n");
1294
- const crIndex = options.allowCR ? chars.indexOf("\r") : -1;
1295
- if (crIndex !== -1 && crIndex !== chars.length - 1 && (lfIndex === -1 || lfIndex - 1 > crIndex)) {
1296
- controller.enqueue(chars.slice(0, crIndex));
1297
- chars = chars.slice(crIndex + 1);
1298
- continue;
1299
- }
1300
- if (lfIndex === -1)
1301
- break;
1302
- const endIndex = chars[lfIndex - 1] === "\r" ? lfIndex - 1 : lfIndex;
1303
- controller.enqueue(chars.slice(0, endIndex));
1304
- chars = chars.slice(lfIndex + 1);
1305
- }
1306
- this.#currentLine = chars;
1307
- },
1308
- flush: (controller) => {
1309
- if (this.#currentLine === "")
1310
- return;
1311
- const currentLine = options.allowCR && this.#currentLine.endsWith("\r") ? this.#currentLine.slice(0, -1) : this.#currentLine;
1312
- controller.enqueue(currentLine);
1313
- }
1314
- });
1315
- }
1124
+ if (!supports_browser_handshake() || zerogpu_handshake_initialized) return;
1125
+ window.addEventListener("message", (event) => {
1126
+ if (event.data === ZEROGPU_HEADERS_MESSAGE) window.supports_zerogpu_headers = true;
1127
+ });
1128
+ zerogpu_handshake_initialized = true;
1129
+ const origin = get_zerogpu_origin(window.location.hostname);
1130
+ if (origin && window.parent !== window) window.parent.postMessage(ZEROGPU_HEADERS_MESSAGE, origin);
1316
1131
  }
1132
+ //#endregion
1133
+ //#region ../../node_modules/.pnpm/fetch-event-stream@0.1.6/node_modules/fetch-event-stream/esm/deps/jsr.io/@std/streams/0.221.0/text_line_stream.js
1134
+ /**
1135
+ * Transform a stream into a stream where each chunk is divided by a newline,
1136
+ * be it `\n` or `\r\n`. `\r` can be enabled via the `allowCR` option.
1137
+ *
1138
+ * @example
1139
+ * ```ts
1140
+ * import { TextLineStream } from "@std/streams/text-line-stream";
1141
+ *
1142
+ * const res = await fetch("https://example.com");
1143
+ * const lines = res.body!
1144
+ * .pipeThrough(new TextDecoderStream())
1145
+ * .pipeThrough(new TextLineStream());
1146
+ * ```
1147
+ */
1148
+ var TextLineStream = class extends TransformStream {
1149
+ #currentLine = "";
1150
+ /** Constructs a new instance. */
1151
+ constructor(options = { allowCR: false }) {
1152
+ super({
1153
+ transform: (chars, controller) => {
1154
+ chars = this.#currentLine + chars;
1155
+ while (true) {
1156
+ const lfIndex = chars.indexOf("\n");
1157
+ const crIndex = options.allowCR ? chars.indexOf("\r") : -1;
1158
+ if (crIndex !== -1 && crIndex !== chars.length - 1 && (lfIndex === -1 || lfIndex - 1 > crIndex)) {
1159
+ controller.enqueue(chars.slice(0, crIndex));
1160
+ chars = chars.slice(crIndex + 1);
1161
+ continue;
1162
+ }
1163
+ if (lfIndex === -1) break;
1164
+ const endIndex = chars[lfIndex - 1] === "\r" ? lfIndex - 1 : lfIndex;
1165
+ controller.enqueue(chars.slice(0, endIndex));
1166
+ chars = chars.slice(lfIndex + 1);
1167
+ }
1168
+ this.#currentLine = chars;
1169
+ },
1170
+ flush: (controller) => {
1171
+ if (this.#currentLine === "") return;
1172
+ const currentLine = options.allowCR && this.#currentLine.endsWith("\r") ? this.#currentLine.slice(0, -1) : this.#currentLine;
1173
+ controller.enqueue(currentLine);
1174
+ }
1175
+ });
1176
+ }
1177
+ };
1178
+ //#endregion
1179
+ //#region ../../node_modules/.pnpm/fetch-event-stream@0.1.6/node_modules/fetch-event-stream/esm/utils.js
1317
1180
  function stream$1(input) {
1318
- let decoder = new TextDecoderStream();
1319
- let split2 = new TextLineStream({ allowCR: true });
1320
- return input.pipeThrough(decoder).pipeThrough(split2);
1181
+ let decoder = new TextDecoderStream();
1182
+ let split = new TextLineStream({ allowCR: true });
1183
+ return input.pipeThrough(decoder).pipeThrough(split);
1321
1184
  }
1322
1185
  function split(input) {
1323
- let rgx = /[:]\s*/;
1324
- let match = rgx.exec(input);
1325
- let idx = match && match.index;
1326
- if (idx) {
1327
- return [
1328
- input.substring(0, idx),
1329
- input.substring(idx + match[0].length)
1330
- ];
1331
- }
1186
+ let match = /[:]\s*/.exec(input);
1187
+ let idx = match && match.index;
1188
+ if (idx) return [input.substring(0, idx), input.substring(idx + match[0].length)];
1332
1189
  }
1333
1190
  function fallback(headers, key, value) {
1334
- let tmp = headers.get(key);
1335
- if (!tmp)
1336
- headers.set(key, value);
1191
+ if (!headers.get(key)) headers.set(key, value);
1337
1192
  }
1193
+ //#endregion
1194
+ //#region ../../node_modules/.pnpm/fetch-event-stream@0.1.6/node_modules/fetch-event-stream/esm/mod.js
1195
+ /**
1196
+ * Convert a `Response` body containing Server Sent Events (SSE) into an Async Iterator that yields {@linkcode ServerSentEventMessage} objects.
1197
+ *
1198
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events}
1199
+ *
1200
+ * @example
1201
+ * ```js
1202
+ * // Optional
1203
+ * let abort = new AbortController;
1204
+ *
1205
+ * // Manually fetch a Response
1206
+ * let res = await fetch('https://...', {
1207
+ * method: 'POST',
1208
+ * signal: abort.signal,
1209
+ * headers: {
1210
+ * 'api-key': 'token <value>',
1211
+ * 'content-type': 'application/json',
1212
+ * },
1213
+ * body: JSON.stringify({
1214
+ * stream: true, // <- hypothetical
1215
+ * // ...
1216
+ * })
1217
+ * });
1218
+ *
1219
+ * if (res.ok) {
1220
+ * let stream = events(res, abort.signal);
1221
+ * for await (let event of stream) {
1222
+ * console.log('<<', event.data);
1223
+ * }
1224
+ * }
1225
+ * ```
1226
+ */
1338
1227
  async function* events(res, signal) {
1339
- if (!res.body)
1340
- return;
1341
- let iter = stream$1(res.body);
1342
- let line, reader = iter.getReader();
1343
- let event;
1344
- for (; ; ) {
1345
- if (signal && signal.aborted) {
1346
- return reader.cancel();
1347
- }
1348
- line = await reader.read();
1349
- if (line.done)
1350
- return;
1351
- if (!line.value) {
1352
- if (event)
1353
- yield event;
1354
- event = void 0;
1355
- continue;
1356
- }
1357
- let [field, value] = split(line.value) || [];
1358
- if (field === "data") {
1359
- event ||= {};
1360
- event[field] = event[field] ? event[field] + "\n" + value : value;
1361
- } else if (field === "event") {
1362
- event ||= {};
1363
- event[field] = value;
1364
- } else if (field === "id") {
1365
- event ||= {};
1366
- event[field] = String(+value) === value ? +value : value;
1367
- } else if (field === "retry") {
1368
- event ||= {};
1369
- event[field] = +value || void 0;
1370
- }
1371
- }
1228
+ if (!res.body) return;
1229
+ let iter = stream$1(res.body);
1230
+ let line, reader = iter.getReader();
1231
+ let event;
1232
+ for (;;) {
1233
+ if (signal && signal.aborted) return reader.cancel();
1234
+ line = await reader.read();
1235
+ if (line.done) return;
1236
+ if (!line.value) {
1237
+ if (event) yield event;
1238
+ event = void 0;
1239
+ continue;
1240
+ }
1241
+ let [field, value] = split(line.value) || [];
1242
+ if (field === "data") {
1243
+ event ||= {};
1244
+ event[field] = event[field] ? event[field] + "\n" + value : value;
1245
+ } else if (field === "event") {
1246
+ event ||= {};
1247
+ event[field] = value;
1248
+ } else if (field === "id") {
1249
+ event ||= {};
1250
+ event[field] = String(+value) === value ? +value : value;
1251
+ } else if (field === "retry") {
1252
+ event ||= {};
1253
+ event[field] = +value || void 0;
1254
+ }
1255
+ }
1372
1256
  }
1257
+ /**
1258
+ * Convenience function that will `fetch` with the given arguments and, if ok, will return the {@linkcode events} async iterator.
1259
+ *
1260
+ * If the response is not ok (status 200-299), the `Response` is thrown.
1261
+ *
1262
+ * @example
1263
+ * ```js
1264
+ * // NOTE: throws `Response` if not 2xx status
1265
+ * let events = await stream('https://api.openai.com/...', {
1266
+ * method: 'POST',
1267
+ * headers: {
1268
+ * 'Authorization': 'Bearer <token>',
1269
+ * 'Content-Type': 'application/json',
1270
+ * },
1271
+ * body: JSON.stringify({
1272
+ * stream: true,
1273
+ * // ...
1274
+ * })
1275
+ * });
1276
+ *
1277
+ * for await (let event of events) {
1278
+ * console.log('<<', JSON.parse(event.data));
1279
+ * }
1280
+ * ```
1281
+ */
1373
1282
  async function stream(input, init) {
1374
- let req = new Request(input, init);
1375
- fallback(req.headers, "Accept", "text/event-stream");
1376
- fallback(req.headers, "Content-Type", "application/json");
1377
- let r = await fetch(req);
1378
- if (!r.ok)
1379
- throw r;
1380
- return events(r, req.signal);
1283
+ let req = new Request(input, init);
1284
+ fallback(req.headers, "Accept", "text/event-stream");
1285
+ fallback(req.headers, "Content-Type", "application/json");
1286
+ let r = await fetch(req);
1287
+ if (!r.ok) throw r;
1288
+ return events(r, req.signal);
1381
1289
  }
1290
+ //#endregion
1291
+ //#region src/utils/stream.ts
1382
1292
  async function open_stream() {
1383
- let {
1384
- event_callbacks,
1385
- unclosed_events,
1386
- pending_stream_messages,
1387
- stream_status,
1388
- config,
1389
- jwt
1390
- } = this;
1391
- const that = this;
1392
- if (!config) {
1393
- throw new Error("Could not resolve app config");
1394
- }
1395
- stream_status.open = true;
1396
- let stream2 = null;
1397
- let params = new URLSearchParams({
1398
- session_hash: this.session_hash
1399
- }).toString();
1400
- let url = new URL(`${config.root}${this.api_prefix}/${SSE_URL}?${params}`);
1401
- if (jwt) {
1402
- url.searchParams.set("__sign", jwt);
1403
- }
1404
- stream2 = this.stream(url);
1405
- if (!stream2) {
1406
- console.warn("Cannot connect to SSE endpoint: " + url.toString());
1407
- return;
1408
- }
1409
- stream2.onmessage = async function(event) {
1410
- let _data = JSON.parse(event.data);
1411
- if (_data.msg === "close_stream") {
1412
- close_stream(stream_status, that.abort_controller);
1413
- return;
1414
- }
1415
- const event_id = _data.event_id;
1416
- if (!event_id) {
1417
- await Promise.all(
1418
- Object.keys(event_callbacks).map(
1419
- (event_id2) => event_callbacks[event_id2](_data)
1420
- )
1421
- );
1422
- } else if (event_callbacks[event_id] && config) {
1423
- if (_data.msg === "process_completed" && ["sse", "sse_v1", "sse_v2", "sse_v2.1", "sse_v3"].includes(
1424
- config.protocol
1425
- )) {
1426
- unclosed_events.delete(event_id);
1427
- }
1428
- let fn = event_callbacks[event_id];
1429
- if (typeof window !== "undefined" && typeof document !== "undefined") {
1430
- setTimeout(fn, 0, _data);
1431
- } else {
1432
- fn(_data);
1433
- }
1434
- } else {
1435
- if (!pending_stream_messages[event_id]) {
1436
- pending_stream_messages[event_id] = [];
1437
- }
1438
- pending_stream_messages[event_id].push(_data);
1439
- }
1440
- };
1441
- stream2.onerror = async function(e) {
1442
- console.error(e);
1443
- await Promise.all(
1444
- Object.keys(event_callbacks).map(
1445
- (event_id) => event_callbacks[event_id]({
1446
- msg: "broken_connection",
1447
- message: BROKEN_CONNECTION_MSG
1448
- })
1449
- )
1450
- );
1451
- };
1293
+ let { event_callbacks, unclosed_events, pending_stream_messages, stream_status, config, jwt } = this;
1294
+ const that = this;
1295
+ if (!config) throw new Error("Could not resolve app config");
1296
+ stream_status.open = true;
1297
+ let stream = null;
1298
+ let params = new URLSearchParams({ session_hash: this.session_hash }).toString();
1299
+ let url = new URL(`${config.root}${this.api_prefix}/${SSE_URL}?${params}`);
1300
+ if (jwt) url.searchParams.set("__sign", jwt);
1301
+ stream = this.stream(url);
1302
+ if (!stream) {
1303
+ console.warn("Cannot connect to SSE endpoint: " + url.toString());
1304
+ return;
1305
+ }
1306
+ stream.onmessage = async function(event) {
1307
+ let _data = JSON.parse(event.data);
1308
+ if (_data.msg === "close_stream") {
1309
+ close_stream(stream_status, that.abort_controller);
1310
+ return;
1311
+ }
1312
+ const event_id = _data.event_id;
1313
+ if (!event_id) await Promise.all(Object.keys(event_callbacks).map((event_id) => event_callbacks[event_id](_data)));
1314
+ else if (event_callbacks[event_id] && config) {
1315
+ if (_data.msg === "process_completed" && [
1316
+ "sse",
1317
+ "sse_v1",
1318
+ "sse_v2",
1319
+ "sse_v2.1",
1320
+ "sse_v3"
1321
+ ].includes(config.protocol)) unclosed_events.delete(event_id);
1322
+ let fn = event_callbacks[event_id];
1323
+ if (typeof window !== "undefined" && typeof document !== "undefined" && document.visibilityState !== "hidden") setTimeout(fn, 0, _data);
1324
+ else fn(_data);
1325
+ } else {
1326
+ if (!pending_stream_messages[event_id]) pending_stream_messages[event_id] = [];
1327
+ pending_stream_messages[event_id].push(_data);
1328
+ }
1329
+ };
1330
+ stream.onerror = async function(e) {
1331
+ console.error(e);
1332
+ await Promise.all(Object.keys(event_callbacks).map((event_id) => event_callbacks[event_id]({
1333
+ msg: "broken_connection",
1334
+ message: BROKEN_CONNECTION_MSG
1335
+ })));
1336
+ };
1452
1337
  }
1453
1338
  function close_stream(stream_status, abort_controller) {
1454
- if (stream_status) {
1455
- stream_status.open = false;
1456
- abort_controller?.abort();
1457
- }
1339
+ if (stream_status) {
1340
+ stream_status.open = false;
1341
+ abort_controller?.abort();
1342
+ }
1458
1343
  }
1459
1344
  function apply_diff_stream(pending_diff_streams, event_id, data) {
1460
- let is_first_generation = !pending_diff_streams[event_id];
1461
- if (is_first_generation) {
1462
- pending_diff_streams[event_id] = [];
1463
- data.data.forEach((value, i) => {
1464
- pending_diff_streams[event_id][i] = value;
1465
- });
1466
- } else {
1467
- data.data.forEach((value, i) => {
1468
- let new_data = apply_diff(pending_diff_streams[event_id][i], value);
1469
- pending_diff_streams[event_id][i] = new_data;
1470
- data.data[i] = new_data;
1471
- });
1472
- }
1345
+ if (!pending_diff_streams[event_id]) {
1346
+ pending_diff_streams[event_id] = [];
1347
+ data.data.forEach((value, i) => {
1348
+ pending_diff_streams[event_id][i] = value;
1349
+ });
1350
+ } else data.data.forEach((value, i) => {
1351
+ let new_data = apply_diff(i < pending_diff_streams[event_id].length ? pending_diff_streams[event_id][i] : null, value);
1352
+ pending_diff_streams[event_id][i] = new_data;
1353
+ data.data[i] = new_data;
1354
+ });
1473
1355
  }
1474
1356
  function apply_diff(obj, diff) {
1475
- diff.forEach(([action, path, value]) => {
1476
- obj = apply_edit(obj, path, action, value);
1477
- });
1478
- return obj;
1357
+ diff.forEach(([action, path, value]) => {
1358
+ obj = apply_edit(obj, path, action, value);
1359
+ });
1360
+ return obj;
1479
1361
  }
1480
1362
  function apply_edit(target, path, action, value) {
1481
- if (path.length === 0) {
1482
- if (action === "replace") {
1483
- return value;
1484
- } else if (action === "append") {
1485
- return target + value;
1486
- }
1487
- throw new Error(`Unsupported action: ${action}`);
1488
- }
1489
- let current = target;
1490
- for (let i = 0; i < path.length - 1; i++) {
1491
- current = current[path[i]];
1492
- }
1493
- const last_path = path[path.length - 1];
1494
- switch (action) {
1495
- case "replace":
1496
- current[last_path] = value;
1497
- break;
1498
- case "append":
1499
- current[last_path] += value;
1500
- break;
1501
- case "add":
1502
- if (Array.isArray(current)) {
1503
- current.splice(Number(last_path), 0, value);
1504
- } else {
1505
- current[last_path] = value;
1506
- }
1507
- break;
1508
- case "delete":
1509
- if (Array.isArray(current)) {
1510
- current.splice(Number(last_path), 1);
1511
- } else {
1512
- delete current[last_path];
1513
- }
1514
- break;
1515
- default:
1516
- throw new Error(`Unknown action: ${action}`);
1517
- }
1518
- return target;
1363
+ if (path.length === 0) {
1364
+ if (action === "replace") return value;
1365
+ else if (action === "append") return target + value;
1366
+ throw new Error(`Unsupported action: ${action}`);
1367
+ }
1368
+ let current = target;
1369
+ for (let i = 0; i < path.length - 1; i++) current = current[path[i]];
1370
+ const last_path = path[path.length - 1];
1371
+ switch (action) {
1372
+ case "replace":
1373
+ current[last_path] = value;
1374
+ break;
1375
+ case "append":
1376
+ current[last_path] += value;
1377
+ break;
1378
+ case "add":
1379
+ if (Array.isArray(current)) current.splice(Number(last_path), 0, value);
1380
+ else current[last_path] = value;
1381
+ break;
1382
+ case "delete":
1383
+ if (Array.isArray(current)) current.splice(Number(last_path), 1);
1384
+ else delete current[last_path];
1385
+ break;
1386
+ default: throw new Error(`Unknown action: ${action}`);
1387
+ }
1388
+ return target;
1519
1389
  }
1520
1390
  function readable_stream(input, init = {}) {
1521
- const instance = {
1522
- close: () => {
1523
- console.warn("Method not implemented.");
1524
- },
1525
- onerror: null,
1526
- onmessage: null,
1527
- onopen: null,
1528
- readyState: 0,
1529
- url: input.toString(),
1530
- withCredentials: false,
1531
- CONNECTING: 0,
1532
- OPEN: 1,
1533
- CLOSED: 2,
1534
- addEventListener: () => {
1535
- throw new Error("Method not implemented.");
1536
- },
1537
- dispatchEvent: () => {
1538
- throw new Error("Method not implemented.");
1539
- },
1540
- removeEventListener: () => {
1541
- throw new Error("Method not implemented.");
1542
- }
1543
- };
1544
- stream(input, init).then(async (res) => {
1545
- instance.readyState = instance.OPEN;
1546
- try {
1547
- for await (const chunk of res) {
1548
- instance.onmessage && instance.onmessage(chunk);
1549
- }
1550
- instance.readyState = instance.CLOSED;
1551
- } catch (e) {
1552
- instance.onerror && instance.onerror(e);
1553
- instance.readyState = instance.CLOSED;
1554
- }
1555
- }).catch((e) => {
1556
- console.error(e);
1557
- instance.onerror && instance.onerror(e);
1558
- instance.readyState = instance.CLOSED;
1559
- });
1560
- return instance;
1391
+ const instance = {
1392
+ close: () => {
1393
+ console.warn("Method not implemented.");
1394
+ },
1395
+ onerror: null,
1396
+ onmessage: null,
1397
+ onopen: null,
1398
+ readyState: 0,
1399
+ url: input.toString(),
1400
+ withCredentials: false,
1401
+ CONNECTING: 0,
1402
+ OPEN: 1,
1403
+ CLOSED: 2,
1404
+ addEventListener: () => {
1405
+ throw new Error("Method not implemented.");
1406
+ },
1407
+ dispatchEvent: () => {
1408
+ throw new Error("Method not implemented.");
1409
+ },
1410
+ removeEventListener: () => {
1411
+ throw new Error("Method not implemented.");
1412
+ }
1413
+ };
1414
+ stream(input, init).then(async (res) => {
1415
+ instance.readyState = instance.OPEN;
1416
+ try {
1417
+ for await (const chunk of res) instance.onmessage && instance.onmessage(chunk);
1418
+ instance.readyState = instance.CLOSED;
1419
+ } catch (e) {
1420
+ instance.onerror && instance.onerror(e);
1421
+ instance.readyState = instance.CLOSED;
1422
+ }
1423
+ }).catch((e) => {
1424
+ console.error(e);
1425
+ instance.onerror && instance.onerror(e);
1426
+ instance.readyState = instance.CLOSED;
1427
+ });
1428
+ return instance;
1429
+ }
1430
+ //#endregion
1431
+ //#region src/utils/run_history.ts
1432
+ var KEY_ROOT = "gradio:run-history:";
1433
+ var STORAGE_PREFIX = `${KEY_ROOT}v2:`;
1434
+ var REPLAY_PREFIX = `${KEY_ROOT}replay:v2:`;
1435
+ var MAX_RUNS = 100;
1436
+ var MAX_APPS = 8;
1437
+ /**
1438
+ * Run history is a side effect of submitting, never the point of it, so no
1439
+ * failure in here may propagate into the caller and break the app. Every
1440
+ * exported function routes through this.
1441
+ */
1442
+ function safely(operation, fallback) {
1443
+ try {
1444
+ return operation();
1445
+ } catch (error) {
1446
+ console.warn("Could not update the run history.", error);
1447
+ return fallback;
1448
+ }
1449
+ }
1450
+ /**
1451
+ * The URL of the run history page for an app. `root` never carries a trailing
1452
+ * slash, so it cannot simply be concatenated with the path.
1453
+ */
1454
+ function run_history_url(root, api_prefix = "/gradio_api") {
1455
+ return `${root.replace(/\/+$/, "")}${api_prefix}/runs`;
1456
+ }
1457
+ function storage_key(scope) {
1458
+ if (typeof window === "undefined") return null;
1459
+ const app_id = scope?.app_id;
1460
+ if (app_id === null || app_id === void 0 || app_id === "") return null;
1461
+ try {
1462
+ if (!window.localStorage) return null;
1463
+ return `${STORAGE_PREFIX}${app_id}${scope?.username ? `:user:${encodeURIComponent(scope.username)}` : ""}`;
1464
+ } catch {
1465
+ return null;
1466
+ }
1467
+ }
1468
+ function replay_key(scope) {
1469
+ const key = storage_key(scope);
1470
+ return key ? key.replace(STORAGE_PREFIX, REPLAY_PREFIX) : null;
1471
+ }
1472
+ /** When a run was most recently saved under a key, for deciding what to drop. */
1473
+ function last_saved_at(key) {
1474
+ try {
1475
+ const runs = JSON.parse(window.localStorage.getItem(key) || "[]");
1476
+ return Array.isArray(runs) && runs.length ? Date.parse(runs[0]?.started_at) || 0 : 0;
1477
+ } catch {
1478
+ return 0;
1479
+ }
1480
+ }
1481
+ /**
1482
+ * Drops the histories of long-gone app instances. Every restart mints a new app
1483
+ * id, so without this the browser would keep every history an app ever had and
1484
+ * eventually run out of room for the current one.
1485
+ */
1486
+ function prune_apps(current_key) {
1487
+ const keys = Object.keys(window.localStorage).filter((key) => key.startsWith(KEY_ROOT));
1488
+ const stale = [...keys.filter((key) => !key.startsWith(STORAGE_PREFIX) && !key.startsWith(REPLAY_PREFIX)), ...keys.filter((key) => key.startsWith(STORAGE_PREFIX) && key !== current_key).sort((a, b) => last_saved_at(b) - last_saved_at(a)).slice(MAX_APPS - 1)];
1489
+ for (const key of stale) try {
1490
+ window.localStorage.removeItem(key);
1491
+ window.sessionStorage.removeItem(key.replace(STORAGE_PREFIX, REPLAY_PREFIX));
1492
+ } catch {}
1493
+ }
1494
+ function make_id() {
1495
+ if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
1496
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
1561
1497
  }
1498
+ function clone_for_storage(value) {
1499
+ const seen = /* @__PURE__ */ new WeakSet();
1500
+ try {
1501
+ return JSON.parse(JSON.stringify(value, (_key, item) => {
1502
+ if (typeof item === "bigint") return item.toString();
1503
+ if (typeof item === "object" && item !== null) {
1504
+ if (seen.has(item)) return "[Circular]";
1505
+ seen.add(item);
1506
+ }
1507
+ return item;
1508
+ }));
1509
+ } catch {
1510
+ return "[Unserializable value]";
1511
+ }
1512
+ }
1513
+ function read_run_history_impl(scope) {
1514
+ const key = storage_key(scope);
1515
+ if (!key) return [];
1516
+ try {
1517
+ const value = JSON.parse(window.localStorage.getItem(key) || "[]");
1518
+ return Array.isArray(value) ? value : [];
1519
+ } catch {
1520
+ return [];
1521
+ }
1522
+ }
1523
+ function write_run_history(scope, runs) {
1524
+ const key = storage_key(scope);
1525
+ if (!key) return;
1526
+ let next = runs.slice(0, MAX_RUNS);
1527
+ let pruned = false;
1528
+ while (next.length > 0) try {
1529
+ window.localStorage.setItem(key, JSON.stringify(next));
1530
+ return;
1531
+ } catch {
1532
+ if (!pruned) {
1533
+ pruned = true;
1534
+ prune_apps(key);
1535
+ continue;
1536
+ }
1537
+ next = next.slice(0, -1);
1538
+ }
1539
+ try {
1540
+ window.localStorage.removeItem(key);
1541
+ } catch {}
1542
+ }
1543
+ function clear_run_history_impl(scope) {
1544
+ const key = storage_key(scope);
1545
+ if (!key) return;
1546
+ try {
1547
+ window.localStorage.removeItem(key);
1548
+ } catch {}
1549
+ notify_run_history_change();
1550
+ }
1551
+ function delete_run_history_impl(scope, id) {
1552
+ write_run_history(scope, read_run_history_impl(scope).filter((run) => run.id !== id));
1553
+ notify_run_history_change();
1554
+ }
1555
+ var CHANGE_EVENT = "gradio:run-history-change";
1556
+ function notify_run_history_change() {
1557
+ if (typeof window === "undefined") return;
1558
+ try {
1559
+ window.dispatchEvent(new Event(CHANGE_EVENT));
1560
+ } catch {}
1561
+ }
1562
+ /**
1563
+ * Subscribes to runs being added, deleted or cleared. `storage` covers other
1564
+ * tabs; the custom event covers this one, which `storage` never fires for.
1565
+ * Only counts change, not per-run progress, so listeners stay cheap.
1566
+ *
1567
+ * @returns a function that unsubscribes.
1568
+ */
1569
+ function on_run_history_change_impl(listener) {
1570
+ if (typeof window === "undefined") return () => {};
1571
+ window.addEventListener(CHANGE_EVENT, listener);
1572
+ window.addEventListener("storage", listener);
1573
+ return () => {
1574
+ window.removeEventListener(CHANGE_EVENT, listener);
1575
+ window.removeEventListener("storage", listener);
1576
+ };
1577
+ }
1578
+ function stage_run_history_replay_impl(scope, run) {
1579
+ const key = replay_key(scope);
1580
+ if (!key) return;
1581
+ try {
1582
+ window.sessionStorage.setItem(key, JSON.stringify(run));
1583
+ } catch {}
1584
+ }
1585
+ function consume_run_history_replay_impl(scope) {
1586
+ const key = replay_key(scope);
1587
+ if (!key) return null;
1588
+ try {
1589
+ const value = window.sessionStorage.getItem(key);
1590
+ window.sessionStorage.removeItem(key);
1591
+ return value ? JSON.parse(value) : null;
1592
+ } catch {
1593
+ return null;
1594
+ }
1595
+ }
1596
+ function start_run_history_impl(options) {
1597
+ const key = storage_key(options);
1598
+ if (!key) return null;
1599
+ prune_apps(key);
1600
+ const run = {
1601
+ id: make_id(),
1602
+ endpoint: options.endpoint,
1603
+ api_name: options.api_name,
1604
+ fn_index: options.fn_index,
1605
+ page: `${window.location.pathname}${window.location.search}`,
1606
+ inputs: clone_for_storage(options.inputs),
1607
+ outputs: null,
1608
+ ...options.input_components ? { input_components: clone_for_storage(options.input_components) } : {},
1609
+ ...options.output_components ? { output_components: clone_for_storage(options.output_components) } : {},
1610
+ status: "running",
1611
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
1612
+ };
1613
+ write_run_history(options, [run, ...read_run_history_impl(options)]);
1614
+ notify_run_history_change();
1615
+ return run.id;
1616
+ }
1617
+ function update_run_inputs_impl(scope, id, inputs) {
1618
+ if (!id) return;
1619
+ const runs = read_run_history_impl(scope);
1620
+ const run = runs.find((item) => item.id === id);
1621
+ if (!run) return;
1622
+ run.inputs = clone_for_storage(inputs);
1623
+ write_run_history(scope, runs);
1624
+ }
1625
+ function update_run_history_impl(scope, id, event) {
1626
+ if (!id) return;
1627
+ const runs = read_run_history_impl(scope);
1628
+ const run = runs.find((item) => item.id === id);
1629
+ if (!run) return;
1630
+ let finished = false;
1631
+ if (event.type === "data") {
1632
+ run.outputs = clone_for_storage(event.data);
1633
+ deferred_outputs.set(id, run.outputs);
1634
+ } else if (event.type === "status" && event.original_msg === "process_starts") mark_process_start(run, event.time);
1635
+ else if (event.type === "status" && (event.stage === "generating" || event.stage === "streaming")) run.streamed = true;
1636
+ else if (event.type === "status" && event.stage === "complete") {
1637
+ run.status = "completed";
1638
+ mark_complete(run, event);
1639
+ finished = true;
1640
+ } else if (event.type === "status" && event.stage === "error") {
1641
+ run.status = "failed";
1642
+ run.error = typeof event.message === "string" ? event.message : JSON.stringify(event.message || "Unknown error");
1643
+ mark_complete(run, event);
1644
+ finished = true;
1645
+ } else return;
1646
+ if (finished) {
1647
+ if (deferred_outputs.has(id)) run.outputs = deferred_outputs.get(id);
1648
+ deferred_outputs.delete(id);
1649
+ last_write.delete(id);
1650
+ } else if (run.streamed) {
1651
+ if (Date.now() - (last_write.get(id) ?? 0) < STREAM_WRITE_INTERVAL_MS) return;
1652
+ last_write.set(id, Date.now());
1653
+ deferred_outputs.delete(id);
1654
+ }
1655
+ write_run_history(scope, runs);
1656
+ }
1657
+ var STREAM_WRITE_INTERVAL_MS = 500;
1658
+ /** When each in-flight streamed run was last written. */
1659
+ var last_write = /* @__PURE__ */ new Map();
1660
+ /** The newest output of a streamed run that has not been written yet. */
1661
+ var deferred_outputs = /* @__PURE__ */ new Map();
1662
+ function mark_process_start(run, time) {
1663
+ if (run.process_started_at) return;
1664
+ const started = time || /* @__PURE__ */ new Date();
1665
+ run.process_started_at = started.toISOString();
1666
+ run.queued_ms = Math.max(0, started.getTime() - Date.parse(run.started_at));
1667
+ }
1668
+ function mark_complete(run, event) {
1669
+ const completed = event.time || /* @__PURE__ */ new Date();
1670
+ run.completed_at = completed.toISOString();
1671
+ run.duration_ms = (!run.streamed && typeof event.cache_duration === "number" && event.cache_duration >= 0 ? event.cache_duration * 1e3 : null) ?? Math.max(0, completed.getTime() - Date.parse(run.process_started_at || run.started_at));
1672
+ }
1673
+ function read_run_history(scope) {
1674
+ return safely(() => read_run_history_impl(scope), []);
1675
+ }
1676
+ function clear_run_history(scope) {
1677
+ safely(() => clear_run_history_impl(scope), void 0);
1678
+ }
1679
+ function delete_run_history(scope, id) {
1680
+ safely(() => delete_run_history_impl(scope, id), void 0);
1681
+ }
1682
+ function stage_run_history_replay(scope, run) {
1683
+ safely(() => stage_run_history_replay_impl(scope, run), void 0);
1684
+ }
1685
+ function consume_run_history_replay(scope) {
1686
+ return safely(() => consume_run_history_replay_impl(scope), null);
1687
+ }
1688
+ function start_run_history(options) {
1689
+ return safely(() => start_run_history_impl(options), null);
1690
+ }
1691
+ function update_run_inputs(scope, id, inputs) {
1692
+ safely(() => update_run_inputs_impl(scope, id, inputs), void 0);
1693
+ }
1694
+ function update_run_history(scope, id, event) {
1695
+ safely(() => update_run_history_impl(scope, id, event), void 0);
1696
+ }
1697
+ function on_run_history_change(listener) {
1698
+ return safely(() => on_run_history_change_impl(() => safely(listener, void 0)), () => {});
1699
+ }
1700
+ //#endregion
1701
+ //#region src/utils/submit.ts
1562
1702
  function submit(endpoint, data = {}, event_data, trigger_id, all_events, additional_headers) {
1563
- try {
1564
- let fire_event = function(event) {
1565
- if (all_events || events_to_publish[event.type]) {
1566
- push_event(event);
1567
- }
1568
- }, close = function() {
1569
- done = true;
1570
- while (resolvers.length > 0)
1571
- resolvers.shift()({
1572
- value: void 0,
1573
- done: true
1574
- });
1575
- }, push = function(data2) {
1576
- if (resolvers.length > 0) {
1577
- resolvers.shift()(data2);
1578
- } else {
1579
- values.push(data2);
1580
- }
1581
- }, push_error = function(error) {
1582
- push(thenable_reject(error));
1583
- close();
1584
- }, push_event = function(event) {
1585
- push({ value: event, done: false });
1586
- }, next = function() {
1587
- if (values.length > 0) {
1588
- return Promise.resolve(values.shift());
1589
- }
1590
- if (done) {
1591
- return Promise.resolve({ value: void 0, done: true });
1592
- }
1593
- return new Promise((resolve) => resolvers.push(resolve));
1594
- };
1595
- const { token } = this.options;
1596
- const {
1597
- fetch: fetch2,
1598
- app_reference,
1599
- config,
1600
- session_hash,
1601
- api_info,
1602
- api_map,
1603
- stream_status,
1604
- pending_stream_messages,
1605
- pending_diff_streams,
1606
- event_callbacks,
1607
- unclosed_events,
1608
- post_data: post_data2,
1609
- options,
1610
- api_prefix
1611
- } = this;
1612
- const addt_headers = additional_headers || { "x-gradio-user": "api" };
1613
- const that = this;
1614
- if (!api_info) throw new Error("No API found");
1615
- if (!config) throw new Error("Could not resolve app config");
1616
- let { fn_index, endpoint_info, dependency } = get_endpoint_info(
1617
- api_info,
1618
- endpoint,
1619
- api_map,
1620
- config
1621
- );
1622
- let resolved_data = map_data_to_params(data, endpoint_info);
1623
- let stream2;
1624
- let protocol = config.protocol ?? "ws";
1625
- if (protocol === "ws") {
1626
- throw new Error("WebSocket protocol is not supported in this version");
1627
- }
1628
- let event_id_final = "";
1629
- let event_id_cb = () => event_id_final;
1630
- const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint;
1631
- let payload;
1632
- let event_id = null;
1633
- let complete = false;
1634
- let last_status = {};
1635
- let url_params = typeof window !== "undefined" && typeof document !== "undefined" ? new URLSearchParams(window.location.search).toString() : "";
1636
- const events_to_publish = options?.events?.reduce(
1637
- (acc, event) => {
1638
- acc[event] = true;
1639
- return acc;
1640
- },
1641
- {}
1642
- ) || {};
1643
- async function cancel() {
1644
- let reset_request = {};
1645
- let cancel_request = {};
1646
- reset_request = { event_id };
1647
- cancel_request = { event_id, session_hash, fn_index };
1648
- try {
1649
- if (!config) {
1650
- throw new Error("Could not resolve app config");
1651
- }
1652
- if ("event_id" in cancel_request) {
1653
- await fetch2(`${config.root}${api_prefix}/${CANCEL_URL}`, {
1654
- headers: { "Content-Type": "application/json" },
1655
- method: "POST",
1656
- body: JSON.stringify(cancel_request)
1657
- });
1658
- }
1659
- await fetch2(`${config.root}${api_prefix}/${RESET_URL}`, {
1660
- headers: { "Content-Type": "application/json" },
1661
- method: "POST",
1662
- body: JSON.stringify(reset_request)
1663
- });
1664
- } catch (e) {
1665
- console.warn(
1666
- "The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable."
1667
- );
1668
- }
1669
- }
1670
- const resolve_heartbeat = async (config2) => {
1671
- await this._resolve_heartbeat(config2);
1672
- };
1673
- async function handle_render_config(render_config) {
1674
- if (!config) return;
1675
- let render_id = render_config.render_id;
1676
- config.components = [
1677
- ...config.components.filter((c) => c.props.rendered_in !== render_id),
1678
- ...render_config.components
1679
- ];
1680
- config.dependencies = [
1681
- ...config.dependencies.filter((d) => d.rendered_in !== render_id),
1682
- ...render_config.dependencies
1683
- ];
1684
- const any_state = config.components.some((c) => c.type === "state");
1685
- const any_unload = config.dependencies.some(
1686
- (d) => d.targets.some((t) => t[1] === "unload")
1687
- );
1688
- config.connect_heartbeat = any_state || any_unload;
1689
- await resolve_heartbeat(config);
1690
- fire_event({
1691
- type: "render",
1692
- data: render_config,
1693
- endpoint: _endpoint,
1694
- fn_index
1695
- });
1696
- }
1697
- const job = this.handle_blob(
1698
- config.root,
1699
- resolved_data,
1700
- endpoint_info
1701
- ).then(async (_payload) => {
1702
- let input_data = handle_payload(
1703
- _payload,
1704
- dependency,
1705
- config.components,
1706
- "input",
1707
- true
1708
- );
1709
- payload = {
1710
- data: input_data || [],
1711
- event_data,
1712
- fn_index,
1713
- trigger_id
1714
- };
1715
- if (skip_queue(fn_index, config)) {
1716
- fire_event({
1717
- type: "status",
1718
- endpoint: _endpoint,
1719
- stage: "pending",
1720
- queue: false,
1721
- fn_index,
1722
- time: /* @__PURE__ */ new Date()
1723
- });
1724
- post_data2(
1725
- `${config.root}${api_prefix}/run${_endpoint.startsWith("/") ? _endpoint : `/${_endpoint}`}${url_params ? "?" + url_params : ""}`,
1726
- {
1727
- ...payload,
1728
- session_hash
1729
- },
1730
- addt_headers
1731
- ).then(async ([output, status_code]) => {
1732
- const data2 = output.data;
1733
- if (status_code == 200) {
1734
- fire_event({
1735
- type: "data",
1736
- endpoint: _endpoint,
1737
- fn_index,
1738
- data: handle_payload(
1739
- data2,
1740
- dependency,
1741
- config.components,
1742
- "output",
1743
- options.with_null_state
1744
- ),
1745
- time: /* @__PURE__ */ new Date(),
1746
- event_data,
1747
- trigger_id
1748
- });
1749
- if (output.render_config) {
1750
- await handle_render_config(output.render_config);
1751
- }
1752
- fire_event({
1753
- type: "status",
1754
- endpoint: _endpoint,
1755
- fn_index,
1756
- stage: "complete",
1757
- eta: output.average_duration,
1758
- queue: false,
1759
- time: /* @__PURE__ */ new Date()
1760
- });
1761
- } else {
1762
- const is_connection_error = output?.error === BROKEN_CONNECTION_MSG;
1763
- fire_event({
1764
- type: "status",
1765
- stage: "error",
1766
- endpoint: _endpoint,
1767
- fn_index,
1768
- message: output.error,
1769
- broken: is_connection_error,
1770
- queue: false,
1771
- time: /* @__PURE__ */ new Date()
1772
- });
1773
- }
1774
- }).catch((e) => {
1775
- fire_event({
1776
- type: "status",
1777
- stage: "error",
1778
- message: e.message,
1779
- endpoint: _endpoint,
1780
- fn_index,
1781
- queue: false,
1782
- time: /* @__PURE__ */ new Date()
1783
- });
1784
- });
1785
- } else if (protocol == "sse") {
1786
- fire_event({
1787
- type: "status",
1788
- stage: "pending",
1789
- queue: true,
1790
- endpoint: _endpoint,
1791
- fn_index,
1792
- time: /* @__PURE__ */ new Date()
1793
- });
1794
- var params = new URLSearchParams({
1795
- fn_index: fn_index.toString(),
1796
- session_hash
1797
- }).toString();
1798
- let url = new URL(
1799
- `${config.root}${api_prefix}/${SSE_URL}?${url_params ? url_params + "&" : ""}${params}`
1800
- );
1801
- if (this.jwt) {
1802
- url.searchParams.set("__sign", this.jwt);
1803
- }
1804
- stream2 = this.stream(url);
1805
- if (!stream2) {
1806
- return Promise.reject(
1807
- new Error("Cannot connect to SSE endpoint: " + url.toString())
1808
- );
1809
- }
1810
- stream2.onmessage = async function(event) {
1811
- const _data = JSON.parse(event.data);
1812
- const { type, status, data: data2 } = handle_message(
1813
- _data,
1814
- last_status[fn_index]
1815
- );
1816
- if (type === "update" && status && !complete) {
1817
- fire_event({
1818
- type: "status",
1819
- endpoint: _endpoint,
1820
- fn_index,
1821
- time: /* @__PURE__ */ new Date(),
1822
- ...status
1823
- });
1824
- if (status.stage === "error") {
1825
- stream2?.close();
1826
- close();
1827
- }
1828
- } else if (type === "data") {
1829
- let [_, status2] = await post_data2(
1830
- `${config.root}${api_prefix}/queue/data`,
1831
- {
1832
- ...payload,
1833
- session_hash,
1834
- event_id
1835
- }
1836
- );
1837
- if (status2 !== 200) {
1838
- fire_event({
1839
- type: "status",
1840
- stage: "error",
1841
- message: BROKEN_CONNECTION_MSG,
1842
- queue: true,
1843
- endpoint: _endpoint,
1844
- fn_index,
1845
- time: /* @__PURE__ */ new Date()
1846
- });
1847
- stream2?.close();
1848
- close();
1849
- }
1850
- } else if (type === "complete") {
1851
- complete = status;
1852
- } else if (type === "log") {
1853
- fire_event({
1854
- type: "log",
1855
- title: data2.title,
1856
- log: data2.log,
1857
- level: data2.level,
1858
- endpoint: _endpoint,
1859
- duration: data2.duration,
1860
- visible: data2.visible,
1861
- fn_index
1862
- });
1863
- } else if (type === "generating" || type === "streaming") {
1864
- fire_event({
1865
- type: "status",
1866
- time: /* @__PURE__ */ new Date(),
1867
- ...status,
1868
- stage: status?.stage,
1869
- queue: true,
1870
- endpoint: _endpoint,
1871
- fn_index
1872
- });
1873
- }
1874
- if (data2) {
1875
- fire_event({
1876
- type: "data",
1877
- time: /* @__PURE__ */ new Date(),
1878
- data: handle_payload(
1879
- data2.data,
1880
- dependency,
1881
- config.components,
1882
- "output",
1883
- options.with_null_state
1884
- ),
1885
- endpoint: _endpoint,
1886
- fn_index,
1887
- event_data,
1888
- trigger_id
1889
- });
1890
- if (complete) {
1891
- fire_event({
1892
- type: "status",
1893
- time: /* @__PURE__ */ new Date(),
1894
- ...complete,
1895
- stage: status?.stage,
1896
- queue: true,
1897
- endpoint: _endpoint,
1898
- fn_index
1899
- });
1900
- stream2?.close();
1901
- close();
1902
- }
1903
- }
1904
- };
1905
- } else if (protocol == "sse_v1" || protocol == "sse_v2" || protocol == "sse_v2.1" || protocol == "sse_v3") {
1906
- fire_event({
1907
- type: "status",
1908
- stage: "pending",
1909
- queue: true,
1910
- endpoint: _endpoint,
1911
- fn_index,
1912
- time: /* @__PURE__ */ new Date()
1913
- });
1914
- let hostname = "";
1915
- if (typeof window !== "undefined" && typeof document !== "undefined") {
1916
- hostname = window?.location?.hostname;
1917
- }
1918
- const origin = get_zerogpu_origin(hostname);
1919
- const is_zerogpu_iframe = typeof window !== "undefined" && typeof document !== "undefined" && window.parent != window && !!origin && window.supports_zerogpu_headers;
1920
- const zerogpu_auth_promise = is_zerogpu_iframe ? post_message("zerogpu-headers", origin) : Promise.resolve(null);
1921
- const post_data_promise = zerogpu_auth_promise.then((headers) => {
1922
- const combined_headers = { ...addt_headers, ...headers || {} };
1923
- return post_data2(
1924
- `${config.root}${api_prefix}/${SSE_DATA_URL}?${url_params}`,
1925
- {
1926
- ...payload,
1927
- session_hash
1928
- },
1929
- combined_headers
1930
- );
1931
- });
1932
- return post_data_promise.then(async ([response, status]) => {
1933
- if (response.event_id) {
1934
- event_id_final = response.event_id;
1935
- }
1936
- if (status === 503) {
1937
- fire_event({
1938
- type: "status",
1939
- stage: "error",
1940
- message: QUEUE_FULL_MSG,
1941
- queue: true,
1942
- endpoint: _endpoint,
1943
- fn_index,
1944
- time: /* @__PURE__ */ new Date(),
1945
- visible: true
1946
- });
1947
- close();
1948
- } else if (status === 422) {
1949
- fire_event({
1950
- type: "status",
1951
- stage: "error",
1952
- message: response.detail,
1953
- queue: true,
1954
- endpoint: _endpoint,
1955
- fn_index,
1956
- code: "validation_error",
1957
- time: /* @__PURE__ */ new Date(),
1958
- visible: true
1959
- });
1960
- close();
1961
- } else if (status !== 200) {
1962
- const is_connection_error = response?.error === BROKEN_CONNECTION_MSG;
1963
- fire_event({
1964
- type: "status",
1965
- stage: "error",
1966
- broken: is_connection_error,
1967
- message: is_connection_error ? BROKEN_CONNECTION_MSG : response.detail || response.error,
1968
- queue: true,
1969
- endpoint: _endpoint,
1970
- fn_index,
1971
- time: /* @__PURE__ */ new Date(),
1972
- visible: true
1973
- });
1974
- close();
1975
- } else {
1976
- event_id = response.event_id;
1977
- event_id_final = event_id;
1978
- let callback = async function(_data) {
1979
- try {
1980
- const { type, status: status2, data: data2, original_msg } = handle_message(
1981
- _data,
1982
- last_status[fn_index]
1983
- );
1984
- if (type == "heartbeat") {
1985
- return;
1986
- }
1987
- if (type === "update" && status2 && !complete) {
1988
- fire_event({
1989
- type: "status",
1990
- endpoint: _endpoint,
1991
- fn_index,
1992
- time: /* @__PURE__ */ new Date(),
1993
- original_msg,
1994
- ...status2
1995
- });
1996
- } else if (type === "complete") {
1997
- complete = status2;
1998
- } else if (type == "unexpected_error" || type == "broken_connection") {
1999
- console.error("Unexpected error", status2?.message);
2000
- const broken = type === "broken_connection";
2001
- fire_event({
2002
- type: "status",
2003
- stage: "error",
2004
- message: status2?.message || "An Unexpected Error Occurred!",
2005
- queue: true,
2006
- endpoint: _endpoint,
2007
- broken,
2008
- session_not_found: status2?.session_not_found,
2009
- fn_index,
2010
- time: /* @__PURE__ */ new Date()
2011
- });
2012
- } else if (type === "log") {
2013
- fire_event({
2014
- type: "log",
2015
- title: data2.title,
2016
- log: data2.log,
2017
- level: data2.level,
2018
- endpoint: _endpoint,
2019
- duration: data2.duration,
2020
- visible: data2.visible,
2021
- fn_index
2022
- });
2023
- return;
2024
- } else if (type === "generating" || type === "streaming") {
2025
- fire_event({
2026
- type: "status",
2027
- time: /* @__PURE__ */ new Date(),
2028
- ...status2,
2029
- stage: status2?.stage,
2030
- queue: true,
2031
- endpoint: _endpoint,
2032
- fn_index
2033
- });
2034
- if (data2 && dependency.connection !== "stream" && ["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol)) {
2035
- apply_diff_stream(pending_diff_streams, event_id, data2);
2036
- }
2037
- }
2038
- if (data2) {
2039
- fire_event({
2040
- type: "data",
2041
- time: /* @__PURE__ */ new Date(),
2042
- data: handle_payload(
2043
- data2.data,
2044
- dependency,
2045
- config.components,
2046
- "output",
2047
- options.with_null_state
2048
- ),
2049
- endpoint: _endpoint,
2050
- fn_index
2051
- });
2052
- if (data2.render_config) {
2053
- await handle_render_config(data2.render_config);
2054
- }
2055
- if (complete) {
2056
- fire_event({
2057
- type: "status",
2058
- time: /* @__PURE__ */ new Date(),
2059
- ...complete,
2060
- stage: status2?.stage,
2061
- queue: true,
2062
- endpoint: _endpoint,
2063
- fn_index
2064
- });
2065
- close();
2066
- }
2067
- }
2068
- if (status2?.stage === "complete" || status2?.stage === "error") {
2069
- if (event_callbacks[event_id]) {
2070
- delete event_callbacks[event_id];
2071
- }
2072
- if (event_id in pending_diff_streams) {
2073
- delete pending_diff_streams[event_id];
2074
- }
2075
- close();
2076
- }
2077
- } catch (e) {
2078
- console.error("Unexpected client exception", e);
2079
- fire_event({
2080
- type: "status",
2081
- stage: "error",
2082
- message: "An Unexpected Error Occurred!",
2083
- queue: true,
2084
- endpoint: _endpoint,
2085
- fn_index,
2086
- time: /* @__PURE__ */ new Date()
2087
- });
2088
- if (["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol)) {
2089
- close_stream(stream_status, that.abort_controller);
2090
- stream_status.open = false;
2091
- close();
2092
- }
2093
- }
2094
- };
2095
- if (event_id in pending_stream_messages) {
2096
- pending_stream_messages[event_id].forEach((msg) => callback(msg));
2097
- delete pending_stream_messages[event_id];
2098
- }
2099
- event_callbacks[event_id] = callback;
2100
- unclosed_events.add(event_id);
2101
- if (!stream_status.open) {
2102
- await this.open_stream();
2103
- }
2104
- }
2105
- });
2106
- }
2107
- });
2108
- let done = false;
2109
- const values = [];
2110
- const resolvers = [];
2111
- const iterator = {
2112
- [Symbol.asyncIterator]: () => iterator,
2113
- next,
2114
- throw: async (value) => {
2115
- push_error(value);
2116
- return next();
2117
- },
2118
- return: async () => {
2119
- close();
2120
- return { value: void 0, done: true };
2121
- },
2122
- cancel,
2123
- send_chunk: (payload2) => {
2124
- this.post_data(`${config.root}${api_prefix}/stream/${event_id_final}`, {
2125
- ...payload2,
2126
- session_hash: this.session_hash
2127
- });
2128
- },
2129
- close_stream: () => {
2130
- this.post_data(
2131
- `${config.root}${api_prefix}/stream/${event_id_final}/close`,
2132
- {}
2133
- );
2134
- close();
2135
- },
2136
- event_id: () => event_id_final,
2137
- wait_for_id: async () => {
2138
- await job;
2139
- return event_id;
2140
- }
2141
- };
2142
- return iterator;
2143
- } catch (error) {
2144
- console.error("Submit function encountered an error:", error);
2145
- throw error;
2146
- }
1703
+ try {
1704
+ const { token } = this.options;
1705
+ const { fetch, app_reference, config, session_hash, api_info, api_map, stream_status, pending_stream_messages, pending_diff_streams, event_callbacks, unclosed_events, post_data, options, api_prefix } = this;
1706
+ const addt_headers = additional_headers || { "x-gradio-user": "api" };
1707
+ const that = this;
1708
+ if (!api_info) throw new Error(NO_API_INFO_MSG);
1709
+ if (!config) throw new Error("Could not resolve app config");
1710
+ let { fn_index, endpoint_info, dependency } = get_endpoint_info(api_info, endpoint, api_map, config);
1711
+ let resolved_data = map_data_to_params(data, endpoint_info);
1712
+ let protocol = config.protocol ?? "ws";
1713
+ if (protocol === "ws") throw new Error(WS_PROTOCOL_MSG);
1714
+ const history_endpoint = typeof dependency.api_name === "string" ? `/${dependency.api_name}` : endpoint;
1715
+ const history_api_name = typeof dependency.api_name === "string" ? `/${dependency.api_name}` : `Function ${fn_index}`;
1716
+ const component_metadata = (id) => {
1717
+ const component = config.components.find((item) => item.id === id);
1718
+ if (!component) return null;
1719
+ return {
1720
+ type: component.type,
1721
+ component_class_id: component.component_class_id,
1722
+ props: component.props
1723
+ };
1724
+ };
1725
+ const is_documented_endpoint = dependency.api_visibility === "public";
1726
+ const history_enabled = config.run_history !== false && this.options.record_history !== false;
1727
+ const history_scope = {
1728
+ app_id: config.app_id,
1729
+ username: config.username
1730
+ };
1731
+ const history_run_id = !history_enabled || !is_documented_endpoint ? null : start_run_history({
1732
+ ...history_scope,
1733
+ endpoint: history_endpoint,
1734
+ api_name: history_api_name,
1735
+ fn_index,
1736
+ inputs: handle_payload(resolved_data, dependency, config.components, "input", true),
1737
+ input_components: dependency.inputs.map(component_metadata),
1738
+ output_components: dependency.outputs.map(component_metadata)
1739
+ });
1740
+ let stream;
1741
+ let event_id_final = "";
1742
+ const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint;
1743
+ let payload;
1744
+ let event_id = null;
1745
+ let complete = false;
1746
+ let last_status = {};
1747
+ let url_params = typeof window !== "undefined" && typeof document !== "undefined" ? new URLSearchParams(window.location.search).toString() : "";
1748
+ const events_to_publish = options?.events?.reduce((acc, event) => {
1749
+ acc[event] = true;
1750
+ return acc;
1751
+ }, {}) || {};
1752
+ function fire_event(event) {
1753
+ update_run_history(history_scope, history_run_id, event);
1754
+ if (all_events || events_to_publish[event.type]) push_event(event);
1755
+ }
1756
+ async function cancel() {
1757
+ let reset_request = {};
1758
+ let cancel_request = {};
1759
+ reset_request = { event_id };
1760
+ cancel_request = {
1761
+ event_id,
1762
+ session_hash,
1763
+ fn_index
1764
+ };
1765
+ try {
1766
+ if (!config) throw new Error("Could not resolve app config");
1767
+ if ("event_id" in cancel_request) await fetch(`${config.root}${api_prefix}/${CANCEL_URL}`, {
1768
+ headers: { "Content-Type": "application/json" },
1769
+ method: "POST",
1770
+ body: JSON.stringify(cancel_request)
1771
+ });
1772
+ await fetch(`${config.root}${api_prefix}/${RESET_URL}`, {
1773
+ headers: { "Content-Type": "application/json" },
1774
+ method: "POST",
1775
+ body: JSON.stringify(reset_request)
1776
+ });
1777
+ } catch (e) {
1778
+ console.warn("The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable.");
1779
+ }
1780
+ }
1781
+ const resolve_heartbeat = async (config) => {
1782
+ await this._resolve_heartbeat(config);
1783
+ };
1784
+ async function handle_render_config(render_config) {
1785
+ if (!config) return;
1786
+ let render_id = render_config.render_id;
1787
+ config.components = [...config.components.filter((c) => c.props.rendered_in !== render_id), ...render_config.components];
1788
+ config.dependencies = [...config.dependencies.filter((d) => d.rendered_in !== render_id), ...render_config.dependencies];
1789
+ const any_state = config.components.some((c) => c.type === "state");
1790
+ const any_unload = config.dependencies.some((d) => d.targets.some((t) => t[1] === "unload"));
1791
+ config.connect_heartbeat = any_state || any_unload;
1792
+ await resolve_heartbeat(config);
1793
+ fire_event({
1794
+ type: "render",
1795
+ data: render_config,
1796
+ endpoint: _endpoint,
1797
+ fn_index
1798
+ });
1799
+ }
1800
+ const job = this.handle_blob(config.root, resolved_data, endpoint_info).then(async (_payload) => {
1801
+ let input_data = handle_payload(_payload, dependency, config.components, "input", true);
1802
+ update_run_inputs(history_scope, history_run_id, input_data || []);
1803
+ payload = {
1804
+ data: input_data || [],
1805
+ event_data,
1806
+ fn_index,
1807
+ trigger_id,
1808
+ ...options.oauth_token && endpoint_info?.oauth_token ? { oauth_token: options.oauth_token } : {}
1809
+ };
1810
+ if (skip_queue(fn_index, config)) {
1811
+ fire_event({
1812
+ type: "status",
1813
+ endpoint: _endpoint,
1814
+ stage: "pending",
1815
+ queue: false,
1816
+ fn_index,
1817
+ time: /* @__PURE__ */ new Date()
1818
+ });
1819
+ post_data(`${config.root}${api_prefix}/run${_endpoint.startsWith("/") ? _endpoint : `/${_endpoint}`}${url_params ? "?" + url_params : ""}`, {
1820
+ ...payload,
1821
+ session_hash
1822
+ }, addt_headers).then(async ([output, status_code]) => {
1823
+ const data = output.data;
1824
+ if (status_code == 200) {
1825
+ fire_event({
1826
+ type: "data",
1827
+ endpoint: _endpoint,
1828
+ fn_index,
1829
+ data: handle_payload(data, dependency, config.components, "output", options.with_null_state),
1830
+ time: /* @__PURE__ */ new Date(),
1831
+ event_data,
1832
+ trigger_id
1833
+ });
1834
+ if (output.render_config) await handle_render_config(output.render_config);
1835
+ fire_event({
1836
+ type: "status",
1837
+ endpoint: _endpoint,
1838
+ fn_index,
1839
+ stage: "complete",
1840
+ eta: output.average_duration,
1841
+ queue: false,
1842
+ time: /* @__PURE__ */ new Date()
1843
+ });
1844
+ } else {
1845
+ const is_connection_error = output?.error === BROKEN_CONNECTION_MSG;
1846
+ fire_event({
1847
+ type: "status",
1848
+ stage: "error",
1849
+ endpoint: _endpoint,
1850
+ fn_index,
1851
+ message: output.error,
1852
+ broken: is_connection_error,
1853
+ queue: false,
1854
+ time: /* @__PURE__ */ new Date()
1855
+ });
1856
+ }
1857
+ }).catch((e) => {
1858
+ fire_event({
1859
+ type: "status",
1860
+ stage: "error",
1861
+ message: e.message,
1862
+ endpoint: _endpoint,
1863
+ fn_index,
1864
+ queue: false,
1865
+ time: /* @__PURE__ */ new Date()
1866
+ });
1867
+ });
1868
+ } else if (protocol == "sse") {
1869
+ fire_event({
1870
+ type: "status",
1871
+ stage: "pending",
1872
+ queue: true,
1873
+ endpoint: _endpoint,
1874
+ fn_index,
1875
+ time: /* @__PURE__ */ new Date()
1876
+ });
1877
+ var params = new URLSearchParams({
1878
+ fn_index: fn_index.toString(),
1879
+ session_hash
1880
+ }).toString();
1881
+ let url = new URL(`${config.root}${api_prefix}/${SSE_URL}?${url_params ? url_params + "&" : ""}${params}`);
1882
+ if (this.jwt) url.searchParams.set("__sign", this.jwt);
1883
+ stream = this.stream(url);
1884
+ if (!stream) return Promise.reject(/* @__PURE__ */ new Error("Cannot connect to SSE endpoint: " + url.toString()));
1885
+ stream.onmessage = async function(event) {
1886
+ const { type, status, data } = handle_message(JSON.parse(event.data), last_status[fn_index]);
1887
+ if (type === "update" && status && !complete) {
1888
+ fire_event({
1889
+ type: "status",
1890
+ endpoint: _endpoint,
1891
+ fn_index,
1892
+ time: /* @__PURE__ */ new Date(),
1893
+ ...status
1894
+ });
1895
+ if (status.stage === "error") {
1896
+ stream?.close();
1897
+ close();
1898
+ }
1899
+ } else if (type === "data") {
1900
+ let [_, status] = await post_data(`${config.root}${api_prefix}/queue/data`, {
1901
+ ...payload,
1902
+ session_hash,
1903
+ event_id
1904
+ });
1905
+ if (status !== 200) {
1906
+ fire_event({
1907
+ type: "status",
1908
+ stage: "error",
1909
+ message: BROKEN_CONNECTION_MSG,
1910
+ queue: true,
1911
+ endpoint: _endpoint,
1912
+ fn_index,
1913
+ time: /* @__PURE__ */ new Date()
1914
+ });
1915
+ stream?.close();
1916
+ close();
1917
+ }
1918
+ } else if (type === "complete") complete = status;
1919
+ else if (type === "log") fire_event({
1920
+ type: "log",
1921
+ title: data.title,
1922
+ log: data.log,
1923
+ level: data.level,
1924
+ endpoint: _endpoint,
1925
+ duration: data.duration,
1926
+ visible: data.visible,
1927
+ fn_index
1928
+ });
1929
+ else if (type === "generating" || type === "streaming") fire_event({
1930
+ type: "status",
1931
+ time: /* @__PURE__ */ new Date(),
1932
+ ...status,
1933
+ stage: status?.stage,
1934
+ queue: true,
1935
+ endpoint: _endpoint,
1936
+ fn_index
1937
+ });
1938
+ if (data) {
1939
+ fire_event({
1940
+ type: "data",
1941
+ time: /* @__PURE__ */ new Date(),
1942
+ data: handle_payload(data.data, dependency, config.components, "output", options.with_null_state),
1943
+ endpoint: _endpoint,
1944
+ fn_index,
1945
+ event_data,
1946
+ trigger_id
1947
+ });
1948
+ if (complete) {
1949
+ fire_event({
1950
+ type: "status",
1951
+ time: /* @__PURE__ */ new Date(),
1952
+ ...complete,
1953
+ stage: status?.stage,
1954
+ queue: true,
1955
+ endpoint: _endpoint,
1956
+ fn_index
1957
+ });
1958
+ stream?.close();
1959
+ close();
1960
+ }
1961
+ }
1962
+ };
1963
+ } else if (protocol == "sse_v1" || protocol == "sse_v2" || protocol == "sse_v2.1" || protocol == "sse_v3") {
1964
+ fire_event({
1965
+ type: "status",
1966
+ stage: "pending",
1967
+ queue: true,
1968
+ endpoint: _endpoint,
1969
+ fn_index,
1970
+ time: /* @__PURE__ */ new Date()
1971
+ });
1972
+ let hostname = "";
1973
+ if (typeof window !== "undefined" && typeof document !== "undefined") hostname = window?.location?.hostname;
1974
+ const origin = get_zerogpu_origin(hostname);
1975
+ return (typeof window !== "undefined" && typeof document !== "undefined" && window.parent != window && !!origin && window.supports_zerogpu_headers ? post_message("zerogpu-headers", origin) : Promise.resolve(null)).then((headers) => {
1976
+ const combined_headers = {
1977
+ ...addt_headers,
1978
+ ...headers || {}
1979
+ };
1980
+ return post_data(`${config.root}${api_prefix}/${SSE_DATA_URL}?${url_params}`, {
1981
+ ...payload,
1982
+ session_hash
1983
+ }, combined_headers);
1984
+ }).then(async ([response, status]) => {
1985
+ if (response.event_id) event_id_final = response.event_id;
1986
+ if (status === 503) {
1987
+ fire_event({
1988
+ type: "status",
1989
+ stage: "error",
1990
+ message: QUEUE_FULL_MSG,
1991
+ queue: true,
1992
+ endpoint: _endpoint,
1993
+ fn_index,
1994
+ time: /* @__PURE__ */ new Date(),
1995
+ visible: true
1996
+ });
1997
+ close();
1998
+ } else if (status === 422) {
1999
+ fire_event({
2000
+ type: "status",
2001
+ stage: "error",
2002
+ message: response.detail,
2003
+ queue: true,
2004
+ endpoint: _endpoint,
2005
+ fn_index,
2006
+ code: "validation_error",
2007
+ time: /* @__PURE__ */ new Date(),
2008
+ visible: true
2009
+ });
2010
+ close();
2011
+ } else if (status !== 200) {
2012
+ const is_connection_error = response?.error === BROKEN_CONNECTION_MSG;
2013
+ fire_event({
2014
+ type: "status",
2015
+ stage: "error",
2016
+ broken: is_connection_error,
2017
+ message: is_connection_error ? BROKEN_CONNECTION_MSG : response.detail || response.error,
2018
+ queue: true,
2019
+ endpoint: _endpoint,
2020
+ fn_index,
2021
+ time: /* @__PURE__ */ new Date(),
2022
+ visible: true
2023
+ });
2024
+ close();
2025
+ } else {
2026
+ event_id = response.event_id;
2027
+ event_id_final = event_id;
2028
+ let callback = async function(_data) {
2029
+ try {
2030
+ const { type, status, data, original_msg } = handle_message(_data, last_status[fn_index]);
2031
+ if (type == "heartbeat") return;
2032
+ if (type === "update" && status && !complete) fire_event({
2033
+ type: "status",
2034
+ endpoint: _endpoint,
2035
+ fn_index,
2036
+ time: /* @__PURE__ */ new Date(),
2037
+ original_msg,
2038
+ ...status
2039
+ });
2040
+ else if (type === "complete") complete = status;
2041
+ else if (type == "unexpected_error" || type == "broken_connection") {
2042
+ console.error("Unexpected error", status?.message);
2043
+ const broken = type === "broken_connection";
2044
+ fire_event({
2045
+ type: "status",
2046
+ stage: "error",
2047
+ message: status?.message || "An Unexpected Error Occurred!",
2048
+ queue: true,
2049
+ endpoint: _endpoint,
2050
+ broken,
2051
+ session_not_found: status?.session_not_found,
2052
+ fn_index,
2053
+ time: /* @__PURE__ */ new Date()
2054
+ });
2055
+ } else if (type === "log") {
2056
+ fire_event({
2057
+ type: "log",
2058
+ title: data.title,
2059
+ log: data.log,
2060
+ level: data.level,
2061
+ endpoint: _endpoint,
2062
+ duration: data.duration,
2063
+ visible: data.visible,
2064
+ fn_index
2065
+ });
2066
+ return;
2067
+ } else if (type === "generating" || type === "streaming") {
2068
+ fire_event({
2069
+ type: "status",
2070
+ time: /* @__PURE__ */ new Date(),
2071
+ ...status,
2072
+ stage: status?.stage,
2073
+ queue: true,
2074
+ endpoint: _endpoint,
2075
+ fn_index
2076
+ });
2077
+ if (data && dependency.connection !== "stream" && [
2078
+ "sse_v2",
2079
+ "sse_v2.1",
2080
+ "sse_v3"
2081
+ ].includes(protocol)) apply_diff_stream(pending_diff_streams, event_id, data);
2082
+ }
2083
+ if (data) {
2084
+ fire_event({
2085
+ type: "data",
2086
+ time: /* @__PURE__ */ new Date(),
2087
+ data: handle_payload(data.data, dependency, config.components, "output", options.with_null_state),
2088
+ endpoint: _endpoint,
2089
+ fn_index
2090
+ });
2091
+ if (data.render_config) await handle_render_config(data.render_config);
2092
+ if (complete) {
2093
+ fire_event({
2094
+ type: "status",
2095
+ time: /* @__PURE__ */ new Date(),
2096
+ ...complete,
2097
+ stage: status?.stage,
2098
+ queue: true,
2099
+ endpoint: _endpoint,
2100
+ fn_index
2101
+ });
2102
+ close();
2103
+ }
2104
+ }
2105
+ if (status?.stage === "complete" || status?.stage === "error") {
2106
+ if (event_callbacks[event_id]) delete event_callbacks[event_id];
2107
+ if (event_id in pending_diff_streams) delete pending_diff_streams[event_id];
2108
+ close();
2109
+ }
2110
+ } catch (e) {
2111
+ console.error("Unexpected client exception", e);
2112
+ fire_event({
2113
+ type: "status",
2114
+ stage: "error",
2115
+ message: "An Unexpected Error Occurred!",
2116
+ queue: true,
2117
+ endpoint: _endpoint,
2118
+ fn_index,
2119
+ time: /* @__PURE__ */ new Date()
2120
+ });
2121
+ if ([
2122
+ "sse_v2",
2123
+ "sse_v2.1",
2124
+ "sse_v3"
2125
+ ].includes(protocol)) {
2126
+ close_stream(stream_status, that.abort_controller);
2127
+ stream_status.open = false;
2128
+ close();
2129
+ }
2130
+ }
2131
+ };
2132
+ if (event_id in pending_stream_messages) {
2133
+ pending_stream_messages[event_id].forEach((msg) => callback(msg));
2134
+ delete pending_stream_messages[event_id];
2135
+ }
2136
+ event_callbacks[event_id] = callback;
2137
+ unclosed_events.add(event_id);
2138
+ if (!stream_status.open) await this.open_stream();
2139
+ }
2140
+ });
2141
+ }
2142
+ });
2143
+ job.catch((e) => {
2144
+ fire_event({
2145
+ type: "status",
2146
+ stage: "error",
2147
+ message: e instanceof Error ? e.message : String(e),
2148
+ queue: !skip_queue(fn_index, config),
2149
+ endpoint: _endpoint,
2150
+ fn_index,
2151
+ time: /* @__PURE__ */ new Date()
2152
+ });
2153
+ close();
2154
+ });
2155
+ let done = false;
2156
+ const values = [];
2157
+ const resolvers = [];
2158
+ function close() {
2159
+ done = true;
2160
+ while (resolvers.length > 0) resolvers.shift()({
2161
+ value: void 0,
2162
+ done: true
2163
+ });
2164
+ }
2165
+ function push(data) {
2166
+ if (resolvers.length > 0) resolvers.shift()(data);
2167
+ else values.push(data);
2168
+ }
2169
+ function push_error(error) {
2170
+ push(thenable_reject(error));
2171
+ close();
2172
+ }
2173
+ function push_event(event) {
2174
+ push({
2175
+ value: event,
2176
+ done: false
2177
+ });
2178
+ }
2179
+ function next() {
2180
+ if (values.length > 0) return Promise.resolve(values.shift());
2181
+ if (done) return Promise.resolve({
2182
+ value: void 0,
2183
+ done: true
2184
+ });
2185
+ return new Promise((resolve) => resolvers.push(resolve));
2186
+ }
2187
+ const iterator = {
2188
+ [Symbol.asyncIterator]: () => iterator,
2189
+ next,
2190
+ throw: async (value) => {
2191
+ push_error(value);
2192
+ return next();
2193
+ },
2194
+ return: async () => {
2195
+ close();
2196
+ return {
2197
+ value: void 0,
2198
+ done: true
2199
+ };
2200
+ },
2201
+ cancel,
2202
+ send_chunk: (payload) => {
2203
+ this.post_data(`${config.root}${api_prefix}/stream/${event_id_final}`, {
2204
+ ...payload,
2205
+ session_hash: this.session_hash
2206
+ });
2207
+ },
2208
+ close_stream: () => {
2209
+ this.post_data(`${config.root}${api_prefix}/stream/${event_id_final}/close`, {});
2210
+ close();
2211
+ },
2212
+ event_id: () => event_id_final,
2213
+ wait_for_id: async () => {
2214
+ await job;
2215
+ return event_id;
2216
+ }
2217
+ };
2218
+ return iterator;
2219
+ } catch (error) {
2220
+ console.error("Submit function encountered an error:", error);
2221
+ throw error;
2222
+ }
2147
2223
  }
2148
2224
  function thenable_reject(error) {
2149
- return {
2150
- then: (resolve, reject) => reject(error)
2151
- };
2225
+ return { then: (resolve, reject) => reject(error) };
2152
2226
  }
2153
2227
  function get_endpoint_info(api_info, endpoint, api_map, config) {
2154
- let fn_index;
2155
- let endpoint_info;
2156
- let dependency;
2157
- if (typeof endpoint === "number") {
2158
- fn_index = endpoint;
2159
- endpoint_info = api_info.unnamed_endpoints[fn_index];
2160
- dependency = config.dependencies.find((dep) => dep.id == endpoint);
2161
- } else {
2162
- const trimmed_endpoint = endpoint.replace(/^\//, "");
2163
- fn_index = api_map[trimmed_endpoint];
2164
- endpoint_info = api_info.named_endpoints[endpoint.trim()];
2165
- dependency = config.dependencies.find(
2166
- (dep) => dep.id == api_map[trimmed_endpoint]
2167
- );
2168
- }
2169
- if (typeof fn_index !== "number") {
2170
- throw new Error(
2171
- "There is no endpoint matching that name of fn_index matching that number."
2172
- );
2173
- }
2174
- return { fn_index, endpoint_info, dependency };
2175
- }
2176
- class Client {
2177
- app_reference;
2178
- options;
2179
- deep_link = null;
2180
- config;
2181
- api_prefix = "";
2182
- api_info;
2183
- api_map = {};
2184
- session_hash = Math.random().toString(36).substring(2);
2185
- jwt = false;
2186
- last_status = {};
2187
- cookies = null;
2188
- // streaming
2189
- stream_status = { open: false };
2190
- closed = false;
2191
- pending_stream_messages = {};
2192
- pending_diff_streams = {};
2193
- event_callbacks = {};
2194
- unclosed_events = /* @__PURE__ */ new Set();
2195
- heartbeat_event = null;
2196
- abort_controller = null;
2197
- stream_instance = null;
2198
- current_payload;
2199
- get_url_config(url = null) {
2200
- if (!this.config) {
2201
- throw new Error(CONFIG_ERROR_MSG);
2202
- }
2203
- if (url === null) {
2204
- url = window.location.href;
2205
- }
2206
- const stripSlashes = (str) => str.replace(/^\/+|\/+$/g, "");
2207
- let root_path = stripSlashes(new URL(this.config.root).pathname);
2208
- let url_path = stripSlashes(new URL(url).pathname);
2209
- let page;
2210
- if (!url_path.startsWith(root_path)) {
2211
- page = "";
2212
- } else {
2213
- page = stripSlashes(url_path.substring(root_path.length));
2214
- }
2215
- return this.get_page_config(page);
2216
- }
2217
- get_page_config(page) {
2218
- if (!this.config) {
2219
- throw new Error(CONFIG_ERROR_MSG);
2220
- }
2221
- let config = this.config;
2222
- if (!(page in config.page)) {
2223
- page = "";
2224
- }
2225
- return {
2226
- ...config,
2227
- current_page: page,
2228
- layout: config.page[page].layout,
2229
- components: config.components.filter(
2230
- (c) => config.page[page].components.includes(c.id)
2231
- ),
2232
- dependencies: this.config.dependencies.filter(
2233
- (d) => config.page[page].dependencies.includes(d.id)
2234
- )
2235
- };
2236
- }
2237
- fetch(input, init) {
2238
- const headers = new Headers(init?.headers || {});
2239
- if (this && this.cookies) {
2240
- headers.append("Cookie", this.cookies);
2241
- }
2242
- if (this && this.options.headers) {
2243
- let additional_headers = new Headers(this.options.headers);
2244
- additional_headers.forEach((value, name) => {
2245
- headers.append(name, value);
2246
- });
2247
- }
2248
- return fetch(input, { ...init, headers });
2249
- }
2250
- stream(url) {
2251
- const headers = new Headers();
2252
- if (this && this.cookies) {
2253
- headers.append("Cookie", this.cookies);
2254
- }
2255
- if (this && this.options.headers) {
2256
- let additional_headers = new Headers(this.options.headers);
2257
- additional_headers.forEach((value, name) => {
2258
- headers.append(name, value);
2259
- });
2260
- }
2261
- if (this && this.options.token) {
2262
- headers.append("Authorization", `Bearer ${this.options.token}`);
2263
- }
2264
- this.abort_controller = new AbortController();
2265
- this.stream_instance = readable_stream(url.toString(), {
2266
- credentials: this.options.credentials ?? "same-origin",
2267
- headers,
2268
- signal: this.abort_controller.signal
2269
- });
2270
- return this.stream_instance;
2271
- }
2272
- view_api;
2273
- upload_files;
2274
- upload;
2275
- handle_blob;
2276
- post_data;
2277
- submit;
2278
- predict;
2279
- open_stream;
2280
- resolve_config;
2281
- resolve_cookies;
2282
- constructor(app_reference, options = { events: ["data"] }) {
2283
- this.app_reference = app_reference;
2284
- this.deep_link = options.query_params?.deep_link || null;
2285
- if (!options.events) {
2286
- options.events = ["data"];
2287
- }
2288
- this.options = options;
2289
- this.current_payload = {};
2290
- if (options.cookies) {
2291
- this.cookies = options.cookies;
2292
- }
2293
- this.view_api = view_api.bind(this);
2294
- this.upload_files = upload_files.bind(this);
2295
- this.handle_blob = handle_blob.bind(this);
2296
- this.post_data = post_data.bind(this);
2297
- this.submit = submit.bind(this);
2298
- this.predict = predict.bind(this);
2299
- this.open_stream = open_stream.bind(this);
2300
- this.resolve_config = resolve_config.bind(this);
2301
- this.resolve_cookies = resolve_cookies.bind(this);
2302
- this.upload = upload.bind(this);
2303
- this.fetch = this.fetch.bind(this);
2304
- this.handle_space_success = this.handle_space_success.bind(this);
2305
- this.stream = this.stream.bind(this);
2306
- }
2307
- async init() {
2308
- initialize_zerogpu_handshake();
2309
- if (this.options.auth) {
2310
- await this.resolve_cookies();
2311
- }
2312
- await this._resolve_config().then(
2313
- ({ config }) => this._resolve_heartbeat(config)
2314
- );
2315
- this.api_info = await this.view_api();
2316
- this.api_map = map_names_to_ids(this.config?.dependencies || []);
2317
- }
2318
- async _resolve_heartbeat(_config) {
2319
- if (_config) {
2320
- this.config = _config;
2321
- this.api_prefix = _config.api_prefix || "";
2322
- if (this.config && this.config.connect_heartbeat) {
2323
- if (this.config.space_id && this.options.token) {
2324
- this.jwt = await get_jwt(
2325
- this.config.space_id,
2326
- this.options.token,
2327
- this.cookies
2328
- );
2329
- }
2330
- }
2331
- }
2332
- if (_config.space_id && this.options.token) {
2333
- this.jwt = await get_jwt(_config.space_id, this.options.token);
2334
- }
2335
- if (this.config && this.config.connect_heartbeat) {
2336
- const heartbeat_url = new URL(
2337
- `${this.config.root}${this.api_prefix}/${HEARTBEAT_URL}/${this.session_hash}`
2338
- );
2339
- if (this.jwt) {
2340
- heartbeat_url.searchParams.set("__sign", this.jwt);
2341
- }
2342
- if (!this.heartbeat_event) {
2343
- this.heartbeat_event = this.stream(heartbeat_url);
2344
- }
2345
- }
2346
- }
2347
- static async connect(app_reference, options = {
2348
- events: ["data"]
2349
- }) {
2350
- const client2 = new this(app_reference, options);
2351
- if (options.session_hash) {
2352
- client2.session_hash = options.session_hash;
2353
- }
2354
- await client2.init();
2355
- return client2;
2356
- }
2357
- async reconnect() {
2358
- const app_id_url = new URL(
2359
- `${this.config.root}${this.api_prefix}/${APP_ID_URL}`
2360
- );
2361
- let app_id;
2362
- try {
2363
- const response = await this.fetch(app_id_url);
2364
- if (!response.ok) {
2365
- throw new Error();
2366
- }
2367
- app_id = (await response.json()).app_id;
2368
- } catch (e) {
2369
- return "broken";
2370
- }
2371
- if (app_id !== this.config.app_id) {
2372
- return "changed";
2373
- }
2374
- return "connected";
2375
- }
2376
- close() {
2377
- this.closed = true;
2378
- close_stream(this.stream_status, this.abort_controller);
2379
- }
2380
- set_current_payload(payload) {
2381
- this.current_payload = payload;
2382
- }
2383
- static async duplicate(app_reference, options = {
2384
- events: ["data"]
2385
- }) {
2386
- return duplicate(app_reference, options);
2387
- }
2388
- async _resolve_config() {
2389
- const { http_protocol, host, space_id } = await process_endpoint(
2390
- this.app_reference,
2391
- this.options.token
2392
- );
2393
- const { status_callback } = this.options;
2394
- if (space_id && status_callback) {
2395
- await check_and_wake_space(space_id, status_callback);
2396
- }
2397
- let config;
2398
- try {
2399
- let configUrl = `${http_protocol}//${host}`;
2400
- config = await this.resolve_config(configUrl);
2401
- if (!config) {
2402
- throw new Error(CONFIG_ERROR_MSG);
2403
- }
2404
- return this.config_success(config);
2405
- } catch (e) {
2406
- if (space_id && status_callback) {
2407
- check_space_status(
2408
- space_id,
2409
- RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain",
2410
- this.handle_space_success
2411
- );
2412
- } else {
2413
- if (status_callback)
2414
- status_callback({
2415
- status: "error",
2416
- message: "Could not load this space.",
2417
- load_status: "error",
2418
- detail: "NOT_FOUND"
2419
- });
2420
- throw Error(e);
2421
- }
2422
- }
2423
- }
2424
- async config_success(_config) {
2425
- this.config = _config;
2426
- this.api_prefix = _config.api_prefix || "";
2427
- if (this.config.auth_required) {
2428
- return this.prepare_return_obj();
2429
- }
2430
- try {
2431
- this.api_info = await this.view_api();
2432
- } catch (e) {
2433
- console.error(API_INFO_ERROR_MSG + e.message);
2434
- }
2435
- return this.prepare_return_obj();
2436
- }
2437
- async handle_space_success(status) {
2438
- if (!this) {
2439
- throw new Error(CONFIG_ERROR_MSG);
2440
- }
2441
- const { status_callback } = this.options;
2442
- if (status_callback) status_callback(status);
2443
- if (status.status === "running") {
2444
- try {
2445
- this.config = await this._resolve_config();
2446
- this.api_prefix = this?.config?.api_prefix || "";
2447
- if (!this.config) {
2448
- throw new Error(CONFIG_ERROR_MSG);
2449
- }
2450
- const _config = await this.config_success(this.config);
2451
- return _config;
2452
- } catch (e) {
2453
- if (status_callback) {
2454
- status_callback({
2455
- status: "error",
2456
- message: "Could not load this space.",
2457
- load_status: "error",
2458
- detail: "NOT_FOUND"
2459
- });
2460
- }
2461
- throw e;
2462
- }
2463
- }
2464
- }
2465
- async component_server(component_id, fn_name, data) {
2466
- if (!this.config) {
2467
- throw new Error(CONFIG_ERROR_MSG);
2468
- }
2469
- const headers = {};
2470
- const { token } = this.options;
2471
- const { session_hash } = this;
2472
- if (token) {
2473
- headers.Authorization = `Bearer ${this.options.token}`;
2474
- }
2475
- let root_url;
2476
- let component = this.config.components.find(
2477
- (comp) => comp.id === component_id
2478
- );
2479
- if (component?.props?.root_url) {
2480
- root_url = component.props.root_url;
2481
- } else {
2482
- root_url = this.config.root;
2483
- }
2484
- let body;
2485
- if (typeof data === "object" && data !== null && "binary" in data) {
2486
- const _data = data;
2487
- body = new FormData();
2488
- for (const key in _data.data) {
2489
- if (key === "binary") continue;
2490
- body.append(key, _data.data[key]);
2491
- }
2492
- body.set("component_id", component_id.toString());
2493
- body.set("fn_name", fn_name);
2494
- body.set("session_hash", session_hash);
2495
- } else {
2496
- body = JSON.stringify({
2497
- data,
2498
- component_id,
2499
- fn_name,
2500
- session_hash
2501
- });
2502
- headers["Content-Type"] = "application/json";
2503
- }
2504
- if (token) {
2505
- headers.Authorization = `Bearer ${token}`;
2506
- }
2507
- try {
2508
- const response = await this.fetch(
2509
- `${root_url}${this.api_prefix}/${COMPONENT_SERVER_URL}/`,
2510
- {
2511
- method: "POST",
2512
- body,
2513
- headers,
2514
- credentials: this.options.credentials ?? "same-origin"
2515
- }
2516
- );
2517
- if (!response.ok) {
2518
- throw new Error(
2519
- "Could not connect to component server: " + response.statusText
2520
- );
2521
- }
2522
- const output = await response.json();
2523
- return output;
2524
- } catch (e) {
2525
- console.warn(e);
2526
- }
2527
- }
2528
- set_cookies(raw_cookies) {
2529
- this.cookies = parse_and_set_cookies(raw_cookies).join("; ");
2530
- }
2531
- prepare_return_obj() {
2532
- return {
2533
- config: this.config,
2534
- predict: this.predict,
2535
- submit: this.submit,
2536
- view_api: this.view_api,
2537
- component_server: this.component_server
2538
- };
2539
- }
2540
- }
2541
- async function client(app_reference, options = {
2542
- events: ["data"]
2543
- }) {
2544
- return await Client.connect(app_reference, options);
2228
+ let fn_index;
2229
+ let endpoint_info;
2230
+ let dependency;
2231
+ if (typeof endpoint === "number") {
2232
+ fn_index = endpoint;
2233
+ endpoint_info = api_info.unnamed_endpoints[fn_index];
2234
+ dependency = config.dependencies.find((dep) => dep.id == endpoint);
2235
+ } else {
2236
+ const trimmed_endpoint = endpoint.replace(/^\//, "");
2237
+ fn_index = api_map[trimmed_endpoint];
2238
+ endpoint_info = api_info.named_endpoints[endpoint.trim()] ?? api_info.named_endpoints[`/${trimmed_endpoint}`];
2239
+ dependency = config.dependencies.find((dep) => dep.id == api_map[trimmed_endpoint]);
2240
+ }
2241
+ if (typeof fn_index !== "number" || !dependency) {
2242
+ const valid_endpoints = config.dependencies.filter((dep) => dep.api_name).map((dep) => `"/${dep.api_name}"`).join(", ");
2243
+ throw new Error(`No endpoint matching ${JSON.stringify(endpoint)} was found. ` + (valid_endpoints ? `Valid named endpoints are: ${valid_endpoints}. ` : "This app exposes no named endpoints. ") + "An fn_index (number) of an existing dependency can also be used.");
2244
+ }
2245
+ return {
2246
+ fn_index,
2247
+ endpoint_info,
2248
+ dependency
2249
+ };
2545
2250
  }
2546
- async function duplicate_space(app_reference, options) {
2547
- return await Client.duplicate(app_reference, options);
2548
- }
2549
- export {
2550
- Client,
2551
- FileData,
2552
- MISSING_CREDENTIALS_MSG,
2553
- client,
2554
- duplicate_space as duplicate,
2555
- handle_file,
2556
- predict,
2557
- prepare_files,
2558
- submit,
2559
- upload,
2560
- upload_files
2251
+ //#endregion
2252
+ //#region src/client.ts
2253
+ var Client = class {
2254
+ app_reference;
2255
+ options;
2256
+ deep_link = null;
2257
+ config;
2258
+ api_prefix = "";
2259
+ api_info;
2260
+ api_map = {};
2261
+ session_hash = Math.random().toString(36).substring(2);
2262
+ jwt = false;
2263
+ last_status = {};
2264
+ cookies = null;
2265
+ stream_status = { open: false };
2266
+ closed = false;
2267
+ pending_stream_messages = {};
2268
+ pending_diff_streams = {};
2269
+ event_callbacks = {};
2270
+ unclosed_events = /* @__PURE__ */ new Set();
2271
+ heartbeat_event = null;
2272
+ abort_controller = null;
2273
+ stream_instance = null;
2274
+ current_payload;
2275
+ get_url_config(url = null) {
2276
+ if (!this.config) throw new Error(CONFIG_ERROR_MSG);
2277
+ if (url === null) url = window.location.href;
2278
+ const stripSlashes = (str) => str.replace(/^\/+|\/+$/g, "");
2279
+ let root_path = stripSlashes(new URL(this.config.root).pathname);
2280
+ let url_path = stripSlashes(new URL(url).pathname);
2281
+ let page;
2282
+ if (!url_path.startsWith(root_path)) page = "";
2283
+ else page = stripSlashes(url_path.substring(root_path.length));
2284
+ return this.get_page_config(page);
2285
+ }
2286
+ get_page_config(page) {
2287
+ if (!this.config) throw new Error(CONFIG_ERROR_MSG);
2288
+ let config = this.config;
2289
+ if (!(page in config.page)) page = "";
2290
+ return {
2291
+ ...config,
2292
+ current_page: page,
2293
+ layout: config.page[page].layout,
2294
+ components: config.components.filter((c) => config.page[page].components.includes(c.id)),
2295
+ dependencies: this.config.dependencies.filter((d) => config.page[page].dependencies.includes(d.id))
2296
+ };
2297
+ }
2298
+ fetch(input, init) {
2299
+ const headers = new Headers(init?.headers || {});
2300
+ if (this && this.cookies) headers.append("Cookie", this.cookies);
2301
+ if (this && this.options.headers) new Headers(this.options.headers).forEach((value, name) => {
2302
+ headers.append(name, value);
2303
+ });
2304
+ return fetch(input, {
2305
+ ...init,
2306
+ headers
2307
+ });
2308
+ }
2309
+ stream(url) {
2310
+ const headers = new Headers();
2311
+ if (this && this.cookies) headers.append("Cookie", this.cookies);
2312
+ if (this && this.options.headers) new Headers(this.options.headers).forEach((value, name) => {
2313
+ headers.append(name, value);
2314
+ });
2315
+ if (this && this.options.token) headers.append("Authorization", `Bearer ${this.options.token}`);
2316
+ this.abort_controller = new AbortController();
2317
+ this.stream_instance = readable_stream(url.toString(), {
2318
+ credentials: this.options.credentials ?? "same-origin",
2319
+ headers,
2320
+ signal: this.abort_controller.signal
2321
+ });
2322
+ return this.stream_instance;
2323
+ }
2324
+ view_api;
2325
+ upload_files;
2326
+ upload;
2327
+ handle_blob;
2328
+ post_data;
2329
+ submit;
2330
+ predict;
2331
+ open_stream;
2332
+ resolve_config;
2333
+ resolve_cookies;
2334
+ constructor(app_reference, options = { events: ["data"] }) {
2335
+ this.app_reference = app_reference;
2336
+ this.deep_link = options.query_params?.deep_link || null;
2337
+ if (!options.events) options.events = ["data"];
2338
+ normalise_token_option(options);
2339
+ this.options = options;
2340
+ this.current_payload = {};
2341
+ if (options.cookies) this.cookies = options.cookies;
2342
+ this.view_api = view_api.bind(this);
2343
+ this.upload_files = upload_files.bind(this);
2344
+ this.handle_blob = handle_blob.bind(this);
2345
+ this.post_data = post_data.bind(this);
2346
+ this.submit = submit.bind(this);
2347
+ this.predict = predict.bind(this);
2348
+ this.open_stream = open_stream.bind(this);
2349
+ this.resolve_config = resolve_config.bind(this);
2350
+ this.resolve_cookies = resolve_cookies.bind(this);
2351
+ this.upload = upload.bind(this);
2352
+ this.fetch = this.fetch.bind(this);
2353
+ this.handle_space_success = this.handle_space_success.bind(this);
2354
+ this.stream = this.stream.bind(this);
2355
+ }
2356
+ async init() {
2357
+ initialize_zerogpu_handshake();
2358
+ if (this.options.auth) await this.resolve_cookies();
2359
+ await this._resolve_config().then((res) => res?.config && this._resolve_heartbeat(res.config));
2360
+ try {
2361
+ this.api_info = await this.view_api();
2362
+ } catch (e) {
2363
+ console.error(e.message);
2364
+ }
2365
+ this.api_map = map_names_to_ids(this.config?.dependencies || []);
2366
+ }
2367
+ async _resolve_heartbeat(_config) {
2368
+ if (_config) {
2369
+ this.config = _config;
2370
+ this.api_prefix = _config.api_prefix || "";
2371
+ if (this.config && this.config.connect_heartbeat) {
2372
+ if (this.config.space_id && this.options.token) this.jwt = await get_jwt(this.config.space_id, this.options.token, this.cookies);
2373
+ }
2374
+ }
2375
+ if (_config.space_id && this.options.token) this.jwt = await get_jwt(_config.space_id, this.options.token);
2376
+ if (this.config && this.config.connect_heartbeat) {
2377
+ const heartbeat_url = new URL(`${this.config.root}${this.api_prefix}/${HEARTBEAT_URL}/${this.session_hash}`);
2378
+ if (this.jwt) heartbeat_url.searchParams.set("__sign", this.jwt);
2379
+ if (!this.heartbeat_event) this.heartbeat_event = this.stream(heartbeat_url);
2380
+ }
2381
+ }
2382
+ static async connect(app_reference, options = { events: ["data"] }) {
2383
+ const client = new this(app_reference, options);
2384
+ if (options.session_hash) client.session_hash = options.session_hash;
2385
+ await client.init();
2386
+ return client;
2387
+ }
2388
+ async reconnect() {
2389
+ const app_id_url = new URL(`${this.config.root}${this.api_prefix}/${APP_ID_URL}`);
2390
+ let app_id;
2391
+ try {
2392
+ const response = await this.fetch(app_id_url);
2393
+ if (!response.ok) throw new Error();
2394
+ app_id = (await response.json()).app_id;
2395
+ } catch (e) {
2396
+ return "broken";
2397
+ }
2398
+ if (app_id !== this.config.app_id) return "changed";
2399
+ return "connected";
2400
+ }
2401
+ close() {
2402
+ this.closed = true;
2403
+ close_stream(this.stream_status, this.abort_controller);
2404
+ }
2405
+ /**
2406
+ * Re-fetch the app config without closing the SSE stream.
2407
+ * Used by hot-reload so in-flight generators keep delivering updates.
2408
+ */
2409
+ async refresh() {
2410
+ if (!this.config) throw new Error(CONFIG_ERROR_MSG);
2411
+ const config = await this.resolve_config(this.config.root, false);
2412
+ if (!config) throw new Error(CONFIG_ERROR_MSG);
2413
+ this.config = config;
2414
+ this.api_prefix = config.api_prefix || "";
2415
+ this.api_map = map_names_to_ids(config.dependencies || []);
2416
+ try {
2417
+ this.api_info = await this.view_api();
2418
+ } catch (e) {
2419
+ console.error(API_INFO_ERROR_MSG + e.message);
2420
+ }
2421
+ return this.get_url_config();
2422
+ }
2423
+ set_current_payload(payload) {
2424
+ this.current_payload = payload;
2425
+ }
2426
+ static async duplicate(app_reference, options = { events: ["data"] }) {
2427
+ return duplicate(app_reference, options);
2428
+ }
2429
+ async _resolve_config() {
2430
+ const { http_protocol, host, space_id } = await process_endpoint(this.app_reference, this.options.token);
2431
+ const { status_callback } = this.options;
2432
+ if (space_id && status_callback) await check_and_wake_space(space_id, status_callback);
2433
+ let config;
2434
+ try {
2435
+ let configUrl = `${http_protocol}//${host}`;
2436
+ config = await this.resolve_config(configUrl);
2437
+ if (!config) throw new Error(CONFIG_ERROR_MSG);
2438
+ return this.config_success(config);
2439
+ } catch (e) {
2440
+ if (space_id && status_callback) check_space_status(space_id, RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", this.handle_space_success);
2441
+ else {
2442
+ if (status_callback) status_callback({
2443
+ status: "error",
2444
+ message: "Could not load this space.",
2445
+ load_status: "error",
2446
+ detail: "NOT_FOUND"
2447
+ });
2448
+ throw e instanceof Error ? e : new Error(String(e));
2449
+ }
2450
+ }
2451
+ }
2452
+ async config_success(_config) {
2453
+ this.config = _config;
2454
+ this.api_prefix = _config.api_prefix || "";
2455
+ if (_config.run_history === false) clear_run_history({
2456
+ app_id: _config.app_id,
2457
+ username: _config.username
2458
+ });
2459
+ if (this.config.auth_required) return this.prepare_return_obj();
2460
+ try {
2461
+ this.api_info = await this.view_api();
2462
+ } catch (e) {
2463
+ console.error(API_INFO_ERROR_MSG + e.message);
2464
+ }
2465
+ return this.prepare_return_obj();
2466
+ }
2467
+ async handle_space_success(status) {
2468
+ if (!this) throw new Error(CONFIG_ERROR_MSG);
2469
+ const { status_callback } = this.options;
2470
+ if (status_callback) status_callback(status);
2471
+ if (status.status === "running") try {
2472
+ this.config = await this._resolve_config();
2473
+ this.api_prefix = this?.config?.api_prefix || "";
2474
+ if (!this.config) throw new Error(CONFIG_ERROR_MSG);
2475
+ return await this.config_success(this.config);
2476
+ } catch (e) {
2477
+ if (status_callback) status_callback({
2478
+ status: "error",
2479
+ message: "Could not load this space.",
2480
+ load_status: "error",
2481
+ detail: "NOT_FOUND"
2482
+ });
2483
+ throw e;
2484
+ }
2485
+ }
2486
+ async component_server(component_id, fn_name, data) {
2487
+ if (!this.config) throw new Error(CONFIG_ERROR_MSG);
2488
+ const headers = {};
2489
+ const { token } = this.options;
2490
+ const { session_hash } = this;
2491
+ if (token) headers.Authorization = `Bearer ${this.options.token}`;
2492
+ let root_url;
2493
+ let component = this.config.components.find((comp) => comp.id === component_id);
2494
+ if (component?.props?.root_url) root_url = component.props.root_url;
2495
+ else root_url = this.config.root;
2496
+ let body;
2497
+ if (typeof data === "object" && data !== null && "binary" in data) {
2498
+ const _data = data;
2499
+ body = new FormData();
2500
+ for (const key in _data.data) {
2501
+ if (key === "binary") continue;
2502
+ body.append(key, _data.data[key]);
2503
+ }
2504
+ body.set("component_id", component_id.toString());
2505
+ body.set("fn_name", fn_name);
2506
+ body.set("session_hash", session_hash);
2507
+ } else {
2508
+ body = JSON.stringify({
2509
+ data,
2510
+ component_id,
2511
+ fn_name,
2512
+ session_hash
2513
+ });
2514
+ headers["Content-Type"] = "application/json";
2515
+ }
2516
+ if (token) headers.Authorization = `Bearer ${token}`;
2517
+ try {
2518
+ const response = await this.fetch(`${root_url}${this.api_prefix}/${COMPONENT_SERVER_URL}/`, {
2519
+ method: "POST",
2520
+ body,
2521
+ headers,
2522
+ credentials: this.options.credentials ?? "same-origin"
2523
+ });
2524
+ if (!response.ok) throw new Error("Could not connect to component server: " + response.statusText);
2525
+ return await response.json();
2526
+ } catch (e) {
2527
+ console.warn(e);
2528
+ }
2529
+ }
2530
+ set_cookies(raw_cookies) {
2531
+ this.cookies = parse_and_set_cookies(raw_cookies).join("; ");
2532
+ }
2533
+ prepare_return_obj() {
2534
+ return {
2535
+ config: this.config,
2536
+ predict: this.predict,
2537
+ submit: this.submit,
2538
+ view_api: this.view_api,
2539
+ component_server: this.component_server
2540
+ };
2541
+ }
2561
2542
  };
2543
+ /**
2544
+ * @deprecated This method will be removed in v1.0. Use `Client.connect()` instead.
2545
+ * Creates a client instance for interacting with Gradio apps.
2546
+ *
2547
+ * @param {string} app_reference - The reference or URL to a Gradio space or app.
2548
+ * @param {ClientOptions} options - Configuration options for the client.
2549
+ * @returns {Promise<Client>} A promise that resolves to a `Client` instance.
2550
+ */
2551
+ async function client(app_reference, options = { events: ["data"] }) {
2552
+ return await Client.connect(app_reference, options);
2553
+ }
2554
+ /**
2555
+ * @deprecated This method will be removed in v1.0. Use `Client.duplicate()` instead.
2556
+ * Creates a duplicate of a space and returns a client instance for the duplicated space.
2557
+ *
2558
+ * @param {string} app_reference - The reference or URL to a Gradio space or app to duplicate.
2559
+ * @param {DuplicateOptions} options - Configuration options for the client.
2560
+ * @returns {Promise<Client>} A promise that resolves to a `Client` instance.
2561
+ */
2562
+ async function duplicate_space(app_reference, options) {
2563
+ return await Client.duplicate(app_reference, options);
2564
+ }
2565
+ //#endregion
2566
+ export { Client, FileData, MISSING_CREDENTIALS_MSG, clear_run_history, client, consume_run_history_replay, delete_run_history, duplicate_space as duplicate, handle_file, on_run_history_change, predict, prepare_files, read_run_history, run_history_url, stage_run_history_replay, submit, upload, upload_files };