mirror of
https://github.com/NebulaServices/Nebula.git
synced 2025-05-16 21:10:02 -04:00
Some plugin logic (still kinda broken)
This commit is contained in:
parent
4f1a8960f1
commit
fff4d0b286
19 changed files with 464 additions and 52 deletions
|
@ -5,7 +5,7 @@ import { baremuxPath } from "@mercuryworkshop/bare-mux";
|
|||
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
|
||||
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
|
||||
import playformCompress from "@playform/compress";
|
||||
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
||||
import { uvPath } from "@rubynetwork/ultraviolet";
|
||||
import icon from "astro-icon";
|
||||
import { defineConfig, envField } from "astro/config";
|
||||
import { viteStaticCopy } from "vite-plugin-static-copy";
|
||||
|
|
11
database_assets/com.nebula.darkMode/index.js
Normal file
11
database_assets/com.nebula.darkMode/index.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const script = `
|
||||
console.error('GYATT')
|
||||
`
|
||||
|
||||
self.entryFunc = function(){
|
||||
return {
|
||||
host: 'example.com',
|
||||
html: `<script>${script}</script>`,
|
||||
injectTo: 'body'
|
||||
}
|
||||
}
|
|
@ -33,8 +33,8 @@
|
|||
"@playform/compress": "^0.1.4",
|
||||
"@rubynetwork/rammerhead": "^1.3.5",
|
||||
"@rubynetwork/rammerhead-browser": "^1.0.9",
|
||||
"@rubynetwork/ultraviolet": "3.2.7-ruby.1",
|
||||
"@svelte-drama/suspense": "0.5.1",
|
||||
"@titaniumnetwork-dev/ultraviolet": "3.1.2",
|
||||
"@types/node": "^22.7.5",
|
||||
"@types/sequelize": "^4.28.20",
|
||||
"astro": "^4.16.2",
|
||||
|
|
49
pnpm-lock.yaml
generated
49
pnpm-lock.yaml
generated
|
@ -56,12 +56,12 @@ importers:
|
|||
'@rubynetwork/rammerhead-browser':
|
||||
specifier: ^1.0.9
|
||||
version: 1.0.9
|
||||
'@rubynetwork/ultraviolet':
|
||||
specifier: 3.2.7-ruby.1
|
||||
version: 3.2.7-ruby.1
|
||||
'@svelte-drama/suspense':
|
||||
specifier: 0.5.1
|
||||
version: 0.5.1(svelte@4.2.19)
|
||||
'@titaniumnetwork-dev/ultraviolet':
|
||||
specifier: 3.1.2
|
||||
version: 3.1.2
|
||||
'@types/node':
|
||||
specifier: ^22.7.5
|
||||
version: 22.7.5
|
||||
|
@ -871,6 +871,9 @@ packages:
|
|||
'@mercuryworkshop/bare-mux@1.1.1':
|
||||
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':
|
||||
resolution: {integrity: sha512-drnffDo9Ls73Fpmcup2Ys1z+BjzK+WLnzyfS4APFfWr9cJ0gu7567tx4M06XH5PUZMOS1J1Z3wqnRaBh/RX5bQ==}
|
||||
|
||||
|
@ -1017,6 +1020,9 @@ packages:
|
|||
'@rubynetwork/rh@1.2.74':
|
||||
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':
|
||||
resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==}
|
||||
|
||||
|
@ -1052,9 +1058,6 @@ packages:
|
|||
svelte: ^4.0.0 || ^5.0.0-next.0
|
||||
vite: ^5.0.0
|
||||
|
||||
'@titaniumnetwork-dev/ultraviolet@3.1.2':
|
||||
resolution: {integrity: sha512-PvhyL9IQtSwHTVRRpNGn+YCWkSzP7JEk0wX7M5YfUSobBicoRLOJhCC4u6T9qh/vObDpLDE3TfP4GKqMTSa2rw==}
|
||||
|
||||
'@tootallnate/once@1.1.2':
|
||||
resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -1277,6 +1280,10 @@ packages:
|
|||
array-iterate@2.0.1:
|
||||
resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==}
|
||||
|
||||
astring@1.9.0:
|
||||
resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
|
||||
hasBin: true
|
||||
|
||||
astro-icon@1.1.1:
|
||||
resolution: {integrity: sha512-HKBesWk2Faw/0+klLX+epQVqdTfSzZz/9+5vxXUjTJaN/HnpDf608gRPgHh7ZtwBPNJMEFoU5GLegxoDcT56OQ==}
|
||||
|
||||
|
@ -2146,6 +2153,9 @@ packages:
|
|||
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
idb@8.0.0:
|
||||
resolution: {integrity: sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==}
|
||||
|
||||
ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
|
||||
|
@ -2534,6 +2544,10 @@ packages:
|
|||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
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:
|
||||
resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==}
|
||||
|
||||
|
@ -4834,6 +4848,11 @@ snapshots:
|
|||
'@types/uuid': 9.0.8
|
||||
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-transport@https://codeload.github.com/motortruck1221/epoxytransport/tar.gz/5e8205cdfef67e1cf73fbba7fb56cb181de070f7':
|
||||
|
@ -5001,6 +5020,16 @@ snapshots:
|
|||
- supports-color
|
||||
- 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':
|
||||
dependencies:
|
||||
'@shikijs/engine-javascript': 1.22.0
|
||||
|
@ -5055,8 +5084,6 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@titaniumnetwork-dev/ultraviolet@3.1.2': {}
|
||||
|
||||
'@tootallnate/once@1.1.2':
|
||||
optional: true
|
||||
|
||||
|
@ -5309,6 +5336,8 @@ snapshots:
|
|||
|
||||
array-iterate@2.0.1: {}
|
||||
|
||||
astring@1.9.0: {}
|
||||
|
||||
astro-icon@1.1.1:
|
||||
dependencies:
|
||||
'@iconify/tools': 4.0.7
|
||||
|
@ -6389,6 +6418,8 @@ snapshots:
|
|||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
idb@8.0.0: {}
|
||||
|
||||
ieee754@1.2.1: {}
|
||||
|
||||
import-meta-resolve@4.1.0: {}
|
||||
|
@ -6810,6 +6841,8 @@ snapshots:
|
|||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
meriyah@6.0.2: {}
|
||||
|
||||
micromark-core-commonmark@2.0.1:
|
||||
dependencies:
|
||||
decode-named-character-reference: 1.0.2
|
||||
|
|
28
public/sw.js
28
public/sw.js
|
@ -4,6 +4,34 @@ importScripts("/uv/uv.bundle.js");
|
|||
importScripts("/uv/uv.config.js");
|
||||
importScripts(__uv$config.sw || "/uv/uv.sw.js");
|
||||
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) {
|
||||
if (event.request.url.startsWith(location.origin + __uv$config.prefix)) {
|
||||
event.respondWith(
|
||||
|
|
6
public/workerware/WWError.js
Normal file
6
public/workerware/WWError.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
class WWError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = "[WorkerWare Exception]";
|
||||
}
|
||||
}
|
168
public/workerware/workerware.js
Normal file
168
public/workerware/workerware.js
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -22,7 +22,8 @@ async function installItems(db: ModelStatic<CatalogModel>, items: Items[]) {
|
|||
payload: item.payload,
|
||||
background_video: item.background_video,
|
||||
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",
|
||||
tags: ["Theme", "Simple"],
|
||||
payload: "gruvbox.css",
|
||||
type: "theme"
|
||||
type: "theme",
|
||||
entryFunc: null
|
||||
},
|
||||
{
|
||||
package_name: "com.nebula.oled",
|
||||
|
@ -50,7 +52,8 @@ async function setupDB(db: ModelStatic<CatalogModel>) {
|
|||
description: "A sleek & simple Oled theme for Nebula",
|
||||
tags: ["Theme", "Simple", "Sleek"],
|
||||
payload: "oled.css",
|
||||
type: "theme"
|
||||
type: "theme",
|
||||
entryFunc: null
|
||||
},
|
||||
{
|
||||
package_name: "com.nebula.lightTheme",
|
||||
|
@ -61,7 +64,8 @@ async function setupDB(db: ModelStatic<CatalogModel>) {
|
|||
description: "A sleek light theme for Nebula",
|
||||
tags: ["Theme", "Simple", "Light"],
|
||||
payload: "light.css",
|
||||
type: "theme"
|
||||
type: "theme",
|
||||
entryFunc: null
|
||||
},
|
||||
{
|
||||
package_name: "com.nebula.retro",
|
||||
|
@ -72,7 +76,20 @@ async function setupDB(db: ModelStatic<CatalogModel>) {
|
|||
description: "Give a retro look to Nebula",
|
||||
tags: ["Theme", "Simple", "Dark", "Retro"],
|
||||
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();
|
||||
|
|
|
@ -28,6 +28,7 @@ interface Catalog {
|
|||
background_video: string;
|
||||
payload: string;
|
||||
type: CatalogType;
|
||||
entryFunc: string;
|
||||
}
|
||||
|
||||
interface CatalogModel
|
||||
|
@ -45,7 +46,8 @@ const catalogAssets = db.define<CatalogModel>("catalog_assets", {
|
|||
background_image: { type: DataTypes.TEXT, allowNull: true },
|
||||
background_video: { type: DataTypes.TEXT, allowNull: true },
|
||||
payload: { type: DataTypes.TEXT },
|
||||
type: { type: DataTypes.TEXT }
|
||||
type: { type: DataTypes.TEXT },
|
||||
entryFunc: { type: DataTypes.STRING }
|
||||
});
|
||||
|
||||
function marketplaceAPI(app: FastifyInstance) {
|
||||
|
@ -78,7 +80,8 @@ function marketplaceAPI(app: FastifyInstance) {
|
|||
background_image: asset.background_image,
|
||||
background_video: asset.background_video,
|
||||
payload: asset.payload,
|
||||
type: asset.type
|
||||
type: asset.type,
|
||||
entryFunc: asset.entryFunc
|
||||
};
|
||||
return acc;
|
||||
}, {});
|
||||
|
@ -105,7 +108,8 @@ function marketplaceAPI(app: FastifyInstance) {
|
|||
background_image: packageRow.get("background_image"),
|
||||
background_video: packageRow.get("background_video"),
|
||||
payload: packageRow.get("payload"),
|
||||
type: packageRow.get("type")
|
||||
type: packageRow.get("type"),
|
||||
entryFunc: packageRow.get("entryFunc")
|
||||
};
|
||||
reply.send(details);
|
||||
} catch (error) {
|
||||
|
@ -128,6 +132,7 @@ function marketplaceAPI(app: FastifyInstance) {
|
|||
background_video: string;
|
||||
background_image: string;
|
||||
type: CatalogType;
|
||||
entryFunc: string;
|
||||
};
|
||||
}>;
|
||||
interface VerifyStatus {
|
||||
|
@ -193,7 +198,8 @@ function marketplaceAPI(app: FastifyInstance) {
|
|||
payload: request.body.payload,
|
||||
background_video: request.body.background_video,
|
||||
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({
|
||||
package_name: body.package_name,
|
||||
|
@ -206,7 +212,8 @@ function marketplaceAPI(app: FastifyInstance) {
|
|||
payload: body.payload,
|
||||
background_video: body.background_video,
|
||||
background_image: body.background_image,
|
||||
type: body.type
|
||||
type: body.type,
|
||||
entryFunc: body.entryFunc
|
||||
});
|
||||
const assets = fileURLToPath(new URL("../database_assets", import.meta.url));
|
||||
try {
|
||||
|
|
56
src/components/catalog/InstalledPlugins.svelte
Normal file
56
src/components/catalog/InstalledPlugins.svelte
Normal 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
2
src/env.d.ts
vendored
|
@ -1,5 +1,5 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
/// <reference types="@titaniumnetwork-dev/ultraviolet/client" />
|
||||
/// <reference types="@rubynetwork/ultraviolet/client" />
|
||||
declare var BareMux: any;
|
||||
declare var EpxMod: any;
|
||||
|
|
|
@ -53,17 +53,24 @@ const assetsJson = await response.json();
|
|||
}
|
||||
customElements.define('variable-define', VariableDefiner);
|
||||
const fn = () => {
|
||||
const items = JSON.parse(localStorage.getItem(Settings.AppearanceSettings.themes) as string) || [];
|
||||
const itemExists = items.indexOf(packageName) !== -1;
|
||||
const cssItems = JSON.parse(localStorage.getItem(Settings.AppearanceSettings.themes) as string) || [];
|
||||
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 uninstallButton = document.getElementById("uninstall") as HTMLButtonElement;
|
||||
const payload = assetsJson ? JSON.parse(assetsJson) : undefined;
|
||||
if (itemExists) {
|
||||
if (cssItemExists || pluginItemExists) {
|
||||
uninstallButton.classList.remove("hidden");
|
||||
installButton.classList.add("hidden");
|
||||
}
|
||||
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");
|
||||
uninstallButton.classList.remove("hidden");
|
||||
})
|
||||
|
|
|
@ -54,7 +54,8 @@ import { VERSION } from "astro:env/client";
|
|||
WispServerURLS,
|
||||
SearchEngines,
|
||||
Settings,
|
||||
cloak,
|
||||
cloak,
|
||||
settings
|
||||
} from "@utils/settings/index";
|
||||
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.
|
||||
|
@ -81,14 +82,16 @@ import { VERSION } from "astro:env/client";
|
|||
}
|
||||
}
|
||||
function uv(iframe: HTMLIFrameElement, term: string) {
|
||||
initSw().then(() => {
|
||||
setTransport(localStorage.getItem(Settings.ProxySettings.transport) as string).then(async () => {
|
||||
iframe.classList.remove("hidden");
|
||||
const url = await proxy(term, false);
|
||||
if (url) {
|
||||
iframe.src = url as string;
|
||||
}
|
||||
});
|
||||
initSw().then((reg) => {
|
||||
settings.marketPlaceSettings.handlePlugins(reg).then(() => {
|
||||
setTransport(localStorage.getItem(Settings.ProxySettings.transport) as string).then(async () => {
|
||||
iframe.classList.remove("hidden");
|
||||
const url = await proxy(term, false);
|
||||
if (url) {
|
||||
iframe.src = url as string;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
async function rh(iframe: HTMLIFrameElement, term: string) {
|
||||
|
|
|
@ -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">
|
||||
<InstalledThemes client:only="svelte" />
|
||||
{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]">
|
||||
<Icon name="ph:plus-bold" class="h-16 w-16" />
|
||||
</div>
|
||||
|
|
|
@ -6,6 +6,8 @@ import Layout from "@layouts/Layout.astro";
|
|||
import SettingsLayout from "@layouts/SettingsLayout.astro";
|
||||
import SettingsSection from "@layouts/SettingsSection.astro";
|
||||
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 t = useTranslations(lang);
|
||||
|
@ -95,7 +97,20 @@ export const prerender = true;
|
|||
}}
|
||||
/>
|
||||
</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>
|
||||
<ToastWrapper client:load>
|
||||
<Toast toastProp={{
|
||||
|
|
|
@ -56,12 +56,12 @@ function setTransport(transport?: string) {
|
|||
|
||||
function initSw() {
|
||||
//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) {
|
||||
navigator.serviceWorker.ready.then(async () => {
|
||||
navigator.serviceWorker.ready.then(async (reg) => {
|
||||
console.debug("Service worker ready!");
|
||||
await loadProxyScripts();
|
||||
resolve();
|
||||
resolve(reg);
|
||||
});
|
||||
navigator.serviceWorker.register("/sw.js", { scope: "/" });
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//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 { TabSettings, cloak, tabSettings } from "./tab";
|
||||
import {
|
||||
|
@ -19,7 +19,9 @@ import {
|
|||
const Settings = {
|
||||
AppearanceSettings,
|
||||
TabSettings,
|
||||
ProxySettings
|
||||
ProxySettings,
|
||||
MarketPlaceExtras,
|
||||
PluginSettings
|
||||
};
|
||||
|
||||
const settings = {
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
//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 = {
|
||||
themes: "nebula||themes",
|
||||
themeName: "nebula||themeName",
|
||||
stylePayload: "nebula||stylepayload",
|
||||
video: "nebula||video",
|
||||
image: "nebula||image",
|
||||
};
|
||||
|
||||
const PluginSettings = {
|
||||
plugins: "nebula||plugins"
|
||||
}
|
||||
|
||||
const MarketPlaceExtras = {
|
||||
proxy: "nebula||marketplaceProxy",
|
||||
hostname: "nebula||marketplaceHostname"
|
||||
};
|
||||
}
|
||||
|
||||
const marketPlaceSettings = {
|
||||
install: function (p: Package, packageName: string, payload?: any) {
|
||||
|
@ -23,6 +31,16 @@ const marketPlaceSettings = {
|
|||
}
|
||||
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) {
|
||||
|
@ -38,6 +56,31 @@ const marketPlaceSettings = {
|
|||
}
|
||||
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 (
|
||||
|
@ -105,4 +148,4 @@ const marketPlaceSettings = {
|
|||
}
|
||||
};
|
||||
|
||||
export { AppearanceSettings, marketPlaceSettings };
|
||||
export { AppearanceSettings, PluginSettings, MarketPlaceExtras, marketPlaceSettings };
|
||||
|
|
|
@ -5,14 +5,6 @@ type OpenIn = "a:b" | "blob" | "direct" | "embed";
|
|||
type Proxy = "automatic" | "uv" | "rh";
|
||||
type Transport = "epoxy" | "libcurl";
|
||||
type PackageType = "theme" | "plugin";
|
||||
interface Package {
|
||||
theme?: {
|
||||
payload: string;
|
||||
video?: string;
|
||||
bgImage?: string;
|
||||
};
|
||||
plugin?: {};
|
||||
}
|
||||
const SearchEngines: Record<string, string> = {
|
||||
ddg: "https://duckduckgo.com/?q=%s",
|
||||
google: "https://google.com/search?q=%s",
|
||||
|
@ -24,6 +16,27 @@ const WispServerURLS: Record<string, string> = {
|
|||
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 {
|
||||
type TabCloaks,
|
||||
type AbCloaks,
|
||||
|
@ -32,6 +45,9 @@ export {
|
|||
type Transport,
|
||||
type PackageType,
|
||||
type Package,
|
||||
type PluginType,
|
||||
type Plugin,
|
||||
type SWPlugin,
|
||||
SearchEngines,
|
||||
type SearchEngine,
|
||||
WispServerURLS,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue