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", "typescript": "^5.2.2",
"vite": "^4.4.9", "vite": "^4.4.9",
"vite-plugin-compression2": "^0.10.4", "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": { "node_modules/@aashutoshrathi/word-wrap": {
@ -2541,6 +2542,33 @@
"vue": "^3.2.25" "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": { "node_modules/@vue/compat": {
"version": "3.3.4", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.3.4.tgz", "resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.3.4.tgz",
@ -2619,6 +2647,54 @@
"prettier": ">= 3.0.0" "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": { "node_modules/@vue/reactivity": {
"version": "3.3.4", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz", "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", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" "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": { "node_modules/@vueuse/core": {
"version": "10.4.1", "version": "10.4.1",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.4.1.tgz", "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", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz",
"integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" "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": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -4194,6 +4286,15 @@
"node": ">=4" "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": { "node_modules/html-encoding-sniffer": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "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==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true "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": { "node_modules/nanoid": {
"version": "3.3.6", "version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", "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", "resolved": "https://registry.npmjs.org/vue-simple-progress/-/vue-simple-progress-1.1.1.tgz",
"integrity": "sha512-ltLWYBA5eVQHWyt1NwZeGeK0VQC69JVh1oqUdro0po7r8Hc8SEMEyEfuwyCO4s27h5I3jbD99BKKkyPSQZgoZA==" "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": { "node_modules/w3c-xmlserializer": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
export default function (name) { export default function (name: string) {
let re = new RegExp( let re = new RegExp(
"(?:(?:^|.*;\\s*)" + name + "\\s*\\=\\s*([^;]*).*$)|^.*$" "(?:(?:^|.*;\\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++) { for (let i = 0; i < rules.length; i++) {
rules[i] = rules[i].toLowerCase(); 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 { useUploadStore } from "@/stores/upload";
import url from "@/utils/url"; import url from "@/utils/url";
export function checkConflict(files, items) { export function checkConflict(files: file[], items: item[]) {
if (typeof items === "undefined" || items === null) { if (typeof items === "undefined" || items === null) {
items = []; items = [];
} }
@ -21,6 +21,7 @@ export function checkConflict(files, items) {
} }
let res = items.findIndex(function hasConflict(element) { let res = items.findIndex(function hasConflict(element) {
// @ts-ignore Don't know what this does
return element.name === this; return element.name === this;
}, name); }, name);
@ -33,10 +34,10 @@ export function checkConflict(files, items) {
return conflict; return conflict;
} }
export function scanFiles(dt) { export function scanFiles(dt: {[key: string]: any, item: item}) {
return new Promise((resolve) => { return new Promise((resolve) => {
let reading = 0; let reading = 0;
const contents = []; const contents: any[] = [];
if (dt.items !== undefined) { if (dt.items !== undefined) {
for (let item of dt.items) { for (let item of dt.items) {
@ -52,10 +53,10 @@ export function scanFiles(dt) {
resolve(dt.files); resolve(dt.files);
} }
function readEntry(entry, directory = "") { function readEntry(entry: any, directory = "") {
if (entry.isFile) { if (entry.isFile) {
reading++; reading++;
entry.file((file) => { entry.file((file: file) => {
reading--; reading--;
file.fullPath = `${directory}${file.name}`; file.fullPath = `${directory}${file.name}`;
@ -79,10 +80,10 @@ export function scanFiles(dt) {
} }
} }
function readReaderContent(reader, directory) { function readReaderContent(reader: any, directory: string) {
reading++; reading++;
reader.readEntries(function (entries) { reader.readEntries(function (entries: any[]) {
reading--; reading--;
if (entries.length > 0) { if (entries.length > 0) {
for (const entry of entries) { 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("video")) return "video";
if (mimetype.startsWith("audio")) return "audio"; if (mimetype.startsWith("audio")) return "audio";
if (mimetype.startsWith("image")) return "image"; if (mimetype.startsWith("image")) return "image";
@ -109,7 +110,7 @@ function detectType(mimetype) {
return "blob"; return "blob";
} }
export function handleFiles(files, base, overwrite = false) { export function handleFiles(files: file[], base: string, overwrite = false) {
const uploadStore = useUploadStore(); const uploadStore = useUploadStore();
for (let i = 0; i < files.length; i++) { 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("/"); var arr = url.split("/");
if (arr.pop() === "") { if (arr.pop() === "") {
arr.pop(); arr.pop();
@ -9,7 +9,7 @@ export function removeLastDir(url) {
// this function is taken from mozilla // this function is taken from mozilla
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Examples // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Examples
export function encodeRFC5987ValueChars(str) { export function encodeRFC5987ValueChars(str: string) {
return ( return (
encodeURIComponent(str) encodeURIComponent(str)
// The following creates the sequences %27 %28 %29 %2A (Note that // 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 return str
.split("/") .split("/")
.map((v) => encodeURIComponent(v)) .map((v) => encodeURIComponent(v))