Some plugin logic (still kinda broken)

This commit is contained in:
MotorTruck1221 2024-10-21 05:30:12 -06:00
parent 4f1a8960f1
commit fff4d0b286
No known key found for this signature in database
GPG key ID: 08F417E2B8B61EA4
19 changed files with 464 additions and 52 deletions

View file

@ -5,7 +5,7 @@ import { baremuxPath } from "@mercuryworkshop/bare-mux";
import { epoxyPath } from "@mercuryworkshop/epoxy-transport"; import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
import { libcurlPath } from "@mercuryworkshop/libcurl-transport"; import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
import playformCompress from "@playform/compress"; import playformCompress from "@playform/compress";
import { uvPath } from "@titaniumnetwork-dev/ultraviolet"; import { uvPath } from "@rubynetwork/ultraviolet";
import icon from "astro-icon"; import icon from "astro-icon";
import { defineConfig, envField } from "astro/config"; import { defineConfig, envField } from "astro/config";
import { viteStaticCopy } from "vite-plugin-static-copy"; import { viteStaticCopy } from "vite-plugin-static-copy";

View file

@ -0,0 +1,11 @@
const script = `
console.error('GYATT')
`
self.entryFunc = function(){
return {
host: 'example.com',
html: `<script>${script}</script>`,
injectTo: 'body'
}
}

View file

@ -33,8 +33,8 @@
"@playform/compress": "^0.1.4", "@playform/compress": "^0.1.4",
"@rubynetwork/rammerhead": "^1.3.5", "@rubynetwork/rammerhead": "^1.3.5",
"@rubynetwork/rammerhead-browser": "^1.0.9", "@rubynetwork/rammerhead-browser": "^1.0.9",
"@rubynetwork/ultraviolet": "3.2.7-ruby.1",
"@svelte-drama/suspense": "0.5.1", "@svelte-drama/suspense": "0.5.1",
"@titaniumnetwork-dev/ultraviolet": "3.1.2",
"@types/node": "^22.7.5", "@types/node": "^22.7.5",
"@types/sequelize": "^4.28.20", "@types/sequelize": "^4.28.20",
"astro": "^4.16.2", "astro": "^4.16.2",

49
pnpm-lock.yaml generated
View file

