parent
06d02c42f1
commit
4cb20539fd
18 changed files with 0 additions and 9778 deletions
12
.astro/astro/env.d.ts
vendored
12
.astro/astro/env.d.ts
vendored
|
|
@ -1,12 +0,0 @@
|
||||||
declare module 'astro:env/client' {
|
|
||||||
export const VERSION: string;
|
|
||||||
export const MARKETPLACE_ENABLED: boolean;
|
|
||||||
export const SEO: string;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'astro:env/server' {
|
|
||||||
|
|
||||||
|
|
||||||
export const getSecret: (key: string) => string | undefined;
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export default new Map();
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export default new Map();
|
|
||||||
155
.astro/content.d.ts
vendored
155
.astro/content.d.ts
vendored
|
|
@ -1,155 +0,0 @@
|
||||||
declare module 'astro:content' {
|
|
||||||
export interface RenderResult {
|
|
||||||
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
|
|
||||||
headings: import('astro').MarkdownHeading[];
|
|
||||||
remarkPluginFrontmatter: Record<string, any>;
|
|
||||||
}
|
|
||||||
interface Render {
|
|
||||||
'.md': Promise<RenderResult>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RenderedContent {
|
|
||||||
html: string;
|
|
||||||
metadata?: {
|
|
||||||
imagePaths: Array<string>;
|
|
||||||
[key: string]: unknown;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'astro:content' {
|
|
||||||
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
|
||||||
|
|
||||||
export type CollectionKey = keyof AnyEntryMap;
|
|
||||||
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
|
|
||||||
|
|
||||||
export type ContentCollectionKey = keyof ContentEntryMap;
|
|
||||||
export type DataCollectionKey = keyof DataEntryMap;
|
|
||||||
|
|
||||||
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
|
|
||||||
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
|
|
||||||
ContentEntryMap[C]
|
|
||||||
>['slug'];
|
|
||||||
|
|
||||||
/** @deprecated Use `getEntry` instead. */
|
|
||||||
export function getEntryBySlug<
|
|
||||||
C extends keyof ContentEntryMap,
|
|
||||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
|
||||||
>(
|
|
||||||
collection: C,
|
|
||||||
// Note that this has to accept a regular string too, for SSR
|
|
||||||
entrySlug: E,
|
|
||||||
): E extends ValidContentEntrySlug<C>
|
|
||||||
? Promise<CollectionEntry<C>>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
|
|
||||||
/** @deprecated Use `getEntry` instead. */
|
|
||||||
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
|
|
||||||
collection: C,
|
|
||||||
entryId: E,
|
|
||||||
): Promise<CollectionEntry<C>>;
|
|
||||||
|
|
||||||
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
|
|
||||||
collection: C,
|
|
||||||
filter?: (entry: CollectionEntry<C>) => entry is E,
|
|
||||||
): Promise<E[]>;
|
|
||||||
export function getCollection<C extends keyof AnyEntryMap>(
|
|
||||||
collection: C,
|
|
||||||
filter?: (entry: CollectionEntry<C>) => unknown,
|
|
||||||
): Promise<CollectionEntry<C>[]>;
|
|
||||||
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof ContentEntryMap,
|
|
||||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
|
||||||
>(entry: {
|
|
||||||
collection: C;
|
|
||||||
slug: E;
|
|
||||||
}): E extends ValidContentEntrySlug<C>
|
|
||||||
? Promise<CollectionEntry<C>>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof DataEntryMap,
|
|
||||||
E extends keyof DataEntryMap[C] | (string & {}),
|
|
||||||
>(entry: {
|
|
||||||
collection: C;
|
|
||||||
id: E;
|
|
||||||
}): E extends keyof DataEntryMap[C]
|
|
||||||
? Promise<DataEntryMap[C][E]>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof ContentEntryMap,
|
|
||||||
E extends ValidContentEntrySlug<C> | (string & {}),
|
|
||||||
>(
|
|
||||||
collection: C,
|
|
||||||
slug: E,
|
|
||||||
): E extends ValidContentEntrySlug<C>
|
|
||||||
? Promise<CollectionEntry<C>>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
export function getEntry<
|
|
||||||
C extends keyof DataEntryMap,
|
|
||||||
E extends keyof DataEntryMap[C] | (string & {}),
|
|
||||||
>(
|
|
||||||
collection: C,
|
|
||||||
id: E,
|
|
||||||
): E extends keyof DataEntryMap[C]
|
|
||||||
? string extends keyof DataEntryMap[C]
|
|
||||||
? Promise<DataEntryMap[C][E]> | undefined
|
|
||||||
: Promise<DataEntryMap[C][E]>
|
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
|
||||||
|
|
||||||
/** Resolve an array of entry references from the same collection */
|
|
||||||
export function getEntries<C extends keyof ContentEntryMap>(
|
|
||||||
entries: {
|
|
||||||
collection: C;
|
|
||||||
slug: ValidContentEntrySlug<C>;
|
|
||||||
}[],
|
|
||||||
): Promise<CollectionEntry<C>[]>;
|
|
||||||
export function getEntries<C extends keyof DataEntryMap>(
|
|
||||||
entries: {
|
|
||||||
collection: C;
|
|
||||||
id: keyof DataEntryMap[C];
|
|
||||||
}[],
|
|
||||||
): Promise<CollectionEntry<C>[]>;
|
|
||||||
|
|
||||||
export function render<C extends keyof AnyEntryMap>(
|
|
||||||
entry: AnyEntryMap[C][string],
|
|
||||||
): Promise<RenderResult>;
|
|
||||||
|
|
||||||
export function reference<C extends keyof AnyEntryMap>(
|
|
||||||
collection: C,
|
|
||||||
): import('astro/zod').ZodEffects<
|
|
||||||
import('astro/zod').ZodString,
|
|
||||||
C extends keyof ContentEntryMap
|
|
||||||
? {
|
|
||||||
collection: C;
|
|
||||||
slug: ValidContentEntrySlug<C>;
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
collection: C;
|
|
||||||
id: keyof DataEntryMap[C];
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
// Allow generic `string` to avoid excessive type errors in the config
|
|
||||||
// if `dev` is not running to update as you edit.
|
|
||||||
// Invalid collection names will be caught at build time.
|
|
||||||
export function reference<C extends string>(
|
|
||||||
collection: C,
|
|
||||||
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
|
|
||||||
|
|
||||||
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
|
|
||||||
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
|
|
||||||
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
|
|
||||||
>;
|
|
||||||
|
|
||||||
type ContentEntryMap = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
type DataEntryMap = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
type AnyEntryMap = ContentEntryMap & DataEntryMap;
|
|
||||||
|
|
||||||
export type ContentConfig = typeof import("../src/content.config.mjs");
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.1.2","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"http://localhost:4321\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":\"0.0.0.0\",\"port\":4321,\"streaming\":true},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[]},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":\"shiki\",\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{\"VERSION\":{\"context\":\"client\",\"access\":\"public\",\"type\":\"string\",\"optional\":true,\"default\":\"9.0.4\"},\"MARKETPLACE_ENABLED\":{\"context\":\"client\",\"access\":\"public\",\"type\":\"boolean\",\"optional\":true,\"default\":true},\"SEO\":{\"context\":\"client\",\"access\":\"public\",\"type\":\"string\",\"optional\":true,\"default\":\"{\\\"enabled\\\":true,\\\"domain\\\":\\\"localhost:4321\\\"}\"}},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"responsiveImages\":false},\"legacy\":{\"collections\":false}}"]
|
|
||||||
5
.astro/env.d.ts
vendored
5
.astro/env.d.ts
vendored
|
|
@ -1,5 +0,0 @@
|
||||||
declare module 'astro:env/client' {
|
|
||||||
export const VERSION: string;
|
|
||||||
export const MARKETPLACE_ENABLED: boolean;
|
|
||||||
export const SEO: string;
|
|
||||||
}
|
|
||||||
9167
.astro/icon.d.ts
vendored
9167
.astro/icon.d.ts
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"_variables": {
|
|
||||||
"lastUpdateCheck": 1736496310589
|
|
||||||
}
|
|
||||||
}
|
|
||||||
3
.astro/types.d.ts
vendored
3
.astro/types.d.ts
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
/// <reference types="astro/client" />
|
|
||||||
/// <reference path="content.d.ts" />
|
|
||||||
/// <reference path="env.d.ts" />
|
|
||||||
23
config.toml
23
config.toml
|
|
@ -1,23 +0,0 @@
|
||||||
[marketplace]
|
|
||||||
enabled = true # Turn on or off the marketplace entirely
|
|
||||||
psk = "CHANGEME" # Change this to something more secure.
|
|
||||||
level = 1
|
|
||||||
|
|
||||||
[db]
|
|
||||||
name = "database" # Your databsae name
|
|
||||||
username = "username" # The username of your DB (SQLITE just ignores this)
|
|
||||||
password = "password" # The password to your DB (SQLITE ignores this)
|
|
||||||
postgres = false # Enable to use postgres over sqlite (recommended for large prod instances)
|
|
||||||
|
|
||||||
[postgres] # Set the "domain" to either and ip address or a actual domain
|
|
||||||
domain = ""
|
|
||||||
port = 5432
|
|
||||||
|
|
||||||
[seo]
|
|
||||||
enabled = true # Disabled by default as you probably don't want it
|
|
||||||
domain = "http://localhost:4321" # Set to YOUR domain. Make sure to include http or https://
|
|
||||||
|
|
||||||
[server.server]
|
|
||||||
port = 8080
|
|
||||||
wisp = true
|
|
||||||
logging = false # Disable for the tons & tons of logs to go away (useful for debugging but otherwise eh)
|
|
||||||
BIN
database.sqlite
BIN
database.sqlite
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 9.6 KiB |
|
|
@ -1,55 +0,0 @@
|
||||||
import { readFileSync } from "node:fs";
|
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
import chalk from "chalk";
|
|
||||||
import { parse } from "smol-toml";
|
|
||||||
let doc = readFileSync(fileURLToPath(new URL("../config.toml", import.meta.url))).toString();
|
|
||||||
const parsedDoc = parse(doc);
|
|
||||||
function verify(t) {
|
|
||||||
for (let i = 0; i !== t.length; i++) {
|
|
||||||
if (typeof t[i].typeOF !== t[i].type) {
|
|
||||||
throw new Error(`Invalid structure: "${t[i].name}" should be a(n) ${t[i].type}`);
|
|
||||||
}
|
|
||||||
if (t[i].verifyExtras) {
|
|
||||||
const extra = t[i].verifyExtras();
|
|
||||||
if (extra !== true) {
|
|
||||||
throw extra;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verify([
|
|
||||||
{ name: "marketplace", typeOF: parsedDoc.marketplace, type: "object" },
|
|
||||||
{ name: "marketplace.enabled", typeOF: parsedDoc.marketplace.enabled, type: "boolean" },
|
|
||||||
{ name: "marketplace.psk", typeOF: parsedDoc.marketplace.psk, type: "string" },
|
|
||||||
{ name: "server", typeOF: parsedDoc.server, type: "object" },
|
|
||||||
{ name: "server.server", typeOF: parsedDoc.server.server, type: "object" },
|
|
||||||
{ name: "server.server.port", typeOF: parsedDoc.server.server.port, type: "number" },
|
|
||||||
{ name: "server.server.wisp", typeOF: parsedDoc.server.server.wisp, type: "boolean" },
|
|
||||||
{ name: "server.server.logging", typeOF: parsedDoc.server.server.logging, type: "boolean" },
|
|
||||||
{ name: "seo", typeOF: parsedDoc.seo, type: "object" },
|
|
||||||
{ name: "seo.enabled", typeOF: parsedDoc.seo.enabled, type: "boolean" },
|
|
||||||
{ name: "seo.domain", typeOF: parsedDoc.seo.domain, type: "string", verifyExtras: () => {
|
|
||||||
try {
|
|
||||||
new URL(parsedDoc.seo.domain);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
return Error(e);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} },
|
|
||||||
{ name: "db", typeOF: parsedDoc.db, type: "object" },
|
|
||||||
{ name: "db.name", typeOF: parsedDoc.db.name, type: "string" },
|
|
||||||
{ name: "db.username", typeOF: parsedDoc.db.username, type: "string" },
|
|
||||||
{ name: "db.password", typeOF: parsedDoc.db.password, type: "string" },
|
|
||||||
{ name: "db.postgres", typeOF: parsedDoc.db.postgres, type: "boolean" },
|
|
||||||
{ name: "postgres", typeOF: parsedDoc.postgres, type: "object" },
|
|
||||||
{ name: "postgres.domain", typeOF: parsedDoc.postgres.domain, type: "string" },
|
|
||||||
{ name: "postgres.port", typeOF: parsedDoc.postgres.port, type: "number" }
|
|
||||||
]);
|
|
||||||
if (parsedDoc.marketplace.psk === "CHANGEME") {
|
|
||||||
console.warn(chalk.yellow.bold('PSK should be changed from "CHANGEME"'));
|
|
||||||
}
|
|
||||||
if (parsedDoc.db.password === "password") {
|
|
||||||
console.warn(chalk.red.bold("You should change your DB password!!"));
|
|
||||||
}
|
|
||||||
export { parsedDoc };
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
import chalk from "chalk";
|
|
||||||
import ora from "ora";
|
|
||||||
async function installItems(db, items) {
|
|
||||||
items.forEach(async (item) => {
|
|
||||||
await db.create({
|
|
||||||
package_name: item.package_name,
|
|
||||||
title: item.title,
|
|
||||||
image: item.image,
|
|
||||||
author: item.author,
|
|
||||||
version: item.version,
|
|
||||||
description: item.description,
|
|
||||||
tags: item.tags,
|
|
||||||
payload: item.payload,
|
|
||||||
background_video: item.background_video,
|
|
||||||
background_image: item.background_image,
|
|
||||||
type: item.type
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async function setupDB(db) {
|
|
||||||
//We have some packages that need to be installed if they aren't.
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
package_name: "com.nebula.gruvbox",
|
|
||||||
title: "Gruvbox",
|
|
||||||
image: "gruvbox.jpg",
|
|
||||||
author: "Nebula Services",
|
|
||||||
version: "1.0.0",
|
|
||||||
description: "The gruvbox theme",
|
|
||||||
tags: ["Theme", "Simple"],
|
|
||||||
payload: "gruvbox.css",
|
|
||||||
type: "theme"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
package_name: "com.nebula.oled",
|
|
||||||
title: "Oled theme",
|
|
||||||
image: "oled.jpg",
|
|
||||||
author: "Nebula Services",
|
|
||||||
version: "1.0.0",
|
|
||||||
description: "A sleek & simple Oled theme for Nebula",
|
|
||||||
tags: ["Theme", "Simple", "Sleek"],
|
|
||||||
payload: "oled.css",
|
|
||||||
type: "theme"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
package_name: "com.nebula.lightTheme",
|
|
||||||
title: "Light Theme",
|
|
||||||
image: "light.png",
|
|
||||||
author: "Nebula Services",
|
|
||||||
version: "1.0.0",
|
|
||||||
description: "A sleek light theme for Nebula",
|
|
||||||
tags: ["Theme", "Simple", "Light"],
|
|
||||||
payload: "light.css",
|
|
||||||
type: "theme"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
package_name: "com.nebula.retro",
|
|
||||||
title: "Retro Theme",
|
|
||||||
image: "retro.png",
|
|
||||||
author: "Nebula Services",
|
|
||||||
version: "1.0.0",
|
|
||||||
description: "Give a retro look to Nebula",
|
|
||||||
tags: ["Theme", "Simple", "Dark", "Retro"],
|
|
||||||
payload: "retro.css",
|
|
||||||
type: "theme"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
package_name: 'gyatt',
|
|
||||||
title: 'gyatt',
|
|
||||||
image: 'gyatt',
|
|
||||||
author: "nebuka",
|
|
||||||
version: "2",
|
|
||||||
description: "e",
|
|
||||||
tags: ["e"],
|
|
||||||
payload: "gyatt.js",
|
|
||||||
type: "plugin-page"
|
|
||||||
}
|
|
||||||
//To add plugins: plugin types consist of plugin-sw (workerware) & plugin-page (uv.config.inject)
|
|
||||||
];
|
|
||||||
const dbItems = await db.findAll();
|
|
||||||
if (dbItems.length === 0) {
|
|
||||||
const spinner = ora(chalk.hex("#7967dd")("Performing DB setup...")).start();
|
|
||||||
await installItems(db, items);
|
|
||||||
spinner.succeed(chalk.hex("#eb6f92")("DB setup complete!"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export { setupDB };
|
|
||||||
|
|
@ -1,169 +0,0 @@
|
||||||
import { createWriteStream } from "node:fs";
|
|
||||||
import { constants, access, mkdir } from "node:fs/promises";
|
|
||||||
import { pipeline } from "node:stream/promises";
|
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
import { DataTypes, Sequelize } from "sequelize";
|
|
||||||
import { parsedDoc } from "./config.js";
|
|
||||||
const db = new Sequelize(parsedDoc.db.name, parsedDoc.db.username, parsedDoc.db.password, {
|
|
||||||
host: parsedDoc.db.postgres ? `${parsedDoc.postgres.domain}` : "localhost",
|
|
||||||
port: parsedDoc.db.postgres ? parsedDoc.postgres.port : undefined,
|
|
||||||
dialect: parsedDoc.db.postgres ? "postgres" : "sqlite",
|
|
||||||
logging: parsedDoc.server.server.logging,
|
|
||||||
storage: "database.sqlite" //this is sqlite only
|
|
||||||
});
|
|
||||||
const catalogAssets = db.define("catalog_assets", {
|
|
||||||
package_name: { type: DataTypes.STRING, unique: true },
|
|
||||||
title: { type: DataTypes.TEXT },
|
|
||||||
description: { type: DataTypes.TEXT },
|
|
||||||
author: { type: DataTypes.TEXT },
|
|
||||||
image: { type: DataTypes.TEXT },
|
|
||||||
tags: { type: DataTypes.JSON, allowNull: true },
|
|
||||||
version: { type: DataTypes.TEXT },
|
|
||||||
background_image: { type: DataTypes.TEXT, allowNull: true },
|
|
||||||
background_video: { type: DataTypes.TEXT, allowNull: true },
|
|
||||||
payload: { type: DataTypes.TEXT },
|
|
||||||
type: { type: DataTypes.TEXT }
|
|
||||||
});
|
|
||||||
function marketplaceAPI(app) {
|
|
||||||
app.get("/api/catalog-stats/", (request, reply) => {
|
|
||||||
reply.send({
|
|
||||||
version: "1.0.0",
|
|
||||||
spec: "Nebula Services",
|
|
||||||
enabled: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
app.get("/api/catalog-assets/", async (request, reply) => {
|
|
||||||
try {
|
|
||||||
const { page } = request.query;
|
|
||||||
const pageNum = parseInt(page, 10) || 1;
|
|
||||||
if (pageNum < 1) {
|
|
||||||
reply.status(400).send({ error: "Page must be a positive number!" });
|
|
||||||
}
|
|
||||||
const offset = (pageNum - 1) * 20;
|
|
||||||
const totalItems = await catalogAssets.count();
|
|
||||||
const dbAssets = await catalogAssets.findAll({ offset: offset, limit: 20 });
|
|
||||||
const assets = dbAssets.reduce((acc, asset) => {
|
|
||||||
acc[asset.package_name] = {
|
|
||||||
title: asset.title,
|
|
||||||
description: asset.description,
|
|
||||||
author: asset.author,
|
|
||||||
image: asset.image,
|
|
||||||
tags: asset.tags,
|
|
||||||
version: asset.version,
|
|
||||||
background_image: asset.background_image,
|
|
||||||
background_video: asset.background_video,
|
|
||||||
payload: asset.payload,
|
|
||||||
type: asset.type
|
|
||||||
};
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
return reply.send({ assets, pages: Math.ceil(totalItems / 20) });
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
return reply.status(500).send({ error: "An error occured" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app.get("/api/packages/:package", async (request, reply) => {
|
|
||||||
try {
|
|
||||||
const packageRow = await catalogAssets.findOne({
|
|
||||||
where: { package_name: request.params.package }
|
|
||||||
});
|
|
||||||
if (!packageRow)
|
|
||||||
return reply.status(404).send({ error: "Package not found!" });
|
|
||||||
const details = {
|
|
||||||
title: packageRow.get("title"),
|
|
||||||
description: packageRow.get("description"),
|
|
||||||
image: packageRow.get("image"),
|
|
||||||
author: packageRow.get("author"),
|
|
||||||
tags: packageRow.get("tags"),
|
|
||||||
version: packageRow.get("version"),
|
|
||||||
background_image: packageRow.get("background_image"),
|
|
||||||
background_video: packageRow.get("background_video"),
|
|
||||||
payload: packageRow.get("payload"),
|
|
||||||
type: packageRow.get("type")
|
|
||||||
};
|
|
||||||
reply.send(details);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
reply.status(500).send({ error: "An unexpected error occured" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
async function verifyReq(request, upload, data) {
|
|
||||||
if (request.headers.psk !== parsedDoc.marketplace.psk) {
|
|
||||||
return { status: 403, error: new Error("PSK isn't correct!") };
|
|
||||||
}
|
|
||||||
else if (upload && !request.headers.packagename) {
|
|
||||||
return { status: 500, error: new Error("No packagename defined!") };
|
|
||||||
}
|
|
||||||
else if (upload && !data) {
|
|
||||||
return { status: 400, error: new Error("No file uploaded!") };
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return { status: 200 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.post("/api/upload-asset", async (request, reply) => {
|
|
||||||
const data = await request.file();
|
|
||||||
const verify = await verifyReq(request, true, data);
|
|
||||||
if (verify.error !== undefined) {
|
|
||||||
reply.status(verify.status).send({ status: verify.error.message });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
await pipeline(data.file, createWriteStream(fileURLToPath(new URL(`../database_assets/${request.headers.packagename}/${data.filename}`, import.meta.url))));
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
return reply.status(500).send({
|
|
||||||
status: `File couldn't be uploaded! (Package most likely doesn't exist)`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return reply.status(verify.status).send({ status: "File uploaded successfully!" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app.post("/api/create-package", async (request, reply) => {
|
|
||||||
const verify = await verifyReq(request, false, undefined);
|
|
||||||
if (verify.error !== undefined) {
|
|
||||||
reply.status(verify.status).send({ status: verify.error.message });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const body = {
|
|
||||||
package_name: request.body.uuid,
|
|
||||||
title: request.body.title,
|
|
||||||
image: request.body.image,
|
|
||||||
author: request.body.author,
|
|
||||||
version: request.body.version,
|
|
||||||
description: request.body.description,
|
|
||||||
tags: request.body.tags,
|
|
||||||
payload: request.body.payload,
|
|
||||||
background_video: request.body.background_video,
|
|
||||||
background_image: request.body.background_image,
|
|
||||||
type: request.body.type
|
|
||||||
};
|
|
||||||
await catalogAssets.create({
|
|
||||||
package_name: body.package_name,
|
|
||||||
title: body.title,
|
|
||||||
image: body.image,
|
|
||||||
author: body.author,
|
|
||||||
version: body.version,
|
|
||||||
description: body.description,
|
|
||||||
tags: body.tags,
|
|
||||||
payload: body.payload,
|
|
||||||
background_video: body.background_video,
|
|
||||||
background_image: body.background_image,
|
|
||||||
type: body.type
|
|
||||||
});
|
|
||||||
const assets = fileURLToPath(new URL("../database_assets", import.meta.url));
|
|
||||||
try {
|
|
||||||
await access(`${assets}/${body.package_name}/`, constants.F_OK);
|
|
||||||
return reply.status(500).send({ status: "Package already exists!" });
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
await mkdir(`${assets}/${body.package_name}/`);
|
|
||||||
return reply
|
|
||||||
.status(verify.status)
|
|
||||||
.send({ status: "Package created successfully!" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
export { marketplaceAPI, db, catalogAssets };
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
import fastifyCompress from "@fastify/compress";
|
|
||||||
import fastifyHelmet from "@fastify/helmet";
|
|
||||||
import fastifyMiddie from "@fastify/middie";
|
|
||||||
import fastifyMultipart from "@fastify/multipart";
|
|
||||||
import fastifyStatic from "@fastify/static";
|
|
||||||
import chalk from "chalk";
|
|
||||||
import Fastify from "fastify";
|
|
||||||
import gradient from "gradient-string";
|
|
||||||
//@ts-ignore WHY would I want this typechecked AT ALL
|
|
||||||
import { handler as ssrHandler } from "../dist/server/entry.mjs";
|
|
||||||
import { parsedDoc } from "./config.js";
|
|
||||||
import { setupDB } from "./dbSetup.js";
|
|
||||||
import { catalogAssets, marketplaceAPI } from "./marketplace.js";
|
|
||||||
import { serverFactory } from "./serverFactory.js";
|
|
||||||
const app = Fastify({
|
|
||||||
logger: parsedDoc.server.server.logging,
|
|
||||||
ignoreDuplicateSlashes: true,
|
|
||||||
ignoreTrailingSlash: true,
|
|
||||||
serverFactory: serverFactory
|
|
||||||
});
|
|
||||||
await app.register(fastifyCompress, {
|
|
||||||
encodings: ["br", "gzip", "deflate"]
|
|
||||||
});
|
|
||||||
await app.register(fastifyMultipart, {
|
|
||||||
limits: {
|
|
||||||
fileSize: 25 * 1024 * 1024,
|
|
||||||
parts: Infinity
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await app.register(fastifyHelmet, {
|
|
||||||
xPoweredBy: false,
|
|
||||||
crossOriginEmbedderPolicy: true,
|
|
||||||
crossOriginOpenerPolicy: true,
|
|
||||||
contentSecurityPolicy: false //Disabled because astro DOES NOT LIKE IT
|
|
||||||
});
|
|
||||||
await app.register(fastifyStatic, {
|
|
||||||
root: fileURLToPath(new URL("../dist/client", import.meta.url))
|
|
||||||
});
|
|
||||||
//Our marketplace API. Not middleware as I don't want to deal with that LOL. Just a function that passes our app to it.
|
|
||||||
if (parsedDoc.marketplace.enabled) {
|
|
||||||
await app.register(fastifyStatic, {
|
|
||||||
root: fileURLToPath(new URL("../database_assets", import.meta.url)),
|
|
||||||
prefix: "/packages/",
|
|
||||||
decorateReply: false
|
|
||||||
});
|
|
||||||
marketplaceAPI(app);
|
|
||||||
}
|
|
||||||
await app.register(fastifyMiddie);
|
|
||||||
app.use(ssrHandler);
|
|
||||||
const port = parseInt(process.env.PORT) || parsedDoc.server.server.port || parseInt("8080");
|
|
||||||
const titleText = `
|
|
||||||
_ _ _ _ ____ _
|
|
||||||
| \\ | | ___| |__ _ _| | __ _ / ___| ___ _ ____ _(_) ___ ___ ___
|
|
||||||
| \\| |/ _ \\ '_ \\| | | | |/ _' | \\___ \\ / _ \\ '__\\ \\ / / |/ __/ _ \\/ __|
|
|
||||||
| |\\ | __/ |_) | |_| | | (_| | ___) | __/ | \\ V /| | (_| __/\\__ \\
|
|
||||||
|_| \\_|\\___|_.__/ \\__,_|_|\\__,_| |____/ \\___|_| \\_/ |_|\\___\\___||___/
|
|
||||||
`;
|
|
||||||
const titleColors = {
|
|
||||||
purple: "#7967dd",
|
|
||||||
pink: "#eb6f92"
|
|
||||||
};
|
|
||||||
console.log(gradient(Object.values(titleColors)).multiline(titleText));
|
|
||||||
app.listen({ port: port, host: "0.0.0.0" }).then(async () => {
|
|
||||||
console.log(chalk.hex("#7967dd")(`Server listening on ${chalk.hex("#eb6f92").bold("http://localhost:" + port + "/")}`));
|
|
||||||
console.log(chalk.hex("#7967dd")(`Server also listening on ${chalk.hex("#eb6f92").bold("http://0.0.0.0:" + port + "/")}`));
|
|
||||||
if (parsedDoc.marketplace.enabled) {
|
|
||||||
await catalogAssets.sync();
|
|
||||||
await setupDB(catalogAssets);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { createServer } from "node:http";
|
|
||||||
import wisp from "wisp-server-node";
|
|
||||||
import { LOG_LEVEL } from "wisp-server-node/dist/Types.js";
|
|
||||||
import { parsedDoc } from "./config.js";
|
|
||||||
const wispOptions = {
|
|
||||||
logLevel: parsedDoc.server.server.logging ? LOG_LEVEL.DEBUG : LOG_LEVEL.NONE,
|
|
||||||
pingInterval: 30
|
|
||||||
};
|
|
||||||
const serverFactory = (handler) => {
|
|
||||||
const httpServer = createServer();
|
|
||||||
httpServer.on("request", (req, res) => {
|
|
||||||
handler(req, res);
|
|
||||||
});
|
|
||||||
httpServer.on("upgrade", (req, socket, head) => {
|
|
||||||
if (parsedDoc.server.server.wisp) {
|
|
||||||
if (req.url?.endsWith("/wisp/")) {
|
|
||||||
wisp.routeRequest(req, socket, head, wispOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return httpServer;
|
|
||||||
};
|
|
||||||
export { serverFactory };
|
|
||||||
Loading…
Add table
Reference in a new issue