No more silly globals
This commit is contained in:
parent
1616fa21f2
commit
1bd272ec8d
8 changed files with 234 additions and 21 deletions
|
|
@ -27,6 +27,7 @@
|
||||||
import { SW, createProxyScripts, checkProxyScripts, createBareMuxConn, setTransport } from "@utils/serviceWorker";
|
import { SW, createProxyScripts, checkProxyScripts, createBareMuxConn, setTransport } from "@utils/serviceWorker";
|
||||||
import { Settings } from "@utils/settings";
|
import { Settings } from "@utils/settings";
|
||||||
import { log } from "@utils/index";
|
import { log } from "@utils/index";
|
||||||
|
import { Marketplace } from "@utils/marketplace";
|
||||||
const titleText = `
|
const titleText = `
|
||||||
_ _ _ _ ____ _
|
_ _ _ _ ____ _
|
||||||
| \\ | | ___| |__ _ _| | __ _ / ___| ___ _ ____ _(_) ___ ___ ___
|
| \\ | | ___| |__ _ _| | __ _ / ___| ___ _ ____ _(_) ___ ___ ___
|
||||||
|
|
@ -46,9 +47,11 @@
|
||||||
}
|
}
|
||||||
await checkProxyScripts();
|
await checkProxyScripts();
|
||||||
const conn = await createBareMuxConn("/baremux/worker.js");
|
const conn = await createBareMuxConn("/baremux/worker.js");
|
||||||
window.sw = new SW(conn);
|
const sw = new SW(conn);
|
||||||
for await (const _ of Settings.initDefaults()) {};
|
new Marketplace();
|
||||||
const { serviceWorker, bareMuxConn, sj } = await window.sw.getSWInfo();
|
// We don't do anything with the values (they aren't even any), so we just are iterating.
|
||||||
|
for await (const _ of Settings.initDefaults());
|
||||||
|
const { serviceWorker, bareMuxConn, sj } = await sw.getSWInfo();
|
||||||
log({ type: 'info', bg: true, prefix: true }, `General init completed! \n\nServiceWorker: ${serviceWorker.active?.state} \nBareMuxConn: ${bareMuxConn ? 'Active': 'Not active'} \nScramjetController: ${sj ? 'Active' : 'Not active'}`);
|
log({ type: 'info', bg: true, prefix: true }, `General init completed! \n\nServiceWorker: ${serviceWorker.active?.state} \nBareMuxConn: ${bareMuxConn ? 'Active': 'Not active'} \nScramjetController: ${sj ? 'Active' : 'Not active'}`);
|
||||||
}
|
}
|
||||||
const initSettings = async () => {
|
const initSettings = async () => {
|
||||||
|
|
|
||||||
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
|
|
@ -1,10 +1,10 @@
|
||||||
// LEGIT here for ONE global.
|
// LEGIT here for ONE global.
|
||||||
|
|
||||||
|
import type { Marketplace } from "@utils/marketplace";
|
||||||
import type { SW } from "@utils/serviceWorker";
|
import type { SW } from "@utils/serviceWorker";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
sw: SW;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ import { VERSION } from "astro:env/client";
|
||||||
import { BareClient } from "@mercuryworkshop/bare-mux";
|
import { BareClient } from "@mercuryworkshop/bare-mux";
|
||||||
import { defaultStore } from "@utils/storage";
|
import { defaultStore } from "@utils/storage";
|
||||||
import { Settings } from "@utils/settings";
|
import { Settings } from "@utils/settings";
|
||||||
import { setTransport } from "@utils/serviceWorker";
|
import { setTransport, SW } from "@utils/serviceWorker";
|
||||||
|
|
||||||
type Suggestion = {
|
type Suggestion = {
|
||||||
phrase: string;
|
phrase: string;
|
||||||
|
|
@ -81,7 +81,8 @@ import { VERSION } from "astro:env/client";
|
||||||
iframe.src = `${__uv$config.prefix}${__uv$config.encodeUrl!(val)}`;
|
iframe.src = `${__uv$config.prefix}${__uv$config.encodeUrl!(val)}`;
|
||||||
break;
|
break;
|
||||||
case "sj":
|
case "sj":
|
||||||
const { sj } = await window.sw.getSWInfo();
|
const sw = SW.getInstances().next().value as SW;
|
||||||
|
const { sj } = await sw.getSWInfo();
|
||||||
iframe.src = sj.encodeUrl(val);
|
iframe.src = sj.encodeUrl(val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { log } from "./index";
|
import { Elements, log } from "./index";
|
||||||
import { StoreManager } from "./storage";
|
import { StoreManager } from "./storage";
|
||||||
import { SettingsVals } from "./values";
|
import { SettingsVals } from "./values";
|
||||||
|
|
||||||
|
|
@ -54,25 +54,71 @@ interface Theme {
|
||||||
bgImage?: string;
|
bgImage?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class where for all of the Marketplace handlers.
|
||||||
|
* It creates it's own StoreManager where all of it's values will live.
|
||||||
|
* And it has 2 static items. instances and getInstances.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* //Create a new Marketplace instance
|
||||||
|
* const mp = new Marketplace();
|
||||||
|
* //Use one of the very many methods available.
|
||||||
|
*
|
||||||
|
* //Get all instances of a Marketplace is as easy as:
|
||||||
|
* // const mp = Marketplace.getInstances.next().value;
|
||||||
|
* // Consume and use the class.
|
||||||
|
*/
|
||||||
class Marketplace {
|
class Marketplace {
|
||||||
//create our own subsidized StoreManager with it's own prefix so the marketplace stuff NEVER touches the other data
|
//create our own subsidized StoreManager with it's own prefix so the marketplace stuff NEVER touches the other data
|
||||||
#storage: StoreManager<"nebula||marketplace">;
|
#storage: StoreManager<"nebula||marketplace">;
|
||||||
|
static #instances = new Set();
|
||||||
constructor() {
|
constructor() {
|
||||||
this.#storage = new StoreManager("nebula||marketplace");
|
this.#storage = new StoreManager("nebula||marketplace");
|
||||||
|
log({ type: 'info', bg: true, prefix: true }, 'Marketplace instance created and ready!');
|
||||||
|
Marketplace.#instances.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A static method to aquire an instance of a marketplace object.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* //Get the first insatnce available.
|
||||||
|
* const mp = Marketplace.getInstances.next().value
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Iterate over every instance
|
||||||
|
* for (const instance of Marketplace.getInstances()) {
|
||||||
|
* // Do some work
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static *getInstances() {
|
||||||
|
//Marketplace.instances.forEach((val) => yield val);
|
||||||
|
for (const item of Marketplace.#instances.keys()) {
|
||||||
|
yield item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a theme into both localstorage AND set the theme.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const mp = new Marketplace() // OR get an instances from getInstances()
|
||||||
|
* mp.installTheme({
|
||||||
|
* name: "testTheme",
|
||||||
|
* payload: "/packages/testTheme/index.css",
|
||||||
|
* // video: if you have a bg video, pass it here.
|
||||||
|
* //bgImage: pass the BG image here if you have one
|
||||||
|
* });
|
||||||
|
*/
|
||||||
async installTheme(theme: Theme) {
|
async installTheme(theme: Theme) {
|
||||||
const themes = this.#storage.getVal(SettingsVals.marketPlace.themes)
|
const themes = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.themes)) || [];
|
||||||
? JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.themes))
|
|
||||||
: [];
|
|
||||||
if (themes.find((t: any) => t === theme.name)) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${theme.name} is already installed!`)
|
if (themes.find((t: any) => t === theme.name)) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${theme.name} is already installed!`)
|
||||||
themes.push(theme.name);
|
themes.push(theme.name);
|
||||||
this.#storage.setVal(SettingsVals.marketPlace.themes, JSON.stringify(themes));
|
this.#storage.setVal(SettingsVals.marketPlace.themes, JSON.stringify(themes));
|
||||||
}
|
}
|
||||||
|
|
||||||
async installPlugin(plugin: Plug) {
|
async installPlugin(plugin: Plug) {
|
||||||
const plugins = this.#storage.getVal(SettingsVals.marketPlace.plugins)
|
const plugins = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
|
||||||
? JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins))
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const plug = plugins.find(({ name }: { name: string }) => name === plugin.name);
|
const plug = plugins.find(({ name }: { name: string }) => name === plugin.name);
|
||||||
if (plug && plug.remove === false) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${plugin.name} is already installed!`);
|
if (plug && plug.remove === false) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${plugin.name} is already installed!`);
|
||||||
|
|
@ -80,8 +126,140 @@ class Marketplace {
|
||||||
plugins.push({ name: plugin.name, src: plugin.src, type: plugin.type } as unknown as Plug);
|
plugins.push({ name: plugin.name, src: plugin.src, type: plugin.type } as unknown as Plug);
|
||||||
this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(plugins));
|
this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(plugins));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async uninstallTheme(theme: Theme) {
|
||||||
|
const items = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
|
||||||
|
if (!items.find((th: string) => th === theme.name)) {
|
||||||
|
return log({ type: 'error', bg: false, prefix: false, throw: true }, `Theme: ${theme.name} is not installed!`);
|
||||||
|
}
|
||||||
|
const idx = items.indexOf(theme.name.toLowerCase());
|
||||||
|
items.splice(idx, 1);
|
||||||
|
this.#storage.setVal(SettingsVals.marketPlace.themes, JSON.stringify(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
async uninstallPlugin(plug: Plug) {
|
||||||
|
const items = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
|
||||||
|
const plugin = items.find(({ name }: { name: string }) => name === plug.name.toLowerCase());
|
||||||
|
if (!plugin) return log({ type: 'error', bg: false, prefix: false, throw: true }, `Plugin: ${plug.name} is not installed!`);
|
||||||
|
plugin.remove = true;
|
||||||
|
this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
async handlePlugins(worker: ServiceWorkerRegistration) {
|
||||||
|
let plugins = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
|
||||||
|
const pagePlugins: SWPagePlugin[] = [];
|
||||||
|
const swPlugins: SWPlugin[] = [];
|
||||||
|
if (plugins.length === 0) return log({ type: 'info', bg: false, prefix: true }, 'No plugins to add! Exiting.');
|
||||||
|
plugins.map(async (plugin: Plug) => {
|
||||||
|
if (plugin.type === "page") {
|
||||||
|
const script = await fetch(`/packages/${plugin.name.toLowerCase()}/${plugin.src}`);
|
||||||
|
const scriptRes = await script.text();
|
||||||
|
const evaledScript = eval(scriptRes);
|
||||||
|
const inject = (await evaledScript()) as unknown as SWPagePlugin;
|
||||||
|
if (!plugin.remove) {
|
||||||
|
pagePlugins.push({
|
||||||
|
host: inject.host,
|
||||||
|
html: inject.html,
|
||||||
|
injectTo: inject.injectTo,
|
||||||
|
type: 'page'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
plugins = plugins.filter(({ name }: { name: string }) => name !== plugin.name.toLowerCase());
|
||||||
|
pagePlugins.push({
|
||||||
|
remove: true,
|
||||||
|
host: inject.host,
|
||||||
|
html: inject.html,
|
||||||
|
injectTo: inject.injectTo,
|
||||||
|
type: 'page'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
worker.active?.postMessage(pagePlugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.type === "serviceWorker") {
|
||||||
|
const s = await fetch(`/packages/${plugin.name.toLowerCase()}/${plugin.src}`);
|
||||||
|
const sRes = await s.text();
|
||||||
|
const eScript = eval(sRes);
|
||||||
|
const inject = (await eScript()) as unknown as SWPlugin;
|
||||||
|
if (!plugin.remove) {
|
||||||
|
swPlugins.push({
|
||||||
|
function: inject.function.toString(),
|
||||||
|
name: plugin.name,
|
||||||
|
events: inject.events,
|
||||||
|
type: 'serviceWorker'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
plugins = plugins.filter(({ name }: { name: string }) => name !== plugin.name.toLowerCase());
|
||||||
|
swPlugins.push({
|
||||||
|
remove: true,
|
||||||
|
function: inject.function.toString(),
|
||||||
|
name: plugin.name,
|
||||||
|
events: inject.events,
|
||||||
|
type: 'serviceWorker'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
worker.active?.postMessage(swPlugins);
|
||||||
|
}
|
||||||
|
this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(plugins));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async theme(opts: { type: 'normal', payload: string, sources?: { video?: string, bg?: string }, name: string } | { type: 'remove', payload?: string, sources?: { video?: string, bg?: string }, name?: string }) {
|
||||||
|
const elems = Elements.select([
|
||||||
|
{ type: 'id', val: 'stylesheet' },
|
||||||
|
{ type: 'id', val: 'nebulaVideo' },
|
||||||
|
{ type: 'id', val: 'nebulaImage' }
|
||||||
|
]);
|
||||||
|
const s = Elements.exists<HTMLLinkElement>(await elems.next());
|
||||||
|
const nv = Elements.exists<HTMLVideoElement>(await elems.next());
|
||||||
|
const ni = Elements.exists<HTMLImageElement>(await elems.next());
|
||||||
|
|
||||||
|
const nvl = this.#storage.getVal(SettingsVals.marketPlace.appearance.video);
|
||||||
|
const nil = this.#storage.getVal(SettingsVals.marketPlace.appearance.image);
|
||||||
|
const tsp = this.#storage.getVal(SettingsVals.marketPlace.appearance.theme.payload);
|
||||||
|
const tsn = this.#storage.getVal(SettingsVals.marketPlace.appearance.theme.name);
|
||||||
|
|
||||||
|
const reset = (style: boolean) => {
|
||||||
|
const st = this.#storage;
|
||||||
|
if (style) {
|
||||||
|
st.removeVal(SettingsVals.marketPlace.appearance.theme.name);
|
||||||
|
st.removeVal(SettingsVals.marketPlace.appearance.theme.payload);
|
||||||
|
s.href = "/nebula.css";
|
||||||
|
}
|
||||||
|
st.removeVal(SettingsVals.marketPlace.appearance.video);
|
||||||
|
nv.src = "";
|
||||||
|
st.removeVal(SettingsVals.marketPlace.appearance.image);
|
||||||
|
ni.style.display = "none";
|
||||||
|
ni.src = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.type === 'remove') return reset(true);
|
||||||
|
|
||||||
|
if (opts.sources?.video || nvl) {
|
||||||
|
reset(false);
|
||||||
|
if (!nvl) this.#storage.setVal(SettingsVals.marketPlace.appearance.video, opts.sources?.video || nvl);
|
||||||
|
nv.src = `/packages/${opts.name}/${opts.sources?.video ? opts.sources.video : nvl}`
|
||||||
|
}
|
||||||
|
if (opts.sources?.bg || nil) {
|
||||||
|
reset(false);
|
||||||
|
if (!nil) this.#storage.setVal(SettingsVals.marketPlace.appearance.image, opts.sources?.bg || nil);
|
||||||
|
ni.style.display = "block";
|
||||||
|
ni.src = `/packages/${opts.name}/${opts.sources?.bg ? opts.sources.bg : nil}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.payload) {
|
||||||
|
if (tsp !== opts.payload) {
|
||||||
|
this.#storage.setVal(SettingsVals.marketPlace.appearance.theme.payload, opts.payload);
|
||||||
|
this.#storage.setVal(SettingsVals.marketPlace.appearance.theme.name, opts.name);
|
||||||
|
s.href = `/packages/${opts.name}/${opts.payload}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (tsp) return s.href = `/packages/${tsn}/${tsp}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.mp = Marketplace
|
|
||||||
|
|
||||||
export { Marketplace }
|
export { Marketplace }
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,9 @@ type SWInit = {
|
||||||
class SW {
|
class SW {
|
||||||
#init!: SWInit;
|
#init!: SWInit;
|
||||||
#ready: boolean = false;
|
#ready: boolean = false;
|
||||||
|
static #instances = new Set();
|
||||||
constructor(conn: BareMuxConnection) {
|
constructor(conn: BareMuxConnection) {
|
||||||
|
SW.#instances.add(this);
|
||||||
const sj = (): ScramjetController => {
|
const sj = (): ScramjetController => {
|
||||||
const sj = new ScramjetController({
|
const sj = new ScramjetController({
|
||||||
prefix: '/~/scramjet',
|
prefix: '/~/scramjet',
|
||||||
|
|
@ -133,7 +135,25 @@ class SW {
|
||||||
throw new Error('Your browser is not supported! This website uses Service Workers heavily.');
|
throw new Error('Your browser is not supported! This website uses Service Workers heavily.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static method to get an already existing SW class
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* SW.getInstances.next().value // Get the first instance.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Loop through every instance
|
||||||
|
* for (const sw of SW.getInstances()) {
|
||||||
|
* console.log(sw) // DO some real work
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static *getInstances() {
|
||||||
|
for (const value of SW.#instances.keys()) {
|
||||||
|
yield value as SW;
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Allows you to overrid the items set. Should be used sparingly or never.
|
* Allows you to overrid the items set. Should be used sparingly or never.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { defaultStore } from "./storage";
|
import { defaultStore } from "./storage";
|
||||||
import { SettingsVals, WispServers } from "./values";
|
import { SettingsVals, WispServers } from "./values";
|
||||||
import { Marketplace } from "./marketplace";
|
import { Marketplace } from "./marketplace";
|
||||||
import { setTransport } from "./serviceWorker";
|
import { setTransport, SW } from "./serviceWorker";
|
||||||
|
|
||||||
const tab = {
|
const tab = {
|
||||||
ab: (redirect: string) => {
|
ab: (redirect: string) => {
|
||||||
|
|
@ -86,7 +86,8 @@ const proxy = {
|
||||||
defaultStore.setVal(SettingsVals.proxy.wispServer, s);
|
defaultStore.setVal(SettingsVals.proxy.wispServer, s);
|
||||||
},
|
},
|
||||||
transport: async (t: "libcurl" | "epoxy") => {
|
transport: async (t: "libcurl" | "epoxy") => {
|
||||||
const { bareMuxConn } = await window.sw.getSWInfo();
|
const sw = SW.getInstances().next().value!;
|
||||||
|
const { bareMuxConn } = await sw.getSWInfo();
|
||||||
await setTransport(bareMuxConn, t as "libcurl" | "epoxy");
|
await setTransport(bareMuxConn, t as "libcurl" | "epoxy");
|
||||||
defaultStore.setVal(SettingsVals.proxy.transport.key, t);
|
defaultStore.setVal(SettingsVals.proxy.transport.key, t);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,13 @@ class StoreManager<Prefix extends string /* This is here so I know what prefix i
|
||||||
return localStorage.getItem(`${this.#prefix}||${key}`) as string;
|
return localStorage.getItem(`${this.#prefix}||${key}`) as string;
|
||||||
}
|
}
|
||||||
setVal(key: string, val: string): void {
|
setVal(key: string, val: string): void {
|
||||||
|
log({ type: 'info', bg: false, prefix: true }, `Setting ${key} with value: ${val}`);
|
||||||
localStorage.setItem(`${this.#prefix}||${key}`, val);
|
localStorage.setItem(`${this.#prefix}||${key}`, val);
|
||||||
}
|
}
|
||||||
|
removeVal(key: string): void {
|
||||||
|
log({ type: 'info', bg: true, prefix: true }, `Removing ${this.#prefix}||${key}`);
|
||||||
|
localStorage.removeItem(`${this.#prefix}||${key}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//this is done so I can see the prefix used.
|
//this is done so I can see the prefix used.
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,10 @@ interface SettingsVals {
|
||||||
appearance: {
|
appearance: {
|
||||||
video: string;
|
video: string;
|
||||||
image: string;
|
image: string;
|
||||||
themeName: string;
|
theme: {
|
||||||
|
payload: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +108,10 @@ const SettingsVals: SettingsVals = {
|
||||||
appearance: {
|
appearance: {
|
||||||
video: "video",
|
video: "video",
|
||||||
image: "image",
|
image: "image",
|
||||||
themeName: "themeName"
|
theme: {
|
||||||
|
name: "themeName",
|
||||||
|
payload: "themePayload"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue