@gradio/client 2.5.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/browser.js +442 -311
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/helpers/data.d.ts +9 -0
- package/dist/helpers/data.d.ts.map +1 -1
- package/dist/helpers/init_helpers.d.ts +1 -1
- package/dist/helpers/init_helpers.d.ts.map +1 -1
- package/dist/index.cjs +207 -19
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +201 -20
- package/dist/index.min.js +481 -350
- package/dist/types.d.ts +5 -5
- package/dist/upload.d.ts.map +1 -1
- package/dist/utils/bucket_sync.d.ts +38 -0
- package/dist/utils/bucket_sync.d.ts.map +1 -0
- package/dist/utils/run_history.d.ts +9 -0
- package/dist/utils/run_history.d.ts.map +1 -1
- package/dist/utils/submit.d.ts.map +1 -1
- package/dist/utils/view_api.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +19 -15
- package/src/helpers/data.ts +77 -0
- package/src/helpers/init_helpers.ts +29 -14
- package/src/index.ts +12 -0
- package/src/test/bucket_sync.test.ts +138 -0
- package/src/test/data.test.ts +95 -0
- package/src/test/init.test.ts +47 -1
- package/src/test/run_history.test.ts +46 -0
- package/src/test/server.ts +3 -0
- package/src/test/submit.test.ts +75 -1
- package/src/test/upload.test.ts +25 -0
- package/src/types.ts +5 -5
- package/src/upload.ts +5 -1
- package/src/utils/bucket_sync.ts +153 -0
- package/src/utils/run_history.ts +64 -1
- package/src/utils/submit.ts +21 -3
- package/src/utils/view_api.ts +4 -1
package/dist/index.js
CHANGED
|
@@ -62,9 +62,11 @@ function map_names_to_ids(fns) {
|
|
|
62
62
|
});
|
|
63
63
|
return apis;
|
|
64
64
|
}
|
|
65
|
-
function resolve_config_root(root, current_location) {
|
|
66
|
-
const root_url = new URL(root, current_location);
|
|
65
|
+
function resolve_config_root(root, current_location, prioritize_current_location = false) {
|
|
67
66
|
const current_url = new URL(current_location);
|
|
67
|
+
const root_url = new URL(root, current_url);
|
|
68
|
+
const is_colab_runtime = root_url.hostname.endsWith(".colab-user-runtimes.internal") || root_url.hostname.endsWith(".codatalab-user-runtimes.internal");
|
|
69
|
+
if (prioritize_current_location || is_colab_runtime) return new URL(new URL(root, current_url).pathname, current_url).toString().replace(/\/$/, "");
|
|
68
70
|
if (root_url.hostname !== current_url.hostname) return root;
|
|
69
71
|
root_url.protocol = current_url.protocol;
|
|
70
72
|
root_url.host = current_url.host;
|
|
@@ -75,7 +77,9 @@ async function resolve_config(endpoint, strip_current_page = true) {
|
|
|
75
77
|
if (typeof window !== "undefined" && window.gradio_config && location.origin !== "http://localhost:9876") {
|
|
76
78
|
if (strip_current_page && window.gradio_config.current_page) endpoint = endpoint.substring(0, endpoint.lastIndexOf("/"));
|
|
77
79
|
if (window.gradio_config.dev_mode || typeof window !== "undefined" && window?.BUILD_MODE === "dev") {
|
|
78
|
-
let config_url = join_urls(endpoint,
|
|
80
|
+
let config_url = new URL(join_urls(endpoint, CONFIG_URL));
|
|
81
|
+
if (this.deep_link) config_url.searchParams.set("deep_link", this.deep_link);
|
|
82
|
+
if (this.page !== null) config_url.searchParams.set("page", this.page);
|
|
79
83
|
const config = await handleConfigResponse(await this.fetch(config_url, {
|
|
80
84
|
headers,
|
|
81
85
|
credentials: this.options.credentials ?? "same-origin"
|
|
@@ -87,10 +91,12 @@ async function resolve_config(endpoint, strip_current_page = true) {
|
|
|
87
91
|
};
|
|
88
92
|
}
|
|
89
93
|
const config = { ...window.gradio_config };
|
|
90
|
-
config.root = resolve_config_root(config.root, location.href);
|
|
94
|
+
config.root = resolve_config_root(config.root, location.href, config.is_colab);
|
|
91
95
|
return config;
|
|
92
96
|
} else if (endpoint) {
|
|
93
|
-
let config_url = join_urls(endpoint,
|
|
97
|
+
let config_url = new URL(join_urls(endpoint, CONFIG_URL));
|
|
98
|
+
if (this.deep_link) config_url.searchParams.set("deep_link", this.deep_link);
|
|
99
|
+
if (this.page !== null) config_url.searchParams.set("page", this.page);
|
|
94
100
|
const config = await handleConfigResponse(await this.fetch(config_url, {
|
|
95
101
|
headers,
|
|
96
102
|
credentials: this.options.credentials ?? "same-origin"
|
|
@@ -489,7 +495,8 @@ async function view_api() {
|
|
|
489
495
|
let api_info;
|
|
490
496
|
if (typeof window !== "undefined" && window.gradio_api_info) api_info = window.gradio_api_info;
|
|
491
497
|
else {
|
|
492
|
-
const url = join_urls(config.root, this.api_prefix, API_INFO_URL);
|
|
498
|
+
const url = new URL(join_urls(config.root, this.api_prefix, API_INFO_URL));
|
|
499
|
+
if (this.page !== null) url.searchParams.set("page", this.page);
|
|
493
500
|
response = await this.fetch(url, {
|
|
494
501
|
headers,
|
|
495
502
|
credentials: this.options.credentials ?? "same-origin"
|
|
@@ -609,10 +616,11 @@ async function upload(file_data, root_url, upload_id, max_file_size) {
|
|
|
609
616
|
if (response.error) throw new Error(response.error);
|
|
610
617
|
else {
|
|
611
618
|
if (response.files) return response.files.map((f, i) => {
|
|
619
|
+
const encoded_path = f.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
612
620
|
return new FileData({
|
|
613
621
|
...file_data[i],
|
|
614
622
|
path: f,
|
|
615
|
-
url: `${root_url}${this.api_prefix}/file=${
|
|
623
|
+
url: `${root_url}${this.api_prefix}/file=${encoded_path}`
|
|
616
624
|
});
|
|
617
625
|
});
|
|
618
626
|
return [];
|
|
@@ -774,6 +782,48 @@ function handle_payload(resolved_payload, dependency, components, type, with_nul
|
|
|
774
782
|
}
|
|
775
783
|
return updated_payload;
|
|
776
784
|
}
|
|
785
|
+
var FILE_ROUTE_PREFIXES = [
|
|
786
|
+
"/file=",
|
|
787
|
+
"/file/",
|
|
788
|
+
"/stream/",
|
|
789
|
+
"/proxy="
|
|
790
|
+
];
|
|
791
|
+
/**
|
|
792
|
+
* Add the Space JWT required for browser-managed media requests.
|
|
793
|
+
*
|
|
794
|
+
* This is a bearer credential and must not be logged or persisted. Restrict it
|
|
795
|
+
* to Gradio routes that serve files; the user's Hugging Face token remains in
|
|
796
|
+
* the Authorization header used to obtain this credential.
|
|
797
|
+
*/
|
|
798
|
+
function sign_file_urls(data, root, api_prefix, jwt) {
|
|
799
|
+
if (!jwt || data === null || typeof data !== "object") return;
|
|
800
|
+
const signature = jwt;
|
|
801
|
+
const root_url = new URL(root);
|
|
802
|
+
const root_path = root_url.pathname.replace(/\/+$/, "");
|
|
803
|
+
const normalized_api_prefix = api_prefix ? `/${api_prefix.replace(/^\/+|\/+$/g, "")}` : "";
|
|
804
|
+
const route_bases = new Set([`${root_path}${normalized_api_prefix}`, normalized_api_prefix]);
|
|
805
|
+
if (!normalized_api_prefix) {
|
|
806
|
+
route_bases.add(`${root_path}/gradio_api`);
|
|
807
|
+
route_bases.add("/gradio_api");
|
|
808
|
+
}
|
|
809
|
+
function visit(value) {
|
|
810
|
+
if (value === null || typeof value !== "object") return;
|
|
811
|
+
const object = value;
|
|
812
|
+
if (object.meta?._type === "gradio.FileData" && typeof object.url === "string") {
|
|
813
|
+
const file_url = new URL(object.url, `${root_url.toString().replace(/\/$/, "")}/`);
|
|
814
|
+
const is_file_route = [...route_bases].some((base) => FILE_ROUTE_PREFIXES.some((route) => file_url.pathname.startsWith(`${base}${route}`)));
|
|
815
|
+
if ((file_url.protocol === "http:" || file_url.protocol === "https:") && file_url.origin === root_url.origin && is_file_route) {
|
|
816
|
+
file_url.searchParams.set("__sign", signature);
|
|
817
|
+
object.url = file_url.toString();
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
for (const child of Object.values(object)) visit(child);
|
|
821
|
+
}
|
|
822
|
+
visit(data);
|
|
823
|
+
}
|
|
824
|
+
function sign_config_file_urls(config, jwt) {
|
|
825
|
+
for (const component of config.components || []) sign_file_urls(component.props?.value, config.root, config.api_prefix || "", jwt);
|
|
826
|
+
}
|
|
777
827
|
//#endregion
|
|
778
828
|
//#region src/utils/handle_blob.ts
|
|
779
829
|
async function handle_blob(endpoint, data, api_info) {
|
|
@@ -1432,6 +1482,7 @@ function readable_stream(input, init = {}) {
|
|
|
1432
1482
|
var KEY_ROOT = "gradio:run-history:";
|
|
1433
1483
|
var STORAGE_PREFIX = `${KEY_ROOT}v2:`;
|
|
1434
1484
|
var REPLAY_PREFIX = `${KEY_ROOT}replay:v2:`;
|
|
1485
|
+
var DESTINATION_PREFIX = `${KEY_ROOT}destination:v1:`;
|
|
1435
1486
|
var MAX_RUNS = 100;
|
|
1436
1487
|
var MAX_APPS = 8;
|
|
1437
1488
|
/**
|
|
@@ -1469,6 +1520,34 @@ function replay_key(scope) {
|
|
|
1469
1520
|
const key = storage_key(scope);
|
|
1470
1521
|
return key ? key.replace(STORAGE_PREFIX, REPLAY_PREFIX) : null;
|
|
1471
1522
|
}
|
|
1523
|
+
function destination_key(scope) {
|
|
1524
|
+
const key = storage_key(scope);
|
|
1525
|
+
return key ? key.replace(STORAGE_PREFIX, DESTINATION_PREFIX) : null;
|
|
1526
|
+
}
|
|
1527
|
+
function read_run_history_storage_impl(scope) {
|
|
1528
|
+
const key = destination_key(scope);
|
|
1529
|
+
if (!key) return { type: "browser" };
|
|
1530
|
+
try {
|
|
1531
|
+
const value = JSON.parse(window.localStorage.getItem(key) || "null");
|
|
1532
|
+
if (typeof value?.bucket_id === "string") return value.type === "bucket" ? {
|
|
1533
|
+
type: "bucket",
|
|
1534
|
+
bucket_id: value.bucket_id
|
|
1535
|
+
} : {
|
|
1536
|
+
type: "browser",
|
|
1537
|
+
bucket_id: value.bucket_id
|
|
1538
|
+
};
|
|
1539
|
+
return { type: "browser" };
|
|
1540
|
+
} catch {
|
|
1541
|
+
return { type: "browser" };
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
function set_run_history_storage_impl(scope, storage) {
|
|
1545
|
+
const key = destination_key(scope);
|
|
1546
|
+
if (!key) return;
|
|
1547
|
+
if (storage.type === "browser" && !storage.bucket_id) window.localStorage.removeItem(key);
|
|
1548
|
+
else window.localStorage.setItem(key, JSON.stringify(storage));
|
|
1549
|
+
notify_run_history_change();
|
|
1550
|
+
}
|
|
1472
1551
|
/** When a run was most recently saved under a key, for deciding what to drop. */
|
|
1473
1552
|
function last_saved_at(key) {
|
|
1474
1553
|
try {
|
|
@@ -1485,7 +1564,7 @@ function last_saved_at(key) {
|
|
|
1485
1564
|
*/
|
|
1486
1565
|
function prune_apps(current_key) {
|
|
1487
1566
|
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)];
|
|
1567
|
+
const stale = [...keys.filter((key) => !key.startsWith(STORAGE_PREFIX) && !key.startsWith(REPLAY_PREFIX) && !key.startsWith(DESTINATION_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
1568
|
for (const key of stale) try {
|
|
1490
1569
|
window.localStorage.removeItem(key);
|
|
1491
1570
|
window.sessionStorage.removeItem(key.replace(STORAGE_PREFIX, REPLAY_PREFIX));
|
|
@@ -1615,6 +1694,7 @@ function apply_run_history_replay_impl(config) {
|
|
|
1615
1694
|
return run ? restore_run_impl(config, run) : false;
|
|
1616
1695
|
}
|
|
1617
1696
|
function start_run_history_impl(options) {
|
|
1697
|
+
if (read_run_history_storage_impl(options).type === "bucket") return null;
|
|
1618
1698
|
const key = storage_key(options);
|
|
1619
1699
|
if (!key) return null;
|
|
1620
1700
|
prune_apps(key);
|
|
@@ -1694,6 +1774,12 @@ function mark_complete(run, event) {
|
|
|
1694
1774
|
function read_run_history(scope) {
|
|
1695
1775
|
return safely(() => read_run_history_impl(scope), []);
|
|
1696
1776
|
}
|
|
1777
|
+
function read_run_history_storage(scope) {
|
|
1778
|
+
return safely(() => read_run_history_storage_impl(scope), { type: "browser" });
|
|
1779
|
+
}
|
|
1780
|
+
function set_run_history_storage(scope, storage) {
|
|
1781
|
+
safely(() => set_run_history_storage_impl(scope, storage), void 0);
|
|
1782
|
+
}
|
|
1697
1783
|
function clear_run_history(scope) {
|
|
1698
1784
|
safely(() => clear_run_history_impl(scope), void 0);
|
|
1699
1785
|
}
|
|
@@ -1734,10 +1820,11 @@ function submit(endpoint, data = {}, event_data, trigger_id, all_events, additio
|
|
|
1734
1820
|
try {
|
|
1735
1821
|
const { token } = this.options;
|
|
1736
1822
|
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;
|
|
1737
|
-
const
|
|
1823
|
+
const base_headers = additional_headers || { "x-gradio-user": "api" };
|
|
1738
1824
|
const that = this;
|
|
1739
1825
|
if (!api_info) throw new Error(NO_API_INFO_MSG);
|
|
1740
1826
|
if (!config) throw new Error("Could not resolve app config");
|
|
1827
|
+
const root = config.root;
|
|
1741
1828
|
let { fn_index, endpoint_info, dependency } = get_endpoint_info(api_info, endpoint, api_map, config);
|
|
1742
1829
|
let resolved_data = map_data_to_params(data, endpoint_info);
|
|
1743
1830
|
let protocol = config.protocol ?? "ws";
|
|
@@ -1759,6 +1846,11 @@ function submit(endpoint, data = {}, event_data, trigger_id, all_events, additio
|
|
|
1759
1846
|
app_id: config.app_id,
|
|
1760
1847
|
username: config.username
|
|
1761
1848
|
};
|
|
1849
|
+
const history_storage = read_run_history_storage(history_scope);
|
|
1850
|
+
const addt_headers = {
|
|
1851
|
+
...base_headers,
|
|
1852
|
+
...history_enabled && history_storage.type === "bucket" ? { "x-gradio-history-bucket": history_storage.bucket_id } : {}
|
|
1853
|
+
};
|
|
1762
1854
|
const history_run_id = !history_enabled || !is_documented_endpoint ? null : start_run_history({
|
|
1763
1855
|
...history_scope,
|
|
1764
1856
|
endpoint: history_endpoint,
|
|
@@ -1782,6 +1874,7 @@ function submit(endpoint, data = {}, event_data, trigger_id, all_events, additio
|
|
|
1782
1874
|
}, {}) || {};
|
|
1783
1875
|
function fire_event(event) {
|
|
1784
1876
|
update_run_history(history_scope, history_run_id, event);
|
|
1877
|
+
if (event.type === "data" || event.type === "render") sign_file_urls(event.data, root, api_prefix, that.jwt);
|
|
1785
1878
|
if (all_events || events_to_publish[event.type]) push_event(event);
|
|
1786
1879
|
}
|
|
1787
1880
|
async function cancel() {
|
|
@@ -1932,7 +2025,7 @@ function submit(endpoint, data = {}, event_data, trigger_id, all_events, additio
|
|
|
1932
2025
|
...payload,
|
|
1933
2026
|
session_hash,
|
|
1934
2027
|
event_id
|
|
1935
|
-
});
|
|
2028
|
+
}, addt_headers);
|
|
1936
2029
|
if (status !== 200) {
|
|
1937
2030
|
fire_event({
|
|
1938
2031
|
type: "status",
|
|
@@ -2285,6 +2378,7 @@ var Client = class {
|
|
|
2285
2378
|
app_reference;
|
|
2286
2379
|
options;
|
|
2287
2380
|
deep_link = null;
|
|
2381
|
+
page = null;
|
|
2288
2382
|
config;
|
|
2289
2383
|
api_prefix = "";
|
|
2290
2384
|
api_info;
|
|
@@ -2365,6 +2459,7 @@ var Client = class {
|
|
|
2365
2459
|
constructor(app_reference, options = { events: ["data"] }) {
|
|
2366
2460
|
this.app_reference = app_reference;
|
|
2367
2461
|
this.deep_link = options.query_params?.deep_link || null;
|
|
2462
|
+
this.page = options.query_params?.page ?? null;
|
|
2368
2463
|
if (!options.events) options.events = ["data"];
|
|
2369
2464
|
normalise_token_option(options);
|
|
2370
2465
|
this.options = options;
|
|
@@ -2396,14 +2491,10 @@ var Client = class {
|
|
|
2396
2491
|
this.api_map = map_names_to_ids(this.config?.dependencies || []);
|
|
2397
2492
|
}
|
|
2398
2493
|
async _resolve_heartbeat(_config) {
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
if (this.config.space_id && this.options.token) this.jwt = await get_jwt(this.config.space_id, this.options.token, this.cookies);
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
if (_config.space_id && this.options.token) this.jwt = await get_jwt(_config.space_id, this.options.token);
|
|
2494
|
+
this.config = _config;
|
|
2495
|
+
this.api_prefix = _config.api_prefix || "";
|
|
2496
|
+
if (_config.space_id && this.options.token) this.jwt = await get_jwt(_config.space_id, this.options.token, this.cookies);
|
|
2497
|
+
sign_config_file_urls(this.config, this.jwt);
|
|
2407
2498
|
if (this.config && this.config.connect_heartbeat) {
|
|
2408
2499
|
const heartbeat_url = new URL(`${this.config.root}${this.api_prefix}/${HEARTBEAT_URL}/${this.session_hash}`);
|
|
2409
2500
|
if (this.jwt) heartbeat_url.searchParams.set("__sign", this.jwt);
|
|
@@ -2444,6 +2535,7 @@ var Client = class {
|
|
|
2444
2535
|
this.config = config;
|
|
2445
2536
|
this.api_prefix = config.api_prefix || "";
|
|
2446
2537
|
this.api_map = map_names_to_ids(config.dependencies || []);
|
|
2538
|
+
sign_config_file_urls(this.config, this.jwt);
|
|
2447
2539
|
try {
|
|
2448
2540
|
this.api_info = await this.view_api();
|
|
2449
2541
|
} catch (e) {
|
|
@@ -2553,7 +2645,9 @@ var Client = class {
|
|
|
2553
2645
|
credentials: this.options.credentials ?? "same-origin"
|
|
2554
2646
|
});
|
|
2555
2647
|
if (!response.ok) throw new Error("Could not connect to component server: " + response.statusText);
|
|
2556
|
-
|
|
2648
|
+
const output = await response.json();
|
|
2649
|
+
sign_file_urls(output, this.config.root, this.config.api_prefix || "", this.jwt);
|
|
2650
|
+
return output;
|
|
2557
2651
|
} catch (e) {
|
|
2558
2652
|
console.warn(e);
|
|
2559
2653
|
}
|
|
@@ -2594,4 +2688,91 @@ async function duplicate_space(app_reference, options) {
|
|
|
2594
2688
|
return await Client.duplicate(app_reference, options);
|
|
2595
2689
|
}
|
|
2596
2690
|
//#endregion
|
|
2597
|
-
|
|
2691
|
+
//#region src/utils/bucket_sync.ts
|
|
2692
|
+
/**
|
|
2693
|
+
* Client for the durable run history in an HF Hub bucket
|
|
2694
|
+
* (`/gradio_api/run-history/*`).
|
|
2695
|
+
*
|
|
2696
|
+
* Read-only by design. Records are written by the server from the run it
|
|
2697
|
+
* actually executed — there is no push function here, and nothing in this
|
|
2698
|
+
* module can create a record.
|
|
2699
|
+
*
|
|
2700
|
+
* Every call names the bucket it is talking about. The server holds no
|
|
2701
|
+
* per-session binding, so two tabs (or two apps on one origin) cannot end up
|
|
2702
|
+
* reading each other's history.
|
|
2703
|
+
*/
|
|
2704
|
+
var BUCKET_ID_RE = /^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-][a-zA-Z0-9_./-]*$/;
|
|
2705
|
+
function is_valid_bucket_id(id) {
|
|
2706
|
+
if (!BUCKET_ID_RE.test(id)) return false;
|
|
2707
|
+
return !id.split("/").some((seg) => seg === "" || seg === "." || seg === "..");
|
|
2708
|
+
}
|
|
2709
|
+
function url(root, path, params) {
|
|
2710
|
+
const query = params ? `?${new URLSearchParams(params)}` : "";
|
|
2711
|
+
const base = root.replace(/\/+$/, "");
|
|
2712
|
+
if (base) return `${base}/gradio_api/run-history/${path}${query}`;
|
|
2713
|
+
if (typeof document !== "undefined" && document.baseURI) return new URL(`gradio_api/run-history/${path}${query}`, document.baseURI).toString();
|
|
2714
|
+
return `gradio_api/run-history/${path}${query}`;
|
|
2715
|
+
}
|
|
2716
|
+
async function parse_error(res) {
|
|
2717
|
+
try {
|
|
2718
|
+
const j = await res.json();
|
|
2719
|
+
return typeof j?.detail === "string" ? j.detail : `${res.status}`;
|
|
2720
|
+
} catch {
|
|
2721
|
+
return `${res.status}`;
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
async function request(input, init, fallback, pick) {
|
|
2725
|
+
try {
|
|
2726
|
+
const res = await fetch(input, {
|
|
2727
|
+
credentials: "include",
|
|
2728
|
+
...init
|
|
2729
|
+
});
|
|
2730
|
+
if (!res.ok) return {
|
|
2731
|
+
ok: false,
|
|
2732
|
+
status: res.status,
|
|
2733
|
+
data: fallback,
|
|
2734
|
+
detail: await parse_error(res)
|
|
2735
|
+
};
|
|
2736
|
+
return {
|
|
2737
|
+
ok: true,
|
|
2738
|
+
status: res.status,
|
|
2739
|
+
data: pick(await res.json())
|
|
2740
|
+
};
|
|
2741
|
+
} catch (e) {
|
|
2742
|
+
return {
|
|
2743
|
+
ok: false,
|
|
2744
|
+
status: 0,
|
|
2745
|
+
data: fallback,
|
|
2746
|
+
detail: String(e)
|
|
2747
|
+
};
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
/**
|
|
2751
|
+
* Create the bucket if it does not exist and confirm it is writable. Stores
|
|
2752
|
+
* nothing server-side — the caller keeps its own choice and names it on every
|
|
2753
|
+
* later request.
|
|
2754
|
+
*/
|
|
2755
|
+
async function connect_bucket(root, bucket_id) {
|
|
2756
|
+
if (!is_valid_bucket_id(bucket_id)) return {
|
|
2757
|
+
ok: false,
|
|
2758
|
+
status: 422,
|
|
2759
|
+
data: null,
|
|
2760
|
+
detail: "invalid bucket id"
|
|
2761
|
+
};
|
|
2762
|
+
return request(url(root, "connect"), {
|
|
2763
|
+
method: "POST",
|
|
2764
|
+
headers: { "Content-Type": "application/json" },
|
|
2765
|
+
body: JSON.stringify({ bucket_id })
|
|
2766
|
+
}, null, () => null);
|
|
2767
|
+
}
|
|
2768
|
+
async function list_user_buckets(root) {
|
|
2769
|
+
return request(url(root, "buckets"), {}, [], (b) => Array.isArray(b?.buckets) ? b.buckets : []);
|
|
2770
|
+
}
|
|
2771
|
+
async function list_bucket_records(root, bucket) {
|
|
2772
|
+
return request(url(root, "records", { bucket }), {}, [], (b) => Array.isArray(b?.records) ? b.records : []);
|
|
2773
|
+
}
|
|
2774
|
+
function asset_url(root, bucket, endpoint, record_id, filename) {
|
|
2775
|
+
return url(root, `records/${encodeURIComponent(endpoint)}/${encodeURIComponent(record_id)}/assets/${encodeURIComponent(filename)}`, { bucket });
|
|
2776
|
+
}
|
|
2777
|
+
//#endregion
|
|
2778
|
+
export { Client, FileData, MISSING_CREDENTIALS_MSG, apply_run_history_replay, asset_url, clear_run_history, client, connect_bucket, consume_run_history_replay, delete_run_history, duplicate_space as duplicate, handle_file, is_valid_bucket_id, list_bucket_records, list_user_buckets, on_run_history_change, predict, prepare_files, read_run_history, read_run_history_storage, run_history_url, set_run_history_storage, stage_run_history_replay, submit, upload, upload_files };
|