Added and changed all of the js files to typescript files, fixed errors as well

This commit is contained in:
Joep 2023-09-08 00:12:37 +02:00
parent 0907429e9a
commit 5a8ca3a50d
27 changed files with 287 additions and 672 deletions

View File

@ -50,7 +50,8 @@
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vite-plugin-compression2": "^0.10.4",
"vite-plugin-rewrite-all": "^1.0.1"
"vite-plugin-rewrite-all": "^1.0.1",
"vue-tsc": "^1.8.10"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -2541,6 +2542,33 @@
"vue": "^3.2.25"
}
},
"node_modules/@volar/language-core": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.1.tgz",
"integrity": "sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==",
"dev": true,
"dependencies": {
"@volar/source-map": "1.10.1"
}
},
"node_modules/@volar/source-map": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.1.tgz",
"integrity": "sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==",
"dev": true,
"dependencies": {
"muggle-string": "^0.3.1"
}
},
"node_modules/@volar/typescript": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.10.1.tgz",
"integrity": "sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ==",
"dev": true,
"dependencies": {
"@volar/language-core": "1.10.1"
}
},
"node_modules/@vue/compat": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.3.4.tgz",
@ -2619,6 +2647,54 @@
"prettier": ">= 3.0.0"
}
},
"node_modules/@vue/language-core": {
"version": "1.8.10",
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.10.tgz",
"integrity": "sha512-db8PtM4ZZr7SYNH30XpKxUYnUBYaTvcuJ4c2whKK04fuAjbtjAIZ2al5GzGEfUlesmvkpgdbiSviRXUxgD9Omw==",
"dev": true,
"dependencies": {
"@volar/language-core": "~1.10.0",
"@volar/source-map": "~1.10.0",
"@vue/compiler-dom": "^3.3.0",
"@vue/reactivity": "^3.3.0",
"@vue/shared": "^3.3.0",
"minimatch": "^9.0.0",
"muggle-string": "^0.3.1",
"vue-template-compiler": "^2.7.14"
},
"peerDependencies": {
"typescript": "*"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@vue/language-core/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@vue/language-core/node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@vue/reactivity": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz",
@ -2675,6 +2751,16 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
},
"node_modules/@vue/typescript": {
"version": "1.8.10",
"resolved": "https://registry.npmjs.org/@vue/typescript/-/typescript-1.8.10.tgz",
"integrity": "sha512-vPSpTXMk4chYwvyTGjM891cKgnx2r6vtbdANOp2mRU31f4HYGyLrZBlGgiua7SaO2cLjUg8y91OipJe0t8OFhA==",
"dev": true,
"dependencies": {
"@volar/typescript": "~1.10.0",
"@vue/language-core": "1.8.10"
}
},
"node_modules/@vueuse/core": {
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.4.1.tgz",
@ -3301,6 +3387,12 @@
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz",
"integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA=="
},
"node_modules/de-indent": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
"integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
"dev": true
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -4194,6 +4286,15 @@
"node": ">=4"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true,
"bin": {
"he": "bin/he"
}
},
"node_modules/html-encoding-sniffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
@ -4858,6 +4959,12 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/muggle-string": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz",
"integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==",
"dev": true
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
@ -6321,6 +6428,66 @@
"resolved": "https://registry.npmjs.org/vue-simple-progress/-/vue-simple-progress-1.1.1.tgz",
"integrity": "sha512-ltLWYBA5eVQHWyt1NwZeGeK0VQC69JVh1oqUdro0po7r8Hc8SEMEyEfuwyCO4s27h5I3jbD99BKKkyPSQZgoZA=="
},
"node_modules/vue-template-compiler": {
"version": "2.7.14",
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
"integrity": "sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==",
"dev": true,
"dependencies": {
"de-indent": "^1.0.2",
"he": "^1.2.0"
}
},
"node_modules/vue-tsc": {
"version": "1.8.10",
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.10.tgz",
"integrity": "sha512-ptpTFFDoHQgkWJF7i5iERxooiQzOGtG1uKTfmAUuS3qPuSQGq+Ky/S8BFHhnFGwoOxq/PjmGN2QSZEfg1rtzQA==",
"dev": true,
"dependencies": {
"@vue/language-core": "1.8.10",
"@vue/typescript": "1.8.10",
"semver": "^7.3.8"
},
"bin": {
"vue-tsc": "bin/vue-tsc.js"
},
"peerDependencies": {
"typescript": "*"
}
},
"node_modules/vue-tsc/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/vue-tsc/node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/vue-tsc/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",