@ -56,12 +56,12 @@ importers:
'@rubynetwork/rammerhead-browser': '@rubynetwork/rammerhead-browser':
specifier: ^1.0.9 specifier: ^1.0.9
version: 1.0.9 version: 1.0.9
'@rubynetwork/ultraviolet':
specifier: 3.2.7-ruby.1
version: 3.2.7-ruby.1
'@svelte-drama/suspense': '@svelte-drama/suspense':
specifier: 0.5.1 specifier: 0.5.1
version: 0.5.1(svelte@4.2.19) version: 0.5.1(svelte@4.2.19)
'@titaniumnetwork-dev/ultraviolet':
specifier: 3.1.2
version: 3.1.2
'@types/node': '@types/node':
specifier: ^22.7.5 specifier: ^22.7.5
version: 22.7.5 version: 22.7.5
@ -871,6 +871,9 @@ packages:
'@mercuryworkshop/bare-mux@1.1.1': '@mercuryworkshop/bare-mux@1.1.1':
resolution: {integrity: sha512-qKOnTsIjwv4wBvToek3Jm+y3F/BcFtjy6HOsdyzIUemCOw51kodzRsvWvU9Pf/JYDVPV8or0zbsg+qOKtasjhA==} resolution: {integrity: sha512-qKOnTsIjwv4wBvToek3Jm+y3F/BcFtjy6HOsdyzIUemCOw51kodzRsvWvU9Pf/JYDVPV8or0zbsg+qOKtasjhA==}
'@mercuryworkshop/bare-mux@1.1.4':
resolution: {integrity: sha512-mJPezqEpiKTCs+wu/3TowilnVXQgFs4SqoQnnbCbOc5cV6bDggaolKkyYjDnmOB9t/nptIIXDWDB31oS9vX9kA==}
'@mercuryworkshop/epoxy-tls@2.1.6-1': '@mercuryworkshop/epoxy-tls@2.1.6-1':
resolution: {integrity: sha512-drnffDo9Ls73Fpmcup2Ys1z+BjzK+WLnzyfS4APFfWr9cJ0gu7567tx4M06XH5PUZMOS1J1Z3wqnRaBh/RX5bQ==} resolution: {integrity: sha512-drnffDo9Ls73Fpmcup2Ys1z+BjzK+WLnzyfS4APFfWr9cJ0gu7567tx4M06XH5PUZMOS1J1Z3wqnRaBh/RX5bQ==}
@ -1017,6 +1020,9 @@ packages:
'@rubynetwork/rh@1.2.74': '@rubynetwork/rh@1.2.74':
resolution: {integrity: sha512-qbVueaMHxSXF8dysQE3eL2Fj8x5L1cBMzk5G6iVokntQjYxCHcV+vWvZbykXspvPJjs4b5uYnZ+D/rMHmSVhrg==} resolution: {integrity: sha512-qbVueaMHxSXF8dysQE3eL2Fj8x5L1cBMzk5G6iVokntQjYxCHcV+vWvZbykXspvPJjs4b5uYnZ+D/rMHmSVhrg==}
'@rubynetwork/ultraviolet@3.2.7-ruby.1':
resolution: {integrity: sha512-JaIlRFRObrXk5lWCfOs4CQ+caRm0aqRqZFMvFhXoRXK02YbhemF01/+JQEHwWgC1XeldyHf60LfL4JKhGqD3MA==}
'@shikijs/core@1.22.0': '@shikijs/core@1.22.0':
resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==} resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==}
@ -1052,9 +1058,6 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0 svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0 vite: ^5.0.0
'@titaniumnetwork-dev/ultraviolet@3.1.2':
resolution: {integrity: sha512-PvhyL9IQtSwHTVRRpNGn+YCWkSzP7JEk0wX7M5YfUSobBicoRLOJhCC4u6T9qh/vObDpLDE3TfP4GKqMTSa2rw==}
'@tootallnate/once@1.1.2': '@tootallnate/once@1.1.2':
resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -1277,6 +1280,10 @@ packages:
array-iterate@2.0.1: array-iterate@2.0.1:
resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==}
astring@1.9.0:
resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
hasBin: true
astro-icon@1.1.1: astro-icon@1.1.1:
resolution: {integrity: sha512-HKBesWk2Faw/0+klLX+epQVqdTfSzZz/9+5vxXUjTJaN/HnpDf608gRPgHh7ZtwBPNJMEFoU5GLegxoDcT56OQ==} resolution: {integrity: sha512-HKBesWk2Faw/0+klLX+epQVqdTfSzZz/9+5vxXUjTJaN/HnpDf608gRPgHh7ZtwBPNJMEFoU5GLegxoDcT56OQ==}
@ -2146,6 +2153,9 @@ packages:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
idb@8.0.0:
resolution: {integrity: sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==}
ieee754@1.2.1: ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@ -2534,6 +2544,10 @@ packages:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
meriyah@6.0.2:
resolution: {integrity: sha512-RHlo7GK3qrswKzVcMJ/2bMMkMChpn4L/JUOBfs81c3SKp/ZOS5u2aC/qY+sZCiE4qPkrC+a1yNPfGieh0uz19Q==}
engines: {node: '>=18.0.0'}
micromark-core-commonmark@2.0.1: micromark-core-commonmark@2.0.1:
resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==} resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==}
@ -4834,6 +4848,11 @@ snapshots:
'@types/uuid': 9.0.8 '@types/uuid': 9.0.8
uuid: 9.0.1 uuid: 9.0.1
'@mercuryworkshop/bare-mux@1.1.4':
dependencies:
'@types/uuid': 9.0.8
uuid: 9.0.1
'@mercuryworkshop/epoxy-tls@2.1.6-1': {} '@mercuryworkshop/epoxy-tls@2.1.6-1': {}
'@mercuryworkshop/epoxy-transport@https://codeload.github.com/motortruck1221/epoxytransport/tar.gz/5e8205cdfef67e1cf73fbba7fb56cb181de070f7': '@mercuryworkshop/epoxy-transport@https://codeload.github.com/motortruck1221/epoxytransport/tar.gz/5e8205cdfef67e1cf73fbba7fb56cb181de070f7':
@ -5001,6 +5020,16 @@ snapshots:
- supports-color - supports-color
- utf-8-validate - utf-8-validate
'@rubynetwork/ultraviolet@3.2.7-ruby.1':
dependencies:
'@mercuryworkshop/bare-mux': 1.1.4
astring: 1.9.0
events: 3.3.0
idb: 8.0.0
meriyah: 6.0.2
parse5: 7.2.0
set-cookie-parser: 2.7.0
'@shikijs/core@1.22.0': '@shikijs/core@1.22.0':
dependencies: dependencies:
'@shikijs/engine-javascript': 1.22.0 '@shikijs/engine-javascript': 1.22.0
@ -5055,8 +5084,6 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@titaniumnetwork-dev/ultraviolet@3.1.2': {}
'@tootallnate/once@1.1.2': '@tootallnate/once@1.1.2':
optional: true optional: true
@ -5309,6 +5336,8 @@ snapshots:
array-iterate@2.0.1: {} array-iterate@2.0.1: {}
astring@1.9.0: {}
astro-icon@1.1.1: astro-icon@1.1.1:
dependencies: dependencies:
'@iconify/tools': 4.0.7 '@iconify/tools': 4.0.7
@ -6389,6 +6418,8 @@ snapshots:
dependencies: dependencies:
safer-buffer: 2.1.2 safer-buffer: 2.1.2
idb@8.0.0: {}
ieee754@1.2.1: {} ieee754@1.2.1: {}
import-meta-resolve@4.1.0: {} import-meta-resolve@4.1.0: {}
@ -6810,6 +6841,8 @@ snapshots:
merge2@1.4.1: {} merge2@1.4.1: {}
meriyah@6.0.2: {}
micromark-core-commonmark@2.0.1: micromark-core-commonmark@2.0.1:
dependencies: dependencies:
decode-named-character-reference: 1.0.2 decode-named-character-reference: 1.0.2

