Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ const app = http.createServer(async (req, res) => {
sendFile(filePath);
});

export type instace = {
export type instance = {
name: string;
description?: string;
descriptionLong?: string;
Expand All @@ -157,7 +157,7 @@ export type instace = {
};
const instances = JSON.parse(
readFileSync(process.env.JANK_INSTANCES_PATH || __dirname + "/webpage/instances.json").toString(),
) as instace[];
) as instance[];

const instanceNames = new Map<string, Instance>();

Expand Down
96 changes: 77 additions & 19 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {instace} from "./index.js";
import {instance} from "./index.js";

interface ApiUrls {
api: string;
gateway: string;
Expand All @@ -8,16 +9,17 @@ interface ApiUrls {

export async function getApiUrls(
url: string,
instances: instace[],
instances: instance[],
check = true,
): Promise<ApiUrls | null> {
if (!url.endsWith("/")) {
url += "/";
}

if (check) {
let valid = false;
for (const instace of instances) {
const urlstr = instace.url || instace.urls?.api;
for (const instance of instances) {
const urlstr = instance.url || instance.urls?.api;
if (!urlstr) {
continue;
}
Expand All @@ -34,21 +36,77 @@ export async function getApiUrls(
throw new Error("Invalid instance");
}
}

const hostName = new URL(url).hostname;
try {
const info: ApiUrls = await fetch(`${url}.well-known/spacebar`).then((res) => res.json());
const api = info.api;
const apiUrl = new URL(api);
const policies: any = await fetch(
`${api}${apiUrl.pathname.includes("api") ? "" : "api"}/policies/instance/domains`,
).then((res) => res.json());
return {
api: policies.apiEndpoint,
gateway: policies.gateway,
cdn: policies.cdn,
wellknown: url,
};
} catch (error) {
console.error("Error fetching API URLs:", error);
return null;
return await getApiUrlsV2(url);
} catch (e) {
console.warn(
`[WARN] Failed to get V2 API URLs for ${hostName}, trying V1...`,
(e as Error).message,
);
try {
return await getApiUrlsV1(url);
} catch (e) {
console.error(`[ERROR] Failed to get V1 API URLs for ${hostName}:`, (e as Error).message);
throw e;
}
}
}

//region Well-Known V1 Interfaces

interface WellKnownV1 {
api: string;
}

export async function getApiUrlsV1(url: string): Promise<ApiUrls | null> {
const info: WellKnownV1 = await fetch(`${url}.well-known/spacebar`).then((res) => res.json());
const api = info.api;
const apiUrl = new URL(api);
const policies: any = await fetch(
`${api}${apiUrl.pathname.includes("api") ? "" : "api"}/policies/instance/domains`,
).then((res) => res.json());
return {
api: policies.apiEndpoint,
gateway: policies.gateway,
cdn: policies.cdn,
wellknown: url,
};
}
//endregion

//region Well-Known V2 Interfaces
interface WellKnownV2BasicEndpoint {
baseUrl: string;
}

interface WellKnownV2ApiVersions {
default: string;
active: string[];
}

interface WellKnownV2GatewayOptions {
encoding: ("json" | "etf")[];
compression: ("zlib-stream" | "zstd-stream" | null)[];
}

interface WellKnownV2 {
admin?: WellKnownV2BasicEndpoint;
api: WellKnownV2BasicEndpoint & {apiVersions: WellKnownV2ApiVersions};
cdn: WellKnownV2BasicEndpoint;
gateway: WellKnownV2BasicEndpoint & WellKnownV2GatewayOptions;
}

export async function getApiUrlsV2(url: string): Promise<ApiUrls | null> {
const info: WellKnownV2 = await fetch(`${url}.well-known/spacebar/client`).then((res) =>
res.json(),
);
return {
api: info.api.baseUrl + "/api/v" + info.api.apiVersions.default,
gateway: info.gateway.baseUrl,
cdn: info.cdn.baseUrl,
wellknown: url,
};
}
//endregion
2 changes: 1 addition & 1 deletion src/webpage/404.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {I18n} from "./i18n";
import {setTheme, SW} from "./utils/utils";

setTheme();
await setTheme();
await I18n.done;
I18n.translatePage();

Expand Down
2 changes: 1 addition & 1 deletion src/webpage/audio/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {BinWrite} from "../utils/binaryUtils.js";
import {setTheme} from "../utils/utils.js";
import {Play} from "./play.js";

setTheme();
await setTheme();
const w = new BinWrite(2 ** 12);
w.writeStringNo("jasf");
w.write8(4);
Expand Down
18 changes: 9 additions & 9 deletions src/webpage/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Channel extends SnowFlake {
this.createInvite();
},
{
visable: function () {
visible: function () {
return this.hasPermission("CREATE_INSTANT_INVITE") && this.type !== 4;
},
color: "blue",
Expand All @@ -119,7 +119,7 @@ class Channel extends SnowFlake {
this.muteChannel();
},
{
visable: function () {
visible: function () {
return !this.muted && this.type !== 4;
},
},
Expand All @@ -130,7 +130,7 @@ class Channel extends SnowFlake {
this.unmuteChannel();
},
{
visable: function () {
visible: function () {
return this.muted;
},
},
Expand All @@ -142,7 +142,7 @@ class Channel extends SnowFlake {
this.generateSettings();
},
{
visable: function () {
visible: function () {
return this.hasPermission("MANAGE_CHANNELS");
},
icon: {
Expand All @@ -162,7 +162,7 @@ class Channel extends SnowFlake {
this.deleteChannel();
},
{
visable: function () {
visible: function () {
return this.hasPermission("MANAGE_CHANNELS");
},
icon: {
Expand Down Expand Up @@ -741,7 +741,7 @@ class Channel extends SnowFlake {
}
static dragged: [Channel, HTMLDivElement] | [] = [];
html: WeakRef<HTMLElement> | undefined;
get visable() {
get visible() {
return this.hasPermission("VIEW_CHANNEL");
}
voiceUsers = new WeakRef(document.createElement("div"));
Expand Down Expand Up @@ -807,10 +807,10 @@ class Channel extends SnowFlake {
);
}
this.html = new WeakRef(div);
if (!this.visable) {
if (!this.visible) {
let quit = true;
for (const thing of this.children) {
if (thing.visable) {
if (thing.visible) {
quit = false;
}
}
Expand Down Expand Up @@ -1706,7 +1706,7 @@ class Channel extends SnowFlake {
command.render(typebox, this);
}
async getHTML(addstate = true, getMessages: boolean | void = undefined, aroundMessage?: string) {
if (!this.visable) {
if (!this.visible) {
this.guild.loadChannel();
return;
}
Expand Down
44 changes: 22 additions & 22 deletions src/webpage/contextmenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ContextButton<x, y> implements menuPart<x, y> {
private text: string | ((this: x, arg: y) => string);
private onClick: (this: x, arg: y, e: MouseEvent) => void;
private icon?: iconJson;
private visable?: (this: x, arg: y) => boolean;
private visible?: (this: x, arg: y) => boolean;
private enabled?: (this: x, arg: y) => boolean;
//TODO there *will* be more colors
private color?: "red" | "blue";
Expand All @@ -35,7 +35,7 @@ class ContextButton<x, y> implements menuPart<x, y> {
onClick: ContextButton<x, y>["onClick"],
addProps: {
icon?: iconJson;
visable?: (this: x, arg: y) => boolean;
visible?: (this: x, arg: y) => boolean;
enabled?: (this: x, arg: y) => boolean;
color?: "red" | "blue";
group?: string;
Expand All @@ -44,17 +44,17 @@ class ContextButton<x, y> implements menuPart<x, y> {
this.text = text;
this.onClick = onClick;
this.icon = addProps.icon;
this.visable = addProps.visable;
this.visible = addProps.visible;
this.enabled = addProps.enabled;
this.color = addProps.color;
this.group = addProps.group;
}
isVisable(obj1: x, obj2: y): boolean {
if (!this.visable) return true;
return this.visable.call(obj1, obj2);
isVisible(obj1: x, obj2: y): boolean {
if (!this.visible) return true;
return this.visible.call(obj1, obj2);
}
makeContextHTML(obj1: x, obj2: y, menu: HTMLDivElement) {
if (!this.isVisable(obj1, obj2)) {
if (!this.isVisible(obj1, obj2)) {
return;
}

Expand Down Expand Up @@ -113,22 +113,22 @@ class ContextButton<x, y> implements menuPart<x, y> {
}
}
class ContextGroup<x, y> implements menuPart<x, y> {
private visable?: (this: x, arg: y) => boolean;
private visible?: (this: x, arg: y) => boolean;
groupSel: string;
group = undefined;
constructor(
group: string,
addProps: {
visable?: (this: x, arg: y) => boolean;
visible?: (this: x, arg: y) => boolean;
} = {},
) {
this.visable = addProps.visable;
this.visible = addProps.visible;

this.groupSel = group;
}
isVisable(obj1: x, obj2: y): boolean {
if (!this.visable) return true;
return this.visable.call(obj1, obj2);
isVisible(obj1: x, obj2: y): boolean {
if (!this.visible) return true;
return this.visible.call(obj1, obj2);
}
makeContextHTML(
x: x,
Expand All @@ -137,7 +137,7 @@ class ContextGroup<x, y> implements menuPart<x, y> {
layered: contextCluster<unknown, unknown>[],
processed: WeakSet<menuPart<unknown, unknown>>,
) {
if (!this.isVisable(x, y)) {
if (!this.isVisible(x, y)) {
return;
}
for (const [menu, x, y] of layered) {
Expand All @@ -151,14 +151,14 @@ class ContextGroup<x, y> implements menuPart<x, y> {
}
}
class Seperator<x, y> implements menuPart<x, y> {
private visable?: (obj1: x, obj2: y) => boolean;
private visible?: (obj1: x, obj2: y) => boolean;
group?: string;
constructor(visable?: (obj1: x, obj2: y) => boolean, group?: string) {
this.visable = visable;
constructor(visible?: (obj1: x, obj2: y) => boolean, group?: string) {
this.visible = visible;
this.group = group;
}
makeContextHTML(obj1: x, obj2: y, menu: HTMLDivElement): void {
if (!this.visable || this.visable(obj1, obj2)) {
if (!this.visible || this.visible(obj1, obj2)) {
if (menu.children[menu.children.length - 1].tagName === "HR") {
return;
}
Expand Down Expand Up @@ -236,21 +236,21 @@ class Contextmenu<x, y> {
onClick: ContextButton<x, y>["onClick"],
addProps: {
icon?: iconJson;
visable?: (this: x, arg: y) => boolean;
visible?: (this: x, arg: y) => boolean;
enabled?: (this: x, arg: y) => boolean;
color?: "red" | "blue";
group?: string;
} = {},
) {
this.buttons.push(new ContextButton(text, onClick, addProps));
}
addSeperator(visable?: (obj1: x, obj2: y) => boolean, group?: string) {
this.buttons.push(new Seperator(visable, group));
addSeperator(visible?: (obj1: x, obj2: y) => boolean, group?: string) {
this.buttons.push(new Seperator(visible, group));
}
addGroup(
group: string,
addprops?: {
visable?: (this: x, arg: y) => boolean;
visible?: (this: x, arg: y) => boolean;
},
) {
this.buttons.push(new ContextGroup<x, y>(group, addprops));
Expand Down
7 changes: 3 additions & 4 deletions src/webpage/direct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ class Group extends Channel {
},
{
group: "default",
visable: function (user) {
visible: function (user) {
return this.localuser.user.id !== user.id && this.owner_id === this.localuser.user.id;
},
color: "red",
Expand All @@ -435,7 +435,7 @@ class Group extends Channel {
this.edit();
},
{
visable: function () {
visible: function () {
return this.type !== 1;
},
},
Expand Down Expand Up @@ -466,7 +466,7 @@ class Group extends Channel {
navigator.clipboard.writeText(this.users[0].id);
},
{
visable: function () {
visible: function () {
return this.type === 1;
},
},
Expand Down Expand Up @@ -576,7 +576,6 @@ class Group extends Channel {
} else if (this.lastmessage) {
this.position = this.lastmessage.getTimeStamp();
} else if (this.lastmessageid) {
console.log(this.lastmessageid);
this.position = SnowFlake.stringToUnixTime(this.lastmessageid);
} else {
this.position = 0;
Expand Down
Loading