View File

@ -6,7 +6,7 @@
"scripts": {
"dev": "vite dev",
"serve": "vite serve",
"build": "vite build",
"build": "vue-tsc -p ./tsconfig.json --noEmit && vite build --emptyOutDir",
"watch": "vite build --watch",
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
"lint": "eslint --ext .vue,.js src/",
@ -56,7 +56,8 @@
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vite-plugin-compression2": "^0.10.4",
"vite-plugin-rewrite-all": "^1.0.1"
"vite-plugin-rewrite-all": "^1.0.1",
"vue-tsc": "^1.8.10"
},
"browserslist": [
"> 1%",

View File

@ -179,7 +179,7 @@
</div>
</div>
<script type="module" src="/src/main.js"></script>
<script type="module" src="/src/main.ts"></script>
[{[ if .Theme -]}]
<link

View File

@ -1,18 +0,0 @@
import { removePrefix } from "./utils";
import { baseURL } from "@/utils/constants";
import { useAuthStore } from "@/stores/auth";
const ssl = window.location.protocol === "https:";
const protocol = ssl ? "wss:" : "ws:";
export default function command(url, command, onmessage, onclose) {
const authStore = useAuthStore();
url = removePrefix(url);
url = `${protocol}//${window.location.host}${baseURL}/api/command${url}?auth=${authStore.jwt}`;
let conn = new window.WebSocket(url);
conn.onopen = () => conn.send(command);
conn.onmessage = onmessage;
conn.onclose = onclose;
}

View File

@ -1,204 +0,0 @@
import { createURL, fetchURL, removePrefix } from "./utils";
import { baseURL } from "@/utils/constants";
import { useAuthStore } from "@/stores/auth";
import { upload as postTus, useTus } from "./tus";
export async function fetch(url) {
url = removePrefix(url);
const res = await fetchURL(`/api/resources${url}`, {});
let data = await res.json();
data.url = `/files${url}`;
if (data.isDir) {
if (!data.url.endsWith("/")) data.url += "/";
data.items = data.items.map((item, index) => {
item.index = index;
item.url = `${data.url}${encodeURIComponent(item.name)}`;
if (item.isDir) {
item.url += "/";
}
return item;
});
}
return data;
}
async function resourceAction(url, method, content) {
url = removePrefix(url);
let opts = { method };
if (content) {
opts.body = content;
}
const res = await fetchURL(`/api/resources${url}`, opts);
return res;
}
export async function remove(url) {
return resourceAction(url, "DELETE");
}
export async function put(url, content = "") {
return resourceAction(url, "PUT", content);
}
export function download(format, ...files) {
let url = `${baseURL}/api/raw`;
if (files.length === 1) {
url += removePrefix(files[0]) + "?";
} else {
let arg = "";
for (let file of files) {
arg += removePrefix(file) + ",";
}
arg = arg.substring(0, arg.length - 1);
arg = encodeURIComponent(arg);
url += `/?files=${arg}&`;
}
if (format) {
url += `algo=${format}&`;
}
const authStore = useAuthStore();
if (authStore.jwt) {
url += `auth=${authStore.jwt}&`;
}
window.open(url);
}
export async function post(url, content = "", overwrite = false, onupload) {
// Use the pre-existing API if:
const useResourcesApi =
// a folder is being created
url.endsWith("/") ||
// We're not using http(s)
(content instanceof Blob &&
!["http:", "https:"].includes(window.location.protocol)) ||
// Tus is disabled / not applicable
!(await useTus(content));
return useResourcesApi
? postResources(url, content, overwrite, onupload)
: postTus(url, content, overwrite, onupload);
}
async function postResources(url, content = "", overwrite = false, onupload) {
url = removePrefix(url);
let bufferContent;
if (
content instanceof Blob &&
!["http:", "https:"].includes(window.location.protocol)
) {
bufferContent = await new Response(content).arrayBuffer();
}
const authStore = useAuthStore();
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest();
request.open(
"POST",
`${baseURL}/api/resources${url}?override=${overwrite}`,
true
);
request.setRequestHeader("X-Auth", authStore.jwt);
if (typeof onupload === "function") {
request.upload.onprogress = onupload;
}
request.onload = () => {
if (request.status === 200) {
resolve(request.responseText);
} else if (request.status === 409) {
reject(request.status);
} else {
reject(request.responseText);
}
};
request.onerror = () => {
reject(new Error("001 Connection aborted"));
};
request.send(bufferContent || content);
});
}
function moveCopy(items, copy = false, overwrite = false, rename = false) {
let promises = [];
for (let item of items) {
const from = item.from;
const to = encodeURIComponent(removePrefix(item.to));
const url = `${from}?action=${
copy ? "copy" : "rename"
}&destination=${to}&override=${overwrite}&rename=${rename}`;
promises.push(resourceAction(url, "PATCH"));
}
return Promise.all(promises);
}
export function move(items, overwrite = false, rename = false) {
return moveCopy(items, false, overwrite, rename);
}
export function copy(items, overwrite = false, rename = false) {
return moveCopy(items, true, overwrite, rename);
}
export async function checksum(url, algo) {
const data = await resourceAction(`${url}?checksum=${algo}`, "GET");
return (await data.json()).checksums[algo];
}
export function getDownloadURL(file, inline) {
const params = {
...(inline && { inline: "true" }),
};
return createURL("api/raw" + file.path, params);
}
export function getPreviewURL(file, size) {
const params = {
inline: "true",
key: Date.parse(file.modified),
};
return createURL("api/preview/" + size + file.path, params);
}
export function getSubtitlesURL(file) {
const params = {
inline: "true",
};
const subtitles = [];
for (const sub of file.subtitles) {
subtitles.push(createURL("api/raw" + sub, params));
}
return subtitles;
}
export async function usage(url) {
url = removePrefix(url);
const res = await fetchURL(`/api/usage${url}`, {});
return await res.json();
}

