From 11b6f0c19e8fde2135a1d222e5b9f81c2f9ce51d Mon Sep 17 00:00:00 2001 From: WardPearce Date: Mon, 23 Feb 2026 19:37:47 +1300 Subject: [PATCH] Better code seperation for backend --- materialious/src/lib/api/backend.ts | 346 ------------------ .../src/lib/api/backend/encryption.ts | 48 +++ materialious/src/lib/api/backend/history.ts | 60 +++ materialious/src/lib/api/backend/index.ts | 112 ++++++ materialious/src/lib/api/backend/keyvalue.ts | 35 ++ .../src/lib/api/backend/subscriptions.ts | 99 +++++ materialious/src/lib/api/index.ts | 3 +- .../src/lib/api/youtubejs/subscriptions.ts | 2 +- .../src/lib/components/settings/Engine.svelte | 2 +- .../src/lib/externalSettings/index.ts | 2 +- materialious/src/lib/watch.ts | 2 +- 11 files changed, 359 insertions(+), 352 deletions(-) delete mode 100644 materialious/src/lib/api/backend.ts create mode 100644 materialious/src/lib/api/backend/encryption.ts create mode 100644 materialious/src/lib/api/backend/history.ts create mode 100644 materialious/src/lib/api/backend/index.ts create mode 100644 materialious/src/lib/api/backend/keyvalue.ts create mode 100644 materialious/src/lib/api/backend/subscriptions.ts diff --git a/materialious/src/lib/api/backend.ts b/materialious/src/lib/api/backend.ts deleted file mode 100644 index 8f5d7ed8..00000000 --- a/materialious/src/lib/api/backend.ts +++ /dev/null @@ -1,346 +0,0 @@ -import sodium from 'libsodium-wrappers-sumo'; -import { rawMasterKeyStore } from '../store'; -import { get } from 'svelte/store'; -import { parseChannelRSS } from './youtubejs/subscriptions'; -import { getChannelYTjs } from './youtubejs/channel'; -import type { ChannelSubscriptions } from '$lib/dexie'; -import type { VideoPlay } from './model'; -import { vi } from 'zod/v4/locales'; -import { getBestThumbnail } from '$lib/images'; - -async function getSecureHash(toHash: string, rawKey: Uint8Array): Promise { - await sodium.ready; - return sodium.to_base64( - sodium.crypto_generichash(sodium.crypto_generichash_BYTES, toHash, rawKey) - ); -} - -async function getRawKey(): Promise { - const rawMasterKey = get(rawMasterKeyStore); - if (!rawMasterKey) return; - - await sodium.ready; - - return sodium.from_base64(rawMasterKey); -} - -export async function getSubscriptionsBackend(): Promise { - const resp = await fetch(`/api/user/subscriptions`, { - method: 'GET', - credentials: 'same-origin' - }); - - if (!resp.ok) return []; - - const subscriptions: ChannelSubscriptions[] = []; - - const respJson = await resp.json(); - - for (const sub of respJson.subscriptions) { - subscriptions.push({ - channelName: (await decryptWithMasterKey(sub.channelNameNonce, sub.channelNameCipher)) ?? '', - channelId: (await decryptWithMasterKey(sub.channelIdNonce, sub.channelIdCipher)) ?? '', - lastRSSFetch: new Date(sub.lastRSSFetch) - }); - } - - return subscriptions; -} - -export async function updateRSSLastUpdated(authorId: string) { - const rawKey = await getRawKey(); - if (!rawKey) return false; - - const internalAuthorId = await getSecureHash(authorId, rawKey); - - await fetch(`/api/user/subscriptions/${internalAuthorId}`, { - method: 'PATCH', - credentials: 'same-origin' - }); -} - -export async function amSubscribedBackend(authorId: string): Promise { - const rawKey = await getRawKey(); - if (!rawKey) return false; - - const internalAuthorId = await getSecureHash(authorId, rawKey); - - const resp = await fetch(`/api/user/subscriptions/${internalAuthorId}`, { - method: 'GET', - credentials: 'same-origin' - }); - if (!resp.ok) return false; - - const respJson = await resp.json(); - - return respJson.amSubscribed; -} - -export async function deleteUnsubscribeBackend(authorId: string) { - const rawKey = await getRawKey(); - if (!rawKey) return false; - - const internalAuthorId = await getSecureHash(authorId, rawKey); - - await fetch(`/api/user/subscriptions/${internalAuthorId}`, { - method: 'DELETE', - credentials: 'same-origin' - }); -} - -export async function postSubscribeBackend( - authorId: string, - authorName: string | undefined = undefined -) { - const rawKey = await getRawKey(); - if (!rawKey) return; - - const internalAuthorId = await getSecureHash(authorId, rawKey); - - if (!authorName) { - const channel = await getChannelYTjs(authorId); - authorName = channel.author; - } - - const channelId = await encryptWithMasterKey(authorId); - const channelName = await encryptWithMasterKey(authorName); - - const resp = await fetch(`/api/user/subscriptions/${internalAuthorId}`, { - method: 'POST', - body: JSON.stringify({ - channelIdCipher: channelId?.cipher, - channelIdNonce: channelId?.nonce, - channelNameCipher: channelName?.cipher, - channelNameNonce: channelName?.nonce - }), - credentials: 'same-origin' - }); - - if (resp.ok) parseChannelRSS(authorId); -} - -export type DerivePassword = (rawPassword: string, passwordSalt: Uint8Array) => Promise; - -export async function createUserBackend( - username: string, - rawPassword: string, - captchaPayload: string, - derivePassword: DerivePassword -): Promise { - await sodium.ready; - - const passwordSalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); - - const loginHash = await derivePassword(rawPassword, passwordSalt); - - const decryptionKeySalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); - const rawDecryptionKey = sodium.crypto_pwhash( - 32, - rawPassword, - decryptionKeySalt, - sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, - sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, - sodium.crypto_pwhash_ALG_DEFAULT - ); - - const rawDecryptionMasterKey = sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES); - const decryptionMasterKeyNonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); - - const masterKeyCipher = sodium.crypto_secretbox_easy( - rawDecryptionMasterKey, - decryptionMasterKeyNonce, - rawDecryptionKey - ); - - const userCreateResp = await fetch('/api/user/create', { - method: 'POST', - body: JSON.stringify({ - username: username, - password: { - hash: sodium.to_base64(loginHash), - salt: sodium.to_base64(passwordSalt) - }, - decryptionKeySalt: sodium.to_base64(decryptionKeySalt), - masterKey: { - cipher: sodium.to_base64(masterKeyCipher), - nonce: sodium.to_base64(decryptionMasterKeyNonce) - }, - captchaPayload - }), - credentials: 'same-origin' - }); - - if (!userCreateResp.ok) return false; - - rawMasterKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); - - return true; -} - -export async function loginUserBackend( - username: string, - rawPassword: string, - captchaPayload: string, - derivePassword: DerivePassword -): Promise { - await sodium.ready; - - const passwordSaltsResp = await fetch(`/api/user/${username}/public`); - if (!passwordSaltsResp.ok) return false; - - const passwordSalts = await passwordSaltsResp.json(); - - const loginHash = await derivePassword( - rawPassword, - sodium.from_base64(passwordSalts.passwordSalt) - ); - - const loginResp = await fetch('/api/user/login', { - method: 'POST', - body: JSON.stringify({ - username, - passwordHash: sodium.to_base64(loginHash), - captchaPayload - }), - credentials: 'same-origin' - }); - - if (!loginResp.ok) return false; - - const loginJson = await loginResp.json(); - - const rawDecryptionKey = sodium.crypto_pwhash( - sodium.crypto_secretbox_KEYBYTES, - rawPassword, - sodium.from_base64(passwordSalts.decryptionKeySalt), - sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, - sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, - sodium.crypto_pwhash_ALG_DEFAULT - ); - - const rawDecryptionMasterKey = sodium.crypto_secretbox_open_easy( - sodium.from_base64(loginJson.masterKeyCipher), - sodium.from_base64(loginJson.masterKeyNonce), - rawDecryptionKey - ); - - rawMasterKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); - - return true; -} - -export async function addOrUpdateKeyValue(key: string, value: string) { - const valueEncrypted = await encryptWithMasterKey(value); - - await fetch(`/api/user/keyValue/${key}`, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - valueCipher: valueEncrypted?.cipher, - valueNonce: valueEncrypted?.nonce - }) - }); -} - -export async function deleteKeyValue(key: string) { - await fetch(`/api/user/keyValue/${key}`, { - method: 'DELETE', - credentials: 'same-origin' - }); -} - -export type KeyValue = boolean | number | string[] | string | object | undefined; - -export async function getKeyValue(key: string): Promise { - const resp = await fetch(`/api/user/keyValue/${key}`, { - method: 'GET', - credentials: 'same-origin' - }); - - if (!resp.ok) return null; - - const respJson = await resp.json(); - return (await decryptWithMasterKey(respJson.valueNonce, respJson.valueCipher)) ?? null; -} - -export async function updateWatchHistory(videoId: string, progress: number) { - await sodium.ready; - const rawKey = await getRawKey(); - if (!rawKey) return; - - const videoHash = await getSecureHash(videoId, rawKey); - - await fetch(`/api/user/history/${videoHash}`, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - watched: new Date(), - progress - }) - }); -} - -export async function saveWatchHistory(video: VideoPlay, progress: number = 0) { - await sodium.ready; - const rawKey = await getRawKey(); - if (!rawKey) return; - - const videoHash = await getSecureHash(video.videoId, rawKey); - - const title = await encryptWithMasterKey(video.title); - const author = await encryptWithMasterKey(video.author); - const thumbnail = await encryptWithMasterKey(getBestThumbnail(video.videoThumbnails)); - const duration = await encryptWithMasterKey(video.lengthSeconds.toString()); - - await fetch('/api/user/history', { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify({ - id: videoHash, - watched: new Date(), - progress: progress, - title: { - cipher: title?.cipher, - nonce: title?.nonce - }, - author: { - cipher: author?.cipher, - nonce: author?.nonce - }, - thumbnail: { - cipher: thumbnail?.cipher, - nonce: thumbnail?.nonce - }, - duration: { - cipher: duration?.cipher, - nonce: duration?.nonce - } - }) - }); -} - -async function encryptWithMasterKey( - text: string -): Promise<{ nonce: string; cipher: string } | undefined> { - await sodium.ready; - const rawKey = await getRawKey(); - if (!rawKey) return; - - const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); - const cipher = sodium.crypto_secretbox_easy(new TextEncoder().encode(text), nonce, rawKey); - - return { - nonce: sodium.to_base64(nonce), - cipher: sodium.to_base64(cipher) - }; -} - -async function decryptWithMasterKey(nonce: string, cipher: string): Promise { - await sodium.ready; - const rawKey = await getRawKey(); - if (!rawKey) return; - - return new TextDecoder().decode( - sodium.crypto_secretbox_open_easy(sodium.from_base64(cipher), sodium.from_base64(nonce), rawKey) - ); -} diff --git a/materialious/src/lib/api/backend/encryption.ts b/materialious/src/lib/api/backend/encryption.ts new file mode 100644 index 00000000..8aa71947 --- /dev/null +++ b/materialious/src/lib/api/backend/encryption.ts @@ -0,0 +1,48 @@ +import { rawMasterKeyStore } from '$lib/store'; +import sodium from 'libsodium-wrappers-sumo'; +import { get } from 'svelte/store'; + +export async function getSecureHash(toHash: string, rawKey: Uint8Array): Promise { + await sodium.ready; + return sodium.to_base64( + sodium.crypto_generichash(sodium.crypto_generichash_BYTES, toHash, rawKey) + ); +} + +export async function getRawKey(): Promise { + const rawMasterKey = get(rawMasterKeyStore); + if (!rawMasterKey) return; + + await sodium.ready; + + return sodium.from_base64(rawMasterKey); +} + +export async function encryptWithMasterKey( + text: string +): Promise<{ nonce: string; cipher: string } | undefined> { + await sodium.ready; + const rawKey = await getRawKey(); + if (!rawKey) return; + + const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); + const cipher = sodium.crypto_secretbox_easy(new TextEncoder().encode(text), nonce, rawKey); + + return { + nonce: sodium.to_base64(nonce), + cipher: sodium.to_base64(cipher) + }; +} + +export async function decryptWithMasterKey( + nonce: string, + cipher: string +): Promise { + await sodium.ready; + const rawKey = await getRawKey(); + if (!rawKey) return; + + return new TextDecoder().decode( + sodium.crypto_secretbox_open_easy(sodium.from_base64(cipher), sodium.from_base64(nonce), rawKey) + ); +} diff --git a/materialious/src/lib/api/backend/history.ts b/materialious/src/lib/api/backend/history.ts new file mode 100644 index 00000000..3aa85758 --- /dev/null +++ b/materialious/src/lib/api/backend/history.ts @@ -0,0 +1,60 @@ +import sodium from 'libsodium-wrappers-sumo'; +import { encryptWithMasterKey, getRawKey, getSecureHash } from './encryption'; +import type { VideoPlay } from '../model'; +import { getBestThumbnail } from '$lib/images'; + +export async function updateWatchHistory(videoId: string, progress: number) { + await sodium.ready; + const rawKey = await getRawKey(); + if (!rawKey) return; + + const videoHash = await getSecureHash(videoId, rawKey); + + await fetch(`/api/user/history/${videoHash}`, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + watched: new Date(), + progress + }) + }); +} + +export async function saveWatchHistory(video: VideoPlay, progress: number = 0) { + await sodium.ready; + const rawKey = await getRawKey(); + if (!rawKey) return; + + const videoHash = await getSecureHash(video.videoId, rawKey); + + const title = await encryptWithMasterKey(video.title); + const author = await encryptWithMasterKey(video.author); + const thumbnail = await encryptWithMasterKey(getBestThumbnail(video.videoThumbnails)); + const duration = await encryptWithMasterKey(video.lengthSeconds.toString()); + + await fetch('/api/user/history', { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + id: videoHash, + watched: new Date(), + progress: progress, + title: { + cipher: title?.cipher, + nonce: title?.nonce + }, + author: { + cipher: author?.cipher, + nonce: author?.nonce + }, + thumbnail: { + cipher: thumbnail?.cipher, + nonce: thumbnail?.nonce + }, + duration: { + cipher: duration?.cipher, + nonce: duration?.nonce + } + }) + }); +} diff --git a/materialious/src/lib/api/backend/index.ts b/materialious/src/lib/api/backend/index.ts new file mode 100644 index 00000000..df1d9162 --- /dev/null +++ b/materialious/src/lib/api/backend/index.ts @@ -0,0 +1,112 @@ +import sodium from 'libsodium-wrappers-sumo'; +import { rawMasterKeyStore } from '$lib/store'; + +export type DerivePassword = (rawPassword: string, passwordSalt: Uint8Array) => Promise; + +export async function createUserBackend( + username: string, + rawPassword: string, + captchaPayload: string, + derivePassword: DerivePassword +): Promise { + await sodium.ready; + + const passwordSalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); + + const loginHash = await derivePassword(rawPassword, passwordSalt); + + const decryptionKeySalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); + const rawDecryptionKey = sodium.crypto_pwhash( + 32, + rawPassword, + decryptionKeySalt, + sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, + sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, + sodium.crypto_pwhash_ALG_DEFAULT + ); + + const rawDecryptionMasterKey = sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES); + const decryptionMasterKeyNonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); + + const masterKeyCipher = sodium.crypto_secretbox_easy( + rawDecryptionMasterKey, + decryptionMasterKeyNonce, + rawDecryptionKey + ); + + const userCreateResp = await fetch('/api/user/create', { + method: 'POST', + body: JSON.stringify({ + username: username, + password: { + hash: sodium.to_base64(loginHash), + salt: sodium.to_base64(passwordSalt) + }, + decryptionKeySalt: sodium.to_base64(decryptionKeySalt), + masterKey: { + cipher: sodium.to_base64(masterKeyCipher), + nonce: sodium.to_base64(decryptionMasterKeyNonce) + }, + captchaPayload + }), + credentials: 'same-origin' + }); + + if (!userCreateResp.ok) return false; + + rawMasterKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); + + return true; +} + +export async function loginUserBackend( + username: string, + rawPassword: string, + captchaPayload: string, + derivePassword: DerivePassword +): Promise { + await sodium.ready; + + const passwordSaltsResp = await fetch(`/api/user/${username}/public`); + if (!passwordSaltsResp.ok) return false; + + const passwordSalts = await passwordSaltsResp.json(); + + const loginHash = await derivePassword( + rawPassword, + sodium.from_base64(passwordSalts.passwordSalt) + ); + + const loginResp = await fetch('/api/user/login', { + method: 'POST', + body: JSON.stringify({ + username, + passwordHash: sodium.to_base64(loginHash), + captchaPayload + }), + credentials: 'same-origin' + }); + + if (!loginResp.ok) return false; + + const loginJson = await loginResp.json(); + + const rawDecryptionKey = sodium.crypto_pwhash( + sodium.crypto_secretbox_KEYBYTES, + rawPassword, + sodium.from_base64(passwordSalts.decryptionKeySalt), + sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, + sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, + sodium.crypto_pwhash_ALG_DEFAULT + ); + + const rawDecryptionMasterKey = sodium.crypto_secretbox_open_easy( + sodium.from_base64(loginJson.masterKeyCipher), + sodium.from_base64(loginJson.masterKeyNonce), + rawDecryptionKey + ); + + rawMasterKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); + + return true; +} diff --git a/materialious/src/lib/api/backend/keyvalue.ts b/materialious/src/lib/api/backend/keyvalue.ts new file mode 100644 index 00000000..695ef00f --- /dev/null +++ b/materialious/src/lib/api/backend/keyvalue.ts @@ -0,0 +1,35 @@ +import { decryptWithMasterKey, encryptWithMasterKey } from './encryption'; + +export async function addOrUpdateKeyValue(key: string, value: string) { + const valueEncrypted = await encryptWithMasterKey(value); + + await fetch(`/api/user/keyValue/${key}`, { + method: 'POST', + credentials: 'same-origin', + body: JSON.stringify({ + valueCipher: valueEncrypted?.cipher, + valueNonce: valueEncrypted?.nonce + }) + }); +} + +export async function deleteKeyValue(key: string) { + await fetch(`/api/user/keyValue/${key}`, { + method: 'DELETE', + credentials: 'same-origin' + }); +} + +export type KeyValue = boolean | number | string[] | string | object | undefined; + +export async function getKeyValue(key: string): Promise { + const resp = await fetch(`/api/user/keyValue/${key}`, { + method: 'GET', + credentials: 'same-origin' + }); + + if (!resp.ok) return null; + + const respJson = await resp.json(); + return (await decryptWithMasterKey(respJson.valueNonce, respJson.valueCipher)) ?? null; +} diff --git a/materialious/src/lib/api/backend/subscriptions.ts b/materialious/src/lib/api/backend/subscriptions.ts new file mode 100644 index 00000000..248a07f5 --- /dev/null +++ b/materialious/src/lib/api/backend/subscriptions.ts @@ -0,0 +1,99 @@ +import { parseChannelRSS } from '$lib/api/youtubejs/subscriptions'; +import { getChannelYTjs } from '$lib/api/youtubejs/channel'; +import type { ChannelSubscriptions } from '$lib/dexie'; +import { decryptWithMasterKey, encryptWithMasterKey, getRawKey, getSecureHash } from './encryption'; + +export async function getSubscriptionsBackend(): Promise { + const resp = await fetch(`/api/user/subscriptions`, { + method: 'GET', + credentials: 'same-origin' + }); + + if (!resp.ok) return []; + + const subscriptions: ChannelSubscriptions[] = []; + + const respJson = await resp.json(); + + for (const sub of respJson.subscriptions) { + subscriptions.push({ + channelName: (await decryptWithMasterKey(sub.channelNameNonce, sub.channelNameCipher)) ?? '', + channelId: (await decryptWithMasterKey(sub.channelIdNonce, sub.channelIdCipher)) ?? '', + lastRSSFetch: new Date(sub.lastRSSFetch) + }); + } + + return subscriptions; +} + +export async function updateRSSLastUpdated(authorId: string) { + const rawKey = await getRawKey(); + if (!rawKey) return false; + + const internalAuthorId = await getSecureHash(authorId, rawKey); + + await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'PATCH', + credentials: 'same-origin' + }); +} + +export async function amSubscribedBackend(authorId: string): Promise { + const rawKey = await getRawKey(); + if (!rawKey) return false; + + const internalAuthorId = await getSecureHash(authorId, rawKey); + + const resp = await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'GET', + credentials: 'same-origin' + }); + if (!resp.ok) return false; + + const respJson = await resp.json(); + + return respJson.amSubscribed; +} + +export async function deleteUnsubscribeBackend(authorId: string) { + const rawKey = await getRawKey(); + if (!rawKey) return false; + + const internalAuthorId = await getSecureHash(authorId, rawKey); + + await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'DELETE', + credentials: 'same-origin' + }); +} + +export async function postSubscribeBackend( + authorId: string, + authorName: string | undefined = undefined +) { + const rawKey = await getRawKey(); + if (!rawKey) return; + + const internalAuthorId = await getSecureHash(authorId, rawKey); + + if (!authorName) { + const channel = await getChannelYTjs(authorId); + authorName = channel.author; + } + + const channelId = await encryptWithMasterKey(authorId); + const channelName = await encryptWithMasterKey(authorName); + + const resp = await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'POST', + body: JSON.stringify({ + channelIdCipher: channelId?.cipher, + channelIdNonce: channelId?.nonce, + channelNameCipher: channelName?.cipher, + channelNameNonce: channelName?.nonce + }), + credentials: 'same-origin' + }); + + if (resp.ok) parseChannelRSS(authorId); +} diff --git a/materialious/src/lib/api/index.ts b/materialious/src/lib/api/index.ts index 3b567109..434816a2 100644 --- a/materialious/src/lib/api/index.ts +++ b/materialious/src/lib/api/index.ts @@ -21,7 +21,6 @@ import type { ReturnYTDislikes, SearchSuggestion, Subscription, - ApiExntendedProgressModel, Video, VideoPlay, SearchOptions, @@ -51,7 +50,7 @@ import { deleteUnsubscribeBackend, getSubscriptionsBackend, postSubscribeBackend -} from './backend'; +} from './backend/subscriptions'; import { getUserLocale } from '$lib/i18n'; export function buildPath(path: string): URL { diff --git a/materialious/src/lib/api/youtubejs/subscriptions.ts b/materialious/src/lib/api/youtubejs/subscriptions.ts index 7853634e..57e28f44 100644 --- a/materialious/src/lib/api/youtubejs/subscriptions.ts +++ b/materialious/src/lib/api/youtubejs/subscriptions.ts @@ -10,7 +10,7 @@ import { engineMaxConcurrentChannelsStore, rawMasterKeyStore } from '$lib/store'; -import { getSubscriptionsBackend } from '../backend'; +import { getSubscriptionsBackend } from '../backend/subscriptions'; export async function getSubscriptionsYTjs(): Promise { const subscriptions: Subscription[] = []; diff --git a/materialious/src/lib/components/settings/Engine.svelte b/materialious/src/lib/components/settings/Engine.svelte index d34cc84d..2c81fa92 100644 --- a/materialious/src/lib/components/settings/Engine.svelte +++ b/materialious/src/lib/components/settings/Engine.svelte @@ -16,7 +16,7 @@ import { postSubscribeYTjs } from '$lib/api/youtubejs/subscriptions'; import { addToast } from '../Toast.svelte'; import { isOwnBackend } from '$lib/shared'; - import { postSubscribeBackend } from '$lib/api/backend'; + import { postSubscribeBackend } from '$lib/api/backend/subscriptions'; const engineFallbacks: EngineFallback[] = [ 'Channel', diff --git a/materialious/src/lib/externalSettings/index.ts b/materialious/src/lib/externalSettings/index.ts index 3c3802f3..468810c6 100644 --- a/materialious/src/lib/externalSettings/index.ts +++ b/materialious/src/lib/externalSettings/index.ts @@ -5,7 +5,7 @@ import { z } from 'zod'; import { persistedStores } from './settings'; import { isOwnBackend } from '$lib/shared'; -import { addOrUpdateKeyValue, getKeyValue } from '$lib/api/backend'; +import { addOrUpdateKeyValue, getKeyValue } from '$lib/api/backend/keyvalue'; import { rawMasterKeyStore } from '$lib/store'; import { getPublicEnv } from '$lib/misc'; diff --git a/materialious/src/lib/watch.ts b/materialious/src/lib/watch.ts index 7de56282..5c34eeb2 100644 --- a/materialious/src/lib/watch.ts +++ b/materialious/src/lib/watch.ts @@ -19,7 +19,7 @@ import { error } from '@sveltejs/kit'; import { get } from 'svelte/store'; import { _ } from './i18n'; import { isOwnBackend } from './shared'; -import { saveWatchHistory } from './api/backend'; +import { saveWatchHistory } from './api/backend/history'; export async function getWatchDetails(videoId: string, url: URL) { const playerStateRetrieved = get(playerState);