View file

@ -4,6 +4,34 @@ importScripts("/uv/uv.bundle.js");
importScripts("/uv/uv.config.js"); importScripts("/uv/uv.config.js");
importScripts(__uv$config.sw || "/uv/uv.sw.js"); importScripts(__uv$config.sw || "/uv/uv.sw.js");
const uv = new UVServiceWorker(); const uv = new UVServiceWorker();
//where we handle our plugins!!!
self.addEventListener("message", function(event) {
//console.log(event.data);
if (uv.config.inject === undefined) {
uv.config.inject = [];
}
//loop over the required data (we don't verify here as types will take care of us :D)
event.data.forEach((data) => {
if (data.remove) {
if (uv.config.inject.find(({ host }) => host === data.host)) {
const idx = uv.config.inject.indexOf(data.host);
uv.config.inject.splice(idx, 1);
}
}
else {
if (!uv.config.inject.find(({ host }) => host === data.host)) {
uv.config.inject.push({
host: data.host,
html: data.html,
injectTo: data.injectTo
});
}
}
});
console.log(uv.config.inject);
});
self.addEventListener("fetch", function (event) { self.addEventListener("fetch", function (event) {
if (event.request.url.startsWith(location.origin + __uv$config.prefix)) { if (event.request.url.startsWith(location.origin + __uv$config.prefix)) {
event.respondWith( event.respondWith(

View file

@ -0,0 +1,6 @@
class WWError extends Error {
constructor(message) {
super(message);
this.name = "[WorkerWare Exception]";
}
}

View file

@ -0,0 +1,168 @@
importScripts("./WWError.js");
const dbg = console.log.bind(console, "[WorkerWare]");
const time = console.time.bind(console, "[WorkerWare]");
const timeEnd = console.timeEnd.bind(console, "[WorkerWare]");
/*
OPTS:
debug - Enables debug logging.
randomNames - Generate random names for middlewares.
timing - Logs timing for each middleware.
*/
const defaultOpt = {
debug: false,
randomNames: false,
timing: false,
};
const validEvents = [
"abortpayment",
"activate",
"backgroundfetchabort",
"backgroundfetchclick",
"backgroundfetchfail",
"backgroundfetchsuccess",
"canmakepayment",
"contentdelete",
"cookiechange",
"fetch",
"install",
"message",
"messageerror",
"notificationclick",
"notificationclose",
"paymentrequest",
"periodicsync",
"push",
"pushsubscriptionchange",
"sync",
];
class WorkerWare {
constructor(opt) {
this._opt = Object.assign({}, defaultOpt, opt);
this._middlewares = [];
}
info() {
return {
version: "0.1.0",
middlewares: this._middlewares,
options: this._opt,
};
}
use(middleware) {
let validateMW = this.validateMiddleware(middleware);
if (validateMW.error) throw new WWError(validateMW.error);
// This means the middleware is an anonymous function, or the user is silly and named their function "function"
if (middleware.function.name == "function") middleware.name = crypto.randomUUID();
if (!middleware.name) middleware.name = middleware.function.name;
if (this._opt.randomNames) middleware.name = crypto.randomUUID();
if (this._opt.debug) dbg("Adding middleware:", middleware.name);
this._middlewares.push(middleware);
}
// Run all middlewares for the event type passed in.
run(event) {
const middlewares = this._middlewares;
const returnList = [];
let fn = async () => {
for (let i = 0; i < middlewares.length; i++) {
if (middlewares[i].events.includes(event.type)) {
if (this._opt.timing) console.time(middlewares[i].name);
// Add the configuration to the event object.
event.workerware = {
config: middlewares[i].configuration || {},
};
if (!middlewares[i].explicitCall) {
let res = await middlewares[i].function(event);
if (this._opt.timing) console.timeEnd(middlewares[i].name);
returnList.push(res);
}
}
}
return returnList;
};
return fn;
}
deleteByName(middlewareID) {
if (this._opt.debug) dbg("Deleting middleware:", middlewareID);
this._middlewares = this._middlewares.filter((mw) => mw.name !== middlewareID);
}
deleteByEvent(middlewareEvent) {
if (this._opt.debug) dbg("Deleting middleware by event:", middlewareEvent);
this._middlewares = this._middlewares.filter((mw) => !mw.events.includes(middlewareEvent));
}
get() {
return this._middlewares;
}
/*
Run a single middleware by ID.
This assumes that the user knows what they're doing, and is running the middleware on an event that it's supposed to run on.
*/
runMW(name, event) {
const middlewares = this._middlewares;
if (this._opt.debug) dbg("Running middleware:", name);
// if (middlewares.includes(name)) {
// return middlewares[name](event);
// } else {
// throw new WWError("Middleware not found!");
// }
let didCall = false;
for (let i = 0; i < middlewares.length; i++) {
if (middlewares[i].name == name) {
didCall = true;
event.workerware = {
config: middlewares[i].configuration || {},
}
if (this._opt.timing) console.time(middlewares[i].name);
let call = middlewares[i].function(event);
if (this._opt.timing) console.timeEnd(middlewares[i].name);
return call;
}
}
if (!didCall) {
throw new WWError("Middleware not found!");
}
}
// type middlewareManifest = {
// function: Function,
// name?: string,
// events: string[], // Should be a union of validEvents.
// configuration?: Object // Optional configuration for the middleware.
// }
validateMiddleware(middleware) {
if (!middleware.function)
return {
error: "middleware.function is required",
};
if (typeof middleware.function !== "function")
return {
error: "middleware.function must be typeof function",
};
if (typeof middleware.configuration !== "object" && middleware.configuration !== undefined) {
return {
error: "middleware.configuration must be typeof object",
};
}
if (!middleware.events)
return {
error: "middleware.events is required",
};
if (!Array.isArray(middleware.events))
return {
error: "middleware.events must be an array",
};
if (middleware.events.some((ev) => !validEvents.includes(ev)))
return {
error: "Invalid event type! Must be one of the following: " + validEvents.join(", "),
};
if (middleware.explicitCall && typeof middleware.explicitCall !== "boolean") {
return {
error: "middleware.explicitCall must be typeof boolean",
};
}
return {
error: undefined,
};
}
}

View file

@ -22,7 +22,8 @@ async function installItems(db: ModelStatic<CatalogModel>, items: Items[]) {
payload: item.payload, payload: item.payload,
background_video: item.background_video, background_video: item.background_video,
background_image: item.background_image, background_image: item.background_image,
type: item.type type: item.type,
entryFunc: item.entryFunc
}); });
}); });
} }
@ -39,7 +40,8 @@ async function setupDB(db: ModelStatic<CatalogModel>) {
description: "The gruvbox theme", description: "The gruvbox theme",
tags: ["Theme", "Simple"], tags: ["Theme", "Simple"],
payload: "gruvbox.css", payload: "gruvbox.css",
type: "theme" type: "theme",
entryFunc: null
}, },
{ {
package_name: "com.nebula.oled", package_name: "com.nebula.oled",
@ -50,7 +52,8 @@ async function setupDB(db: ModelStatic<CatalogModel>) {
description: "A sleek & simple Oled theme for Nebula", description: "A sleek & simple Oled theme for Nebula",
tags: ["Theme", "Simple", "Sleek"], tags: ["Theme", "Simple", "Sleek"],
payload: "oled.css", payload: "oled.css",
type: "theme" type: "theme",
entryFunc: null
}, },
{ {
package_name: "com.nebula.lightTheme", package_name: "com.nebula.lightTheme",
@ -61,7 +64,8 @@ async function setupDB(db: ModelStatic<CatalogModel>) {
description: "A sleek light theme for Nebula", description: "A sleek light theme for Nebula",
tags: ["Theme", "Simple", "Light"], tags: ["Theme", "Simple", "Light"],
payload: "light.css", payload: "light.css",
type: "theme" type: "theme",
entryFunc: null
}, },
{ {
package_name: "com.nebula.retro", package_name: "com.nebula.retro",
@ -72,7 +76,20 @@ async function setupDB(db: ModelStatic<CatalogModel>) {
description: "Give a retro look to Nebula", description: "Give a retro look to Nebula",
tags: ["Theme", "Simple", "Dark", "Retro"], tags: ["Theme", "Simple", "Dark", "Retro"],
payload: "retro.css", payload: "retro.css",
type: "theme" type: "theme",
entryFunc: null
},
{
package_name: "com.nebula.darkMode",
title: "Dark Mode",
image: "dark.png",
author: "Nebula Services",
version: "1.0.0",
description: "Force dark mode on all websites",
tags: ["Plugin", "Dark Mode", "Noctura"],
payload: "index.js",
type: "plugin",
entryFunc: "entryFunc"
} }
]; ];
const dbItems = await db.findAll(); const dbItems = await db.findAll();

View file

@ -28,6 +28,7 @@ interface Catalog {
background_video: string; background_video: string;
payload: string; payload: string;
type: CatalogType; type: CatalogType;
entryFunc: string;
} }
interface CatalogModel interface CatalogModel
@ -45,7 +46,8 @@ const catalogAssets = db.define<CatalogModel>("catalog_assets", {
background_image: { type: DataTypes.TEXT, allowNull: true }, background_image: { type: DataTypes.TEXT, allowNull: true },
background_video: { type: DataTypes.TEXT, allowNull: true }, background_video: { type: DataTypes.TEXT, allowNull: true },
payload: { type: DataTypes.TEXT }, payload: { type: DataTypes.TEXT },
type: { type: DataTypes.TEXT } type: { type: DataTypes.TEXT },
entryFunc: { type: DataTypes.STRING }
}); });
function marketplaceAPI(app: FastifyInstance) { function marketplaceAPI(app: FastifyInstance) {
@ -78,7 +80,8 @@ function marketplaceAPI(app: FastifyInstance) {
background_image: asset.background_image, background_image: asset.background_image,
background_video: asset.background_video, background_video: asset.background_video,
payload: asset.payload, payload: asset.payload,
type: asset.type type: asset.type,
entryFunc: asset.entryFunc
}; };
return acc; return acc;
}, {}); }, {});
@ -105,7 +108,8 @@ function marketplaceAPI(app: FastifyInstance) {
background_image: packageRow.get("background_image"), background_image: packageRow.get("background_image"),
background_video: packageRow.get("background_video"), background_video: packageRow.get("background_video"),
payload: packageRow.get("payload"), payload: packageRow.get("payload"),
type: packageRow.get("type") type: packageRow.get("type"),
entryFunc: packageRow.get("entryFunc")
}; };
reply.send(details); reply.send(details);
} catch (error) { } catch (error) {
@ -128,6 +132,7 @@ function marketplaceAPI(app: FastifyInstance) {
background_video: string; background_video: string;
background_image: string; background_image: string;
type: CatalogType; type: CatalogType;
entryFunc: string;
}; };
}>; }>;
interface VerifyStatus { interface VerifyStatus {
@ -193,7 +198,8 @@ function marketplaceAPI(app: FastifyInstance) {
payload: request.body.payload, payload: request.body.payload,
background_video: request.body.background_video, background_video: request.body.background_video,
background_image: request.body.background_image, background_image: request.body.background_image,
type: request.body.type as CatalogType type: request.body.type as CatalogType,
entryFunc: request.body.entryFunc
}; };
await catalogAssets.create({ await catalogAssets.create({
package_name: body.package_name, package_name: body.package_name,
@ -206,7 +212,8 @@ function marketplaceAPI(app: FastifyInstance) {
payload: body.payload, payload: body.payload,
background_video: body.background_video, background_video: body.background_video,
background_image: body.background_image, background_image: body.background_image,
type: body.type type: body.type,
entryFunc: body.entryFunc
}); });
const assets = fileURLToPath(new URL("../database_assets", import.meta.url)); const assets = fileURLToPath(new URL("../database_assets", import.meta.url));
try { try {

View file

@ -0,0 +1,56 @@
<script lang="ts">
import { Suspense } from "@svelte-drama/suspense";
import { Settings, settings } from "@utils/settings/index";
import Parent from "./Parent.svelte";
async function getItem(item) {
try {
const response = await fetch(`/api/packages/${item}`);
const data = await response.json();
return {
...data,
package_name: item
};
} catch (error) {
console.error("error: failed to fetch", error);
return null;
}
}
async function getAssets() {
const items = JSON.parse(localStorage.getItem(Settings.PluginSettings.plugins)) || [];
const promises = items.map(getItem);
const dataArray = await Promise.all(promises);
const accumulatedData = dataArray.filter((data) => data !== null);
console.log(JSON.stringify(accumulatedData));
return accumulatedData;
}
let assets = getAssets();
let compRef = [];
</script>
<Suspense let:suspend>
{#await suspend(assets) then data}
{#each Object.entries(data) as [key, asset]}
<Parent bind:this={compRef[key]}>
<div class="rounded-3xl bg-navbar-color w-64 flex flex-col cursor-pointer">
<div class="w-full" on:click={() => {settings.marketPlaceSettings.changeTheme(false, asset.payload, asset.background_video, asset.background_image, asset.package_name)}}>
<img src={`/packages/${asset.package_name}/${asset.image}`} alt="theme" class="aspect-[16/9] rounded-t-3xl"/>
</div>
<div class="h-2/6 text-center content-center p-3 font-semibold items-center flex flex-col">
<div class="text-2xl"> {asset.title} </div>
<div class="flex flex-row">
<div class="h-8 w-8 cursor-pointer" on:click={() => {settings.marketPlaceSettings.uninstall("theme", asset.package_name); settings.marketPlaceSettings.changeTheme(true); compRef[key].$destroy()}}>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 256 256" {...$$props}>
<path fill="currentColor" d="M216 48h-40v-8a24 24 0 0 0-24-24h-48a24 24 0 0 0-24 24v8H40a8 8 0 0 0 0 16h8v144a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16V64h8a8 8 0 0 0 0-16M112 168a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Zm48 0a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Zm0-120H96v-8a8 8 0 0 1 8-8h48a8 8 0 0 1 8 8Z" />
</svg>
</div>
<a class="h-8 w-8 cursor-pointer" href={`/catalog/package/${asset.package_name}`}>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 256 256" {...$$props}>
<path fill="currentColor" d="M192 136v72a16 16 0 0 1-16 16H48a16 16 0 0 1-16-16V80a16 16 0 0 1 16-16h72a8 8 0 0 1 0 16H48v128h128v-72a8 8 0 0 1 16 0m32-96a8 8 0 0 0-8-8h-64a8 8 0 0 0-5.66 13.66L172.69 72l-42.35 42.34a8 8 0 0 0 11.32 11.32L184 83.31l26.34 26.35A8 8 0 0 0 224 104Z" />
</svg>
</a>
</div>
</div>
</div>
</Parent>
{/each}
{/await}
</Suspense>

2
src/env.d.ts vendored
View file

@ -1,5 +1,5 @@
/// <reference path="../.astro/types.d.ts" /> /// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" /> /// <reference types="astro/client" />
/// <reference types="@titaniumnetwork-dev/ultraviolet/client" /> /// <reference types="@rubynetwork/ultraviolet/client" />
declare var BareMux: any; declare var BareMux: any;
declare var EpxMod: any; declare var EpxMod: any;

View file

@ -53,17 +53,24 @@ const assetsJson = await response.json();
} }
customElements.define('variable-define', VariableDefiner); customElements.define('variable-define', VariableDefiner);
const fn = () => { const fn = () => {
const items = JSON.parse(localStorage.getItem(Settings.AppearanceSettings.themes) as string) || []; const cssItems = JSON.parse(localStorage.getItem(Settings.AppearanceSettings.themes) as string) || [];
const itemExists = items.indexOf(packageName) !== -1; const cssItemExists = cssItems.indexOf(packageName) !== -1;
const pluginItems = JSON.parse(localStorage.getItem(Settings.PluginSettings.plugins) as string) || [];
//@ts-ignore
const pluginItemExists = pluginItems.find(({ name }) => name === packageName);
const installButton = document.getElementById("install") as HTMLButtonElement; const installButton = document.getElementById("install") as HTMLButtonElement;
const uninstallButton = document.getElementById("uninstall") as HTMLButtonElement; const uninstallButton = document.getElementById("uninstall") as HTMLButtonElement;
const payload = assetsJson ? JSON.parse(assetsJson) : undefined; const payload = assetsJson ? JSON.parse(assetsJson) : undefined;
if (itemExists) { if (cssItemExists || pluginItemExists) {
uninstallButton.classList.remove("hidden"); uninstallButton.classList.remove("hidden");
installButton.classList.add("hidden"); installButton.classList.add("hidden");
} }
installButton.addEventListener("click", () => { installButton.addEventListener("click", () => {
settings.marketPlaceSettings.install({theme: {payload: payload.payload, video: payload.background_video, bgImage: payload.background_image}}, packageName, payload.payload).then(() => { settings.marketPlaceSettings.install(
payload.type === "theme" ? {theme: {payload: payload.payload, video: payload.background_video, bgImage: payload.background_image}} :
{plugin: {name: packageName, src: payload.payload, type: "page", entryFunc: payload.entryFunc }},
packageName, payload.payload
).then(() => {
installButton.classList.add("hidden"); installButton.classList.add("hidden");
uninstallButton.classList.remove("hidden"); uninstallButton.classList.remove("hidden");
}) })

View file

@ -54,7 +54,8 @@ import { VERSION } from "astro:env/client";
WispServerURLS, WispServerURLS,
SearchEngines, SearchEngines,
Settings, Settings,
cloak, cloak,
settings
} from "@utils/settings/index"; } from "@utils/settings/index";
import { search } from "@utils/search.ts"; //../../utils/search.ts import { search } from "@utils/search.ts"; //../../utils/search.ts
//@ts-expect-error No types, expected. See: https://github.com/ading2210/libcurl.js for docs on how to use. //@ts-expect-error No types, expected. See: https://github.com/ading2210/libcurl.js for docs on how to use.
@ -81,14 +82,16 @@ import { VERSION } from "astro:env/client";
} }
} }
function uv(iframe: HTMLIFrameElement, term: string) { function uv(iframe: HTMLIFrameElement, term: string) {
initSw().then(() => { initSw().then((reg) => {
setTransport(localStorage.getItem(Settings.ProxySettings.transport) as string).then(async () => { settings.marketPlaceSettings.handlePlugins(reg).then(() => {
iframe.classList.remove("hidden"); setTransport(localStorage.getItem(Settings.ProxySettings.transport) as string).then(async () => {
const url = await proxy(term, false); iframe.classList.remove("hidden");
if (url) { const url = await proxy(term, false);
iframe.src = url as string; if (url) {
} iframe.src = url as string;
}); }
});
});
}); });
} }
async function rh(iframe: HTMLIFrameElement, term: string) { async function rh(iframe: HTMLIFrameElement, term: string) {

View file

@ -24,7 +24,7 @@ import { MARKETPLACE_ENABLED } from "astro:env/client";
<div class="justify-center flex flex-row gap-6 flex-wrap md:justify-normal"> <div class="justify-center flex flex-row gap-6 flex-wrap md:justify-normal">
<InstalledThemes client:only="svelte" /> <InstalledThemes client:only="svelte" />
{MARKETPLACE_ENABLED && {MARKETPLACE_ENABLED &&
<a href="/catalog/1" class="rounded-3xl bg-navbar-color w-64 flex flex-col"> <a href={`/${lang}/catalog/1`} class="rounded-3xl bg-navbar-color w-64 flex flex-col">
<div class="w-full items-center justify-center flex aspect-[16/9]"> <div class="w-full items-center justify-center flex aspect-[16/9]">
<Icon name="ph:plus-bold" class="h-16 w-16" /> <Icon name="ph:plus-bold" class="h-16 w-16" />
</div> </div>

View file

@ -6,6 +6,8 @@ import Layout from "@layouts/Layout.astro";
import SettingsLayout from "@layouts/SettingsLayout.astro"; import SettingsLayout from "@layouts/SettingsLayout.astro";
import SettingsSection from "@layouts/SettingsSection.astro"; import SettingsSection from "@layouts/SettingsSection.astro";
import { getLangFromUrl, useTranslations } from "../../../i18n/utils"; import { getLangFromUrl, useTranslations } from "../../../i18n/utils";
import InstalledPlugins from "@components/catalog/InstalledPlugins.svelte";
import { Icon } from "astro-icon/components";
const lang = getLangFromUrl(Astro.url); const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang); const t = useTranslations(lang);
@ -95,7 +97,20 @@ export const prerender = true;
}} }}
/> />
</div> </div>
</SettingsSection> </SettingsSection>
<SettingsSection title="Plugins" subtitle="Plugins allow you to modify the way the proxy works (UV only)">
<div class="flex flex-row gap-6 justify-center md:justify-normal">
<InstalledPlugins client:only="svelte" />
<a href={`/${lang}/catalog/1`} class="rounded-3xl bg-navbar-color w-64 flex flex-col">
<div class="w-full items-center justify-center flex aspect-[16/9]">
<Icon name="ph:plus-bold" class="h-16 w-16" />
</div>
<div class="h-2/6 text-center content-center p-3 font-semibold">
Get more plugins in the <strong>Nebula Catalog!</strong>
</div>
</a>
</div>
</SettingsSection>
</SettingsLayout> </SettingsLayout>
<ToastWrapper client:load> <ToastWrapper client:load>
<Toast toastProp={{ <Toast toastProp={{

View file

@ -56,12 +56,12 @@ function setTransport(transport?: string) {
function initSw() { function initSw() {
//this is wrapped in a promise to mostly solve the bare-mux v1 problems //this is wrapped in a promise to mostly solve the bare-mux v1 problems
return new Promise<void>((resolve) => { return new Promise<ServiceWorkerRegistration>((resolve) => {
if ("serviceWorker" in navigator) { if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready.then(async () => { navigator.serviceWorker.ready.then(async (reg) => {
console.debug("Service worker ready!"); console.debug("Service worker ready!");
await loadProxyScripts(); await loadProxyScripts();
resolve(); resolve(reg);
}); });
navigator.serviceWorker.register("/sw.js", { scope: "/" }); navigator.serviceWorker.register("/sw.js", { scope: "/" });
} }

View file

@ -1,5 +1,5 @@
//Combine all of the other settings into one object. And export that (along with types and other things) //Combine all of the other settings into one object. And export that (along with types and other things)
import { AppearanceSettings, marketPlaceSettings } from "./marketplace"; import { AppearanceSettings, MarketPlaceExtras, PluginSettings, marketPlaceSettings } from "./marketplace";
import { ProxySettings, proxySettings } from "./proxy"; import { ProxySettings, proxySettings } from "./proxy";
import { TabSettings, cloak, tabSettings } from "./tab"; import { TabSettings, cloak, tabSettings } from "./tab";
import { import {
@ -19,7 +19,9 @@ import {
const Settings = { const Settings = {
AppearanceSettings, AppearanceSettings,
TabSettings, TabSettings,
ProxySettings ProxySettings,
MarketPlaceExtras,
PluginSettings
}; };
const settings = { const settings = {

View file

@ -1,14 +1,22 @@
//marketplace code & handlers //marketplace code & handlers
import { type Package, type PackageType } from "./types"; import { Settings } from ".";
import { type Package, type PackageType, type Plugin, type PluginType, type SWPlugin } from "./types";
const AppearanceSettings = { const AppearanceSettings = {
themes: "nebula||themes", themes: "nebula||themes",
themeName: "nebula||themeName", themeName: "nebula||themeName",
stylePayload: "nebula||stylepayload", stylePayload: "nebula||stylepayload",
video: "nebula||video", video: "nebula||video",
image: "nebula||image", image: "nebula||image",
};
const PluginSettings = {
plugins: "nebula||plugins"
}
const MarketPlaceExtras = {
proxy: "nebula||marketplaceProxy", proxy: "nebula||marketplaceProxy",
hostname: "nebula||marketplaceHostname" hostname: "nebula||marketplaceHostname"
}; }
const marketPlaceSettings = { const marketPlaceSettings = {
install: function (p: Package, packageName: string, payload?: any) { install: function (p: Package, packageName: string, payload?: any) {
@ -23,6 +31,16 @@ const marketPlaceSettings = {
} }
resolve(); resolve();
} }
if (p.plugin) {
let plugins = localStorage.getItem(PluginSettings.plugins) as any;
plugins ? (plugins = JSON.parse(plugins)) : (plugins = []);
//@ts-ignore
if (!plugins.find(({ name }) => name === packageName)) {
plugins.push({name: packageName, src: p.plugin.src, type: p.plugin.type, entryFunc: p.plugin.entryFunc} as unknown as Plugin)
localStorage.setItem(PluginSettings.plugins, JSON.stringify(plugins));
}
resolve();
}
}); });
}, },
uninstall: function (p: PackageType, packageName: string) { uninstall: function (p: PackageType, packageName: string) {
@ -38,6 +56,31 @@ const marketPlaceSettings = {
} }
resolve(); resolve();
} }
if (p === "plugin") {
let plugins = localStorage.getItem(PluginSettings.plugins) as any;
plugins ? (plugins = JSON.parse(plugins)) : (plugins = []);
//@ts-ignore
if (plugins.find(({name}) => name === packageName)) {
const idx = plugins.indexOf(packageName);
plugins.splice(idx, 1);
localStorage.setItem(PluginSettings.plugins, JSON.stringify(plugins));
}
resolve();
}
});
},
handlePlugins: function(worker: never | ServiceWorkerRegistration) {
return new Promise<void>((resolve) => {
const plugins = JSON.parse(localStorage.getItem(Settings.PluginSettings.plugins) as string) || [];
plugins.forEach(async (plugin: Plugin) => {
if (plugin.type === "page") {
const pluginScript = await fetch(`/packages/${plugin.name}/${plugin.src}`).then((res) => res.text());
const script = eval(pluginScript);
const inject = script() as unknown as SWPlugin;
worker.active?.postMessage([{host: inject.host, html: inject.html, injectTo: inject.injectTo}] as SWPlugin[]);
}
});
resolve();
}); });
}, },
changeTheme: async function ( changeTheme: async function (
@ -105,4 +148,4 @@ const marketPlaceSettings = {
} }
}; };
export { AppearanceSettings, marketPlaceSettings }; export { AppearanceSettings, PluginSettings, MarketPlaceExtras, marketPlaceSettings };

View file

@ -5,14 +5,6 @@ type OpenIn = "a:b" | "blob" | "direct" | "embed";
type Proxy = "automatic" | "uv" | "rh"; type Proxy = "automatic" | "uv" | "rh";
type Transport = "epoxy" | "libcurl"; type Transport = "epoxy" | "libcurl";
type PackageType = "theme" | "plugin"; type PackageType = "theme" | "plugin";
interface Package {
theme?: {
payload: string;
video?: string;
bgImage?: string;
};
plugin?: {};
}
const SearchEngines: Record<string, string> = { const SearchEngines: Record<string, string> = {
ddg: "https://duckduckgo.com/?q=%s", ddg: "https://duckduckgo.com/?q=%s",
google: "https://google.com/search?q=%s", google: "https://google.com/search?q=%s",
@ -24,6 +16,27 @@ const WispServerURLS: Record<string, string> = {
ruby: "wss://ruby.rubynetwork.co/wisp/" ruby: "wss://ruby.rubynetwork.co/wisp/"
}; };
type PluginType = "page" | "serviceWorker"
interface Plugin {
name: string;
src: string;
type: PluginType;
entryFunc: () => unknown | unknown;
}
interface SWPlugin {
host: string;
html: string;
injectTo: "head" | "body";
}
interface Package {
theme?: {
payload: string;
video?: string;
bgImage?: string;
};
plugin?: Plugin;
}
export { export {
type TabCloaks, type TabCloaks,
type AbCloaks, type AbCloaks,
@ -32,6 +45,9 @@ export {
type Transport, type Transport,
type PackageType, type PackageType,
type Package, type Package,
type PluginType,
type Plugin,
type SWPlugin,
SearchEngines, SearchEngines,
type SearchEngine, type SearchEngine,
WispServerURLS, WispServerURLS,