View File

@ -1,9 +0,0 @@
import * as files from "./files";
import * as share from "./share";
import * as users from "./users";
import * as settings from "./settings";
import * as pub from "./pub";
import search from "./search";
import commands from "./commands";
export { files, share, users, settings, pub, commands, search };

View File

@ -1,70 +0,0 @@
import { fetchURL, removePrefix, createURL } from "./utils";
import { baseURL } from "@/utils/constants";
export async function fetch(url, password = "") {
url = removePrefix(url);
const res = await fetchURL(
`/api/public/share${url}`,
{
headers: { "X-SHARE-PASSWORD": encodeURIComponent(password) },
},
false
);
let data = await res.json();
data.url = `/share${url}`;
if (data.isDir) {
if (!data.url.endsWith("/")) data.url += "/";
data.items = data.items.map((item, index) => {
item.index = index;
item.url = `${data.url}${encodeURIComponent(item.name)}`;
if (item.isDir) {
item.url += "/";
}
return item;
});
}
return data;
}
export function download(format, hash, token, ...files) {
let url = `${baseURL}/api/public/dl/${hash}`;
if (files.length === 1) {
url += encodeURIComponent(files[0]) + "?";
} else {
let arg = "";
for (let file of files) {
arg += encodeURIComponent(file) + ",";
}
arg = arg.substring(0, arg.length - 1);
arg = encodeURIComponent(arg);
url += `/?files=${arg}&`;
}
if (format) {
url += `algo=${format}&`;
}
if (token) {
url += `token=${token}&`;
}
window.open(url);
}
export function getDownloadURL(share, inline = false) {
const params = {
...(inline && { inline: "true" }),
...(share.token && { token: share.token }),
};
return createURL("api/public/dl/" + share.hash + share.path, params, false);
}

View File

@ -1,27 +0,0 @@
import { fetchURL, removePrefix } from "./utils";
import url from "../utils/url";
export default async function search(base, query) {
base = removePrefix(base);
query = encodeURIComponent(query);
if (!base.endsWith("/")) {
base += "/";
}
let res = await fetchURL(`/api/search${base}?query=${query}`, {});
let data = await res.json();
data = data.map((item) => {
item.url = `/files${base}` + url.encodePath(item.path);
if (item.dir) {
item.url += "/";
}
return item;
});
return data;
}

View File

@ -1,12 +0,0 @@
import { fetchURL, fetchJSON } from "./utils";
export function get() {
return fetchJSON(`/api/settings`, {});
}
export async function update(settings) {
await fetchURL(`/api/settings`, {
method: "PUT",
body: JSON.stringify(settings),
});
}

View File

@ -1,40 +0,0 @@
import { fetchURL, fetchJSON, removePrefix, createURL } from "./utils";
export async function list() {
return fetchJSON("/api/shares");
}
export async function get(url) {
url = removePrefix(url);
return fetchJSON(`/api/share${url}`);
}
export async function remove(hash) {
await fetchURL(`/api/share/${hash}`, {
method: "DELETE",
});
}
export async function create(url, password = "", expires = "", unit = "hours") {
url = removePrefix(url);
url = `/api/share${url}`;
if (expires !== "") {
url += `?expires=${expires}&unit=${unit}`;
}
let body = "{}";
if (password != "" || expires !== "" || unit !== "hours") {
body = JSON.stringify({
password: password,
expires: expires.toString(), // backend expects string not number
unit: unit,
});
}
return fetchJSON(url, {
method: "POST",
body: body,
});
}
export function getShareURL(share) {
return createURL("share/" + share.hash, {}, false);
}

View File

@ -1,91 +0,0 @@
import * as tus from "tus-js-client";
import { baseURL, tusEndpoint, tusSettings } from "@/utils/constants";
import { useAuthStore } from "@/stores/auth";
import { removePrefix } from "@/api/utils";
import { fetchURL } from "./utils";
const RETRY_BASE_DELAY = 1000;
const RETRY_MAX_DELAY = 20000;
export async function upload(
filePath,
content = "",
overwrite = false,
onupload
) {
if (!tusSettings) {
// Shouldn't happen as we check for tus support before calling this function
throw new Error("Tus.io settings are not defined");
}
filePath = removePrefix(filePath);
let resourcePath = `${tusEndpoint}${filePath}?override=${overwrite}`;
await createUpload(resourcePath);
const authStore = useAuthStore();
return new Promise((resolve, reject) => {
let upload = new tus.Upload(content, {
uploadUrl: `${baseURL}${resourcePath}`,
chunkSize: tusSettings.chunkSize,
retryDelays: computeRetryDelays(tusSettings),
parallelUploads: 1,
storeFingerprintForResuming: false,
headers: {
"X-Auth": authStore.jwt,
},
onError: function (error) {
reject("Upload failed: " + error);
},
onProgress: function (bytesUploaded) {
// Emulate ProgressEvent.loaded which is used by calling functions
// loaded is specified in bytes (https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent/loaded)
if (typeof onupload === "function") {
onupload({ loaded: bytesUploaded });
}
},
onSuccess: function () {
resolve();
},
});
upload.start();
});
}
async function createUpload(resourcePath) {
let headResp = await fetchURL(resourcePath, {
method: "POST",
});
if (headResp.status !== 201) {
throw new Error(
`Failed to create an upload: ${headResp.status} ${headResp.statusText}`
);
}
}
function computeRetryDelays(tusSettings) {
if (!tusSettings.retryCount || tusSettings.retryCount < 1) {
// Disable retries altogether
return null;
}
// The tus client expects our retries as an array with computed backoffs
// E.g.: [0, 3000, 5000, 10000, 20000]
const retryDelays = [];
let delay = 0;
for (let i = 0; i < tusSettings.retryCount; i++) {
retryDelays.push(Math.min(delay, RETRY_MAX_DELAY));
delay =
delay === 0 ? RETRY_BASE_DELAY : Math.min(delay * 2, RETRY_MAX_DELAY);
}
return retryDelays;
}
export async function useTus(content) {
return isTusSupported() && content instanceof Blob;
}
function isTusSupported() {
return tus.isSupported === true;
}

View File

@ -1,41 +0,0 @@
import { fetchURL, fetchJSON } from "./utils";
export async function getAll() {
return fetchJSON(`/api/users`, {});
}
export async function get(id) {
return fetchJSON(`/api/users/${id}`, {});
}
export async function create(user) {
const res = await fetchURL(`/api/users`, {
method: "POST",
body: JSON.stringify({
what: "user",
which: [],
data: user,
}),
});
if (res.status === 201) {
return res.headers.get("Location");
}
}
export async function update(user, which = ["all"]) {
await fetchURL(`/api/users/${user.id}`, {
method: "PUT",
body: JSON.stringify({
what: "user",
which: which,
data: user,
}),
});
}
export async function remove(id) {
await fetchURL(`/api/users/${id}`, {
method: "DELETE",
});
}

View File

@ -1,84 +0,0 @@
import { useAuthStore } from "@/stores/auth";
import { renew, logout } from "@/utils/auth";
import { baseURL } from "@/utils/constants";
import { encodePath } from "@/utils/url";
export async function fetchURL(url, opts, auth = true) {
const authStore = useAuthStore();
opts = opts || {};
opts.headers = opts.headers || {};
let { headers, ...rest } = opts;
let res;
try {
res = await fetch(`${baseURL}${url}`, {
headers: {
"X-Auth": authStore.jwt,
...headers,
},
...rest,
});
} catch {
const error = new Error("000 No connection");
error.status = 0;
throw error;
}
if (auth && res.headers.get("X-Renew-Token") === "true") {
await renew(authStore.jwt);
}
if (res.status < 200 || res.status > 299) {
const error = new Error(await res.text());
error.status = res.status;
if (auth && res.status == 401) {
logout();
}
throw error;
}
return res;
}
export async function fetchJSON(url, opts) {
const res = await fetchURL(url, opts);
if (res.status === 200) {
return res.json();
} else {
throw new Error(res.status);
}
}
export function removePrefix(url) {
url = url.split("/").splice(2).join("/");
if (url === "") url = "/";
if (url[0] !== "/") url = "/" + url;
return url;
}
export function createURL(endpoint, params = {}, auth = true) {
const authStore = useAuthStore();
let prefix = baseURL;
if (!prefix.endsWith("/")) {
prefix = prefix + "/";
}
const url = new URL(prefix + encodePath(endpoint), origin);
const searchParams = {
...(auth && { auth: authStore.jwt }),
...params,
};
for (const key in searchParams) {
url.searchParams.set(key, searchParams[key]);
}
return url.toString();
}

View File

