summaryrefslogtreecommitdiff
path: root/frontend/src/plugin-loader.tsx
diff options
context:
space:
mode:
authorAAGaming <aagaming@riseup.net>2024-05-04 22:39:30 -0400
committerAAGaming <aagaming@riseup.net>2024-05-04 22:39:30 -0400
commit14ea7b964f65460c08f39d42e1621aabd1db22fc (patch)
tree42b62d1eb69a94aa80c1cacb8c89d549c21cf86c /frontend/src/plugin-loader.tsx
parent2a22f000c12bd3704a93e897ed71e644392baeef (diff)
downloaddecky-loader-14ea7b964f65460c08f39d42e1621aabd1db22fc.tar.gz
decky-loader-14ea7b964f65460c08f39d42e1621aabd1db22fc.zip
implement fetch and external resource request apis
Diffstat (limited to 'frontend/src/plugin-loader.tsx')
-rw-r--r--frontend/src/plugin-loader.tsx62
1 files changed, 49 insertions, 13 deletions
diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx
index 75b09091..bb6fa6dd 100644
--- a/frontend/src/plugin-loader.tsx
+++ b/frontend/src/plugin-loader.tsx
@@ -42,7 +42,7 @@ const FilePicker = lazy(() => import('./components/modals/filepicker'));
declare global {
interface Window {
- __DECKY_SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED_deckyPluginBackendAPIInit?: {
+ __DECKY_SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED_deckyLoaderAPIInit?: {
connect: (version: number, key: string) => any; // Returns the backend API used above, no real point adding types to this.
};
}
@@ -51,6 +51,10 @@ declare global {
/** Map of event names to event listeners */
type listenerMap = Map<string, Set<(...args: any) => any>>;
+interface DeckyRequestInit extends RequestInit {
+ excludedHeaders: string[];
+}
+
const callPluginMethod = DeckyBackend.callable<[pluginName: string, method: string, ...args: any], any>(
'loader/call_plugin_method',
);
@@ -357,7 +361,7 @@ class PluginLoader extends Logger {
let res = await fetch(`http://127.0.0.1:1337/plugins/${name}/frontend_bundle`, {
credentials: 'include',
headers: {
- Authentication: deckyAuthToken,
+ 'X-Decky-Auth': deckyAuthToken,
},
});
if (res.ok) {
@@ -484,12 +488,31 @@ class PluginLoader extends Logger {
});
}
- /* TODO replace with the following flow (or similar) so we can reuse the JS Fetch API
- frontend --request URL only--> backend (ws method)
- backend --new temporary backend URL--> frontend (ws response)
- frontend <--> backend <--> target URL (over http!)
- */
- async fetchNoCors(url: string, request: any = {}) {
+ // Useful for audio/video streams
+ getExternalResourceURL(url: string) {
+ return `http://127.0.0.1:1337/fetch?auth=${deckyAuthToken}&fetch_url=${encodeURIComponent(url)}`;
+ }
+
+ // Same syntax as fetch but only supports the url-based syntax and an object for headers since it's the most common usage pattern
+ fetch(input: string, init?: DeckyRequestInit | undefined): Promise<Response> {
+ const headers: { [name: string]: string } = {
+ ...(init?.headers as { [name: string]: string }),
+ 'X-Decky-Auth': deckyAuthToken,
+ 'X-Decky-Fetch-URL': input,
+ };
+
+ if (init?.excludedHeaders) {
+ headers['X-Decky-Fetch-Excluded-Headers'] = init.excludedHeaders.join(', ');
+ }
+
+ return fetch('http://127.0.0.1:1337/fetch', {
+ ...init,
+ credentials: 'include',
+ headers,
+ });
+ }
+
+ async legacyFetchNoCors(url: string, request: any = {}) {
let method: string;
const req = { headers: {}, ...request, data: request.body };
req?.body && delete req.body;
@@ -513,10 +536,10 @@ class PluginLoader extends Logger {
initPluginBackendAPI() {
// Things will break *very* badly if plugin code touches this outside of @decky/backend, so lets make that clear.
- window.__DECKY_SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED_deckyPluginBackendAPIInit = {
+ window.__DECKY_SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED_deckyLoaderAPIInit = {
connect: (version: number, pluginName: string) => {
- if (version <= 0) {
- throw new Error(`Plugin ${pluginName} requested invalid backend api version ${version}.`);
+ if (version < 1 || version > 1) {
+ throw new Error(`Plugin ${pluginName} requested unsupported backend api version ${version}.`);
}
const eventListeners: listenerMap = new Map();
@@ -543,9 +566,22 @@ class PluginLoader extends Logger {
set?.delete(listener);
}
},
+ openFilePicker: this.openFilePicker.bind(this),
+ executeInTab: DeckyBackend.callable<
+ [tab: String, runAsync: Boolean, code: string],
+ { success: boolean; result: any }
+ >('utilities/execute_in_tab'),
+ fetch: this.fetch.bind(this),
+ getExternalResourceURL: this.getExternalResourceURL.bind(this),
+ injectCssIntoTab: DeckyBackend.callable<[tab: string, style: string], string>(
+ 'utilities/inject_css_into_tab',
+ ),
+ removeCssFromTab: DeckyBackend.callable<[tab: string, cssId: string]>('utilities/remove_css_from_tab'),
+ routerHook: this.routerHook,
+ toaster: this.toaster,
};
- this.debug(`${pluginName} connected to backend API.`);
+ this.debug(`${pluginName} connected to loader API.`);
return backendAPI;
},
};
@@ -591,7 +627,7 @@ class PluginLoader extends Logger {
args,
);
},
- fetchNoCors: this.fetchNoCors,
+ fetchNoCors: this.legacyFetchNoCors,
executeInTab: DeckyBackend.callable<
[tab: String, runAsync: Boolean, code: string],
{ success: boolean; result: any }