@ -1,4 +1,4 @@
import { createRouter, createWebHistory } from "vue-router";
import { RouteLocation, createRouter, createWebHistory } from "vue-router";
import Login from "@/views/Login.vue";
import Layout from "@/views/Layout.vue";
import Files from "@/views/Files.vue";
@ -144,7 +144,7 @@ const routes = [
},
{
path: "/:catchAll(.*)*",
redirect: (to) => `/files/${[...to.params.catchAll].join("/")}`,
redirect: (to: RouteLocation) => `/files/${[...to.params.catchAll].join("/")}`,
},
];
@ -156,7 +156,7 @@ async function initAuth() {
}
if (recaptcha) {
await new Promise((resolve) => {
await new Promise<void>((resolve) => {
const check = () => {
if (typeof window.grecaptcha === "undefined") {
setTimeout(check, 100);
@ -175,10 +175,11 @@ const router = createRouter({
routes,
});
router.beforeResolve(async (to, from, next) => {
router.beforeResolve(async (to: RouteLocation, from, next) => {
let title;
try {
// this should not fail after we finished the migration
// @ts-ignore
title = i18n.global.t(titles[to.name]);
} catch (error) {
console.error(error);
@ -187,14 +188,14 @@ router.beforeResolve(async (to, from, next) => {
document.title = title + " - " + name;
/*** RTL related settings per route ****/
const rtlSet = document.querySelector("body").classList.contains("rtl");
const rtlSet = document.querySelector("body")?.classList.contains("rtl");
const shouldSetRtl = rtlLanguages.includes(i18n.global.locale);
switch (true) {
case shouldSetRtl && !rtlSet:
document.querySelector("body").classList.add("rtl");
document.querySelector("body")?.classList.add("rtl");
break;
case !shouldSetRtl && rtlSet:
document.querySelector("body").classList.remove("rtl");
document.querySelector("body")?.classList.remove("rtl");
break;
}
@ -225,7 +226,7 @@ router.beforeResolve(async (to, from, next) => {
}
if (to.matched.some((record) => record.meta.requiresAdmin)) {
if (!authStore.user.perm.admin) {
if (authStore.user === null || !authStore.user.perm.admin) {
next({ path: "/403" });
return;
}

View File

@ -5,7 +5,10 @@ import { cloneDeep } from "lodash-es";
export const useAuthStore = defineStore("auth", {
// convert to a function
state: () => ({
state: (): {
user: user | null,
jwt: string
} => ({
user: null,
jwt: "",
}),
@ -15,7 +18,7 @@ export const useAuthStore = defineStore("auth", {
},
actions: {
// no context as first argument, use `this` instead
setUser(value) {
setUser(value: user) {
if (value === null) {
this.user = null;
return;
@ -23,19 +26,23 @@ export const useAuthStore = defineStore("auth", {
const locale = value.locale || detectLocale();
dayjs.locale(locale);
// @ts-ignore Don't know how to fix this yet
i18n.global.locale.value = locale;
this.user = value;
},
updateUser(value) {
updateUser(value: user) {
if (typeof value !== "object") return;
for (let field in value) {
let field: userKey
for (field in value) {
if (field === "locale") {
const locale = value[field];
dayjs.locale(locale);
// @ts-ignore Don't know how to fix this yet
i18n.global.locale.value = locale;
}
// @ts-ignore to fix
this.user[field] = cloneDeep(value[field]);
}
},

View File

@ -2,7 +2,14 @@ import { defineStore } from "pinia";
export const useFileStore = defineStore("file", {
// convert to a function
state: () => ({
state: (): {
req: req,
oldReq: req,
reload: boolean,
selected: any[],
multiple: boolean,
isFiles: boolean
} => ({
req: {},
oldReq: {},
reload: false,
@ -29,11 +36,11 @@ export const useFileStore = defineStore("file", {
toggleMultiple() {
this.multiple = !this.multiple;
},
updateRequest(value) {
updateRequest(value: req) {
this.oldReq = this.req;
this.req = value;
},
removeSelected(value) {
removeSelected(value: any) {
let i = this.selected.indexOf(value);
if (i === -1) return;
this.selected.splice(i, 1);

View File

@ -1,7 +1,8 @@
import { createPinia as _createPinia } from "pinia";
import { markRaw } from "vue";
import { Router } from "vue-router";
export default function createPinia(router) {
export default function createPinia(router: Router) {
const pinia = _createPinia();
pinia.use(({ store }) => {
store.router = markRaw(router);

View File

@ -4,7 +4,13 @@ import { defineStore } from "pinia";
export const useLayoutStore = defineStore("layout", {
// convert to a function
state: () => ({
state: (): {
loading: boolean,
show: string | null | boolean,
showConfirm: boolean | null,
showAction: boolean | null,
showShell: boolean | null
} => ({
loading: false,
show: null,
showConfirm: null,
@ -19,7 +25,7 @@ export const useLayoutStore = defineStore("layout", {
toggleShell() {
this.showShell = !this.showShell;
},
showHover(value) {
showHover(value: LayoutValue) {
if (typeof value !== "object") {
this.show = value;
return;

View File

@ -6,14 +6,21 @@ import buttons from "@/utils/buttons";
const UPLOADS_LIMIT = 5;
const beforeUnload = (event) => {
const beforeUnload = (event: Event) => {
event.preventDefault();
event.returnValue = "";
// To remove >> is deprecated
// event.returnValue = "";
};
export const useUploadStore = defineStore("upload", {
// convert to a function
state: () => ({
state: (): {
id: number,
sizes: any[],
progress: any[],
queue: any[],
uploads: uploads
} => ({
id: 0,
sizes: [],
progress: [],
@ -29,7 +36,8 @@ export const useUploadStore = defineStore("upload", {
const totalSize = state.sizes.reduce((a, b) => a + b, 0);
const sum = state.progress.reduce((acc, val) => acc + val);
// @ts-ignore
const sum: number = state.progress.reduce((acc, val) => acc + val);
return Math.ceil((sum / totalSize) * 100);
},
filesInUploadCount: (state) => {
@ -64,8 +72,9 @@ export const useUploadStore = defineStore("upload", {
},
actions: {
// no context as first argument, use `this` instead
setProgress({ id, loaded }) {
setProgress(obj: { id: number, loaded: boolean }) {
// Vue.set(this.progress, id, loaded);
const { id, loaded } = obj
this.progress[id] = loaded;
},
reset() {
@ -73,7 +82,7 @@ export const useUploadStore = defineStore("upload", {
this.sizes = [];
this.progress = [];
},
addJob(item) {
addJob(item: item) {
this.queue.push(item);
this.sizes[this.id] = item.file.size;
this.id++;
@ -84,11 +93,11 @@ export const useUploadStore = defineStore("upload", {
// Vue.set(this.uploads, item.id, item);
this.uploads[item.id] = item;
},
removeJob(id) {
removeJob(id: number) {
// Vue.delete(this.uploads, id);
delete this.uploads[id];
},
upload(item) {
upload(item: item) {
let uploadsCount = Object.keys(this.uploads).length;
let isQueueEmpty = this.queue.length == 0;
@ -102,8 +111,8 @@ export const useUploadStore = defineStore("upload", {
this.addJob(item);
this.processUploads();
},
finishUpload(item) {
this.setProgress({ id: item.id, loaded: item.file.size });
finishUpload(item: item) {
this.setProgress({ id: item.id, loaded: (item.file.size > 0) });
this.removeJob(item.id);
this.processUploads();
},

View File

@ -3,5 +3,6 @@ export {};
declare global {
interface Window {
FileBrowser: any;
grecaptcha: any
}
}

View File

@ -3,9 +3,9 @@ import router from "@/router";
import jwt_decode from "jwt-decode";
import { baseURL } from "./constants";
export function parseToken(token) {
export function parseToken(token: string) {
// falsy or malformed jwt will throw InvalidTokenError
const data = jwt_decode(token);
const data = jwt_decode<{[key:string]: any, user: user}>(token);
document.cookie = `auth=${token}; Path=/; SameSite=Strict;`;
@ -19,7 +19,7 @@ export function parseToken(token) {
export async function validateLogin() {
try {
if (localStorage.getItem("jwt")) {
await renew(localStorage.getItem("jwt"));
await renew(<string>localStorage.getItem("jwt"));
}
} catch (error) {
console.warn("Invalid JWT token in storage"); // eslint-disable-line
@ -27,7 +27,7 @@ export async function validateLogin() {
}
}
export async function login(username, password, recaptcha) {
export async function login(username: string, password: string, recaptcha: string) {
const data = { username, password, recaptcha };
const res = await fetch(`${baseURL}/api/login`, {
@ -47,7 +47,7 @@ export async function login(username, password, recaptcha) {
}
}
export async function renew(jwt) {
export async function renew(jwt: string) {
const res = await fetch(`${baseURL}/api/renew`, {
method: "POST",
headers: {
@ -64,7 +64,7 @@ export async function renew(jwt) {
}
}
export async function signup(username, password) {
export async function signup(username: string, password: string) {
const data = { username, password };
const res = await fetch(`${baseURL}/api/signup`, {
@ -76,6 +76,7 @@ export async function signup(username, password) {
});
if (res.status !== 200) {
// @ts-ignore still need to fix these errors
throw new Error(res.status);
}
}
@ -86,6 +87,6 @@ export function logout() {
const authStore = useAuthStore();
authStore.clearUser();
localStorage.setItem("jwt", null);
localStorage.setItem("jwt", '');
router.push({ path: "/login" });
}

View File

@ -1,5 +1,5 @@
function loading(button) {
let el = document.querySelector(`#${button}-button > i`);
function loading(button: string) {
let el: HTMLButtonElement | null = document.querySelector(`#${button}-button > i`);
if (el === undefined || el === null) {
console.log("Error getting button " + button); // eslint-disable-line
@ -11,53 +11,62 @@ function loading(button) {
}
el.dataset.icon = el.innerHTML;
el.style.opacity = 0;
el.style.opacity = "0";
setTimeout(() => {
el.classList.add("spin");
el.innerHTML = "autorenew";
el.style.opacity = 1;
if(el) {
el.classList.add("spin");
el.innerHTML = "autorenew";
el.style.opacity = "1";
}
}, 100);
}
function done(button) {
let el = document.querySelector(`#${button}-button > i`);
function done(button: string) {
let el: HTMLButtonElement | null = document.querySelector(`#${button}-button > i`);
if (el === undefined || el === null) {
console.log("Error getting button " + button); // eslint-disable-line
return;
}
el.style.opacity = 0;
el.style.opacity = "0";
setTimeout(() => {
el.classList.remove("spin");
el.innerHTML = el.dataset.icon;
el.style.opacity = 1;
if(el !== null) {
el.classList.remove("spin");
el.innerHTML = el?.dataset?.icon || "";
el.style.opacity = "1";
}
}, 100);
}
function success(button) {
let el = document.querySelector(`#${button}-button > i`);
function success(button: string) {
let el: HTMLButtonElement | null = document.querySelector(`#${button}-button > i`);
if (el === undefined || el === null) {
console.log("Error getting button " + button); // eslint-disable-line
return;
}
el.style.opacity = 0;
el.style.opacity = "0";
setTimeout(() => {
el.classList.remove("spin");
el.innerHTML = "done";
el.style.opacity = 1;
if(el !== null) {
el.classList.remove("spin");
el.innerHTML = "done";
el.style.opacity = "1";
}
setTimeout(() => {
el.style.opacity = 0;
if(el) el.style.opacity = "0";
setTimeout(() => {
el.innerHTML = el.dataset.icon;
el.style.opacity = 1;
if(el !== null) {
el.innerHTML = el?.dataset?.icon || "";
el.style.opacity = "1";
}
}, 100);
}, 500);
}, 100);

View File

@ -1,4 +1,4 @@
export default function (name) {
export default function (name: string) {
let re = new RegExp(
"(?:(?:^|.*;\\s*)" + name + "\\s*\\=\\s*([^;]*).*$)|^.*$"
);

View File

@ -1,4 +1,4 @@
export default function getRule(rules) {
export default function getRule(rules: any) {
for (let i = 0; i < rules.length; i++) {
rules[i] = rules[i].toLowerCase();
}

View File

@ -1 +1 @@
export * from "./funcs";
// export * from "./funcs";

View File

@ -1,7 +1,7 @@
import { useUploadStore } from "@/stores/upload";
import url from "@/utils/url";
export function checkConflict(files, items) {
export function checkConflict(files: file[], items: item[]) {
if (typeof items === "undefined" || items === null) {
items = [];
}
@ -21,6 +21,7 @@ export function checkConflict(files, items) {
}
let res = items.findIndex(function hasConflict(element) {
// @ts-ignore Don't know what this does
return element.name === this;
}, name);
@ -33,10 +34,10 @@ export function checkConflict(files, items) {
return conflict;
}
export function scanFiles(dt) {
export function scanFiles(dt: {[key: string]: any, item: item}) {
return new Promise((resolve) => {
let reading = 0;
const contents = [];
const contents: any[] = [];
if (dt.items !== undefined) {
for (let item of dt.items) {
@ -52,10 +53,10 @@ export function scanFiles(dt) {
resolve(dt.files);
}
function readEntry(entry, directory = "") {
function readEntry(entry: any, directory = "") {
if (entry.isFile) {
reading++;
entry.file((file) => {
entry.file((file: file) => {
reading--;
file.fullPath = `${directory}${file.name}`;
@ -79,10 +80,10 @@ export function scanFiles(dt) {
}
}
function readReaderContent(reader, directory) {
function readReaderContent(reader: any, directory: string) {
reading++;
reader.readEntries(function (entries) {
reader.readEntries(function (entries: any[]) {
reading--;
if (entries.length > 0) {
for (const entry of entries) {
@ -100,7 +101,7 @@ export function scanFiles(dt) {
});
}
function detectType(mimetype) {
function detectType(mimetype: string): uploadType {
if (mimetype.startsWith("video")) return "video";
if (mimetype.startsWith("audio")) return "audio";
if (mimetype.startsWith("image")) return "image";
@ -109,7 +110,7 @@ function detectType(mimetype) {
return "blob";
}
export function handleFiles(files, base, overwrite = false) {
export function handleFiles(files: file[], base: string, overwrite = false) {
const uploadStore = useUploadStore();
for (let i = 0; i < files.length; i++) {

View File

@ -1,4 +1,4 @@
export function removeLastDir(url) {
export function removeLastDir(url: string) {
var arr = url.split("/");
if (arr.pop() === "") {
arr.pop();
@ -9,7 +9,7 @@ export function removeLastDir(url) {
// this function is taken from mozilla
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Examples
export function encodeRFC5987ValueChars(str) {
export function encodeRFC5987ValueChars(str: string) {
return (
encodeURIComponent(str)
// The following creates the sequences %27 %28 %29 %2A (Note that
@ -28,7 +28,7 @@ export function encodeRFC5987ValueChars(str) {
);
}
export function encodePath(str) {
export function encodePath(str: string) {
return str
.split("/")
.map((v) => encodeURIComponent(v))