From 2aaf0475a03f771904cec84b101f43f135b9fdc5 Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Sun, 14 Jan 2024 19:51:08 +0000 Subject: [PATCH 1/8] =?UTF-8?q?[=F0=9F=92=A5]=20Custom=20virtual=20filesys?= =?UTF-8?q?tem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 1 - package.json | 2 +- src/builtin/apps/editor.ts | 4 +- src/builtin/apps/files.ts | 190 ++++++++-------- src/builtin/apps/settings.ts | 5 +- src/builtin/apps/store.ts | 32 ++- src/filer-types.ts | 171 --------------- src/fs.ts | 414 +++++++++++++++++++++++++++++++++++ src/index.ts | 52 +---- src/instances/Flow.ts | 21 +- src/utils.ts | 3 +- 11 files changed, 546 insertions(+), 349 deletions(-) delete mode 100644 src/filer-types.ts create mode 100644 src/fs.ts diff --git a/index.html b/index.html index d1730f7..1ad808a 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,6 @@ - diff --git a/package.json b/package.json index a8def40..4fbf157 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowos", - "version": "1.0.0", + "version": "1.0.0-indev.0", "description": "The most aesthetic webOS.", "main": "src/index.ts", "scripts": { diff --git a/src/builtin/apps/editor.ts b/src/builtin/apps/editor.ts index 5f08f77..98b0f3a 100644 --- a/src/builtin/apps/editor.ts +++ b/src/builtin/apps/editor.ts @@ -146,7 +146,7 @@ export default class EditorApp implements App { const fileExtension = data.path.split('.').pop()?.toLowerCase() as string const language = fileLanguageMap[fileExtension] ?? 'text' - const value = (await window.fs.promises.readFile(data.path)).toString() + const value = Buffer.from(await window.fs.readFile(data.path)).toString() const editor = fullEditor( win.content.querySelector('.editor') as HTMLElement, { @@ -191,7 +191,7 @@ export default class EditorApp implements App { editor.extensions.searchWidget?.open() } (win.content.querySelector('#save') as HTMLElement).onclick = async () => { - await window.fs.promises.writeFile(data.path, editor.value) + await window.fs.writeFile(data.path, editor.value) } } else { await window.flow.openApp('flow.files') diff --git a/src/builtin/apps/files.ts b/src/builtin/apps/files.ts index 770e0f5..ca76156 100644 --- a/src/builtin/apps/files.ts +++ b/src/builtin/apps/files.ts @@ -3,8 +3,6 @@ import { App } from '../../types' import FlowWindow from '../../structures/FlowWindow' -import { Stats } from 'fs' - export default class FilesApp implements App { meta = { name: 'Files', @@ -26,10 +24,10 @@ export default class FilesApp implements App { win.content.style.flexDirection = 'column' async function setDir (dir: string): Promise { - await window.fs.readdir(dir, (e: NodeJS.ErrnoException, files: string[]) => { - const back = dir === '/' ? 'first_page' : 'chevron_left' + const files = await window.fs.readdir(dir) + const back = dir === '/' ? 'first_page' : 'chevron_left' - win.content.innerHTML = ` + win.content.innerHTML = `
${back}${dir}
@@ -38,110 +36,104 @@ export default class FilesApp implements App {
` - if (back !== 'first_page') { - (win.content.querySelector('.back') as HTMLElement).onclick = async () => { - if (dir.split('/')[1] === dir.replace('/', '')) { - await setDir(`/${dir.split('/')[0]}`) - } else { - await setDir(`/${dir.split('/')[1]}`) + if (back !== 'first_page') { + (win.content.querySelector('.back') as HTMLElement).onclick = async () => { + await setDir(dir.split('/').slice(0, -1).join('/')) + } + } + + (win.content.querySelector('.file') as HTMLElement).onclick = async () => { + const title: string = prompt('Enter file name') ?? 'new-file.txt' + await window.fs.writeFile(`${dir}/${title}`, '') + await setDir(dir) + } + + (win.content.querySelector('.folder') as HTMLElement).onclick = async () => { + const title: string = prompt('Enter folder name') ?? 'new-folder' + await window.fs.mkdir(`${dir}/${title}`) + await setDir(dir) + } + + for (const file of files) { + const seperator = dir === '/' ? '' : '/' + const fileStat = await window.fs.stat(dir + seperator + file) + const element = document.createElement('div') + element.setAttribute('style', 'display: flex;gap: 5px;align-items:center;padding: 5px;border-bottom: 1px solid var(--text);display:flex;align-items:center;gap: 5px;') + + const genIcon = (): string => { + switch (file.split('.').at(-1)) { + case 'js': + case 'mjs': + case 'cjs': { + return 'javascript' + } + + case 'html': + case 'htm': { + return 'html' + } + + case 'css': { + return 'css' + } + + case 'json': { + return 'code' + } + + case 'md': { + return 'markdown' + } + + case 'txt': + case 'text': { + return 'description' + } + + case 'png': + case 'apng': + case 'jpg': + case 'jpeg': + case 'gif': { + return 'image' + } + + default: { + return 'draft' } } } + const icon = fileStat.isDirectory() ? 'folder' : genIcon() - (win.content.querySelector('.file') as HTMLElement).onclick = async () => { - const title: string = prompt('Enter file name') ?? 'new-file.txt' - await window.fs.promises.open(`${dir}/${title}`, 'w') + element.innerHTML += `${icon} ${file}delete_foreveredit`; + (element.querySelector('.rename') as HTMLElement).onclick = async () => { + const value = (prompt('Rename') as string) + if (value !== null || value !== undefined) { + await window.fs.rename(dir + seperator + file, dir + seperator + value) + await setDir(dir) + } + } + (element.querySelector('.delete') as HTMLElement).onclick = async () => { + if (fileStat.isDirectory()) { + await window.fs.rmdir(dir + seperator + file) + } else { + await window.fs.unlink(dir + seperator + file) + } await setDir(dir) } - - (win.content.querySelector('.folder') as HTMLElement).onclick = async () => { - const title: string = prompt('Enter folder name') ?? 'new-folder' - await window.fs.promises.mkdir(`${dir}/${title}`) - await setDir(dir) + element.ondblclick = async () => { + if (fileStat.isDirectory()) { + await setDir(dir + seperator + file) + } else { + await window.flow.openApp('flow.editor', { path: dir + seperator + file }) + } } - for (const file of files) { - const separator = dir === '/' ? '' : '/' - window.fs.stat(dir + separator + file, (e: NodeJS.ErrnoException, fileStat: Stats) => { - const element = document.createElement('div') - element.setAttribute('style', 'display: flex;gap: 5px;align-items:center;padding: 5px;border-bottom: 1px solid var(--text);display:flex;align-items:center;gap: 5px;') - - const genIcon = (): string => { - switch (file.split('.').at(-1)) { - case 'js': - case 'mjs': - case 'cjs': { - return 'javascript' - } - - case 'html': - case 'htm': { - return 'html' - } - - case 'css': { - return 'css' - } - - case 'json': { - return 'code' - } - - case 'md': { - return 'markdown' - } - - case 'txt': - case 'text': { - return 'description' - } - - case 'png': - case 'apng': - case 'jpg': - case 'jpeg': - case 'gif': { - return 'image' - } - - default: { - return 'draft' - } - } - } - const icon = fileStat.isDirectory() ? 'folder' : genIcon() - - element.innerHTML += `${icon} ${file}delete_foreveredit`; - (element.querySelector('.rename') as HTMLElement).onclick = async () => { - const value = (prompt('Rename') as string) - if (value !== null || value !== undefined) { - await window.fs.promises.rename(dir + separator + file, dir + separator + value) - await setDir(dir) - } - } - (element.querySelector('.delete') as HTMLElement).onclick = async () => { - if (fileStat.isDirectory()) { - await window.fs.rmdir(dir + separator + file, () => {}) - } else { - await window.fs.promises.unlink(dir + separator + file) - } - await setDir(dir) - } - element.ondblclick = async () => { - if (fileStat.isDirectory()) { - await setDir(dir + separator + file) - } else { - await window.flow.openApp('flow.editor', { path: dir + separator + file }) - } - } - - win.content.querySelector('.files')?.appendChild(element) - }) - } - }) + win.content.querySelector('.files')?.appendChild(element) + } } - await setDir('/') + await setDir('/home') return win } diff --git a/src/builtin/apps/settings.ts b/src/builtin/apps/settings.ts index c911052..bee65ea 100644 --- a/src/builtin/apps/settings.ts +++ b/src/builtin/apps/settings.ts @@ -57,7 +57,8 @@ export default class SettingsApp implements App { '24HR_CLOCK': '24hr Clock' } - const config = await window.config() + // TODO: settings + const config = {} for (const key of Object.keys(config)) { const container = document.createElement('div') @@ -87,7 +88,7 @@ export default class SettingsApp implements App { } win.content.querySelector('.save')?.addEventListener('click', () => { - window.fs.promises.writeFile('/.config/flow.json', JSON.stringify(config)) + window.fs.writeFile('/.config/flow.json', JSON.stringify(config)) .then(null) .catch(e => console.error(e)) }) diff --git a/src/builtin/apps/store.ts b/src/builtin/apps/store.ts index 68f4769..5fc55a8 100644 --- a/src/builtin/apps/store.ts +++ b/src/builtin/apps/store.ts @@ -23,9 +23,8 @@ export default class MusicApp implements App { win.content.style.background = 'var(--base)' - const config = await window.config() - - fetch(config.SERVER_URL + '/apps/list/') + // TODO: Allow customization of server URL + fetch('https://server.flow-works.me' + '/apps/list/') .then(async (res) => await res.json()) .then(handle) .catch(e => console.error(e)) @@ -61,38 +60,33 @@ export default class MusicApp implements App {
` - window.fs.exists(`/Applications/${app.url.split('/').at(-1) as string}`, (exists) => { + window.fs.exists(`/home/Applications/${app.url.split('/').at(-1) as string}`).then((exists) => { if (exists) { (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).innerHTML = 'delete'; - (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => { - window.fs.unlink(`/Applications/${app.url.split('/').at(-1) as string}`, () => { - window.location.reload() - }) + (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = async () => { + await window.fs.unlink(`/Applications/${app.url.split('/').at(-1) as string}`) + window.location.reload() } } else { (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => { install(app.url) } } - }); - - (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => { - install(app.url) - } + }).catch(e => console.error(e)) }) }) } function install (url: string): void { fetch(url).then(async (res) => await res.text()) - .then((data) => { - window.fs.exists('/Applications', (exists) => { - if (!exists) window.fs.promises.mkdir('/Applications').catch(console.error) + .then(async (data) => { + const exists = await window.fs.exists('/home/Applications') - window.fs.promises.writeFile(`/Applications/${url.split('/').at(-1) as string}`, data).then(() => window.location.reload()).catch(console.error) - }) - }).catch(console.error) + if (!exists) window.fs.mkdir('/home/Applications').catch(console.error) + + window.fs.writeFile(`/home/Applications/${url.split('/').at(-1) as string}`, data).then(() => window.location.reload()).catch(console.error) + }).catch(e => console.error(e)) } return win diff --git a/src/filer-types.ts b/src/filer-types.ts deleted file mode 100644 index 7358753..0000000 --- a/src/filer-types.ts +++ /dev/null @@ -1,171 +0,0 @@ -import * as fs from 'fs' -import { PlatformPath } from 'path' - -export interface Path extends PlatformPath { - basename: (path: string, suffix?: string | undefined) => string - normalize: (path: string) => string - isNull: (path: string) => boolean - addTrailing: (path: string) => string - removeTrailing: (path: string) => string -} - -interface FilerError extends Error { - code: string - errno: number - path?: string -} - -export interface Errors { - EACCES: FilerError - EBADF: FilerError - EBUSY: FilerError - EINVAL: FilerError - ENOTDIR: FilerError - EISDIR: FilerError - ENOENT: FilerError - EEXIST: FilerError - EPERM: FilerError - ELOOP: FilerError - ENOTEMPTY: FilerError - EIO: FilerError - ENOTMOUNTED: FilerError - EFILESYSTEMERROR: FilerError - ENOATTR: FilerError -} - -export type FileSystemOptionsFlags = 'FORMAT' | 'NOCTIME' | 'NOMTIME' - -export interface FileSystemOptions { - name: string - flags: FileSystemOptionsFlags[] - /* TO-DO */ - provider: any -} - -export type FileSystemCallback = (err: FilerError | null, fs: FileSystem) => {} - -export interface FileSystem { - appendFile: typeof fs.appendFile - access: typeof fs.access - chown: typeof fs.chown - chmod: typeof fs.chmod - close: typeof fs.close - exists: typeof fs.exists - fchown: typeof fs.fchown - fchmod: typeof fs.fchmod - fstat: typeof fs.fstat - fsync: typeof fs.fsync - ftruncate: typeof fs.ftruncate - futimes: typeof fs.futimes - link: typeof fs.link - lstat: typeof fs.lstat - mkdir: typeof fs.mkdir - mkdtemp: typeof fs.mkdtemp - open: typeof fs.open - readdir: typeof fs.readdir - read: typeof fs.read - readFile: typeof fs.readFile - readlink: typeof fs.readlink - rename: typeof fs.rename - rmdir: typeof fs.rmdir - stat: typeof fs.stat - symlink: typeof fs.symlink - truncate: typeof fs.truncate - unlink: typeof fs.unlink - utimes: typeof fs.utimes - writeFile: typeof fs.writeFile - write: typeof fs.write - - promises: FileSystemPromises -} - -export interface FileSystemPromises { - appendFile: typeof fs.promises.appendFile - access: typeof fs.promises.access - chown: typeof fs.promises.chown - chmod: typeof fs.promises.chmod - link: typeof fs.promises.link - lstat: typeof fs.promises.lstat - mkdir: typeof fs.promises.mkdir - mkdtemp: typeof fs.promises.mkdtemp - open: typeof fs.promises.open - readdir: typeof fs.promises.readdir - readFile: typeof fs.promises.readFile - readlink: typeof fs.promises.readlink - rename: typeof fs.promises.rename - rmdir: typeof fs.promises.rmdir - stat: typeof fs.promises.stat - symlink: typeof fs.promises.symlink - truncate: typeof fs.promises.truncate - unlink: typeof fs.promises.unlink - utimes: typeof fs.promises.utimes - writeFile: typeof fs.promises.writeFile -} - -export interface FileSystemShell { - cd: (path: string, callback: (err: FilerError | null) => void) => void - pwd: () => string - find: ( - dir: string, - options: { - exec?: (path: string, next: () => void) => void - regex?: RegExp - name?: string - } | ((err: FilerError | null, found: any[]) => void) | undefined | null, - /* INCOMPLETE? */ - callback: (err: FilerError | null, found: any[]) => void - ) => void - ls: ( - dir: string, - options: { - recursive?: boolean - } | ((err: FilerError | null) => void) | undefined | null, - callback: (err: FilerError | null) => void - ) => void - exec: ( - path: string, - args: Array | ((err: FilerError | null, result: string) => void) | undefined | null, - callback: (err: FilerError | null, result: string) => void - ) => void - touch: ( - path: string, - options: { - updateOnly?: boolean - date: Date - } | ((err: FilerError | null) => void) | undefined | null, - callback: (err: FilerError | null) => void - ) => void - cat: ( - files: string[], - callback: (err: FilerError | null, data: string) => void - ) => void - rm: ( - path: string, - options: { - recursive?: boolean - } | ((err: FilerError | null) => void) | undefined | null, - callback: (err: FilerError | null) => void - ) => void - tempDir: ( - callback: (err: FilerError | null, tmp: string) => void - ) => void - mkdirp: ( - path: string, - callback: (err: FilerError | null) => void - ) => void -} - -export interface FileSystemShellOptions { - env: { - [key: string]: string - } -} - -export default interface Filer { - FileSystem: (options: FileSystemOptions, callback: (err: FilerError | null, guid: string) => void) => FileSystem - Buffer: Buffer - Path: Path - path: Path - Errors: Errors - Shell: (fs: FileSystem, options: FileSystemShellOptions) => FileSystemShell -} diff --git a/src/fs.ts b/src/fs.ts new file mode 100644 index 0000000..3f82d1f --- /dev/null +++ b/src/fs.ts @@ -0,0 +1,414 @@ +export enum Errors { + ENOENT = 'ENOENT', + EISDIR = 'EISDIR', + EEXIST = 'EEXIST', + EPERM = 'EPERM', + ENOTDIR = 'ENOTDIR', + EACCES = 'EACCES' +} + +export enum Permission { + ROOT, + ADMIN, + USER +} + +export interface Directory { + type: 'directory' + permission: Permission + children: { + [key: string]: Directory | File + } +} + +export interface File { + type: 'file' + permission: Permission + content: Buffer +} + +const defaultFS: { root: Directory } = { + root: { + type: 'directory', + permission: Permission.ROOT, + children: { + home: { + type: 'directory', + permission: Permission.ROOT, + children: { + Downloads: { + type: 'directory', + permission: Permission.ADMIN, + children: {} + }, + Applications: { + type: 'directory', + permission: Permission.ADMIN, + children: {} + }, + Desktop: { + type: 'directory', + permission: Permission.ADMIN, + children: { + 'README.md': { + type: 'file', + permission: Permission.USER, + content: Buffer.from('# Welcome to FlowOS!') + } + } + }, + Pictures: { + type: 'directory', + permission: Permission.ADMIN, + children: {} + }, + Videos: { + type: 'directory', + permission: Permission.ADMIN, + children: {} + }, + Documents: { + type: 'directory', + permission: Permission.ADMIN, + children: {} + }, + Music: { + type: 'directory', + permission: Permission.ADMIN, + children: {} + } + } + }, + var: { + type: 'directory', + permission: Permission.ROOT, + children: {} + }, + etc: { + type: 'directory', + permission: Permission.ROOT, + children: {} + }, + boot: { + type: 'directory', + permission: Permission.ROOT, + children: {} + } + } + } +} + +export class VirtualFS { + private db: IDBDatabase + private fileSystem: { root: Directory } + + constructor (dbName = 'virtualfs') { + this.initializeDatabase(dbName) + .then(async () => { + this.db.onerror = (event: Event) => { + const target = event.target as IDBRequest + const errorMessage = target.error !== null ? target.error.message : 'Unknown error' + throw new Error(`[VirtualFS] ${target.error?.name ?? 'Unknown Error'}: ${errorMessage}`) + } + navigator.storage.persist().catch(e => console.error(e)) + const fs = await this.read() + fs === undefined ? await this.write(defaultFS) : this.fileSystem = fs + console.log('[VirtualFS] Database initialized') + }) + .catch(e => console.error(e)) + } + + /** + * The function initializes a database using IndexedDB in TypeScript. + * @param {string} dbName - The `dbName` parameter is a string that represents the name of the + * database that you want to initialize. + * @returns a Promise. + */ + private async initializeDatabase (dbName: string): Promise { + return await new Promise((resolve, reject) => { + const request = window.indexedDB.open(dbName) + + request.onupgradeneeded = (event: Event) => { + const target = event.target as IDBRequest + const db = target.result + db.createObjectStore('fs') + } + + request.onerror = (event: Event) => { + reject(new Error('[VirtualFS] Error opening database.')) + } + + request.onsuccess = () => { + this.db = request.result + resolve(true) + } + }) + } + + /** + * The function reads data from an object store in a transaction and returns a promise that resolves + * with the result. + * @returns a Promise that resolves to the result of the `getRequest` operation. + */ + private async read (): Promise { + const transaction = this.db.transaction(['fs'], 'readonly') + const store = transaction.objectStore('fs') + const getRequest = store.get('fs') + + return await new Promise((resolve, reject) => { + getRequest.onsuccess = () => { + resolve(getRequest.result) + } + + getRequest.onerror = () => { + reject(getRequest.error) + } + }) + } + + /** + * The `write` function is a private asynchronous method that takes a `fileSystem` object as a + * parameter, sets it as the current file system, and then saves it. + * @param fileSystem - The `fileSystem` parameter is an object that represents the file system. It + * has a property `root` which is a `Directory` object representing the root directory of the file + * system. + */ + private async write (fileSystem: { root: Directory }): Promise { + this.fileSystem = fileSystem + await this.save() + } + + private async save (): Promise { + const transaction = this.db.transaction(['fs'], 'readwrite') + const store = transaction.objectStore('fs') + const putRequest = store.put(this.fileSystem, 'fs') + + return await new Promise((resolve, reject) => { + putRequest.onsuccess = () => { + resolve() + } + + putRequest.onerror = () => { + reject(putRequest.error) + } + }) + } + + /** + * The function handles permissions for a given path and permission level, throwing an error if the + * current permission level is higher than the requested permission level. + * @param {string} path - A string representing the path to a resource or file. + * @param {Permission} permission - The `permission` parameter is of type `Permission`, which is an + * enum representing different levels of permissions. It is used to determine if the current user has + * sufficient permissions to access a certain path. + */ + private async handlePermissions (path: string, permission: Permission): Promise { + const { current } = await this.navigatePath(path) + + if (current.permission === Permission.ADMIN && current.permission <= permission) throw new Error(Errors.EACCES) + if (current.permission === Permission.ROOT && current.permission <= permission) throw new Error(Errors.EPERM) + } + + /** + * The function `navigatePath` takes a path as input and returns the current directory or file object + * and the individual parts of the path. + * @param {string} path - A string representing the path to navigate in the file system. + * @returns an object with two properties: "current" and "parts". The "current" property represents + * the current directory or file that was navigated to based on the given path. The "parts" property + * is an array of strings representing the individual parts of the path. + */ + private async navigatePath (path: string): Promise<{ current: Directory | File, parts: string[] }> { + const parts = path.split('/').filter(x => x !== '') + let current = this.fileSystem.root + for (const part of parts) { + current = current.children[part] as Directory + } + return { current, parts } + } + + /** + * The function `navigatePathParent` takes a path as input and returns the current directory, the + * parts of the path, and the filename. + * @param {string} path - The `path` parameter is a string that represents the file path. It is used + * to navigate through the file system and locate a specific file or directory. + * @returns an object with three properties: "current", "parts", and "filename". + */ + private async navigatePathParent (path: string): Promise<{ current: Directory, parts: string[], filename: string }> { + const parts = path.split('/').filter(x => x !== '') + const filename = parts.pop() as string + let current = this.fileSystem.root + for (const part of parts) { + current = current.children[part] as Directory + } + return { current, parts, filename } + } + + /** + * The `unlink` function deletes a file from a given path and saves the changes. + * @param {string} path - The `path` parameter is a string that represents the file or directory path + * that you want to unlink (delete). + * @param permission - The `permission` parameter is an optional parameter that specifies the level + * of permission required to perform the unlink operation. It has a default value of + * `Permission.USER`, which means that the operation can be performed by the user. + */ + async unlink (path: string, permission = Permission.USER): Promise { + const { current, filename } = await this.navigatePathParent(path) + + await this.handlePermissions(path, permission) + + Reflect.deleteProperty(current.children, filename) + await this.save() + } + + /** + * The function reads a file from a given path and returns its content as a Buffer. + * @param {string} path - The `path` parameter is a string that represents the file path of the file + * to be read. It specifies the location of the file in the file system. + * @param permission - The `permission` parameter is an optional parameter that specifies the + * permission level required to read the file. It has a default value of `Permission.USER`, which + * means that the file can be read by the current user. + * @returns a Promise that resolves to a Buffer. + */ + async readFile (path: string, permission = Permission.USER): Promise { + const { current } = await this.navigatePath(path) + + await this.handlePermissions(path, permission) + + if (current.type !== 'file') throw new Error(Errors.EISDIR) + return current.content + } + + /** + * The `writeFile` function writes content to a file at a specified path, with an optional permission + * parameter. + * @param {string} path - The `path` parameter is a string that represents the file path where the + * file will be written to. + * @param {string | Buffer} content - The `content` parameter is the data that you want to write to + * the file. It can be either a string or a Buffer object. + * @param permission - The `permission` parameter is an optional parameter that specifies the + * permission level for the file being written. It has a default value of `Permission.USER`, which + * indicates that the file can be accessed and modified only by the user who wrote it. + */ + async writeFile (path: string, content: string | Buffer, permission = Permission.USER): Promise { + const { current, filename } = await this.navigatePathParent(path) + + await this.handlePermissions(path, permission) + + current.children[filename] = { + type: 'file', + permission: Permission.USER, + content: Buffer.from(content) + } + await this.save() + } + + /** + * The `mkdir` function creates a new directory at the specified path with the given permission. + * @param {string} path - The `path` parameter is a string that represents the directory path where + * the new directory will be created. It specifies the location where the new directory will be + * created. + * @param permission - The `permission` parameter is an optional parameter that specifies the + * permission level for the newly created directory. It has a default value of `Permission.USER`, + * which indicates that only the user has permission to access the directory. + */ + async mkdir (path: string, permission = Permission.USER): Promise { + const { current, filename } = await this.navigatePathParent(path) + + await this.handlePermissions(path, permission) + + current.children[filename] = { + type: 'directory', + permission: Permission.USER, + children: {} + } + await this.save() + } + + /** + * The `rmdir` function removes a directory at the specified path, after checking permissions and + * ensuring that the path is a directory. + * @param {string} path - The `path` parameter is a string that represents the path of the directory + * to be removed. + * @param permission - The `permission` parameter is an optional parameter that specifies the level + * of permission required to remove a directory. It has a default value of `Permission.USER`, which + * means that the user must have permission to remove the directory. + */ + async rmdir (path: string, permission = Permission.USER): Promise { + const { current, filename } = await this.navigatePathParent(path) + + await this.handlePermissions(path, permission) + + if (current.children[filename].type !== 'directory') throw new Error(Errors.ENOTDIR) + Reflect.deleteProperty(current.children, filename) + await this.save() + } + + /** + * The `readdir` function reads the contents of a directory and returns an array of file names. + * @param {string} path - The `path` parameter is a string that represents the directory path from + * which you want to read the files. + * @param permission - The `permission` parameter is an optional parameter that specifies the + * permission level for accessing the directory. It has a default value of `Permission.USER`. + * @returns The function `readdir` returns a Promise that resolves to an array of strings. + */ + async readdir (path: string, permission = Permission.USER): Promise { + console.log(this.fileSystem) + const { current } = await this.navigatePath(path) + + if (current.type === 'file') throw new Error(Errors.ENOTDIR) + const result = await Promise.all(Object.keys(current.children ?? {})) + return result + } + + /** + * The `stat` function in TypeScript returns an object with two methods, `isDirectory` and `isFile`, + * which determine if a given path is a directory or a file, respectively. + * @param {string} path - A string representing the path to a file or directory. + * @param permission - The `permission` parameter is an optional parameter that specifies the + * permission level for accessing the file or directory. It has a default value of `Permission.USER`, + * which means that the function will check the permission level for the current user. + * @returns an object with two methods: `isDirectory` and `isFile`. + */ + async stat (path: string, permission = Permission.USER): Promise<{ isDirectory: () => boolean, isFile: () => boolean }> { + const { current } = await this.navigatePath(path) + return { + isDirectory: () => current.type === 'directory', + isFile: () => current.type === 'file' + } + } + + /** + * The `rename` function renames a file or directory by moving it from the old path to the new path, + * while also handling permissions and updating the file system structure. + * @param {string} oldPath - The old path of the file or directory that needs to be renamed. + * @param {string} newPath - The `newPath` parameter is a string that represents the new path or + * location where the file or directory will be renamed to. + * @param permission - The `permission` parameter is an optional parameter that specifies the + * permission level for the file or directory being renamed. It has a default value of + * `Permission.USER`, which indicates that the user has permission to perform the rename operation. + */ + async rename (oldPath: string, newPath: string, permission = Permission.USER): Promise { + const { current: oldCurrent, filename: oldFilename } = await this.navigatePathParent(oldPath) + const { current: newCurrent, filename: newFilename } = await this.navigatePathParent(newPath) + + await this.handlePermissions(oldPath, permission) + await this.handlePermissions(newPath, permission) + + newCurrent.children[newFilename] = oldCurrent.children[oldFilename] + Reflect.deleteProperty(oldCurrent.children, oldFilename) + await this.save() + } + + /** + * The function checks if a file or directory exists at a given path. + * @param {string} path - A string representing the path to check for existence. + * @param permission - The `permission` parameter is an optional parameter that specifies the + * permission level for checking the existence of the path. It has a default value of + * `Permission.USER`. + * @returns a Promise that resolves to a boolean value. + */ + async exists (path: string, permission = Permission.USER): Promise { + const { current } = await this.navigatePath(path) + return current !== undefined + } +} diff --git a/src/index.ts b/src/index.ts index ff95d7c..89b059d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,17 +6,23 @@ import StatusBar from './instances/StatusBar' import WindowManager from './instances/WindowManager' import Flow from './instances/Flow' -import { FileSystem } from './filer-types' -import { FlowConfig } from './types' +import { VirtualFS } from './fs' + +import { version } from '../package.json' + +const flowDetails = { + version, + codename: 'Mochi' +} declare global { interface Window { + flowDetails: typeof flowDetails preloader: Preloader flow: Flow - fs: FileSystem + fs: VirtualFS statusBar: StatusBar wm: WindowManager - config: () => Promise } } @@ -39,47 +45,13 @@ window.wm = new WindowManager(); (async function () { window.preloader.setPending('filesystem') - window.fs = new (window as any).Filer.FileSystem() - - const defaultConfig = { - SERVER_URL: 'https://server.flow-works.me', - HOSTNAME: 'flow', - USERNAME: 'user', - '24HR_CLOCK': false - } - - window.fs.exists('/.config', (exists) => { - if (!exists) window.fs.promises.mkdir('/.config').then(null).catch(e => console.error) - - window.fs.exists('/.config/flow.json', (exists) => { - if (!exists) { - window.fs.promises.writeFile('/.config/flow.json', JSON.stringify(defaultConfig)).then(null).catch(e => console.error) - } - }) - }) - - /** - * Gets the current FlowOS config. - * - * @returns The current FlowOS config. - */ - window.config = async (): Promise => { - return await new Promise((resolve, reject) => { - window.fs.exists('/.config/flow.json', (exists) => { - if (exists) { - window.fs.promises.readFile('/.config/flow.json') - .then(content => { resolve(JSON.parse(content.toString())) }) - .catch(() => reject(new Error('Unable to read config file.'))) - } else reject(new Error('Config file does not exist.')) - }) - }) - } + window.fs = new VirtualFS() const registrations = await navigator.serviceWorker.getRegistrations() for (const registration of registrations) { await registration.unregister() } - await navigator.serviceWorker.register('/uv-sw.js?url=' + encodeURIComponent(btoa((await window.config()).SERVER_URL)), { + await navigator.serviceWorker.register('/uv-sw.js?url=' + encodeURIComponent(btoa('https://server.flow-works.me')), { scope: '/service/' }) diff --git a/src/instances/Flow.ts b/src/instances/Flow.ts index af29e55..63fd54b 100644 --- a/src/instances/Flow.ts +++ b/src/instances/Flow.ts @@ -26,18 +26,15 @@ class Flow { window.preloader.setPending('apps') window.preloader.setStatus('importing apps...') - window.fs.exists('/Applications', (exists) => { - if (!exists) window.fs.promises.mkdir('/Applications').catch(e => console.error(e)) - window.fs.promises.readdir('/Applications').then((list) => { - list.forEach((file) => { - window.fs.promises.readFile('/Applications/' + file).then(content => { - if (!file.endsWith('.js') && !file.endsWith('.mjs')) return - if (content.toString() === '') return - this.appList.push(`data:text/javascript;base64,${btoa(content.toString())}`) - }).catch((e) => console.error(e)) - }) - }).catch(e => console.error(e)) - }) + window.fs.readdir('/home/Applications/').then((list) => { + list.forEach((file) => { + window.fs.readFile('/home/Applications/' + file).then(content => { + if (!file.endsWith('.js') && !file.endsWith('.mjs')) return + if (content.toString() === '') return + this.appList.push(`data:text/javascript;base64,${btoa(content.toString())}`) + }).catch((e) => console.error(e)) + }) + }).catch(e => console.error(e)) for (const appPath of this.defaultAppList) { window.preloader.setStatus(`importing default apps\n${appPath}`) diff --git a/src/utils.ts b/src/utils.ts index 4ae9181..99261d3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,8 +4,7 @@ * @returns The time. */ export const getTime = async (): Promise => { - const config = await window.config() - const use24hrs = config['24HOUR_CLOCK'] + const use24hrs = false const now = new Date() let hours: string | number = now.getHours() From 8de338f8995d508734f04707b3c67ea55f140d6a Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Tue, 16 Jan 2024 04:35:28 +0000 Subject: [PATCH 2/8] =?UTF-8?q?[=F0=9F=92=A5]=20Major=20system=20rewrite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/builtin/apps/info.ts | 39 ++-- src/fs.ts | 89 ++++++--- src/index.ts | 2 +- src/instances/WindowManager.ts | 35 ++++ src/lib.ts | 333 +++++++++++++++++++++++++++++++++ 6 files changed, 463 insertions(+), 37 deletions(-) create mode 100644 src/lib.ts diff --git a/README.md b/README.md index fc690af..3ec857d 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ npm run serve ## Made with FlowOS is made with the following software: -* [Filer](https://github.com/filerjs/filer) +* [Kat21's HTML Library](https://github.com/datkat21/html) * [Prism Code Editor](https://github.com/FIameCaster/prism-code-editor) * [Vite](https://vitejs.dev) * [Ultraviolet](https://github.com/titaniumnetwork-dev/ultraviolet) diff --git a/src/builtin/apps/info.ts b/src/builtin/apps/info.ts index 1aff69a..b661b57 100644 --- a/src/builtin/apps/info.ts +++ b/src/builtin/apps/info.ts @@ -1,8 +1,9 @@ import icon from '../../assets/icons/userinfo.svg' import badge from '../../assets/badge.png' -import { App, PackageJSON } from '../../types' +import { App } from '../../types' import FlowWindow from '../../structures/FlowWindow' +import HTML from '../../lib' export default class InfoApp implements App { meta = { @@ -14,7 +15,6 @@ export default class InfoApp implements App { } async open (): Promise { - const packageJSON: PackageJSON = await import('../../../package.json') const win = window.wm.createWindow({ title: this.meta.name, icon: this.meta.icon, @@ -30,18 +30,29 @@ export default class InfoApp implements App { win.content.style.justifyContent = 'center' win.content.style.alignItems = 'center' win.content.style.background = 'var(--base)' - win.content.innerHTML = ` -
-

FlowOS

-

v${packageJSON.version}

-
-

Created by ThinLiquid, 1nspird_, proudparot2, systemless_

-
- Discord - - - Github -
- ` + + const div = new HTML('div').appendTo(win.content) + new HTML('h1').style({ + margin: '0' + }).text(`FlowOS ${window.flowDetails.codename}`).appendTo(div) + new HTML('p').style({ + margin: '0' + }).text(`v${window.flowDetails.version}`).appendTo(div) + new HTML('br').appendTo(div) + new HTML('img').attr({ + src: badge, + height: '50' + }).appendTo(div) + new HTML('br').appendTo(div) + new HTML('a').text('Discord').attr({ + href: 'https://discord.gg/86F8dK9vfn', + class: 'discord' + }).appendTo(div) + new HTML('span').text(' - ').appendTo(div) + new HTML('a').text('Github').attr({ + href: 'https://github.com/Flow-Works/FlowOS', + class: 'github' + }).appendTo(div) return win } diff --git a/src/fs.ts b/src/fs.ts index 3f82d1f..54dfb1a 100644 --- a/src/fs.ts +++ b/src/fs.ts @@ -8,14 +8,15 @@ export enum Errors { } export enum Permission { - ROOT, - ADMIN, - USER + USER, + ELEVATED, + SYSTEM } export interface Directory { type: 'directory' permission: Permission + deleteable: boolean children: { [key: string]: Directory | File } @@ -24,34 +25,41 @@ export interface Directory { export interface File { type: 'file' permission: Permission + deleteable: boolean content: Buffer } const defaultFS: { root: Directory } = { root: { type: 'directory', - permission: Permission.ROOT, + deleteable: false, + permission: Permission.SYSTEM, children: { home: { type: 'directory', - permission: Permission.ROOT, + deleteable: false, + permission: Permission.SYSTEM, children: { Downloads: { type: 'directory', - permission: Permission.ADMIN, + deleteable: false, + permission: Permission.USER, children: {} }, Applications: { type: 'directory', - permission: Permission.ADMIN, + deleteable: false, + permission: Permission.USER, children: {} }, Desktop: { type: 'directory', - permission: Permission.ADMIN, + deleteable: false, + permission: Permission.USER, children: { 'README.md': { type: 'file', + deleteable: true, permission: Permission.USER, content: Buffer.from('# Welcome to FlowOS!') } @@ -59,39 +67,53 @@ const defaultFS: { root: Directory } = { }, Pictures: { type: 'directory', - permission: Permission.ADMIN, + deleteable: false, + permission: Permission.USER, children: {} }, Videos: { type: 'directory', - permission: Permission.ADMIN, + deleteable: false, + permission: Permission.USER, children: {} }, Documents: { type: 'directory', - permission: Permission.ADMIN, + deleteable: false, + permission: Permission.USER, children: {} }, Music: { type: 'directory', - permission: Permission.ADMIN, + deleteable: false, + permission: Permission.USER, children: {} } } }, var: { type: 'directory', - permission: Permission.ROOT, + deleteable: false, + permission: Permission.SYSTEM, children: {} }, etc: { type: 'directory', - permission: Permission.ROOT, - children: {} + deleteable: false, + permission: Permission.SYSTEM, + children: { + hostname: { + type: 'file', + deleteable: false, + permission: Permission.ELEVATED, + content: Buffer.from('flow') + } + } }, boot: { type: 'directory', - permission: Permission.ROOT, + deleteable: false, + permission: Permission.SYSTEM, children: {} } } @@ -203,10 +225,28 @@ export class VirtualFS { * sufficient permissions to access a certain path. */ private async handlePermissions (path: string, permission: Permission): Promise { - const { current } = await this.navigatePath(path) + let current - if (current.permission === Permission.ADMIN && current.permission <= permission) throw new Error(Errors.EACCES) - if (current.permission === Permission.ROOT && current.permission <= permission) throw new Error(Errors.EPERM) + current = (await this.navigatePath(path)).current + console.log(current) + if (current === undefined) current = (await this.navigatePathParent(path)).current + console.log(current) + + console.log(current.permission, permission) + + if (current.permission === Permission.USER && current.permission < permission) { + const uac = await window.wm.createModal('Elevated Permissions Required', 'You need elevated permissions to perform this operation.') + if (!uac) { + throw new Error(Errors.EACCES) + } + } + if (current.permission === Permission.ELEVATED && current.permission < permission) { + const uac = await window.wm.createModal('Elevated Permissions Required', 'You need elevated permissions to perform this operation.') + if (!uac) { + throw new Error(Errors.EACCES) + } + } + if (current.permission === Permission.SYSTEM && current.permission < permission) throw new Error(Errors.EPERM) } /** @@ -254,6 +294,7 @@ export class VirtualFS { async unlink (path: string, permission = Permission.USER): Promise { const { current, filename } = await this.navigatePathParent(path) + if (!current.children[filename].deleteable) throw new Error(Errors.EPERM) await this.handlePermissions(path, permission) Reflect.deleteProperty(current.children, filename) @@ -296,7 +337,8 @@ export class VirtualFS { current.children[filename] = { type: 'file', - permission: Permission.USER, + deleteable: true, + permission, content: Buffer.from(content) } await this.save() @@ -318,7 +360,8 @@ export class VirtualFS { current.children[filename] = { type: 'directory', - permission: Permission.USER, + deleteable: true, + permission, children: {} } await this.save() @@ -336,6 +379,7 @@ export class VirtualFS { async rmdir (path: string, permission = Permission.USER): Promise { const { current, filename } = await this.navigatePathParent(path) + if (!current.deleteable) throw new Error(Errors.EPERM) await this.handlePermissions(path, permission) if (current.children[filename].type !== 'directory') throw new Error(Errors.ENOTDIR) @@ -391,6 +435,9 @@ export class VirtualFS { const { current: oldCurrent, filename: oldFilename } = await this.navigatePathParent(oldPath) const { current: newCurrent, filename: newFilename } = await this.navigatePathParent(newPath) + if (!oldCurrent.deleteable) throw new Error(Errors.EPERM) + if (!newCurrent.deleteable) throw new Error(Errors.EPERM) + await this.handlePermissions(oldPath, permission) await this.handlePermissions(newPath, permission) diff --git a/src/index.ts b/src/index.ts index 89b059d..bba77f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,6 @@ const flowDetails = { version, codename: 'Mochi' } - declare global { interface Window { flowDetails: typeof flowDetails @@ -38,6 +37,7 @@ if (params.get('debug') !== null && params.get('debug') !== undefined) { enableDebug().catch(e => console.error(e)) } +window.flowDetails = flowDetails window.preloader = new Preloader() window.flow = new Flow() window.statusBar = new StatusBar() diff --git a/src/instances/WindowManager.ts b/src/instances/WindowManager.ts index 37a9094..e7b0524 100644 --- a/src/instances/WindowManager.ts +++ b/src/instances/WindowManager.ts @@ -1,4 +1,5 @@ +import HTML from '../lib' import FlowWindow from '../structures/FlowWindow' import { FlowWindowConfig } from '../types' @@ -43,6 +44,40 @@ class WindowManager { return win } + /** + * Creates a modal window. + * + * @param {string} title - A string representing the title of the modal window. + * @param {string} text - The `text` parameter is a string that represents the content or message to + * be displayed in the modal window. + * @returns The function `createModal` is returning a `FlowWindow` object. + */ + async createModal (title: string, text: string): Promise { + const win = new FlowWindow(this, { + title, + icon: '', + width: 300, + height: 200, + canResize: false + }) + + return await new Promise((resolve) => { + new HTML('h3').text(text).appendTo(win.content) + new HTML('p').text(text).appendTo(win.content) + new HTML('button').text('Allow').appendTo(win.content).on('click', () => { + resolve(true) + win.close() + }) + new HTML('button').text('Allow').appendTo(win.content).on('click', () => { + resolve(false) + win.close() + }) + + this.windows.push(win) + this.windowArea.appendChild(win.element) + }) + } + /** * Toggles the app launcher. */ diff --git a/src/lib.ts b/src/lib.ts new file mode 100644 index 0000000..8a35f69 --- /dev/null +++ b/src/lib.ts @@ -0,0 +1,333 @@ +export default class HTML { + /** The HTML element referenced in this instance. Change using `.swapRef()`, or remove using `.cleanup()`. */ + elm: HTMLInputElement | HTMLElement + /** + * Create a new instance of the HTML class. + * @param elm The HTML element to be created or classified from. + */ + constructor (elm: string | HTMLElement) { + if (elm instanceof HTMLElement) { + this.elm = elm + } else { + this.elm = document.createElement(elm === '' ? 'div' : elm) + } + } + + /** + * Sets the text of the current element. + * @param val The text to set to. + * @returns HTML + */ + text (val: string): HTML { + this.elm.innerText = val + return this + } + + /** + * Sets the text of the current element. + * @param val The text to set to. + * @returns HTML + */ + html (val: string): HTML { + this.elm.innerHTML = val + return this + } + + /** + * Safely remove the element. Can be used in combination with a `.swapRef()` to achieve a "delete & swap" result. + * @returns HTML + */ + cleanup (): HTML { + this.elm.remove() + return this + } + + /** + * querySelector something. + * @param selector The query selector. + * @returns The HTML element (not as HTML) + */ + query (selector: string): HTMLElement | null { + return this.elm.querySelector(selector) + } + + /** + * An easier querySelector method. + * @param query The string to query + * @returns a new HTML + */ + qs (query: string): HTML | null { + if (this.elm.querySelector(query) != null) { + return HTML.from(this.elm.querySelector(query) as HTMLElement) + } else { + return null + } + } + + /** + * An easier querySelectorAll method. + * @param query The string to query + * @returns a new HTML + */ + qsa (query: string): Array | null { + if (this.elm.querySelector(query) != null) { + return Array.from(this.elm.querySelectorAll(query)).map((e) => + HTML.from(e as HTMLElement) + ) + } else { + return null + } + } + + /** + * Sets the ID of the element. + * @param val The ID to set. + * @returns HTML + */ + id (val: string): HTML { + this.elm.id = val + return this + } + + /** + * Toggle on/off a class. + * @param val The class to toggle. + * @returns HTML + */ + class (...val: string[]): HTML { + for (let i = 0; i < val.length; i++) { + this.elm.classList.toggle(val[i]) + } + return this + } + + /** + * Toggles ON a class. + * @param val The class to enable. + * @returns HTML + */ + classOn (...val: string[]): HTML { + for (let i = 0; i < val.length; i++) { + this.elm.classList.add(val[i]) + } + return this + } + + /** + * Toggles OFF a class. + * @param val The class to disable. + * @returns HTML + */ + classOff (...val: string[]): HTML { + for (let i = 0; i < val.length; i++) { + this.elm.classList.remove(val[i]) + } + return this + } + + /** + * Apply CSS styles (dashed method.) Keys use CSS syntax, e.g. `background-color`. + * @param obj The styles to apply (as an object of `key: value;`.) + * @returns HTML + */ + style (obj: { [x: string]: string | null }): HTML { + for (const key of Object.keys(obj)) { + this.elm.style.setProperty(key, obj[key]) + } + return this + } + + /** + * Apply CSS styles (JS method.) Keys use JS syntax, e.g. `backgroundColor`. + * @param obj The styles to apply (as an object of `key: value;`) + * @returns HTML + */ + styleJs (obj: { [key: string]: string | null }): HTML { + for (const key of Object.keys(obj)) { + // @ts-expect-error No other workaround I could find. + this.elm.style[key] = obj[key] + } + return this + } + + /** + * Apply an event listener. + * @param ev The event listener type to add. + * @param cb The event listener callback to add. + * @returns HTML + */ + on (ev: string, cb: EventListenerOrEventListenerObject): HTML { + this.elm.addEventListener(ev, cb) + return this + } + + /** + * Remove an event listener. + * @param ev The event listener type to remove. + * @param cb The event listener callback to remove. + * @returns HTML + */ + un (ev: string, cb: EventListenerOrEventListenerObject): HTML { + this.elm.removeEventListener(ev, cb) + return this + } + + /** + * Append this element to another element. Uses `appendChild()` on the parent. + * @param parent Element to append to. HTMLElement, HTML, and string (as querySelector) are supported. + * @returns HTML + */ + appendTo (parent: HTMLElement | HTML | string): HTML { + if (parent instanceof HTMLElement) { + parent.appendChild(this.elm) + } else if (parent instanceof HTML) { + parent.elm.appendChild(this.elm) + } else if (typeof parent === 'string') { + document.querySelector(parent)?.appendChild(this.elm) + } + return this + } + + /** + * Append an element. Typically used as a `.append(new HTML(...))` call. + * @param elem The element to append. + * @returns HTML + */ + append (elem: string | HTMLElement | HTML): HTML { + if (elem instanceof HTMLElement) { + this.elm.appendChild(elem) + } else if (elem instanceof HTML) { + this.elm.appendChild(elem.elm) + } else if (typeof elem === 'string') { + const newElem = document.createElement(elem) + this.elm.appendChild(newElem) + return new HTML(newElem.tagName) + } + return this + } + + /** + * Append multiple elements. Typically used as a `.appendMany(new HTML(...), new HTML(...)` call. + * @param elements The elements to append. + * @returns HTML + */ + appendMany (...elements: any[]): HTML { + for (const elem of elements) { + this.append(elem) + } + return this + } + + /** + * Clear the innerHTML of the element. + * @returns HTML + */ + clear (): HTML { + this.elm.innerHTML = '' + return this + } + + /** + * Set attributes (object method.) + * @param obj The attributes to set (as an object of `key: value;`) + * @returns HTML + */ + attr (obj: { [x: string]: any }): HTML { + for (const key in obj) { + if (obj[key] !== null && obj[key] !== undefined) { + this.elm.setAttribute(key, obj[key]) + } else { + this.elm.removeAttribute(key) + } + } + return this + } + + /** + * Set the text value of the element. Only works if element is `input` or `textarea`. + * @param str The value to set. + * @returns HTML + */ + val (str: any): HTML { + const x = this.elm as HTMLInputElement + x.value = str + return this + } + + /** + * Retrieve text content from the element. (as innerText, not trimmed) + * @returns string + */ + getText (): string { + return (this.elm as HTMLInputElement).innerText + } + + /** + * Retrieve HTML content from the element. + * @returns string + */ + getHTML (): string { + return (this.elm as HTMLInputElement).innerHTML + } + + /** + * Retrieve the value of the element. Only applicable if it is an `input` or `textarea`. + * @returns string + */ + getValue (): string { + return (this.elm as HTMLInputElement).value + } + + /** + * Swap the local `elm` with a new HTMLElement. + * @param elm The element to swap with. + * @returns HTML + */ + swapRef (elm: HTMLElement): HTML { + this.elm = elm + return this + } + + /** + * An alternative method to create an HTML instance. + * @param elm Element to create from. + * @returns HTML + */ + static from (elm: HTMLElement | string): HTML | null { + if (typeof elm === 'string') { + const element = HTML.qs(elm) + if (element === null) return null + else return element + } else { + return new HTML(elm) + } + } + + /** + * An easier querySelector method. + * @param query The string to query + * @returns a new HTML + */ + static qs (query: string): HTML | null { + if (document.querySelector(query) != null) { + return HTML.from(document.querySelector(query) as HTMLElement) + } else { + return null + } + } + + /** + * An easier querySelectorAll method. + * @param query The string to query + * @returns a new HTML + */ + static qsa (query: string): Array | null { + if (document.querySelector(query) != null) { + return Array.from(document.querySelectorAll(query)).map((e) => + HTML.from(e as HTMLElement) + ) + } else { + return null + } + } +} From 48ae2eab500ac4ab2c02c3b8132992b6419e5452 Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Tue, 16 Jan 2024 05:00:41 +0000 Subject: [PATCH 3/8] =?UTF-8?q?[=F0=9F=9B=81]=20Cleanup=20environment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- package-lock.json | 2120 ++++++----------- package.json | 11 +- public/uv-sw.js | 5 +- public/uv/uv.config.js | 1 - src/{lib.ts => HTML.ts} | 0 src/assets/icons/application-executable.svg | 35 + src/assets/icons/icon-library.svg | 36 + src/assets/icons/org.gnome.Loupe.svg | 1 + src/assets/icons/utilities-system-monitor.svg | 1 + src/builtin/apps/files.ts | 140 -- src/builtin/apps/info.ts | 59 - src/builtin/apps/manager.ts | 55 - src/builtin/apps/music.ts | 27 - src/builtin/apps/settings.ts | 98 - src/builtin/apps/store.ts | 94 - src/builtin/plugins/apps.ts | 33 - src/builtin/plugins/clock.ts | 36 - src/decs.d.ts | 1 + src/fs.ts | 461 ---- src/index.ts | 66 - src/instances/Flow.ts | 166 -- src/instances/Preloader.ts | 70 - src/instances/StatusBar.ts | 187 -- src/instances/WindowManager.ts | 152 -- src/kernel.ts | 141 ++ src/structures/FlowWindow.ts | 29 +- src/structures/LibraryLib.ts | 5 + src/structures/ProcLib.ts | 26 + src/structures/ProcessLib.ts | 123 + src/system/BootLoader.ts | 189 ++ src/system/UserAccessControl.ts | 50 + .../browser.ts => system/apps/Browser.ts} | 91 +- .../apps/editor.ts => system/apps/Editor.ts} | 152 +- src/system/apps/Files.ts | 121 + src/system/apps/ImageViewer.ts | 53 + src/system/apps/Info.ts | 67 + src/system/apps/Manager.ts | 53 + src/system/apps/Settings.ts | 78 + src/system/apps/Store.ts | 100 + src/system/apps/TaskManager.ts | 91 + src/system/lib/Components.ts | 44 + src/system/lib/HTML.ts | 14 + src/system/lib/Launcher.ts | 40 + src/system/lib/MIMETypes.ts | 86 + src/system/lib/SplashScreen.ts | 47 + src/system/lib/StatusBar.ts | 77 + src/system/lib/VirtualFS.ts | 493 ++++ src/system/lib/WindowManager.ts | 90 + src/system/lib/XOR.ts | 46 + src/types.ts | 101 +- vite.config.js | 27 +- 52 files changed, 2992 insertions(+), 3299 deletions(-) rename src/{lib.ts => HTML.ts} (100%) create mode 100644 src/assets/icons/application-executable.svg create mode 100644 src/assets/icons/icon-library.svg create mode 100644 src/assets/icons/org.gnome.Loupe.svg create mode 100644 src/assets/icons/utilities-system-monitor.svg delete mode 100644 src/builtin/apps/files.ts delete mode 100644 src/builtin/apps/info.ts delete mode 100644 src/builtin/apps/manager.ts delete mode 100644 src/builtin/apps/music.ts delete mode 100644 src/builtin/apps/settings.ts delete mode 100644 src/builtin/apps/store.ts delete mode 100644 src/builtin/plugins/apps.ts delete mode 100644 src/builtin/plugins/clock.ts create mode 100644 src/decs.d.ts delete mode 100644 src/fs.ts delete mode 100644 src/index.ts delete mode 100644 src/instances/Flow.ts delete mode 100644 src/instances/Preloader.ts delete mode 100644 src/instances/StatusBar.ts delete mode 100644 src/instances/WindowManager.ts create mode 100644 src/kernel.ts create mode 100644 src/structures/LibraryLib.ts create mode 100644 src/structures/ProcLib.ts create mode 100644 src/structures/ProcessLib.ts create mode 100644 src/system/BootLoader.ts create mode 100644 src/system/UserAccessControl.ts rename src/{builtin/apps/browser.ts => system/apps/Browser.ts} (79%) rename src/{builtin/apps/editor.ts => system/apps/Editor.ts} (53%) create mode 100644 src/system/apps/Files.ts create mode 100644 src/system/apps/ImageViewer.ts create mode 100644 src/system/apps/Info.ts create mode 100644 src/system/apps/Manager.ts create mode 100644 src/system/apps/Settings.ts create mode 100644 src/system/apps/Store.ts create mode 100644 src/system/apps/TaskManager.ts create mode 100644 src/system/lib/Components.ts create mode 100644 src/system/lib/HTML.ts create mode 100644 src/system/lib/Launcher.ts create mode 100644 src/system/lib/MIMETypes.ts create mode 100644 src/system/lib/SplashScreen.ts create mode 100644 src/system/lib/StatusBar.ts create mode 100644 src/system/lib/VirtualFS.ts create mode 100644 src/system/lib/WindowManager.ts create mode 100644 src/system/lib/XOR.ts diff --git a/index.html b/index.html index 1ad808a..62a5c35 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,6 @@ - + diff --git a/package-lock.json b/package-lock.json index 2fbff35..e956061 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,31 +1,32 @@ { "name": "flowos", - "version": "1.0.0", + "version": "1.0.0-indev.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "flowos", - "version": "1.0.0", + "version": "1.0.0-indev.0", "license": "MIT", "dependencies": { - "@ptkdev/logger": "^1.8.0", "eruda": "^3.0.1", - "filer": "^1.4.1", + "js-ini": "^1.6.0", "material-symbols": "^0.14.3", "prism-code-editor": "^2.3.0", + "semver": "^7.5.4", "uuid": "^9.0.1" }, "devDependencies": { - "@types/node": "^20.8.7", + "@types/node": "^20.11.3", "@types/uuid": "^9.0.5", "@types/web": "^0.0.117", "ts-standard": "^12.0.2", "typedoc": "^0.25.3", - "typedoc-material-theme": "^1.0.0", + "typedoc-material-theme": "^1.0.2", "typedoc-plugin-missing-exports": "^2.1.0", "typescript": "^5.2.2", "vite": "^4.4.12", + "vite-plugin-compression": "^0.5.1", "vite-plugin-dynamic-import": "^1.5.0", "vite-plugin-node-polyfills": "^0.15.0" } @@ -407,18 +408,18 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", - "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -438,102 +439,29 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -548,79 +476,17 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@material/material-color-utilities": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.2.7.tgz", @@ -662,21 +528,6 @@ "node": ">= 8" } }, - "node_modules/@ptkdev/logger": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@ptkdev/logger/-/logger-1.8.0.tgz", - "integrity": "sha512-gwg0pleMUyzsZIErDtzz2OP4F2Q3nzRGjhUTP+831/eogq17LpG7PgbHo1n1HZ/dlz/v2xvotfUcPLO3IzwEVQ==", - "dependencies": { - "chalk": "^4.1.2", - "fs-extra": "^10.0.0", - "lowdb": "^1.0.0", - "rotating-file-stream": "^2.1.5", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/@rollup/plugin-inject": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", @@ -699,10 +550,10 @@ } } }, - "node_modules/@rollup/plugin-inject/node_modules/@rollup/pluginutils": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", - "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==", + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", "dev": true, "dependencies": { "@types/estree": "^1.0.0", @@ -722,15 +573,16 @@ } }, "node_modules/@types/estree": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", - "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==" + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", @@ -739,29 +591,29 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", - "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", + "version": "20.11.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.3.tgz", + "integrity": "sha512-nrlmbvGPNGaj84IJZXMPhQuCMEVTT/hXZMJJG/aIqVL9fKxqk814sGGtJA4GI6hpJSLQjpi6cn0Qx9eOf9SDVg==", "dev": true, "dependencies": { - "undici-types": "~5.25.1" + "undici-types": "~5.26.4" } }, "node_modules/@types/prismjs": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.2.tgz", - "integrity": "sha512-/r7Cp7iUIk7gts26mHXD66geUC+2Fo26TZYjQK6Nr4LDfi6lmdRmMqM0oPwfiMhUwoBAOFe8GstKi2pf6hZvwA==" + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==" }, "node_modules/@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/uuid": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.5.tgz", - "integrity": "sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", + "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==", "dev": true }, "node_modules/@types/web": { @@ -804,29 +656,6 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/parser": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", @@ -854,29 +683,6 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", @@ -921,29 +727,6 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/types": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", @@ -984,29 +767,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", @@ -1050,10 +810,16 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1075,6 +841,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1086,18 +853,11 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -1112,6 +872,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1313,7 +1074,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/base64-js": { "version": "1.5.1", @@ -1345,6 +1107,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1453,13 +1216,29 @@ "pako": "~1.0.5" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, - "optional": true, - "peer": true + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } }, "node_modules/buffer-polyfill": { "name": "buffer", @@ -1508,13 +1287,14 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1533,6 +1313,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1544,17 +1325,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -1569,6 +1339,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1579,20 +1350,14 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "optional": true, - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/console-browserify": { "version": "1.2.0", @@ -1606,20 +1371,6 @@ "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", "dev": true }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "is-what": "^3.14.1" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", @@ -1706,12 +1457,20 @@ } }, "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/deep-is": { @@ -1761,20 +1520,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -1817,9 +1562,9 @@ } }, "node_modules/domain-browser": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", - "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", + "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", "dev": true, "engines": { "node": ">=10" @@ -1849,20 +1594,6 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1878,26 +1609,26 @@ "integrity": "sha512-6q1Xdwga4JTr1mKSW4mzuWSSbmXgqpm/8Wa1QGFGfCWRjC0bCQjbS4u06M1te1moucIS3hBLlbSTPWYH2W0qbQ==" }, "node_modules/es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -1907,7 +1638,7 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", @@ -1921,7 +1652,7 @@ "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -1953,32 +1684,32 @@ } }, "node_modules/es-module-lexer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", - "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", "dev": true }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { @@ -1998,14 +1729,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es6-promisify": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-7.0.0.tgz", - "integrity": "sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/esbuild": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", @@ -2043,19 +1766,32 @@ "@esbuild/win32-x64": "0.18.20" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2176,6 +1912,15 @@ "resolve": "^1.22.4" } }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/eslint-module-utils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", @@ -2193,6 +1938,15 @@ } } }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/eslint-plugin-es": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", @@ -2237,28 +1991,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -2267,6 +2021,15 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -2367,15 +2130,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -2415,6 +2169,15 @@ "node": ">=8.0.0" } }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", @@ -2454,35 +2217,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -2499,60 +2233,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -2582,15 +2262,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2603,7 +2274,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -2612,15 +2283,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -2658,12 +2320,13 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2676,10 +2339,23 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -2688,9 +2364,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2708,16 +2384,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/filer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/filer/-/filer-1.4.1.tgz", - "integrity": "sha512-CJqhUN2yPioDov+DYpsUG9vLvAy0pt3aWuwHP+OfR86scb6lg/EdAo3EbZDCGyIRZxte2sAJ6gPtvGji9JlTyQ==", - "dependencies": { - "es6-promisify": "^7.0.0", - "minimatch": "^3.0.4", - "schema-utils": "^3.1.1" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2747,9 +2413,9 @@ } }, "node_modules/flat-cache": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", - "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { "flatted": "^3.2.9", @@ -2757,7 +2423,7 @@ "rimraf": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { @@ -2779,6 +2445,7 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2845,15 +2512,15 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2887,16 +2554,51 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">= 6" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { @@ -2949,7 +2651,8 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true }, "node_modules/graphemer": { "version": "1.4.0", @@ -2957,15 +2660,6 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -2979,17 +2673,18 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { "node": ">=8" } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3058,6 +2753,18 @@ "minimalistic-assert": "^1.0.1" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -3075,20 +2782,6 @@ "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", "dev": true }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -3110,28 +2803,14 @@ ] }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" } }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3148,15 +2827,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3183,13 +2853,13 @@ "dev": true }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -3288,12 +2958,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3432,11 +3102,6 @@ "node": ">=8" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3553,14 +3218,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -3595,6 +3252,11 @@ "set-function-name": "^2.0.1" } }, + "node_modules/js-ini": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/js-ini/-/js-ini-1.6.0.tgz", + "integrity": "sha512-9Vx+NVkMRNY4i7pLLIGdXIQbP1iwB3fP2IG1zMCgeUUvR1ODmTKa33eR/J9FHoorNsfoJr9/2SVqeSKLwPD9Nw==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3628,7 +3290,8 @@ "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -3636,6 +3299,18 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", @@ -3646,6 +3321,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -3677,34 +3353,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/less": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "source-map": "~0.6.0" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3718,256 +3366,16 @@ "node": ">= 0.8.0" } }, - "node_modules/lightningcss": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.22.0.tgz", - "integrity": "sha512-+z0qvwRVzs4XGRXelnWRNwqsXUx8k3bSkbP8vD42kYKSk3z9OM2P3e/gagT7ei/gwh8DTS80LZOFZV6lm8Z8Fg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "detect-libc": "^1.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.22.0", - "lightningcss-darwin-x64": "1.22.0", - "lightningcss-freebsd-x64": "1.22.0", - "lightningcss-linux-arm-gnueabihf": "1.22.0", - "lightningcss-linux-arm64-gnu": "1.22.0", - "lightningcss-linux-arm64-musl": "1.22.0", - "lightningcss-linux-x64-gnu": "1.22.0", - "lightningcss-linux-x64-musl": "1.22.0", - "lightningcss-win32-x64-msvc": "1.22.0" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.22.0.tgz", - "integrity": "sha512-aH2be3nNny+It5YEVm8tBSSdRlBVWQV8m2oJ7dESiYRzyY/E/bQUe2xlw5caaMuhlM9aoTMtOH25yzMhir0qPg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.22.0.tgz", - "integrity": "sha512-9KHRFA0Y6mNxRHeoQMp0YaI0R0O2kOgUlYPRjuasU4d+pI8NRhVn9bt0yX9VPs5ibWX1RbDViSPtGJvYYrfVAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.22.0.tgz", - "integrity": "sha512-xaYL3xperGwD85rQioDb52ozF3NAJb+9wrge3jD9lxGffplu0Mn35rXMptB8Uc2N9Mw1i3Bvl7+z1evlqVl7ww==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.22.0.tgz", - "integrity": "sha512-epQGvXIjOuxrZpMpMnRjK54ZqzhiHhCPLtHvw2fb6NeK2kK9YtF0wqmeTBiQ1AkbWfnnXGTstYaFNiadNK+StQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.22.0.tgz", - "integrity": "sha512-AArGtKSY4DGTA8xP8SDyNyKtpsUl1Rzq6FW4JomeyUQ4nBrR71uPChksTpj3gmWuGhZeRKLeCUI1DBid/zhChg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.22.0.tgz", - "integrity": "sha512-RRraNgP8hnBPhInTTUdlFm+z16C/ghbxBG51Sw00hd7HUyKmEUKRozyc5od+/N6pOrX/bIh5vIbtMXIxsos0lg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.22.0.tgz", - "integrity": "sha512-grdrhYGRi2KrR+bsXJVI0myRADqyA7ekprGxiuK5QRNkv7kj3Yq1fERDNyzZvjisHwKUi29sYMClscbtl+/Zpw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.22.0.tgz", - "integrity": "sha512-t5f90X+iQUtIyR56oXIHMBUyQFX/zwmPt72E6Dane3P8KNGlkijTg2I75XVQS860gNoEFzV7Mm5ArRRA7u5CAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.22.0.tgz", - "integrity": "sha512-64HTDtOOZE9PUCZJiZZQpyqXBbdby1lnztBccnqh+NtbKxjnGzP92R2ngcgeuqMPecMNqNWxgoWgTGpC+yN5Sw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", + "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "engines": { - "node": ">=6" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/load-json-file/node_modules/type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", - "dev": true, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/locate-path": { @@ -3985,11 +3393,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4008,26 +3411,10 @@ "loose-envify": "cli.js" } }, - "node_modules/lowdb": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz", - "integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==", - "dependencies": { - "graceful-fs": "^4.1.3", - "is-promise": "^2.1.0", - "lodash": "4", - "pify": "^3.0.0", - "steno": "^0.4.1" - }, - "engines": { - "node": ">=4" - } - }, "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" }, @@ -4053,43 +3440,6 @@ "node": ">=12" } }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -4103,9 +3453,9 @@ } }, "node_modules/material-symbols": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/material-symbols/-/material-symbols-0.14.3.tgz", - "integrity": "sha512-oys7SbIaPz1sfUCMVYlEE5HJGzh0GMoUK0jCGH7hAqO9iW/b9dnSAeYgOQp2s1ifQP5Y+Q4+Fcujay/ASzvy2w==" + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/material-symbols/-/material-symbols-0.14.5.tgz", + "integrity": "sha512-3fB0MEG93k8C7D7sI0HSQWlKy3rgIQ6HPICkEPs9blsod/nWofSBdDPvUa9XpNRIqciqLA+hZF8DVnA4J19BlQ==" }, "node_modules/md5.js": { "version": "1.3.5", @@ -4159,20 +3509,6 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -4189,6 +3525,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4206,15 +3543,15 @@ } }, "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -4241,25 +3578,6 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "node_modules/needle": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, "node_modules/node-stdlib-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.2.0.tgz", @@ -4298,30 +3616,6 @@ "node": ">=10" } }, - "node_modules/node-stdlib-browser/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/node-stdlib-browser/node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -4338,9 +3632,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4372,13 +3666,13 @@ } }, "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, @@ -4495,36 +3789,6 @@ "dev": true }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", @@ -4539,11 +3803,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-locate/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { "node": ">=10" }, @@ -4604,17 +3871,6 @@ "node": ">=4" } }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -4698,70 +3954,110 @@ } }, "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-conf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz", + "integrity": "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==", "dev": true, "dependencies": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" + "find-up": "^6.0.0", + "load-json-file": "^7.0.0" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-conf/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "dependencies": { - "locate-path": "^3.0.0" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-conf/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-conf/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-conf/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "dependencies": { - "p-limit": "^2.0.0" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-conf/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "engines": { - "node": ">=4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-conf/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-dir": { @@ -4777,9 +4073,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "dev": true, "funding": [ { @@ -4796,7 +4092,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -4814,9 +4110,9 @@ } }, "node_modules/prism-code-editor": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/prism-code-editor/-/prism-code-editor-2.3.0.tgz", - "integrity": "sha512-m34n32yHPb4BEzo8RRsSwrxHTQbGNNhXqqOH6nqzcm8ArqltcCcN2ZLY4fQeIdDqLaJhvEsimeunVCjaUUHTBA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prism-code-editor/-/prism-code-editor-2.4.0.tgz", + "integrity": "sha512-+i/RM6YvGOQ4tztOATbaktf4xm0ESY+hsIkweMfKVuiydeyul3jS9JYtpvQzEV2Uz2lkWBLidn3aAvoJj5a4hg==", "dependencies": { "@types/prismjs": "^1.26.2" } @@ -4841,14 +4137,6 @@ "react-is": "^16.13.1" } }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -4870,13 +4158,29 @@ "dev": true }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "engines": { "node": ">=6" } }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", @@ -5011,6 +4315,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -5036,26 +4349,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -5082,17 +4375,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rotating-file-stream": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/rotating-file-stream/-/rotating-file-stream-2.1.6.tgz", - "integrity": "sha512-qS0ndAlDu80MMXeRonqGMXslF0FErzcUSbcXhus3asRG4cvCS79hc5f7s0x4bPAsH6wAwyHVIeARg69VUe3JmQ==", - "engines": { - "node": ">=10.0" - }, - "funding": { - "url": "https://www.blockchain.com/btc/address/12p1p5q7sK75tPyuesZmssiMYr4TKzpSCN" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -5117,13 +4399,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -5155,15 +4437,18 @@ ] }, "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", "is-regex": "^1.1.4" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5174,36 +4459,10 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "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" }, @@ -5214,6 +4473,22 @@ "node": ">=10" } }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-function-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", @@ -5269,9 +4544,9 @@ } }, "node_modules/shiki": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.5.tgz", - "integrity": "sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==", + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", + "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", "dev": true, "dependencies": { "ansi-sequence-parser": "^1.1.0", @@ -5303,17 +4578,6 @@ "node": ">=8" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -5323,18 +4587,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/standard-engine": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.1.0.tgz", @@ -5364,12 +4616,103 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/steno": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz", - "integrity": "sha512-EEHMVYHNXFHfGtgjNITnka0aHhiAlo93F7z2/Pwd+g0teG9CnM3JIINM7hVVB5/rhw9voufD7Wukwgtw2uqh6w==", + "node_modules/standard-engine/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, "dependencies": { - "graceful-fs": "^4.1.3" + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/standard-engine/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard-engine/node_modules/pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-engine/node_modules/type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true, + "engines": { + "node": ">=6" } }, "node_modules/stream-browserify": { @@ -5472,6 +4815,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5500,6 +4844,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -5512,26 +4868,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/terser": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz", - "integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5591,108 +4927,10 @@ "typescript": "*" } }, - "node_modules/ts-standard/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "dev": true, - "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-standard/node_modules/load-json-file": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", - "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-standard/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-standard/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-standard/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-standard/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/ts-standard/node_modules/pkg-conf": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz", - "integrity": "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==", - "dev": true, - "dependencies": { - "find-up": "^6.0.0", - "load-json-file": "^7.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -5701,25 +4939,11 @@ "strip-bom": "^3.0.0" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true, - "optional": true, - "peer": true + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "node_modules/tsutils": { "version": "3.21.0", @@ -5736,12 +4960,6 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", @@ -5760,6 +4978,18 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", @@ -5826,15 +5056,15 @@ } }, "node_modules/typedoc": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.3.tgz", - "integrity": "sha512-Ow8Bo7uY1Lwy7GTmphRIMEo6IOZ+yYUyrc8n5KXIZg1svpqhZSWgni2ZrDhe+wLosFS8yswowUzljTAV/3jmWw==", + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.7.tgz", + "integrity": "sha512-m6A6JjQRg39p2ZVRIN3NKXgrN8vzlHhOS+r9ymUYtcUP/TIQPvWSq7YgE5ZjASfv5Vd5BW5xrir6Gm2XNNcOow==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", "minimatch": "^9.0.3", - "shiki": "^0.14.1" + "shiki": "^0.14.7" }, "bin": { "typedoc": "bin/typedoc" @@ -5843,13 +5073,13 @@ "node": ">= 16" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x" } }, "node_modules/typedoc-material-theme": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typedoc-material-theme/-/typedoc-material-theme-1.0.0.tgz", - "integrity": "sha512-jrR3xf2lzPMxKOiEKEifs8royJ1zhkQ84+GFnTKMY0Rh4xWoUfxNUgiDijIw4veBlrVG9Tsf5ba1Frr4IFsEsg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typedoc-material-theme/-/typedoc-material-theme-1.0.2.tgz", + "integrity": "sha512-/nH/twYeHrnz5sZaaXzYJ85EOgKqnbl1ivzBKmuEAga1dBsARttwQUTPKAT7XrCPD+rRcoqxuCOdXZ6EGiqRQA==", "dev": true, "funding": [ { @@ -5865,17 +5095,17 @@ "@material/material-color-utilities": "^0.2.7" }, "engines": { - "node": ">=20.0.0", - "npm": ">=9.6.4" + "node": ">=18.0.0", + "npm": ">=8.6.0" }, "peerDependencies": { "typedoc": "^0.25.3" } }, "node_modules/typedoc-plugin-missing-exports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.1.0.tgz", - "integrity": "sha512-+1DhqZCEu7Vu5APnrqpPwl31D+hXpt1fV0Le9ycCRL1eLVdatdl6KVt4SEVwPxnEpKwgOn2dNX6I9+0F1aO2aA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.2.0.tgz", + "integrity": "sha512-2+XR1IcyQ5UwXZVJe9NE6HrLmNufT9i5OwoIuuj79VxuA3eYq+Y6itS9rnNV1D7UeQnUSH8kISYD73gHE5zw+w==", "dev": true, "peerDependencies": { "typedoc": "0.24.x || 0.25.x" @@ -5906,9 +5136,9 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5934,15 +5164,16 @@ } }, "node_modules/undici-types": { - "version": "5.25.3", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", - "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, "engines": { "node": ">= 10.0.0" } @@ -5951,6 +5182,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -5971,21 +5203,6 @@ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true }, - "node_modules/url/node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -6018,9 +5235,9 @@ } }, "node_modules/vite": { - "version": "4.4.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.12.tgz", - "integrity": "sha512-KtPlUbWfxzGVul8Nut8Gw2Qe8sBzWY+8QVc5SL8iRFnpnrcoCaNlzO40c1R6hPmcdTwIPEDkq0Y9+27a5tVbdQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz", + "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==", "dev": true, "dependencies": { "esbuild": "^0.18.10", @@ -6072,6 +5289,20 @@ } } }, + "node_modules/vite-plugin-compression": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/vite-plugin-compression/-/vite-plugin-compression-0.5.1.tgz", + "integrity": "sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "debug": "^4.3.3", + "fs-extra": "^10.0.0" + }, + "peerDependencies": { + "vite": ">=2.0.0" + } + }, "node_modules/vite-plugin-dynamic-import": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/vite-plugin-dynamic-import/-/vite-plugin-dynamic-import-1.5.0.tgz", @@ -6193,13 +5424,13 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.4", "for-each": "^0.3.3", "gopd": "^1.0.1", "has-tostringtag": "^1.0.0" @@ -6238,16 +5469,15 @@ "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 + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { - "node": ">=12.20" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" diff --git a/package.json b/package.json index 4fbf157..53b08c2 100644 --- a/package.json +++ b/package.json @@ -15,24 +15,25 @@ "author": "", "license": "MIT", "devDependencies": { - "@types/node": "^20.8.7", + "@types/node": "^20.11.3", "@types/uuid": "^9.0.5", "@types/web": "^0.0.117", "ts-standard": "^12.0.2", "typedoc": "^0.25.3", - "typedoc-material-theme": "^1.0.0", + "typedoc-material-theme": "^1.0.2", "typedoc-plugin-missing-exports": "^2.1.0", "typescript": "^5.2.2", "vite": "^4.4.12", + "vite-plugin-compression": "^0.5.1", "vite-plugin-dynamic-import": "^1.5.0", "vite-plugin-node-polyfills": "^0.15.0" }, "dependencies": { - "@ptkdev/logger": "^1.8.0", "eruda": "^3.0.1", - "filer": "^1.4.1", - "prism-code-editor": "^2.3.0", + "js-ini": "^1.6.0", "material-symbols": "^0.14.3", + "prism-code-editor": "^2.3.0", + "semver": "^7.5.4", "uuid": "^9.0.1" }, "ts-standard": { diff --git a/public/uv-sw.js b/public/uv-sw.js index 2adfadd..6b70648 100644 --- a/public/uv-sw.js +++ b/public/uv-sw.js @@ -1,7 +1,8 @@ +// @ts-nocheck + importScripts('/uv/uv.sw.js'); -const params = new URL(self.serviceWorker.scriptURL).searchParams - +const params = new URL(self.location.href).searchParams const serverURL = atob(params.get('url')); const sw = new UVServiceWorker(serverURL); diff --git a/public/uv/uv.config.js b/public/uv/uv.config.js index 44c5fa4..32b34a9 100644 --- a/public/uv/uv.config.js +++ b/public/uv/uv.config.js @@ -30,7 +30,6 @@ self.xor = { } self.__uv$config = { prefix: '/service/', - bare: 'https://server.flow-works.me' + '/bare/', encodeUrl: self.xor.encode, decodeUrl: self.xor.decode, handler: '/uv/uv.handler.js', diff --git a/src/lib.ts b/src/HTML.ts similarity index 100% rename from src/lib.ts rename to src/HTML.ts diff --git a/src/assets/icons/application-executable.svg b/src/assets/icons/application-executable.svg new file mode 100644 index 0000000..cb3376b --- /dev/null +++ b/src/assets/icons/application-executable.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/icon-library.svg b/src/assets/icons/icon-library.svg new file mode 100644 index 0000000..0c4e189 --- /dev/null +++ b/src/assets/icons/icon-library.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/org.gnome.Loupe.svg b/src/assets/icons/org.gnome.Loupe.svg new file mode 100644 index 0000000..19db29d --- /dev/null +++ b/src/assets/icons/org.gnome.Loupe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/utilities-system-monitor.svg b/src/assets/icons/utilities-system-monitor.svg new file mode 100644 index 0000000..aae5c01 --- /dev/null +++ b/src/assets/icons/utilities-system-monitor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/builtin/apps/files.ts b/src/builtin/apps/files.ts deleted file mode 100644 index ca76156..0000000 --- a/src/builtin/apps/files.ts +++ /dev/null @@ -1,140 +0,0 @@ -import icon from '../../assets/icons/file-manager.svg' -import { App } from '../../types' - -import FlowWindow from '../../structures/FlowWindow' - -export default class FilesApp implements App { - meta = { - name: 'Files', - description: 'A simple files app.', - pkg: 'flow.files', - version: '1.0.0', - icon - } - - async open (): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 500, - height: 400 - }) - - win.content.style.display = 'flex' - win.content.style.flexDirection = 'column' - - async function setDir (dir: string): Promise { - const files = await window.fs.readdir(dir) - const back = dir === '/' ? 'first_page' : 'chevron_left' - - win.content.innerHTML = ` -
- ${back}${dir} -
- create_new_foldernote_add -
-
- ` - - if (back !== 'first_page') { - (win.content.querySelector('.back') as HTMLElement).onclick = async () => { - await setDir(dir.split('/').slice(0, -1).join('/')) - } - } - - (win.content.querySelector('.file') as HTMLElement).onclick = async () => { - const title: string = prompt('Enter file name') ?? 'new-file.txt' - await window.fs.writeFile(`${dir}/${title}`, '') - await setDir(dir) - } - - (win.content.querySelector('.folder') as HTMLElement).onclick = async () => { - const title: string = prompt('Enter folder name') ?? 'new-folder' - await window.fs.mkdir(`${dir}/${title}`) - await setDir(dir) - } - - for (const file of files) { - const seperator = dir === '/' ? '' : '/' - const fileStat = await window.fs.stat(dir + seperator + file) - const element = document.createElement('div') - element.setAttribute('style', 'display: flex;gap: 5px;align-items:center;padding: 5px;border-bottom: 1px solid var(--text);display:flex;align-items:center;gap: 5px;') - - const genIcon = (): string => { - switch (file.split('.').at(-1)) { - case 'js': - case 'mjs': - case 'cjs': { - return 'javascript' - } - - case 'html': - case 'htm': { - return 'html' - } - - case 'css': { - return 'css' - } - - case 'json': { - return 'code' - } - - case 'md': { - return 'markdown' - } - - case 'txt': - case 'text': { - return 'description' - } - - case 'png': - case 'apng': - case 'jpg': - case 'jpeg': - case 'gif': { - return 'image' - } - - default: { - return 'draft' - } - } - } - const icon = fileStat.isDirectory() ? 'folder' : genIcon() - - element.innerHTML += `${icon} ${file}delete_foreveredit`; - (element.querySelector('.rename') as HTMLElement).onclick = async () => { - const value = (prompt('Rename') as string) - if (value !== null || value !== undefined) { - await window.fs.rename(dir + seperator + file, dir + seperator + value) - await setDir(dir) - } - } - (element.querySelector('.delete') as HTMLElement).onclick = async () => { - if (fileStat.isDirectory()) { - await window.fs.rmdir(dir + seperator + file) - } else { - await window.fs.unlink(dir + seperator + file) - } - await setDir(dir) - } - element.ondblclick = async () => { - if (fileStat.isDirectory()) { - await setDir(dir + seperator + file) - } else { - await window.flow.openApp('flow.editor', { path: dir + seperator + file }) - } - } - - win.content.querySelector('.files')?.appendChild(element) - } - } - - await setDir('/home') - - return win - } -} diff --git a/src/builtin/apps/info.ts b/src/builtin/apps/info.ts deleted file mode 100644 index b661b57..0000000 --- a/src/builtin/apps/info.ts +++ /dev/null @@ -1,59 +0,0 @@ -import icon from '../../assets/icons/userinfo.svg' -import badge from '../../assets/badge.png' -import { App } from '../../types' - -import FlowWindow from '../../structures/FlowWindow' -import HTML from '../../lib' - -export default class InfoApp implements App { - meta = { - name: 'Info', - description: 'FlowOS Information.', - pkg: 'flow.info', - version: '1.0.0', - icon - } - - async open (): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 300, - height: 400, - canResize: false - }) - - win.content.style.padding = '10px' - win.content.style.textAlign = 'center' - win.content.style.display = 'flex' - win.content.style.flexDirection = 'column' - win.content.style.justifyContent = 'center' - win.content.style.alignItems = 'center' - win.content.style.background = 'var(--base)' - - const div = new HTML('div').appendTo(win.content) - new HTML('h1').style({ - margin: '0' - }).text(`FlowOS ${window.flowDetails.codename}`).appendTo(div) - new HTML('p').style({ - margin: '0' - }).text(`v${window.flowDetails.version}`).appendTo(div) - new HTML('br').appendTo(div) - new HTML('img').attr({ - src: badge, - height: '50' - }).appendTo(div) - new HTML('br').appendTo(div) - new HTML('a').text('Discord').attr({ - href: 'https://discord.gg/86F8dK9vfn', - class: 'discord' - }).appendTo(div) - new HTML('span').text(' - ').appendTo(div) - new HTML('a').text('Github').attr({ - href: 'https://github.com/Flow-Works/FlowOS', - class: 'github' - }).appendTo(div) - - return win - } -} diff --git a/src/builtin/apps/manager.ts b/src/builtin/apps/manager.ts deleted file mode 100644 index 14c6d9b..0000000 --- a/src/builtin/apps/manager.ts +++ /dev/null @@ -1,55 +0,0 @@ -import icon from '../../assets/icons/software-properties.svg' -import { App, LoadedApp, LoadedPlugin } from '../../types' -import FlowWindow from '../../structures/FlowWindow' -import nullIcon from '../../assets/icons/application-default-icon.svg' - -export default class ManagerApp implements App { - meta = { - name: 'Flow Manager', - description: 'A FlowOS utility app.', - pkg: 'flow.manager', - version: '1.0.0', - icon - } - - async open (): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 350, - height: 500 - }) - - win.content.style.display = 'flex' - win.content.style.flexDirection = 'column' - win.content.style.gap = '10px' - win.content.style.padding = '10px' - win.content.style.background = 'var(--base)' - win.content.innerHTML = ` - ${window.flow.apps.map((app: LoadedApp) => { - return ` -
- -
-

${app.meta.name} ${(app.builtin ?? false) ? '(builtin)' : ''}

-

${app.meta.pkg} (v${app.meta.version}) - App

-
-
- ` - }).join('')} - ${window.flow.plugins.map((plugin: LoadedPlugin) => { - return ` -
- -
-

${plugin.meta.name} ${(plugin.builtin ?? false) ? '(builtin)' : ''}

-

${plugin.meta.pkg} (v${plugin.meta.version}) - Plugin

-
-
- ` - }).join('')} - ` - - return win - } -} diff --git a/src/builtin/apps/music.ts b/src/builtin/apps/music.ts deleted file mode 100644 index fd55ca3..0000000 --- a/src/builtin/apps/music.ts +++ /dev/null @@ -1,27 +0,0 @@ -import icon from '../../assets/icons/gnome-music.svg' -import { App } from '../../types' -import FlowWindow from '../../structures/FlowWindow' - -export default class MusicApp implements App { - meta = { - name: 'Music', - description: 'A simple music app.', - pkg: 'flow.music', - version: '1.0.0', - icon - } - - async open (): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 700, - height: 300 - }) - - win.content.style.background = 'var(--base)' - win.content.innerHTML = 'hi' - - return win - } -} diff --git a/src/builtin/apps/settings.ts b/src/builtin/apps/settings.ts deleted file mode 100644 index bee65ea..0000000 --- a/src/builtin/apps/settings.ts +++ /dev/null @@ -1,98 +0,0 @@ -import icon from '../../assets/icons/preferences-system.svg' -import { App } from '../../types' -import FlowWindow from '../../structures/FlowWindow' - -export default class SettingsApp implements App { - meta = { - name: 'Settings', - description: 'An easy-to-use configuration app.', - pkg: 'flow.settings', - icon, - version: '1.0.0' - } - - configFileLoc = '/.flow/config.json' - configFolderLoc = '/.flow/' - - async open (): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 700, - height: 300, - canResize: true - }) - - win.content.style.padding = '10px' - - win.content.innerHTML = ` -

Settings

-
- - - ` - - const titles: { - [key: string]: string - } = { - SERVER_URL: 'FlowServer URL', - HOSTNAME: 'Device Hostname', - USERNAME: 'Username', - '24HR_CLOCK': '24hr Clock' - } - - // TODO: settings - const config = {} - - for (const key of Object.keys(config)) { - const container = document.createElement('div') - const label = document.createElement('label') - const input = document.createElement('input') - - if (typeof (config as any)[key] === 'boolean') { - label.innerText = `${titles[key] ?? key}` - input.type = 'checkbox' - } else if (typeof (config as any)[key] === 'string') { - label.innerText = `${titles[key] ?? key}:\n` - input.type = 'text' - } - - input.value = (config as any)[key] - - container.appendChild(label) - container.appendChild(input) - - win.content.querySelector('.settings')?.appendChild(container) - - win.content.querySelector('.save')?.addEventListener('click', () => { - (config as any)[key] = input.value - - window.location.reload() - }) - } - - win.content.querySelector('.save')?.addEventListener('click', () => { - window.fs.writeFile('/.config/flow.json', JSON.stringify(config)) - .then(null) - .catch(e => console.error(e)) - }) - - return win - } -} diff --git a/src/builtin/apps/store.ts b/src/builtin/apps/store.ts deleted file mode 100644 index 5fc55a8..0000000 --- a/src/builtin/apps/store.ts +++ /dev/null @@ -1,94 +0,0 @@ -import icon from '../../assets/icons/softwarecenter.svg' -import { App, RepoData } from '../../types' -import FlowWindow from '../../structures/FlowWindow' -import { sanitize } from '../../utils' -import nullIcon from '../../assets/icons/application-default-icon.svg' - -export default class MusicApp implements App { - meta = { - name: 'Store', - description: 'A simple store app.', - pkg: 'flow.store', - version: '1.0.0', - icon - } - - async open (): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 500, - height: 700 - }) - - win.content.style.background = 'var(--base)' - - // TODO: Allow customization of server URL - fetch('https://server.flow-works.me' + '/apps/list/') - .then(async (res) => await res.json()) - .then(handle) - .catch(e => console.error(e)) - - function handle (repos: RepoData[]): void { - win.content.innerHTML = ` -
- ` - - repos.forEach((repo) => { - (win.content.querySelector('.repos') as HTMLElement).innerHTML += ` -
-
-

${sanitize(repo.name)}

- ${sanitize(repo.id)} -
-
-
-
- ` - - repo.apps.forEach((app) => { - (win.content.querySelector(`div[data-repo-id="${sanitize(repo.id)}"] > .apps`) as HTMLElement).innerHTML += ` -
- -
-

${sanitize(app.name)}

-
- ${sanitize(app.pkg)} - download -
-
-
- ` - - window.fs.exists(`/home/Applications/${app.url.split('/').at(-1) as string}`).then((exists) => { - if (exists) { - (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).innerHTML = 'delete'; - - (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = async () => { - await window.fs.unlink(`/Applications/${app.url.split('/').at(-1) as string}`) - window.location.reload() - } - } else { - (win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => { - install(app.url) - } - } - }).catch(e => console.error(e)) - }) - }) - } - - function install (url: string): void { - fetch(url).then(async (res) => await res.text()) - .then(async (data) => { - const exists = await window.fs.exists('/home/Applications') - - if (!exists) window.fs.mkdir('/home/Applications').catch(console.error) - - window.fs.writeFile(`/home/Applications/${url.split('/').at(-1) as string}`, data).then(() => window.location.reload()).catch(console.error) - }).catch(e => console.error(e)) - } - - return win - } -} diff --git a/src/builtin/plugins/apps.ts b/src/builtin/plugins/apps.ts deleted file mode 100644 index f4e552e..0000000 --- a/src/builtin/plugins/apps.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { AppOpenedEvent, AppClosedEvent } from '../../types' - -export const meta = { - name: 'Apps', - description: 'Displays the current apps open.', - pkg: 'flow.apps', - version: '1.0.0' -} - -export const run = (element: HTMLDivElement): void => { - element.style.display = 'flex' - element.style.alignItems = 'bottom' - element.style.flex = '1' - - window.addEventListener('app_opened', (e: AppOpenedEvent): void => { - const appIcon = document.createElement('app') - const app = e.detail.app - const win = e.detail.win - appIcon.innerHTML = ``; - (appIcon.querySelector('img') as HTMLElement).style.borderBottom = '2px solid var(--text)' - appIcon.onclick = async () => { - const win = await e.detail.win - win.focus() - win.toggleMin() - } - element.appendChild(appIcon) - }) - - window.addEventListener('app_closed', (e: AppClosedEvent): void => { - const win = e.detail.win - element.querySelector(`img[data-id="${win.id}"]`)?.parentElement?.remove() - }) -} diff --git a/src/builtin/plugins/clock.ts b/src/builtin/plugins/clock.ts deleted file mode 100644 index 0208f86..0000000 --- a/src/builtin/plugins/clock.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { getTime } from '../../utils' - -export const meta = { - name: 'Clock', - description: 'Displays the date & time.', - pkg: 'flow.clock', - version: '1.0.0' -} - -export const run = async (element: HTMLDivElement): Promise => { - let date: Date = new Date() - - element.style.display = 'flex' - element.style.flexDirection = 'column' - element.style.padding = '5px 10px' - element.style.fontSize = '12.5px' - element.style.justifyContent = 'center' - - const refreshDate = (): string => { - const split = date.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' }).split(',') - return `${split[0]},${split[1]} ` - } - - let clock = await getTime() - let date_ = refreshDate() - element.innerHTML = `${clock}
${date_}
` - - setInterval(() => { - (async () => { - date = new Date() - clock = await getTime() - date_ = refreshDate() - element.innerHTML = `${clock}
${date_}
` - })().catch(e => console.error(e)) - }, 1000) -} diff --git a/src/decs.d.ts b/src/decs.d.ts new file mode 100644 index 0000000..63a88a9 --- /dev/null +++ b/src/decs.d.ts @@ -0,0 +1 @@ +declare module '*?raw-hex' diff --git a/src/fs.ts b/src/fs.ts deleted file mode 100644 index 54dfb1a..0000000 --- a/src/fs.ts +++ /dev/null @@ -1,461 +0,0 @@ -export enum Errors { - ENOENT = 'ENOENT', - EISDIR = 'EISDIR', - EEXIST = 'EEXIST', - EPERM = 'EPERM', - ENOTDIR = 'ENOTDIR', - EACCES = 'EACCES' -} - -export enum Permission { - USER, - ELEVATED, - SYSTEM -} - -export interface Directory { - type: 'directory' - permission: Permission - deleteable: boolean - children: { - [key: string]: Directory | File - } -} - -export interface File { - type: 'file' - permission: Permission - deleteable: boolean - content: Buffer -} - -const defaultFS: { root: Directory } = { - root: { - type: 'directory', - deleteable: false, - permission: Permission.SYSTEM, - children: { - home: { - type: 'directory', - deleteable: false, - permission: Permission.SYSTEM, - children: { - Downloads: { - type: 'directory', - deleteable: false, - permission: Permission.USER, - children: {} - }, - Applications: { - type: 'directory', - deleteable: false, - permission: Permission.USER, - children: {} - }, - Desktop: { - type: 'directory', - deleteable: false, - permission: Permission.USER, - children: { - 'README.md': { - type: 'file', - deleteable: true, - permission: Permission.USER, - content: Buffer.from('# Welcome to FlowOS!') - } - } - }, - Pictures: { - type: 'directory', - deleteable: false, - permission: Permission.USER, - children: {} - }, - Videos: { - type: 'directory', - deleteable: false, - permission: Permission.USER, - children: {} - }, - Documents: { - type: 'directory', - deleteable: false, - permission: Permission.USER, - children: {} - }, - Music: { - type: 'directory', - deleteable: false, - permission: Permission.USER, - children: {} - } - } - }, - var: { - type: 'directory', - deleteable: false, - permission: Permission.SYSTEM, - children: {} - }, - etc: { - type: 'directory', - deleteable: false, - permission: Permission.SYSTEM, - children: { - hostname: { - type: 'file', - deleteable: false, - permission: Permission.ELEVATED, - content: Buffer.from('flow') - } - } - }, - boot: { - type: 'directory', - deleteable: false, - permission: Permission.SYSTEM, - children: {} - } - } - } -} - -export class VirtualFS { - private db: IDBDatabase - private fileSystem: { root: Directory } - - constructor (dbName = 'virtualfs') { - this.initializeDatabase(dbName) - .then(async () => { - this.db.onerror = (event: Event) => { - const target = event.target as IDBRequest - const errorMessage = target.error !== null ? target.error.message : 'Unknown error' - throw new Error(`[VirtualFS] ${target.error?.name ?? 'Unknown Error'}: ${errorMessage}`) - } - navigator.storage.persist().catch(e => console.error(e)) - const fs = await this.read() - fs === undefined ? await this.write(defaultFS) : this.fileSystem = fs - console.log('[VirtualFS] Database initialized') - }) - .catch(e => console.error(e)) - } - - /** - * The function initializes a database using IndexedDB in TypeScript. - * @param {string} dbName - The `dbName` parameter is a string that represents the name of the - * database that you want to initialize. - * @returns a Promise. - */ - private async initializeDatabase (dbName: string): Promise { - return await new Promise((resolve, reject) => { - const request = window.indexedDB.open(dbName) - - request.onupgradeneeded = (event: Event) => { - const target = event.target as IDBRequest - const db = target.result - db.createObjectStore('fs') - } - - request.onerror = (event: Event) => { - reject(new Error('[VirtualFS] Error opening database.')) - } - - request.onsuccess = () => { - this.db = request.result - resolve(true) - } - }) - } - - /** - * The function reads data from an object store in a transaction and returns a promise that resolves - * with the result. - * @returns a Promise that resolves to the result of the `getRequest` operation. - */ - private async read (): Promise { - const transaction = this.db.transaction(['fs'], 'readonly') - const store = transaction.objectStore('fs') - const getRequest = store.get('fs') - - return await new Promise((resolve, reject) => { - getRequest.onsuccess = () => { - resolve(getRequest.result) - } - - getRequest.onerror = () => { - reject(getRequest.error) - } - }) - } - - /** - * The `write` function is a private asynchronous method that takes a `fileSystem` object as a - * parameter, sets it as the current file system, and then saves it. - * @param fileSystem - The `fileSystem` parameter is an object that represents the file system. It - * has a property `root` which is a `Directory` object representing the root directory of the file - * system. - */ - private async write (fileSystem: { root: Directory }): Promise { - this.fileSystem = fileSystem - await this.save() - } - - private async save (): Promise { - const transaction = this.db.transaction(['fs'], 'readwrite') - const store = transaction.objectStore('fs') - const putRequest = store.put(this.fileSystem, 'fs') - - return await new Promise((resolve, reject) => { - putRequest.onsuccess = () => { - resolve() - } - - putRequest.onerror = () => { - reject(putRequest.error) - } - }) - } - - /** - * The function handles permissions for a given path and permission level, throwing an error if the - * current permission level is higher than the requested permission level. - * @param {string} path - A string representing the path to a resource or file. - * @param {Permission} permission - The `permission` parameter is of type `Permission`, which is an - * enum representing different levels of permissions. It is used to determine if the current user has - * sufficient permissions to access a certain path. - */ - private async handlePermissions (path: string, permission: Permission): Promise { - let current - - current = (await this.navigatePath(path)).current - console.log(current) - if (current === undefined) current = (await this.navigatePathParent(path)).current - console.log(current) - - console.log(current.permission, permission) - - if (current.permission === Permission.USER && current.permission < permission) { - const uac = await window.wm.createModal('Elevated Permissions Required', 'You need elevated permissions to perform this operation.') - if (!uac) { - throw new Error(Errors.EACCES) - } - } - if (current.permission === Permission.ELEVATED && current.permission < permission) { - const uac = await window.wm.createModal('Elevated Permissions Required', 'You need elevated permissions to perform this operation.') - if (!uac) { - throw new Error(Errors.EACCES) - } - } - if (current.permission === Permission.SYSTEM && current.permission < permission) throw new Error(Errors.EPERM) - } - - /** - * The function `navigatePath` takes a path as input and returns the current directory or file object - * and the individual parts of the path. - * @param {string} path - A string representing the path to navigate in the file system. - * @returns an object with two properties: "current" and "parts". The "current" property represents - * the current directory or file that was navigated to based on the given path. The "parts" property - * is an array of strings representing the individual parts of the path. - */ - private async navigatePath (path: string): Promise<{ current: Directory | File, parts: string[] }> { - const parts = path.split('/').filter(x => x !== '') - let current = this.fileSystem.root - for (const part of parts) { - current = current.children[part] as Directory - } - return { current, parts } - } - - /** - * The function `navigatePathParent` takes a path as input and returns the current directory, the - * parts of the path, and the filename. - * @param {string} path - The `path` parameter is a string that represents the file path. It is used - * to navigate through the file system and locate a specific file or directory. - * @returns an object with three properties: "current", "parts", and "filename". - */ - private async navigatePathParent (path: string): Promise<{ current: Directory, parts: string[], filename: string }> { - const parts = path.split('/').filter(x => x !== '') - const filename = parts.pop() as string - let current = this.fileSystem.root - for (const part of parts) { - current = current.children[part] as Directory - } - return { current, parts, filename } - } - - /** - * The `unlink` function deletes a file from a given path and saves the changes. - * @param {string} path - The `path` parameter is a string that represents the file or directory path - * that you want to unlink (delete). - * @param permission - The `permission` parameter is an optional parameter that specifies the level - * of permission required to perform the unlink operation. It has a default value of - * `Permission.USER`, which means that the operation can be performed by the user. - */ - async unlink (path: string, permission = Permission.USER): Promise { - const { current, filename } = await this.navigatePathParent(path) - - if (!current.children[filename].deleteable) throw new Error(Errors.EPERM) - await this.handlePermissions(path, permission) - - Reflect.deleteProperty(current.children, filename) - await this.save() - } - - /** - * The function reads a file from a given path and returns its content as a Buffer. - * @param {string} path - The `path` parameter is a string that represents the file path of the file - * to be read. It specifies the location of the file in the file system. - * @param permission - The `permission` parameter is an optional parameter that specifies the - * permission level required to read the file. It has a default value of `Permission.USER`, which - * means that the file can be read by the current user. - * @returns a Promise that resolves to a Buffer. - */ - async readFile (path: string, permission = Permission.USER): Promise { - const { current } = await this.navigatePath(path) - - await this.handlePermissions(path, permission) - - if (current.type !== 'file') throw new Error(Errors.EISDIR) - return current.content - } - - /** - * The `writeFile` function writes content to a file at a specified path, with an optional permission - * parameter. - * @param {string} path - The `path` parameter is a string that represents the file path where the - * file will be written to. - * @param {string | Buffer} content - The `content` parameter is the data that you want to write to - * the file. It can be either a string or a Buffer object. - * @param permission - The `permission` parameter is an optional parameter that specifies the - * permission level for the file being written. It has a default value of `Permission.USER`, which - * indicates that the file can be accessed and modified only by the user who wrote it. - */ - async writeFile (path: string, content: string | Buffer, permission = Permission.USER): Promise { - const { current, filename } = await this.navigatePathParent(path) - - await this.handlePermissions(path, permission) - - current.children[filename] = { - type: 'file', - deleteable: true, - permission, - content: Buffer.from(content) - } - await this.save() - } - - /** - * The `mkdir` function creates a new directory at the specified path with the given permission. - * @param {string} path - The `path` parameter is a string that represents the directory path where - * the new directory will be created. It specifies the location where the new directory will be - * created. - * @param permission - The `permission` parameter is an optional parameter that specifies the - * permission level for the newly created directory. It has a default value of `Permission.USER`, - * which indicates that only the user has permission to access the directory. - */ - async mkdir (path: string, permission = Permission.USER): Promise { - const { current, filename } = await this.navigatePathParent(path) - - await this.handlePermissions(path, permission) - - current.children[filename] = { - type: 'directory', - deleteable: true, - permission, - children: {} - } - await this.save() - } - - /** - * The `rmdir` function removes a directory at the specified path, after checking permissions and - * ensuring that the path is a directory. - * @param {string} path - The `path` parameter is a string that represents the path of the directory - * to be removed. - * @param permission - The `permission` parameter is an optional parameter that specifies the level - * of permission required to remove a directory. It has a default value of `Permission.USER`, which - * means that the user must have permission to remove the directory. - */ - async rmdir (path: string, permission = Permission.USER): Promise { - const { current, filename } = await this.navigatePathParent(path) - - if (!current.deleteable) throw new Error(Errors.EPERM) - await this.handlePermissions(path, permission) - - if (current.children[filename].type !== 'directory') throw new Error(Errors.ENOTDIR) - Reflect.deleteProperty(current.children, filename) - await this.save() - } - - /** - * The `readdir` function reads the contents of a directory and returns an array of file names. - * @param {string} path - The `path` parameter is a string that represents the directory path from - * which you want to read the files. - * @param permission - The `permission` parameter is an optional parameter that specifies the - * permission level for accessing the directory. It has a default value of `Permission.USER`. - * @returns The function `readdir` returns a Promise that resolves to an array of strings. - */ - async readdir (path: string, permission = Permission.USER): Promise { - console.log(this.fileSystem) - const { current } = await this.navigatePath(path) - - if (current.type === 'file') throw new Error(Errors.ENOTDIR) - const result = await Promise.all(Object.keys(current.children ?? {})) - return result - } - - /** - * The `stat` function in TypeScript returns an object with two methods, `isDirectory` and `isFile`, - * which determine if a given path is a directory or a file, respectively. - * @param {string} path - A string representing the path to a file or directory. - * @param permission - The `permission` parameter is an optional parameter that specifies the - * permission level for accessing the file or directory. It has a default value of `Permission.USER`, - * which means that the function will check the permission level for the current user. - * @returns an object with two methods: `isDirectory` and `isFile`. - */ - async stat (path: string, permission = Permission.USER): Promise<{ isDirectory: () => boolean, isFile: () => boolean }> { - const { current } = await this.navigatePath(path) - return { - isDirectory: () => current.type === 'directory', - isFile: () => current.type === 'file' - } - } - - /** - * The `rename` function renames a file or directory by moving it from the old path to the new path, - * while also handling permissions and updating the file system structure. - * @param {string} oldPath - The old path of the file or directory that needs to be renamed. - * @param {string} newPath - The `newPath` parameter is a string that represents the new path or - * location where the file or directory will be renamed to. - * @param permission - The `permission` parameter is an optional parameter that specifies the - * permission level for the file or directory being renamed. It has a default value of - * `Permission.USER`, which indicates that the user has permission to perform the rename operation. - */ - async rename (oldPath: string, newPath: string, permission = Permission.USER): Promise { - const { current: oldCurrent, filename: oldFilename } = await this.navigatePathParent(oldPath) - const { current: newCurrent, filename: newFilename } = await this.navigatePathParent(newPath) - - if (!oldCurrent.deleteable) throw new Error(Errors.EPERM) - if (!newCurrent.deleteable) throw new Error(Errors.EPERM) - - await this.handlePermissions(oldPath, permission) - await this.handlePermissions(newPath, permission) - - newCurrent.children[newFilename] = oldCurrent.children[oldFilename] - Reflect.deleteProperty(oldCurrent.children, oldFilename) - await this.save() - } - - /** - * The function checks if a file or directory exists at a given path. - * @param {string} path - A string representing the path to check for existence. - * @param permission - The `permission` parameter is an optional parameter that specifies the - * permission level for checking the existence of the path. It has a default value of - * `Permission.USER`. - * @returns a Promise that resolves to a boolean value. - */ - async exists (path: string, permission = Permission.USER): Promise { - const { current } = await this.navigatePath(path) - return current !== undefined - } -} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index bba77f6..0000000 --- a/src/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -import 'material-symbols' -import './assets/style.less' - -import Preloader from './instances/Preloader' -import StatusBar from './instances/StatusBar' -import WindowManager from './instances/WindowManager' -import Flow from './instances/Flow' - -import { VirtualFS } from './fs' - -import { version } from '../package.json' - -const flowDetails = { - version, - codename: 'Mochi' -} -declare global { - interface Window { - flowDetails: typeof flowDetails - preloader: Preloader - flow: Flow - fs: VirtualFS - statusBar: StatusBar - wm: WindowManager - } -} - -const params = new URLSearchParams(window.location.search) - -async function enableDebug (): Promise { - const { default: eruda } = await import('eruda') - eruda.init() - return await Promise.resolve() -} - -if (params.get('debug') !== null && params.get('debug') !== undefined) { - enableDebug().catch(e => console.error(e)) -} - -window.flowDetails = flowDetails -window.preloader = new Preloader() -window.flow = new Flow() -window.statusBar = new StatusBar() -window.wm = new WindowManager(); - -(async function () { - window.preloader.setPending('filesystem') - window.fs = new VirtualFS() - - const registrations = await navigator.serviceWorker.getRegistrations() - for (const registration of registrations) { - await registration.unregister() - } - await navigator.serviceWorker.register('/uv-sw.js?url=' + encodeURIComponent(btoa('https://server.flow-works.me')), { - scope: '/service/' - }) - - await window.preloader.setDone('filesystem') - - await window.wm.init() - await window.flow.init() - await window.statusBar.init() - - window.preloader.setStatus('') - window.preloader.finish() -})().catch(e => console.error) diff --git a/src/instances/Flow.ts b/src/instances/Flow.ts deleted file mode 100644 index 63fd54b..0000000 --- a/src/instances/Flow.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { LoadedApp, LoadedPlugin } from '../types' -import nullIcon from '../assets/icons/application-default-icon.svg' - -class Flow { - apps: LoadedApp[] = [] - defaultAppList: string[] = [ - 'settings', - 'music', - 'files', - 'editor', - 'info', - 'manager', - 'browser', - 'store' - ] - - appList: string[] = [] - - plugins: LoadedPlugin[] = [] - pluginList: string[] = [] - - /** - * Initiates applications. - */ - private async initApps (): Promise { - window.preloader.setPending('apps') - window.preloader.setStatus('importing apps...') - - window.fs.readdir('/home/Applications/').then((list) => { - list.forEach((file) => { - window.fs.readFile('/home/Applications/' + file).then(content => { - if (!file.endsWith('.js') && !file.endsWith('.mjs')) return - if (content.toString() === '') return - this.appList.push(`data:text/javascript;base64,${btoa(content.toString())}`) - }).catch((e) => console.error(e)) - }) - }).catch(e => console.error(e)) - - for (const appPath of this.defaultAppList) { - window.preloader.setStatus(`importing default apps\n${appPath}`) - const { default: ImportedApp } = await import(`../builtin/apps/${appPath}.ts`).catch(async (e: Error) => { - console.error(e) - await window.preloader.setError('apps') - window.preloader.setStatus(`unable to import ${appPath}\n${e.name}: ${e.message}`) - }) - const app = new ImportedApp() - app.builtin = true - app.meta.icon = app.meta.icon ?? nullIcon - - this.addApp(app) - } - - if (this.appList.length > 0) { - for (const appPath of this.appList) { - window.preloader.setStatus(`importing appstore apps\n${appPath}`) - - let error = false - const { default: ImportedApp } = await import(appPath).catch(async (e: Error) => { - console.error(e) - await window.preloader.setError('apps') - window.preloader.setStatus(`unable to import ${appPath}\n${e.name}: ${e.message}`) - error = true - }) - if (error) break - const app = new ImportedApp() - app.builtin = false - app.meta.icon = app.meta.icon ?? nullIcon - - this.addApp(app) - } - } - - window.wm.launcher.style.opacity = '0' - window.wm.launcher.style.filter = 'blur(0px)' - window.wm.launcher.style.pointerEvents = 'none' - - window.preloader.setStatus('adding apps to app launcher...') - - this.apps.forEach((app) => { - window.preloader.setStatus(`adding apps to app launcher\n${app.meta.name}`) - const appElement = document.createElement('app') - appElement.onclick = async () => { - await window.flow.openApp(app.meta.pkg) - window.wm.toggleLauncher() - } - appElement.innerHTML = `
${app.meta.name}
` - window.wm.launcher.querySelector('apps')?.appendChild(appElement) - }) - - document.body.appendChild(window.wm.windowArea) - document.body.appendChild(window.wm.launcher) - - await window.preloader.setDone('apps') - } - - /** - * Initiates plugins. - */ - private async initPlugins (): Promise { - window.preloader.setPending('plugins') - window.preloader.setStatus('importing default plugins...') - - for (const pluginPath of this.pluginList) { - window.preloader.setStatus(`importing default plugins\n${pluginPath}`) - const plugin = await import(`../builtin/plugins/${pluginPath}.ts`).catch((e: Error) => { - console.error(e) - window.preloader.setStatus(`unable to import ${pluginPath}\n${e.name}: ${e.message}`) - }) - const loadedPlugin = { - ...plugin, - builtin: true - } - this.addPlugin(loadedPlugin) - } - } - - /** - * Initiates the Flow session. - */ - async init (): Promise { - await this.initApps() - await this.initPlugins() - } - - /** - * Registers an app. - * - * @param app The app to be registered. - */ - addApp (app: LoadedApp): void { - if (this.apps.some(x => x.meta.pkg === app.meta.pkg)) { - console.error(`Unable to register app; ${app.meta.pkg} is already registered.`) - return - } - - this.apps.push(app) - } - - /** - * Registers a plugin. - * - * @param plugin The plugin to be registered. - */ - addPlugin (plugin: LoadedPlugin): void { - if (window.flow.plugins.some(x => x.meta.pkg === plugin.meta.pkg)) { - console.error(`Unable to register tool; ${plugin.meta.pkg} is already registered.`) - return - } - this.plugins.push(plugin) - } - - /** - * Opens a registered application. - * - * @param pkg The PKG ID of the application. - * @param data Payload info for app to recieve. - */ - async openApp (pkg: string, data?: any): Promise { - const app = this.apps.find(x => x.meta.pkg === pkg) - const win = app?.open(data) - const event = new CustomEvent('app_opened', { detail: { app, win: await win } }) - window.dispatchEvent(event) - } -} - -export default Flow diff --git a/src/instances/Preloader.ts b/src/instances/Preloader.ts deleted file mode 100644 index 3412887..0000000 --- a/src/instances/Preloader.ts +++ /dev/null @@ -1,70 +0,0 @@ -import flowIcon from '../assets/flow.png' - -class Preloader { - element: HTMLElement - - /** - * Creates the preloader. - */ - constructor () { - this.element = document.createElement('preloader') - - this.element.innerHTML = ` - -
-
- ` - - document.body.appendChild(this.element) - } - - /** - * Sets the status text of the preloader. - * - * @param value The preloader status text. - */ - setStatus (value: string): void { - (this.element.querySelector('.status') as HTMLElement).innerText = value - } - - /** - * Sets loading state of an instance to pending. - * - * @param value The name of an instance. - */ - setPending (value: string): void { - (this.element.querySelector('.done') as HTMLElement).innerHTML += `
check_indeterminate_small${value}
` - } - - /** - * Sets loading state of an instance to done. - * - * @param value The name of an instance. - */ - async setDone (value: string): Promise { - const icon = this.element.querySelector('.done')?.querySelector(`.${value.split(' ').join('-')}`)?.querySelector('.material-symbols-rounded') as HTMLElement - icon.innerHTML = 'check_small' - await new Promise(resolve => setTimeout(resolve, 300)) - } - - /** - * Sets loading state of an instance to error. - * - * @param value The name of an instance. - */ - async setError (value: string): Promise { - const icon = this.element.querySelector('.done')?.querySelector(`.${value.split(' ').join('-')}`)?.querySelector('.material-symbols-rounded') as HTMLElement - icon.innerHTML = 'close_small' - await new Promise(resolve => setTimeout(resolve, 300)) - } - - /** - * Removes the preloader. - */ - finish (): void { - this.element.style.opacity = '0' - this.element.style.pointerEvents = 'none' - } -} - -export default Preloader diff --git a/src/instances/StatusBar.ts b/src/instances/StatusBar.ts deleted file mode 100644 index 58c391d..0000000 --- a/src/instances/StatusBar.ts +++ /dev/null @@ -1,187 +0,0 @@ - -import { AppClosedEvent, AppOpenedEvent, Plugin } from '../types' -import { getTime } from '../utils' - -class StatusBar { - element: HTMLElement - - /** - * Creates the status bar. - */ - constructor () { - this.element = document.createElement('toolbar') - - this.element.innerHTML = ` -
space_dashboard
- ${/*
widgets
*/ ''} -
- -
expand_less
-
- battery_2_bar - signal_cellular_4_bar -
-
- ${/*
- notifications -
*/ ''} - ` - - setInterval((): any => { - getTime().then((time) => { - (this.element.querySelector('div[data-toolbar-id="calendar"]') as HTMLElement).innerText = time - }).catch(e => console.error) - }, 1000) - - this.element.querySelector('div[data-toolbar-id="start"]')?.addEventListener('click', () => { - window.wm.toggleLauncher() - }) - - function updateBatteryIcon (battery: any): void { - let iconHTML = '' - - if (battery.charging === true) { - if (battery.level === 1) { - iconHTML = 'battery_charging_full' - } else if (battery.level >= 0.9) { - iconHTML = 'battery_charging_90' - } else if (battery.level >= 0.8) { - iconHTML = 'battery_charging_80' - } else if (battery.level >= 0.6) { - iconHTML = 'battery_charging_60' - } else if (battery.level >= 0.5) { - iconHTML = 'battery_charging_50' - } else if (battery.level >= 0.3) { - iconHTML = 'battery_charging_30' - } else if (battery.level >= 0) { - iconHTML = 'battery_charging_20' - } - } else { - if (battery.level === 1) { - iconHTML = 'battery_full' - } else if (battery.level >= 0.6) { - iconHTML = 'battery_6_bar' - } else if (battery.level >= 0.5) { - iconHTML = 'battery_5_bar' - } else if (battery.level >= 0.4) { - iconHTML = 'battery_4_bar' - } else if (battery.level >= 0.3) { - iconHTML = 'battery_3_bar' - } else if (battery.level >= 0.2) { - iconHTML = 'battery_2_bar' - } else if (battery.level >= 0.1) { - iconHTML = 'battery_1_bar' - } else if (battery.level >= 0) { - iconHTML = 'battery_0_bar' - } - } - - const batteryDiv = document.querySelector('div[data-toolbar-id="controls"] > .battery') - if (batteryDiv != null) { - batteryDiv.innerHTML = iconHTML - } - } - - if ('getBattery' in navigator) { - (navigator as any).getBattery().then(function (battery: any) { - updateBatteryIcon(battery) - - battery.addEventListener('levelchange', function () { - updateBatteryIcon(battery) - }) - - battery.addEventListener('chargingchange', function () { - updateBatteryIcon(battery) - }) - }) - } else { - const batteryDiv = document.querySelector('div[data-toolbar-id="controls"] > .battery') - if (batteryDiv != null) { - batteryDiv.innerHTML = 'battery_unknown' - } - } - - function updateIcon (ms: number): void { - let icon = '' - - if (ms >= 200 && ms < 400) { - icon = 'signal_cellular_1_bar' - } else if (ms >= 400 && ms < 600) { - icon = 'signal_cellular_2_bar' - } else if (ms >= 600 && ms < 800) { - icon = 'signal_cellular_3_bar' - } else if (ms >= 800) { - icon = 'signal_cellular_4_bar' - } else { - icon = 'signal_cellular_0_bar' - } - - (document.querySelector('div[data-toolbar-id="controls"] > .signal') as HTMLElement).innerHTML = icon - } - - async function ping (startTime: number): Promise { - fetch((await window.config()).SERVER_URL + '/bare/') - .then(() => { - const endTime = performance.now() - const pingTime = endTime - startTime - updateIcon(pingTime) - }) - .catch(() => { - (document.querySelector('div[data-toolbar-id="controls"] > .signal') as HTMLElement).innerHTML = 'signal_cellular_connected_no_internet_4_bar' - }) - } - - setInterval((): any => ping(performance.now()), 10000) - - window.addEventListener('app_opened', (e: AppOpenedEvent): void => { - const appIcon = document.createElement('app') - const app = e.detail.app - const win = e.detail.win - appIcon.innerHTML = `` - appIcon.onclick = async () => { - const win = await e.detail.win - win.focus() - win.toggleMin() - } - this.element.querySelector('div[data-toolbar-id="apps"]')?.appendChild(appIcon) - }) - - window.addEventListener('app_closed', (e: AppClosedEvent): void => { - const win = e.detail.win - this.element.querySelector('div[data-toolbar-id="apps"]')?.querySelector(`img[data-id="${win.id}"]`)?.parentElement?.remove() - }) - - document.body.style.flexDirection = 'column-reverse' - document.body.appendChild(this.element) - } - - /** - * Adds a plugin to the status bar. - * - * @param item The plugin to be added to the status bar. - */ - async add (item: Plugin): Promise { - const element = document.createElement('div') - element.setAttribute('data-toolbar-id', item.meta.pkg) - - this.element.appendChild(element) - - await item.run(element, await window.config()) - } - - /** - * Initiates the status bar. - */ - async init (): Promise { - window.preloader.setStatus('adding plugins to statusbar...') - - for (const plugin of window.flow.plugins) { - window.preloader.setStatus(`adding plugins to statusbar\n${plugin.meta.pkg}`) - await this.add(plugin) - } - - await window.preloader.setDone('plugins') - } -} - -export default StatusBar diff --git a/src/instances/WindowManager.ts b/src/instances/WindowManager.ts deleted file mode 100644 index e7b0524..0000000 --- a/src/instances/WindowManager.ts +++ /dev/null @@ -1,152 +0,0 @@ - -import HTML from '../lib' -import FlowWindow from '../structures/FlowWindow' -import { FlowWindowConfig } from '../types' - -class WindowManager { - private isLauncherOpen = false - windowArea: HTMLElement - launcher: HTMLElement - windows: FlowWindow[] = [] - - /** - * Creates the window container. - */ - constructor () { - this.windowArea = document.createElement('window-area') - } - - /** - * Gets the highest window's z-index. - * - * @returns The heighest window's z-index. - */ - getHighestZIndex (): number { - const indexes = this.windows.map((win: FlowWindow) => { - return parseInt(win.element.style.zIndex) - }) - - const max = Math.max(...indexes) - - return max === -Infinity ? 0 : max - } - - /** - * Creates a window. - * - * @param config The config for the window to follow. - * @returns The created window. - */ - createWindow (config: FlowWindowConfig): FlowWindow { - const win = new FlowWindow(this, config) - this.windows.push(win) - this.windowArea.appendChild(win.element) - return win - } - - /** - * Creates a modal window. - * - * @param {string} title - A string representing the title of the modal window. - * @param {string} text - The `text` parameter is a string that represents the content or message to - * be displayed in the modal window. - * @returns The function `createModal` is returning a `FlowWindow` object. - */ - async createModal (title: string, text: string): Promise { - const win = new FlowWindow(this, { - title, - icon: '', - width: 300, - height: 200, - canResize: false - }) - - return await new Promise((resolve) => { - new HTML('h3').text(text).appendTo(win.content) - new HTML('p').text(text).appendTo(win.content) - new HTML('button').text('Allow').appendTo(win.content).on('click', () => { - resolve(true) - win.close() - }) - new HTML('button').text('Allow').appendTo(win.content).on('click', () => { - resolve(false) - win.close() - }) - - this.windows.push(win) - this.windowArea.appendChild(win.element) - }) - } - - /** - * Toggles the app launcher. - */ - toggleLauncher (): boolean { - if (this.isLauncherOpen) { - this.launcher.style.opacity = '0' - this.launcher.style.backdropFilter = 'blur(0px)' - this.launcher.style.pointerEvents = 'none' - } else { - this.launcher.style.opacity = '1' - this.launcher.style.backdropFilter = 'blur(20px)' - this.launcher.style.pointerEvents = 'all' - } - - this.isLauncherOpen = !this.isLauncherOpen - return this.isLauncherOpen - } - - /** - * Initiates the window manager. - */ - async init (): Promise { - window.preloader.setPending('window manager') - window.preloader.setStatus('creating app launcher...') - this.launcher = document.createElement('launcher') - - this.launcher.innerHTML = ` - - - `; - - (this.launcher.querySelector('input') as HTMLInputElement).onkeyup = () => { - (this.launcher.querySelector('apps') as HTMLElement).innerHTML = '' - if ((this.launcher.querySelector('input') as HTMLInputElement).value !== '') { - window.flow.apps.filter(x => x.meta.name.toLowerCase().includes((this.launcher.querySelector('input') as HTMLInputElement).value.toLowerCase())).forEach((app) => { - const appElement = document.createElement('app') - appElement.onclick = async () => { - await window.flow.openApp(app.meta.pkg) - this.toggleLauncher() - } - appElement.innerHTML = `
${app.meta.name}
` - this.launcher.querySelector('apps')?.appendChild(appElement) - }) - } else { - window.flow.apps.forEach((app) => { - window.preloader.setStatus(`adding apps to app launcher\n${app.meta.name}`) - const appElement = document.createElement('app') - appElement.onclick = async () => { - await window.flow.openApp(app.meta.pkg) - window.wm.toggleLauncher() - } - appElement.innerHTML = `
${app.meta.name}
` - window.wm.launcher.querySelector('apps')?.appendChild(appElement) - }) - } - } - - this.launcher.onclick = (e) => { - if (e.target !== e.currentTarget) return - this.toggleLauncher() - } - - (this.launcher.querySelector('apps') as HTMLElement).onclick = (e) => { - if (e.target !== e.currentTarget) return - this.toggleLauncher() - } - - await window.preloader.setDone('window manager') - } -} - -export default WindowManager diff --git a/src/kernel.ts b/src/kernel.ts new file mode 100644 index 0000000..eed125d --- /dev/null +++ b/src/kernel.ts @@ -0,0 +1,141 @@ +import './assets/style.less' +import { version } from '../package.json' +import { v4 as uuid } from 'uuid' +import { Permission } from './system/lib/VirtualFS' +import ProcessLib from './structures/ProcessLib' +import ProcLib from './structures/ProcLib' +import { Executable, Process, Package, ProcessInfo, KernelConfig } from './types' +import semver from 'semver' + +declare global { + interface Window { + kernel: Kernel + } +} + +const params = new URLSearchParams(window.location.search) + +async function enableDebug (): Promise { + const { default: eruda } = await import('eruda') + eruda.init() + return await Promise.resolve() +} + +if (params.get('debug') !== null && params.get('debug') !== undefined) { + enableDebug().catch(e => console.error(e)) +} + +export default class Kernel { + readonly version: string + readonly codename: string + processList: ProcessInfo[] = [] + packageList: { + [key: string]: Package + } = {} + + fs: any + + config: KernelConfig + lastPid: number = 0 + + constructor (version: string) { + this.codename = 'Mochi' + this.version = version + } + + setFS (fs: any, process: ProcessLib): void { + if (process.permission === Permission.SYSTEM) { + this.fs = fs + } + } + + setConfig (data: any, process: ProcessLib): void { + if (process.permission === Permission.SYSTEM) { + this.config = data + document.dispatchEvent(new CustomEvent('config_update', { + detail: { + config: this.config + } + })) + } + } + + async startExecutable (url: string, permission = Permission.USER, data = {}): Promise<{ procLib: ProcessLib, executable: Process } | any> { + let executable: Executable + try { + const comps = import.meta.glob('./system/**/*.ts') + const module = comps[`./system/${url}.ts`] + const importedExecutable = (await module()) as any + executable = importedExecutable.default + } catch { + if (this.fs === undefined) throw new Error('Filesystem hasn\'t been initiated.') + const dataURL = 'data:text/javascript;base64,' + Buffer.from(await this.fs.readFile('/opt/' + url + '.js')).toString('base64') + const importedExecutable = await import(dataURL) + executable = importedExecutable.default + } + + if (semver.gt(executable.config.targetVer, this.version)) throw new Error(`Executable requires a newer version of FlowOS: ${executable.config.targetVer}`) + if (executable === undefined) throw new Error(`No default export found for package: ${url}.`) + + if (this.packageList[executable.config.name] === undefined) this.packageList[executable.config.name] = { url, executable } + else if (this.packageList[executable.config.name].url !== url) throw new Error(`Package name conflict: ${executable.config.name}`) + + return await new Promise((resolve, reject) => { + switch (executable.config.type) { + case 'process': { + const executableProcess = executable as Process + console.group(`Starting ${url}`) + const pid = ProcLib.findEmptyPID(this) + const token = uuid() + const procLib = new ProcessLib(url, pid, token, permission, data, executableProcess, this) + this.processList.push({ + pid, + token, + name: executableProcess.config.name + }) + document.dispatchEvent(new CustomEvent('update_process', {})) + executableProcess.run(procLib).then((value: any) => { + if (value !== undefined) procLib.kill().catch(e => console.error(e)) + document.dispatchEvent(new CustomEvent('update_process', {})) + resolve({ procLib, value }) + }).catch(e => console.error(e)) + break + } + + default: { + reject(new Error(`Unknown executable type: ${executable.config.type as string}`)) + break + } + } + }) + } + + async getExecutable (url: string): Promise { + let executable: Executable + try { + const comps = import.meta.glob('./system/**/*.ts') + const module = comps[`./system/${url}.ts`] + const importedExecutable = (await module()) as any + executable = importedExecutable.default + } catch { + if (this.fs === undefined) throw new Error('Filesystem hasn\'t been initiated.') + const dataURL = 'data:text/javascript;base64,' + Buffer.from(await this.fs.readFile('/opt/' + url + '.js')).toString('base64') + const importedExecutable = await import(dataURL) + executable = importedExecutable.default + } + + if (semver.gt(executable.config.targetVer, this.version)) throw new Error(`Executable requires a newer version of FlowOS: ${executable.config.targetVer}`) + if (executable === undefined) throw new Error(`No default export found for package: ${url}.`) + + if (this.packageList[executable.config.name] === undefined) this.packageList[executable.config.name] = { url, executable } + else if (this.packageList[executable.config.name].url !== url) throw new Error(`Package name conflict: ${executable.config.name}`) + + return executable + } +} + +document.addEventListener('DOMContentLoaded', () => { + import('material-symbols') + const kernel = new Kernel(version) + kernel.startExecutable('BootLoader', Permission.SYSTEM).catch(e => console.error(e)) +}) diff --git a/src/structures/FlowWindow.ts b/src/structures/FlowWindow.ts index 7c4b13e..4017bed 100644 --- a/src/structures/FlowWindow.ts +++ b/src/structures/FlowWindow.ts @@ -1,8 +1,7 @@ -import { v4 as uuid } from 'uuid' -import WindowManager from '../instances/WindowManager' import { FlowWindowConfig } from '../types' import { sanitize } from '../utils' import nullIcon from '../assets/icons/application-default-icon.svg' +import ProcessLib from './ProcessLib' /** * Makes an element draggable. @@ -78,9 +77,11 @@ class FlowWindow { isMinimized = false isMaximized = false - wm: WindowManager + wm: any - id = uuid() + readonly process: ProcessLib + + onClose: () => void config: FlowWindowConfig @@ -90,13 +91,16 @@ class FlowWindow { * @param wm The current window manager session. * @param config The window's pre-set config. */ - constructor (wm: WindowManager, config: FlowWindowConfig) { + constructor (process: ProcessLib, wm: any, config: FlowWindowConfig, onClose = () => {}) { + this.process = process this.wm = wm this.config = config + this.onClose = onClose + this.element = document.createElement('window') - this.element.style.zIndex = (window.wm.getHighestZIndex() + 1).toString() + this.element.style.zIndex = (wm.getHighestZIndex() as number + 1).toString() this.element.style.position = 'absolute' this.focus() @@ -112,13 +116,13 @@ class FlowWindow { this.element.style.height = `${config.height ?? 200}px` this.header = document.createElement('window-header') - this.header.innerHTML = `
${sanitize(config.title)}
minimizeclose` + this.header.innerHTML = `${sanitize(config.title)} icon
${sanitize(config.title)}
minimizeclose` if (config.canResize) { - this.header.innerHTML = `
${sanitize(config.title)}
minimizesquareclose` + this.header.innerHTML = `${sanitize(config.title)} icon
${sanitize(config.title)}
minimizesquareclose` } (this.header.querySelector('#close') as HTMLElement).onclick = () => { - this.close() + this.process.kill().catch((e: any) => console.error(e)) } (this.header.querySelector('#min') as HTMLElement).onclick = () => this.toggleMin() @@ -159,8 +163,6 @@ class FlowWindow { shadow.appendChild(shadowBody) this.content = shadowBody - console.log(this.content) - this.element.appendChild(this.header) this.element.appendChild(this.realContent) @@ -224,7 +226,7 @@ class FlowWindow { */ focus (): void { if (this.element.style.zIndex !== this.wm.getHighestZIndex().toString()) { - this.element.style.zIndex = (this.wm.getHighestZIndex() + 1).toString() + this.element.style.zIndex = (this.wm.getHighestZIndex() as number + 1).toString() } } @@ -235,8 +237,7 @@ class FlowWindow { this.element.style.pointerEvents = 'none' this.element.style.opacity = '0' this.element.style.transform = 'translateY(10px)' - const event = new CustomEvent('app_closed', { detail: { win: this } }) - window.dispatchEvent(event) + this.onClose() setTimeout(() => { this.element.remove() }, 200) diff --git a/src/structures/LibraryLib.ts b/src/structures/LibraryLib.ts new file mode 100644 index 0000000..a06ed89 --- /dev/null +++ b/src/structures/LibraryLib.ts @@ -0,0 +1,5 @@ +import HTML from '../HTML' + +export default class LibraryLib { + HTML = HTML +} diff --git a/src/structures/ProcLib.ts b/src/structures/ProcLib.ts new file mode 100644 index 0000000..60bc136 --- /dev/null +++ b/src/structures/ProcLib.ts @@ -0,0 +1,26 @@ +import Kernel from '../kernel' + +const ProcLib = { + findEmptyPID: function (kernel: Kernel) { + const r = kernel.processList.findIndex((p) => p === null) + return r !== -1 ? r : kernel.processList.length + }, + cleanupProcess: function (kernel: Kernel, pid: number) { + const proc = kernel.processList + .filter((p) => p !== null) + .find((p) => p.pid === pid) + if (proc === undefined) throw new Error(`Process ${pid} not found.`) + console.group(`Killing process ${pid} (${proc.name})`) + document.dispatchEvent(new CustomEvent('app_closed', { + detail: { + token: proc.token + } + })) + kernel.processList.splice(pid, 1) + document.dispatchEvent(new CustomEvent('update_process', {})) + console.groupEnd() + console.groupEnd() + } +} + +export default ProcLib diff --git a/src/structures/ProcessLib.ts b/src/structures/ProcessLib.ts new file mode 100644 index 0000000..e2e6e3e --- /dev/null +++ b/src/structures/ProcessLib.ts @@ -0,0 +1,123 @@ +import semver from 'semver' +import Kernel from '../kernel' +import { Permission } from '../system/lib/VirtualFS' +import { Process, Executable, LibraryData, Package, Library } from '../types' +import FlowWindow from './FlowWindow' +import LibraryLib from './LibraryLib' +import ProcLib from './ProcLib' + +export default class ProcessLib { + readonly pid: number + readonly token: string + process: Process + private readonly _kernel: Kernel + readonly kernel: { + getExecutable: (url: string) => Promise + processList: Array<{ pid: number, name: string, token: string }> + packageList: { + [key: string]: Package + } + config: any + setConfig: (data: any) => void + setFS: (fs: any) => void + } + + readonly permission: Permission + + win: FlowWindow + readonly data: any + + readonly sysInfo: { + codename: string + version: string + } + + constructor (url: string, pid: number, token: string, permission = Permission.USER, data = {}, process: Process, kernel: Kernel) { + this.permission = permission + this.pid = pid + this.token = token + this._kernel = kernel + this.kernel = { + getExecutable: kernel.getExecutable.bind(kernel), + processList: kernel.processList, + packageList: kernel.packageList, + config: kernel.config, + setConfig: (data: any) => kernel.setConfig(data, this), + setFS: (fs: any) => kernel.setFS(fs, this) + } + this.process = process + this.data = data + + this.sysInfo = { + codename: kernel.codename, + version: kernel.version + } + + document.addEventListener('config_update', (e: CustomEvent) => { + this.kernel.config = e.detail.config + }) + } + + async loadLibrary (url: string): Promise { + let executable: Executable + try { + const comps = import.meta.glob('../system/**/*.ts') + const module = comps[`../system/${url}.ts`] + const importedExecutable = (await module()) as any + executable = importedExecutable.default + } catch { + if (this._kernel.fs === undefined) throw new Error('Filesystem hasn\'t been initiated.') + const dataURL = 'data:text/javascript;base64,' + Buffer.from(await this._kernel.fs.readFile('/opt/' + url + '.js')).toString('base64') + const importedExecutable = await import(dataURL) + executable = importedExecutable.default + } + + if (semver.gt(executable.config.targetVer, this.sysInfo.version)) throw new Error(`Executable requires a newer version of FlowOS: ${executable.config.targetVer}`) + if (executable === undefined) throw new Error(`No default export found for package: ${url}.`) + + if (this._kernel.packageList[executable.config.name] === undefined) this._kernel.packageList[executable.config.name] = { url, executable } + else if (this._kernel.packageList[executable.config.name].url !== url) throw new Error(`Package name conflict: ${executable.config.name}`) + + if (executable.config.type !== 'library') throw new Error(`Executable is not a library: ${executable.config.name}`) + const executableLibrary = executable as Library + executableLibrary.init(new LibraryLib(), this._kernel, this) + + return executableLibrary.data + } + + async launch (url: string, data = {}): Promise<{ procLib: ProcessLib, executable: Process } | null> { + const executable = await this._kernel.getExecutable(url) + if (this.permission === Permission.SYSTEM) { + return await this._kernel.startExecutable(url, Permission.USER, data) + } else { + const uac = await this._kernel.startExecutable('UserAccessControl', Permission.SYSTEM, { + type: 'launch', + executable, + process: this + }) as { value: boolean, procLib: ProcessLib } + if (uac.value) { + return await this._kernel.startExecutable(url, Permission.USER, data) + } else { + return null + } + } + } + + async killProcess (pid: number): Promise { + const process = this._kernel.processList.find((p) => p.pid === pid) + if (process === undefined) throw new Error(`Process ${pid} not found.`) + const uac = await this._kernel.startExecutable('UserAccessControl', Permission.SYSTEM, { + type: 'kill', + name: process.name, + process: this + }) as { value: boolean, procLib: ProcessLib } + if (pid === 0) throw new Error('Cannot kill BootLoader process.') + if (uac.value) { + return ProcLib.cleanupProcess(this._kernel, pid) + } + } + + async kill (): Promise { + ProcLib.cleanupProcess(this._kernel, this.pid) + } +} diff --git a/src/system/BootLoader.ts b/src/system/BootLoader.ts new file mode 100644 index 0000000..27e923d --- /dev/null +++ b/src/system/BootLoader.ts @@ -0,0 +1,189 @@ +import HTML from '../HTML' +import { AppClosedEvent, AppOpenedEvent, Process } from '../types' +import { getTime } from '../utils' +import { db, defaultFS, initializeDatabase, read, setFileSystem, write } from './lib/VirtualFS' +import nullIcon from '../assets/icons/application-default-icon.svg' +import { parse } from 'js-ini' +import { v4 as uuid } from 'uuid' + +const BootLoader: Process = { + config: { + name: 'Bootloader', + type: 'process', + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + const splashScreen = await process.loadLibrary('lib/SplashScreen') + const splashElement = splashScreen.getElement() + splashElement.appendTo(document.body) + + const fs = await process.loadLibrary('lib/VirtualFS') + const wm = await process.loadLibrary('lib/WindowManager') + const launcher = await process.loadLibrary('lib/Launcher') + + await initializeDatabase('virtualfs') + db.onerror = (event: Event) => { + const target = event.target as IDBRequest + const errorMessage = target.error !== null ? target.error.message : 'Unknown error' + throw new Error(`[VirtualFS] ${target.error?.name ?? 'Unknown Error'}: ${errorMessage}`) + } + if ('storage' in navigator) { + await navigator.storage?.persist()?.catch(e => console.error(e)) + } else { + console.warn('Persistent storage is not supported.') + } + const fileSystem = await read() + fileSystem === undefined ? await write(defaultFS) : await setFileSystem(fileSystem) + + const config = Buffer.from(await fs.readFile('/etc/flow')).toString() + process.kernel.setFS(fs) + process.kernel.setConfig(parse(config)) + + if ('serviceWorker' in navigator) { + const registrations = await navigator.serviceWorker.getRegistrations() + for (const registration of registrations) { + await registration.unregister() + } + + try { + await navigator.serviceWorker.register('/uv-sw.js?url=' + encodeURIComponent(btoa(process.kernel.config.SERVER)) + '&e=' + uuid(), { + scope: '/service/' + }) + } catch (e) { + console.error(e) + } + } else { + console.warn('Service workers are not supported.') + } + + const input = new HTML('input').attr({ + type: 'text', + placeholder: 'Search' + }).on('keyup', () => { + apps.elm.innerHTML = '' + renderApps().catch(e => console.error(e)) + }).appendTo(launcher.element) + const apps = new HTML('apps').appendTo(launcher.element) + + const renderApps = async (): Promise => { + apps.html('') + const files = await fs.readdir('/home/Applications/') + files + .filter((x: string) => x.endsWith('.app') && ((input.elm as HTMLInputElement) !== null ? x.toLowerCase().includes((input.elm as HTMLInputElement).value.toLowerCase()) : true)) + .forEach(async (file: string) => { + fs.readFile(`/home/Applications/${file}`).then(async (data: Uint8Array) => { + const path = Buffer.from(data).toString() + const executable = await process.kernel.getExecutable(path) as Process + + const appElement = new HTML('app').on('click', () => { + process.launch(path).catch((e: any) => console.error(e)) + launcher.toggle() + }).appendTo(apps) + new HTML('img').attr({ + src: executable.config.icon ?? nullIcon, + alt: executable.config.name + ' icon' + }).appendTo(appElement) + new HTML('div').text(executable.config.name).appendTo(appElement) + }) + }) + } + + await renderApps() + document.addEventListener('fs_update', () => { + renderApps().catch(e => console.error(e)) + }) + + launcher.element.on('click', (e: Event) => { + if (e.target !== e.currentTarget) return + launcher.toggle() + }) + + const statusBar = await process.loadLibrary('lib/StatusBar') + + statusBar.element.html(` +
space_dashboard
+ ${/*
widgets
*/ ''} +
+ +
expand_less
+
+ battery_2_bar + signal_cellular_4_bar +
+
+ ${/*
+ notifications +
*/ ''} + `) + + setInterval((): any => { + getTime().then((time) => { + statusBar.element.qs('div[data-toolbar-id="calendar"]').text(time) + }).catch(e => console.error) + }, 1000) + + statusBar.element.qs('div[data-toolbar-id="start"]').on('click', () => { + launcher.toggle() + }) + + if ('getBattery' in navigator) { + (navigator as any).getBattery().then(function (battery: any) { + statusBar.updateBatteryIcon(battery) + + battery.addEventListener('levelchange', function () { + statusBar.updateBatteryIcon(battery) + }) + + battery.addEventListener('chargingchange', function () { + statusBar.updateBatteryIcon(battery) + }) + }) + } else { + const batteryDiv = document.querySelector('div[data-toolbar-id="controls"] > .battery') + if (batteryDiv != null) { + batteryDiv.innerHTML = 'battery_unknown' + } + } + + async function ping (startTime: number): Promise { + fetch(`${process.kernel.config.SERVER as string}/bare/`) + .then(() => { + const endTime = performance.now() + const pingTime = endTime - startTime + statusBar.updateIcon(pingTime) + }) + .catch(() => { + (document.querySelector('div[data-toolbar-id="controls"] > .signal') as HTMLElement).innerHTML = 'signal_cellular_connected_no_internet_4_bar' + }) + } + + setInterval((): any => ping(performance.now()), 10000) + + document.addEventListener('app_opened', (e: AppOpenedEvent): void => { + new HTML('app').appendMany( + new HTML('img').attr({ + alt: e.detail.proc.config.name + ' icon', + 'data-id': e.detail.token, + src: e.detail.proc.config.icon ?? nullIcon + }).on('click', () => { + e.detail.win.focus() + e.detail.win.toggleMin() + }) + ).appendTo(statusBar.element.qs('div[data-toolbar-id="apps"]')) + }) + + document.addEventListener('app_closed', (e: AppClosedEvent): void => { + statusBar.element.qs('div[data-toolbar-id="apps"]').qs(`img[data-id="${e.detail.token}"]`).elm.parentElement.remove() + }) + + document.body.style.flexDirection = 'column-reverse' + + await statusBar.element.appendTo(document.body) + await launcher.element.appendTo(document.body) + await wm.windowArea.appendTo(document.body) + + splashElement.cleanup() + } +} + +export default BootLoader diff --git a/src/system/UserAccessControl.ts b/src/system/UserAccessControl.ts new file mode 100644 index 0000000..5f2cab3 --- /dev/null +++ b/src/system/UserAccessControl.ts @@ -0,0 +1,50 @@ + +import FlowWindow from '../structures/FlowWindow' +import { Process } from '../types' + +const UserAccessControl: Process = { + config: { + name: 'User Access Control', + type: 'process', + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + if (Object.keys(process.data).length > 0) { + const initiator = process.data.process.process + const target = process.data.executable + return await new Promise((resolve) => { + process.loadLibrary('lib/WindowManager').then(async wm => { + let message + switch (process.data.type) { + case 'launch': { + message = `${initiator.config.name as string} wants to launch ${target.config.name as string}` + break + } + case 'kill': { + message = `${initiator.config.name as string} wants to kill ${process.data.name as string}` + break + } + case 'fs': { + message = `${initiator.config.name as string} wants to modify/access ${process.data.path as string}` + break + } + } + + wm.createModal('User Account Control', message, process) + .then(async ({ value, win }: { + value: boolean + win: FlowWindow + }) => { + if (value) { + resolve(true) + } else { + resolve(false) + } + }) + }).catch((e) => console.error(e)) + }) + } + } +} + +export default UserAccessControl diff --git a/src/builtin/apps/browser.ts b/src/system/apps/Browser.ts similarity index 79% rename from src/builtin/apps/browser.ts rename to src/system/apps/Browser.ts index 55154f4..efead69 100644 --- a/src/builtin/apps/browser.ts +++ b/src/system/apps/Browser.ts @@ -1,25 +1,25 @@ import icon from '../../assets/icons/web-browser.svg' -import { App } from '../../types' +import { Process } from '../../types' -import FlowWindow from '../../structures/FlowWindow' - -export default class BrowserApp implements App { - meta = { +const BrowserApp: Process = { + config: { name: 'Browser', - description: 'A simple browser app.', - pkg: 'flow.browser', - version: '1.0.0', - icon - } - - async open (): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 400, - height: 300 + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Browser', + icon, + width: 500, + height: 700 + }, process) }) + const xor = await process.loadLibrary('lib/XOR') + win.content.style.height = '100%' win.content.style.display = 'flex' win.content.style.flexDirection = 'column' @@ -46,6 +46,7 @@ export default class BrowserApp implements App { #content-container { flex: 1; + background: white; } .add { border: none; @@ -74,7 +75,7 @@ export default class BrowserApp implements App { iframe: HTMLIFrameElement = document.createElement('iframe') constructor (url: string) { - this.iframe.src = `/service/${xor.encode(url)}` + this.iframe.src = `/service/${xor.encode(url) as string}` this.iframe.style.display = 'none' this.header.innerHTML = ` @@ -95,7 +96,7 @@ export default class BrowserApp implements App { if (this === tabManager.activeTab) { (win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_on' } - this.iframe.src = `/service/${xor.encode(win.content.querySelector('input')?.value as string)}` + this.iframe.src = `/service/${xor.encode(win.content.querySelector('input').value) as string}` } } } @@ -166,54 +167,12 @@ export default class BrowserApp implements App { win.content.querySelector('.inp')?.addEventListener('keydown', (event: KeyboardEvent) => { if (event.key === 'Enter') { if (tabManager.activeTab.proxy) { - tabManager.activeTab.iframe.src = `/service/${xor.encode((win.content.querySelector('.inp') as HTMLInputElement).value)}` + tabManager.activeTab.iframe.src = `/service/${xor.encode((win.content.querySelector('.inp') as HTMLInputElement).value) as string}` } else { tabManager.activeTab.iframe.src = (win.content.querySelector('.inp') as HTMLInputElement).value } } - }) - - interface XOR { - randomMax: number - randomMin: number - encode: (str: string) => string - decode: (str: string) => string - } - - const xor: XOR = { - randomMax: 100, - randomMin: -100, - - encode: (str: string): string => { - return encodeURIComponent( - str - .toString() - .split('') - .map((char, ind): string => { - let indCheck - if (ind % 2 === 0) { indCheck = false } else { indCheck = true } - - return indCheck ? String.fromCharCode(char.charCodeAt(0) ^ 2) : char - }) - .join('') - ) - }, - decode: (str: string): string => { - const [input, ...search] = str.split('?') - - return ( - decodeURIComponent(input) - .split('') - .map((char, ind): string => { - let indCheck - if (ind % 2 === 0) { indCheck = false } else { indCheck = true } - - return indCheck ? String.fromCharCode(char.charCodeAt(0) ^ 2) : char - }) - .join('') + ((search.length > 0) ? '?' + search.join('?') : '') - ) - } - }; + }); (win.content.querySelector('button') as HTMLElement).onclick = () => { tabManager.addTab(new Tab('https://google.com')) @@ -247,12 +206,12 @@ export default class BrowserApp implements App { if (document.fullscreenElement !== null) { await document.exitFullscreen().catch(e => console.error) } else { - await win.content.requestFullscreen().catch(e => console.error) + await win.content.requestFullscreen().catch((e: any) => console.error) } } tabManager.addTab(new Tab('https://google.com')) - - return win } } + +export default BrowserApp diff --git a/src/builtin/apps/editor.ts b/src/system/apps/Editor.ts similarity index 53% rename from src/builtin/apps/editor.ts rename to src/system/apps/Editor.ts index 98b0f3a..b9f2187 100644 --- a/src/builtin/apps/editor.ts +++ b/src/system/apps/Editor.ts @@ -1,6 +1,4 @@ import icon from '../../assets/icons/text-editor.svg' -import { App } from '../../types' - import { fullEditor } from 'prism-code-editor/setups' // this will also import markup, clike, javascript, typescript and jsx import 'prism-code-editor/grammars/tsx' @@ -8,7 +6,7 @@ import 'prism-code-editor/grammars/css-extras' import 'prism-code-editor/grammars/markdown' import 'prism-code-editor/grammars/python' -import FlowWindow from '../../structures/FlowWindow' +import { Process } from '../../types' interface EditorConfig { path: string @@ -34,29 +32,36 @@ const fileLanguageMap: { py: 'python' } -export default class EditorApp implements App { - meta = { +const Editor: Process = { + config: { name: 'Editor', - description: 'A simple editor app.', - pkg: 'flow.editor', - version: '1.0.0', - icon - } + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + if (Object.keys(process.data).length > 0) { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Editor', + icon, + width: 350, + height: 500, + canResize: false + }, process) + }) - async open (data?: EditorConfig): Promise { - const win = window.wm.createWindow({ - title: this.meta.name, - icon: this.meta.icon, - width: 500, - height: 400 - }) + const fs = await process.loadLibrary('lib/VirtualFS') - if (data != null) { - win.setTitle(`Editor - ${data.path}`) + const data = process.data as EditorConfig + win.setTitle(`Editor - ${data.path.split('/').at(-1) as string}`) win.content.style.display = 'flex' win.content.style.flexDirection = 'column' - win.content.innerHTML = ` + + if (data != null) { + const render = async (): Promise => { + win.content.innerHTML = `
File
Edit
@@ -114,50 +119,50 @@ export default class EditorApp implements App { ` - const fileBtn = win.content.querySelector('#file-open') - const editBtn = win.content.querySelector('#edit-open') + const fileBtn = win.content.querySelector('#file-open') + const editBtn = win.content.querySelector('#edit-open') - const toggleDropdown = (id: string): void => { - const el = win.content.querySelector(`#${id}`) - el?.classList.toggle('show') - } + const toggleDropdown = (id: string): void => { + const el = win.content.querySelector(`#${id}`) + el?.classList.toggle('show') + } - fileBtn?.addEventListener('click', (e) => { - e.stopPropagation() - toggleDropdown('file') - }) + fileBtn?.addEventListener('click', (e: Event) => { + e.stopPropagation() + toggleDropdown('file') + }) - editBtn?.addEventListener('click', (e) => { - e.stopPropagation() - toggleDropdown('edit') - }) + editBtn?.addEventListener('click', (e: Event) => { + e.stopPropagation() + toggleDropdown('edit') + }) - win.content.addEventListener('click', () => { - const file = (win.content.querySelector('#file') as HTMLElement) - const edit = (win.content.querySelector('#edit') as HTMLElement) - if (file.classList.contains('show')) { - toggleDropdown('file') - } - if (edit.classList.contains('show')) { - toggleDropdown('edit') - } - }) + win.content.addEventListener('click', () => { + const file = (win.content.querySelector('#file') as HTMLElement) + const edit = (win.content.querySelector('#edit') as HTMLElement) + if (file.classList.contains('show')) { + toggleDropdown('file') + } + if (edit.classList.contains('show')) { + toggleDropdown('edit') + } + }) - const fileExtension = data.path.split('.').pop()?.toLowerCase() as string - const language = fileLanguageMap[fileExtension] ?? 'text' + const fileExtension = data.path.split('.').pop()?.toLowerCase() as string + const language = fileLanguageMap[fileExtension] ?? 'text' - const value = Buffer.from(await window.fs.readFile(data.path)).toString() - const editor = fullEditor( - win.content.querySelector('.editor') as HTMLElement, - { - language, - theme: 'github-dark', - value - } - ) + const value = Buffer.from(await fs.readFile(data.path)).toString() + const editor = fullEditor( + win.content.querySelector('.editor') as HTMLElement, + { + language, + theme: 'github-dark', + value + } + ) - const style = document.createElement('style') - style.textContent = ` + const style = document.createElement('style') + style.textContent = ` .prism-code-editor { border-radius: 10px 10px 0 0; caret-color: var(--text); @@ -186,20 +191,29 @@ export default class EditorApp implements App { font-family: 'Satoshi', sans-serif; } ` - editor.scrollContainer.appendChild(style); - (win.content.querySelector('#find') as HTMLElement).onclick = () => { - editor.extensions.searchWidget?.open() - } - (win.content.querySelector('#save') as HTMLElement).onclick = async () => { - await window.fs.writeFile(data.path, editor.value) + editor.scrollContainer.appendChild(style); + (win.content.querySelector('#find') as HTMLElement).onclick = () => { + editor.extensions.searchWidget?.open() + } + (win.content.querySelector('#save') as HTMLElement).onclick = async () => { + await fs.writeFile(data.path, editor.value) + } + } + await render() + document.addEventListener('fs_update', () => { + render().catch(e => console.error(e)) + }) + } else { + await process.launch('lib/FileManager') + setTimeout(() => { + win.close() + }, 10) } } else { - await window.flow.openApp('flow.files') - setTimeout(() => { - win.close() - }, 10) + await process.kill() + await process.launch('apps/Files') } - - return win } } + +export default Editor diff --git a/src/system/apps/Files.ts b/src/system/apps/Files.ts new file mode 100644 index 0000000..a7503d3 --- /dev/null +++ b/src/system/apps/Files.ts @@ -0,0 +1,121 @@ +import icon from '../../assets/icons/file-manager.svg' +import { Process } from '../../types' + +const Files: Process = { + config: { + name: 'Files', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Files', + icon, + width: 500, + height: 400 + }, process) + }) + + const fs = await process.loadLibrary('lib/VirtualFS') + const MIMETypes = await process.loadLibrary('lib/MIMETypes') + + win.content.style.display = 'flex' + win.content.style.flexDirection = 'column' + + let currentDir = '/home' + + async function setDir (dir: string): Promise { + currentDir = dir + const files: string[] = await fs.readdir(dir) + const back = dir === '/' ? 'first_page' : 'chevron_left' + + win.content.innerHTML = ` +
+ ${back}${dir} +
+ create_new_foldernote_add +
+
+ ` + + if (back !== 'first_page') { + (win.content.querySelector('.back') as HTMLElement).onclick = async () => { + await setDir(dir.split('/').slice(0, -1).join('/')) + } + } + + (win.content.querySelector('.file') as HTMLElement).onclick = async () => { + const title: string | null | undefined = prompt('Enter file name') + if (title !== null && title !== undefined) { + await fs.writeFile(`${dir}/${title}`, '') + } + } + + (win.content.querySelector('.folder') as HTMLElement).onclick = async () => { + const title: string | null | undefined = prompt('Enter folder name') + if (title !== null && title !== undefined) { + await fs.mkdir(`${dir}/${title}`, '') + } + } + + for (const file of files) { + const seperator = dir === '/' ? '' : '/' + const fileStat = await fs.stat(dir + seperator + file) + const element = document.createElement('div') + element.setAttribute('style', 'display: flex;gap: 5px;align-items:center;padding: 5px;border-bottom: 1px solid var(--text);display:flex;align-items:center;gap: 5px;') + + const genIcon = (): string => { + return `${(MIMETypes[file.split('.')[1]] === undefined ? 'draft' : MIMETypes[file.split('.')[1]].icon) as string}` + } + const icon = fileStat.isDirectory() as boolean ? 'folder' : genIcon() + + element.innerHTML += `${icon} ${file}delete_foreveredit`; + (element.querySelector('.rename') as HTMLElement).onclick = async () => { + const value = (prompt('Rename') as string) + if (value !== null || value !== undefined) { + await fs.rename(dir + seperator + file, dir + seperator + value) + } + } + (element.querySelector('.delete') as HTMLElement).onclick = async () => { + if (fileStat.isDirectory() as boolean) { + await fs.rmdir(dir + seperator + file) + } else { + await fs.unlink(dir + seperator + file) + } + } + + const run = async (file: string): Promise => { + if (file.split('.').at(-1) === 'lnk') { + await fs.readFile(file).then(async (data: Uint8Array) => { + await run(Buffer.from(data).toString()) + }) + } else if (file.split('.').at(-1) === 'app') { + await fs.readFile(file).then(async (data: Uint8Array) => { + await process.launch(Buffer.from(data).toString()) + }) + } else { + await process.launch(MIMETypes[file.split('.').at(-1) as string] === undefined ? 'apps/Editor' : MIMETypes[file.split('.')[1]].opensWith[0], { path: file }) + } + } + + element.ondblclick = async () => { + if (fileStat.isDirectory() as boolean) { + await setDir(dir + seperator + file) + } else { + await run(dir + seperator + file) + } + } + win.content.querySelector('.files')?.appendChild(element) + } + } + + await setDir(currentDir) + document.addEventListener('fs_update', () => { + setDir(currentDir).catch(e => console.error(e)) + }) + } +} + +export default Files diff --git a/src/system/apps/ImageViewer.ts b/src/system/apps/ImageViewer.ts new file mode 100644 index 0000000..61553b0 --- /dev/null +++ b/src/system/apps/ImageViewer.ts @@ -0,0 +1,53 @@ +import { Process } from '../../types' +import icon from '../../assets/icons/org.gnome.Loupe.svg' + +const ImageViewer: Process = { + config: { + name: 'Image Viewer', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + if (Object.keys(process.data).length > 0) { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Image Viewer', + icon, + width: 500, + height: 500 + }, process) + }) + + const fs = await process.loadLibrary('lib/VirtualFS') + const MIMETypes: Record = await process.loadLibrary('lib/MIMETypes') + const HTML = await process.loadLibrary('lib/HTML') + + const render = async (): Promise => { + win.content.innerHTML = '' + const fileData = await fs.readFile(process.data.path) + const url = `data:${MIMETypes[(process.data.path.split('.').at(-1) as string)].type};base64,${encodeURIComponent(Buffer.from(fileData).toString('base64'))}` + + new HTML('div').style({ + width: '100%', + height: '100%', + background: `url(${url})`, + 'background-size': 'contain', + 'background-position': 'center', + 'background-repeat': 'no-repeat', + 'aspect-ratio': '1 / 1' + }).appendTo(win.content) + } + + await render() + document.addEventListener('fs_update', () => { + render().catch(e => console.error(e)) + }) + } else { + await process.kill() + await process.launch('apps/Files') + } + } +} + +export default ImageViewer diff --git a/src/system/apps/Info.ts b/src/system/apps/Info.ts new file mode 100644 index 0000000..efec703 --- /dev/null +++ b/src/system/apps/Info.ts @@ -0,0 +1,67 @@ +import icon from '../../assets/icons/userinfo.svg' +import badge from '../../assets/badge.png' + +import HTML from '../../HTML' +import { Process } from '../../types' + +const Info: Process = { + config: { + name: 'Info', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Info', + icon, + width: 300, + height: 400, + canResize: false + }, process) + }) + + win.content.style.padding = '10px' + win.content.style.textAlign = 'center' + win.content.style.display = 'flex' + win.content.style.flexDirection = 'column' + win.content.style.justifyContent = 'center' + win.content.style.alignItems = 'center' + win.content.style.background = 'var(--base)' + + new HTML('div').appendTo(win.content) + .appendMany( + new HTML('h1').style({ + margin: '0' + }).text('FlowOS') + .append(new HTML('sup').text(`${process.sysInfo.codename}`).style({ + 'font-size': '0.5em' + })), + new HTML('p').style({ + margin: '0' + }).text(`v${String(process.sysInfo.version)}`), + new HTML('br'), + new HTML('a').attr({ + href: '' + }).append( + new HTML('img').attr({ + src: badge, + height: '50' + }) + ), + new HTML('br'), + new HTML('a').text('Discord').attr({ + href: 'https://discord.gg/86F8dK9vfn', + class: 'discord' + }), + new HTML('span').text(' - '), + new HTML('a').text('Github').attr({ + href: 'https://github.com/Flow-Works/FlowOS', + class: 'github' + }) + ) + } +} + +export default Info diff --git a/src/system/apps/Manager.ts b/src/system/apps/Manager.ts new file mode 100644 index 0000000..0b25fe4 --- /dev/null +++ b/src/system/apps/Manager.ts @@ -0,0 +1,53 @@ +import icon from '../../assets/icons/software-properties.svg' +import nullIcon from '../../assets/icons/application-executable.svg' +import libraryIcon from '../../assets/icons/icon-library.svg' +import { Process } from '../../types' + +const Manager: Process = { + config: { + name: 'Manager', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Manager', + icon, + width: 350, + height: 500, + canResize: false + }, process) + }) + + const HTML = await process.loadLibrary('lib/HTML') + + win.content.style.display = 'flex' + win.content.style.flexDirection = 'column' + win.content.style.gap = '10px' + win.content.style.padding = '10px' + win.content.style.background = 'var(--base)' + + for (const pkg in process.kernel.packageList) { + const container = new HTML('div').style({ + display: 'flex', + gap: '10px', + padding: '10px', + background: 'var(--surface-0)', + borderRadius: '10px' + }).appendTo(win.content) + new HTML('img').attr({ + src: process.kernel.packageList[pkg].executable.config.icon ?? (process.kernel.packageList[pkg].executable.config.type === 'library' ? libraryIcon : nullIcon), + style: 'border-radius: 40%;aspect-ratio: 1 / 1;height: 50px;' + }).appendTo(container) + const div = new HTML('div').appendTo(container) + new HTML('h3').style({ + margin: '0' + }).text(process.kernel.packageList[pkg].executable.config.name).appendTo(div) + new HTML('code').text(process.kernel.packageList[pkg].executable.config.type as string).appendTo(div) + } + } +} + +export default Manager diff --git a/src/system/apps/Settings.ts b/src/system/apps/Settings.ts new file mode 100644 index 0000000..1df8720 --- /dev/null +++ b/src/system/apps/Settings.ts @@ -0,0 +1,78 @@ +import { Process } from '../../types' +import icon from '../../assets/icons/preferences-system.svg' +import { stringify } from 'js-ini' + +const Settings: Process = { + config: { + name: 'Settings', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async process => { + const win = await process + .loadLibrary('lib/WindowManager') + .then((wm: any) => { + return wm.createWindow( + { + title: 'Settings', + icon, + width: 500, + height: 500 + }, + process + ) + }) + + const fs = await process.loadLibrary('lib/VirtualFS') + const HTML = await process.loadLibrary('lib/HTML') + + const { Input, Button } = await process.loadLibrary('lib/Components') + + const render = async (config: any): Promise => { + win.content.innerHTML = '' + for (const item in config) { + const input = Input.new().attr({ + value: config[item] + }) + new HTML('div') + .appendMany( + new HTML('label') + .style({ + 'text-transform': 'capitalize' + }) + .text(`${item.toLowerCase().replaceAll('_', ' ')}:`), + new HTML('br'), + new HTML('div') + .style({ + display: 'flex', + gap: '5px' + }) + .appendMany( + input, + Button.new().text('Save').on('click', async () => { + config[item] = input.getValue() + process.kernel.setConfig(config) + await fs.writeFile('/etc/flow', stringify(config)) + document.dispatchEvent( + new CustomEvent('config_update', { + detail: { + config + } + }) + ) + }) + ) + ) + .appendTo(win.content) + } + } + + await render(process.kernel.config) + document.addEventListener('config_update', (e: CustomEvent) => { + render(e.detail.config).catch(e => console.error(e)) + }) + } +} + +export default Settings diff --git a/src/system/apps/Store.ts b/src/system/apps/Store.ts new file mode 100644 index 0000000..dc05597 --- /dev/null +++ b/src/system/apps/Store.ts @@ -0,0 +1,100 @@ +import { Process, RepoData } from '../../types' +import icon from '../../assets/icons/softwarecenter.svg' + +import { sanitize } from '../../utils' +import nullIcon from '../../assets/icons/application-default-icon.svg' + +const Store: Process = { + config: { + name: 'Store', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Store', + icon, + width: 500, + height: 700 + }, process) + }) + + const fs = await process.loadLibrary('lib/VirtualFS') + + win.content.style.background = 'var(--base)' + + fetch(process.kernel.config.SERVER as string + '/apps/list/') + .then(async (res) => await res.json()) + .then(handle) + .catch(e => console.error(e)) + document.addEventListener('fs_update', () => { + fetch(process.kernel.config.SERVER as string + '/apps/list/') + .then(async (res) => await res.json()) + .then(handle) + .catch(e => console.error(e)) + }) + + function handle (repos: RepoData[]): void { + win.content.innerHTML = ` +
+ ` + + repos.forEach((repo) => { + (win.content.querySelector('.repos') as HTMLElement).innerHTML += ` +
+
+

${sanitize(repo.name)}

+ ${sanitize(repo.id)} +
+
+
+
+ ` + + repo.apps.forEach((app) => { + (win.content.querySelector(`div[data-repo-id="${sanitize(repo.id)}"] > .apps`) as HTMLElement).innerHTML += ` +
+ +
+

${sanitize(app.name)}

+
+ ${sanitize(app.targetVer)} + download +
+
+
+ ` + + fs.exists(`/opt/apps/${app.url.split('/').at(-1) as string}`).then((exists: boolean) => { + fs.exists(`/home/Applications/${app.url.split('/').at(-1)?.replace('.js', '.app') as string}`).then((exists2: boolean) => { + if (exists) { + (win.content.querySelector(`div[data-pkg="${sanitize(app.name)}"] div > .material-symbols-rounded`) as HTMLElement).innerHTML = 'delete'; + + (win.content.querySelector(`div[data-pkg="${sanitize(app.name)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = async () => { + await fs.unlink(`/home/Applications/${app.url.split('/').at(-1)?.replace('.js', '.app') as string}`) + await fs.unlink(`/opt/apps/${app.url.split('/').at(-1) as string}`) + } + } else { + (win.content.querySelector(`div[data-pkg="${sanitize(app.name)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => { + install(app.url) + } + } + }) + }).catch((e: any) => console.error(e)) + }) + }) + } + + function install (url: string): void { + fetch(url).then(async (res) => await res.text()) + .then(async (data) => { + await fs.writeFile(`/home/Applications/${url.split('/').at(-1)?.replace('.js', '.app') as string}`, `apps/${url.split('/').at(-1)?.split('.')[0] as string}`) + await fs.writeFile(`/opt/apps/${url.split('/').at(-1) as string}`, data) + }).catch(e => console.error(e)) + } + } +} + +export default Store diff --git a/src/system/apps/TaskManager.ts b/src/system/apps/TaskManager.ts new file mode 100644 index 0000000..b995887 --- /dev/null +++ b/src/system/apps/TaskManager.ts @@ -0,0 +1,91 @@ +import { Process } from '../../types' +import icon from '../../assets/icons/utilities-system-monitor.svg' + +const TaskManager: Process = { + config: { + name: 'Task Manager', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process) => { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Task Manager', + icon, + width: 600, + height: 200 + }, process) + }) + + const HTML = await process.loadLibrary('lib/HTML') + + win.content.style.display = 'flex' + win.content.style.flexDirection = 'column' + win.content.style.gap = '10px' + win.content.style.padding = '10px' + win.content.style.background = 'var(--base)' + + new HTML('style').html( + `tbody tr:hover { + background: var(--surface-1); + border-radius: 10px; + } + + tr:first-child td:first-child { border-top-left-radius: 10px; } + tr:first-child td:last-child { border-top-right-radius: 10px; } + + tr:last-child td:first-child { border-bottom-left-radius: 10px; } + tr:last-child td:last-child { border-bottom-right-radius: 10px; } + + table, table td, table th { + border: none!important; + border-collapse:collapse; + }` + ).appendTo(win.content) + + const table = new HTML('table').style({ + width: '100%' + }).appendTo(win.content) + + const render = (): void => { + const processList = process.kernel.processList + table.html('') + + new HTML('thead').appendTo(table) + .append( + new HTML('tr').style({ + padding: '5px', + 'border-radius': '10px' + }).appendMany( + new HTML('th').style({ 'text-align': 'center', width: '10%' }).text('PID'), + new HTML('th').style({ 'text-align': 'left', width: '45%' }).text('Process Name'), + new HTML('th').style({ 'text-align': 'left', width: '45%' }).text('Session Token') + ) + ) + + const tbody = new HTML('tbody').appendTo(table) + + for (const proc of processList) { + new HTML('tr').style({ + padding: '5px', + 'border-radius': '10px' + }).appendTo(tbody) + .appendMany( + new HTML('td').style({ 'text-align': 'center' }).text(proc.pid.toString()), + new HTML('td').style({ 'text-align': 'left' }).text(proc.name), + new HTML('td').style({ 'text-align': 'left' }).text(proc.token) + ) + .on('click', () => { + process.killProcess(proc.pid).catch((e: any) => console.error(e)) + }) + } + } + + render() + + document.addEventListener('update_process', () => render()) + } +} + +export default TaskManager diff --git a/src/system/lib/Components.ts b/src/system/lib/Components.ts new file mode 100644 index 0000000..0a5a430 --- /dev/null +++ b/src/system/lib/Components.ts @@ -0,0 +1,44 @@ +import LibraryLib from '../../structures/LibraryLib' +import { Library } from '../../types' + +let library: LibraryLib + +const Components: Library = { + config: { + name: 'Components', + type: 'library', + targetVer: '0.0.1' + }, + init: (l, k, p) => { library = l }, + data: { + Input: { + new: () => { + const { HTML } = library + const input = new HTML('input') + input.style({ + 'border-radius': '5px', + padding: '2.5px', + outline: 'none', + background: 'transparent', + border: '1px solid var(--surface-0)' + }) + return input + } + }, + Button: { + new: () => { + const { HTML } = library + const button = new HTML('button') + button.style({ + 'border-radius': '5px', + padding: '2.5px', + background: 'transparent', + border: '1px solid var(--surface-0)' + }) + return button + } + } + } +} + +export default Components diff --git a/src/system/lib/HTML.ts b/src/system/lib/HTML.ts new file mode 100644 index 0000000..6685244 --- /dev/null +++ b/src/system/lib/HTML.ts @@ -0,0 +1,14 @@ +import HTMLClass from '../../HTML' +import { Library } from '../../types' + +const HTML: Library = { + config: { + name: 'HTML', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k, p) => {}, + data: HTMLClass +} + +export default HTML diff --git a/src/system/lib/Launcher.ts b/src/system/lib/Launcher.ts new file mode 100644 index 0000000..301fd2c --- /dev/null +++ b/src/system/lib/Launcher.ts @@ -0,0 +1,40 @@ +import { Library } from '../../types' + +let isLauncherOpen = false + +const Launcher: Library = { + config: { + name: 'Launcher', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k) => { + Launcher.data.element = new l.HTML('launcher').style({ + opacity: '0', + 'backdrop-filter': 'blur(0px)', + 'pointer-events': 'none' + }) + }, + data: { + toggle: () => { + if (isLauncherOpen) { + Launcher.data.element.style({ + opacity: '0', + 'backdrop-filter': 'blur(0px)', + 'pointer-events': 'none' + }) + } else { + Launcher.data.element.style({ + opacity: '1', + 'backdrop-filter': 'blur(20px)', + 'pointer-events': 'all' + }) + } + + isLauncherOpen = !isLauncherOpen + return isLauncherOpen + } + } +} + +export default Launcher diff --git a/src/system/lib/MIMETypes.ts b/src/system/lib/MIMETypes.ts new file mode 100644 index 0000000..8a276c4 --- /dev/null +++ b/src/system/lib/MIMETypes.ts @@ -0,0 +1,86 @@ +import { Library } from '../../types' + +const MIME: Library = { + config: { + name: 'MIMETypes', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k, p) => {}, + data: { + aac: { + type: 'audio/aac', + description: 'AAC Audio', + opensWith: ['apps/MusicPlayer'], + icon: 'audio_file' + }, + abw: { + type: 'application/x-abiword', + description: 'AbiWord Document', + opensWith: ['apps/Editor'], + icon: 'description' + }, + apng: { + type: 'image/apng', + description: 'Animated PNG File', + opensWith: ['apps/ImageViewer'], + icon: 'image' + }, + app: { + type: 'application/x-flow-executable', + description: 'FlowOS Application', + opensWith: [], + icon: 'deployed_code' + }, + /* arc: { + type: 'application/x-freearc', + description: 'Archive Document', + opensWith: ['apps/ArchiveViewer'], + icon: 'archive' + }, */ + avif: { + type: 'image/avif', + description: 'AVIF Image', + opensWith: ['apps/ImageViewer'], + icon: 'image' + }, + lnk: { + type: 'application/x-ms-shortcut', + description: 'Windows Shortcut', + opensWith: [], + icon: 'file_present' + }, + md: { + type: 'text/markdown', + description: 'Markdown Document', + opensWith: ['apps/Editor'], + icon: 'markdown' + }, + mp4: { + type: 'video/mp4', + description: 'MP4 Video', + opensWith: ['apps/VideoPlayer'], + icon: 'video_file' + }, + png: { + type: 'image/png', + description: 'PNG File', + opensWith: ['apps/ImageViewer'], + icon: 'image' + }, + svg: { + type: 'image/svg+xml', + description: 'SVG File', + opensWith: ['apps/ImageViewer'], + icon: 'image' + }, + txt: { + type: 'text/plain', + description: 'Text Document', + opensWith: ['apps/Editor'], + icon: 'description' + } + } +} + +export default MIME diff --git a/src/system/lib/SplashScreen.ts b/src/system/lib/SplashScreen.ts new file mode 100644 index 0000000..c60c61b --- /dev/null +++ b/src/system/lib/SplashScreen.ts @@ -0,0 +1,47 @@ +import Kernel from '../../kernel' + +import FlowLogo from '../../assets/flow.png' +import { Library } from '../../types' +import LibraryLib from '../../structures/LibraryLib' + +let library: LibraryLib, kernel: Kernel + +const SplashScreen: Library = { + config: { + name: 'SplashScreen', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k, p) => { + library = l + kernel = k + }, + data: { + getElement: () => { + const { HTML } = library + const div = new HTML('div').style({ + position: 'absolute', + top: '0', + left: '0', + width: '100vw', + height: '100vh', + display: 'flex', + 'flex-direction': 'column', + 'align-items': 'center', + 'justify-content': 'center', + 'z-index': '1000000' + }) + new HTML('img').attr({ + src: FlowLogo, + width: 128 + }).appendTo(div) + const h1 = new HTML('h1').style({ margin: '0' }).text('FlowOS').appendTo(div) + new HTML('sup').style({ 'font-size': '0.5em' }).text(kernel.codename).appendTo(h1) + new HTML('p').style({ margin: '0' }).text('loading...').appendTo(div) + + return div + } + } +} + +export default SplashScreen diff --git a/src/system/lib/StatusBar.ts b/src/system/lib/StatusBar.ts new file mode 100644 index 0000000..9343dde --- /dev/null +++ b/src/system/lib/StatusBar.ts @@ -0,0 +1,77 @@ +import { Library } from '../../types' + +const StatusBar: Library = { + config: { + name: 'StatusBar', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k, p) => { + StatusBar.data.element = new l.HTML('toolbar') + }, + data: { + updateBatteryIcon (battery: any) { + let iconHTML = '' + + if (battery.charging === true) { + if (battery.level === 1) { + iconHTML = 'battery_charging_full' + } else if (battery.level >= 0.9) { + iconHTML = 'battery_charging_90' + } else if (battery.level >= 0.8) { + iconHTML = 'battery_charging_80' + } else if (battery.level >= 0.6) { + iconHTML = 'battery_charging_60' + } else if (battery.level >= 0.5) { + iconHTML = 'battery_charging_50' + } else if (battery.level >= 0.3) { + iconHTML = 'battery_charging_30' + } else if (battery.level >= 0) { + iconHTML = 'battery_charging_20' + } + } else { + if (battery.level === 1) { + iconHTML = 'battery_full' + } else if (battery.level >= 0.6) { + iconHTML = 'battery_6_bar' + } else if (battery.level >= 0.5) { + iconHTML = 'battery_5_bar' + } else if (battery.level >= 0.4) { + iconHTML = 'battery_4_bar' + } else if (battery.level >= 0.3) { + iconHTML = 'battery_3_bar' + } else if (battery.level >= 0.2) { + iconHTML = 'battery_2_bar' + } else if (battery.level >= 0.1) { + iconHTML = 'battery_1_bar' + } else if (battery.level >= 0) { + iconHTML = 'battery_0_bar' + } + } + + const batteryDiv = document.querySelector('div[data-toolbar-id="controls"] > .battery') + if (batteryDiv != null) { + batteryDiv.innerHTML = iconHTML + } + }, + updateIcon (ms: number) { + let icon = '' + + if (ms >= 200 && ms < 400) { + icon = 'signal_cellular_1_bar' + } else if (ms >= 400 && ms < 600) { + icon = 'signal_cellular_2_bar' + } else if (ms >= 600 && ms < 800) { + icon = 'signal_cellular_3_bar' + } else if (ms >= 800) { + icon = 'signal_cellular_4_bar' + } else { + icon = 'signal_cellular_0_bar' + } + + (document.querySelector('div[data-toolbar-id="controls"] > .signal') as HTMLElement).innerHTML = icon + } + } +} + +export default StatusBar diff --git a/src/system/lib/VirtualFS.ts b/src/system/lib/VirtualFS.ts new file mode 100644 index 0000000..f8f5291 --- /dev/null +++ b/src/system/lib/VirtualFS.ts @@ -0,0 +1,493 @@ +import Kernel from '../../kernel' +import ProcessLib from '../../structures/ProcessLib' +import { Library } from '../../types' + +console.debug = (...args: any[]) => { + console.log('[VirtualFS]', ...args) +} + +export enum Errors { + ENOENT = 'ENOENT', + EISDIR = 'EISDIR', + EEXIST = 'EEXIST', + EPERM = 'EPERM', + ENOTDIR = 'ENOTDIR', + EACCES = 'EACCES' +} + +export enum Permission { + USER, + ELEVATED, + SYSTEM +} + +export interface Directory { + type: 'directory' + permission: Permission + deleteable: boolean + children: { + [key: string]: Directory | File + } +} + +export interface File { + type: 'file' + permission: Permission + deleteable: boolean + content: Buffer +} + +export const defaultFS: { root: Directory } = { + root: { + type: 'directory', + deleteable: false, + permission: Permission.SYSTEM, + children: { + home: { + type: 'directory', + deleteable: false, + permission: Permission.SYSTEM, + children: { + Downloads: { + type: 'directory', + deleteable: false, + permission: Permission.USER, + children: {} + }, + Applications: { + type: 'directory', + deleteable: false, + permission: Permission.USER, + children: { + 'Info.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Info') + }, + 'Manager.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Manager') + }, + 'Store.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Store') + }, + 'TaskManager.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/TaskManager') + }, + 'Browser.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Browser') + }, + 'ImageViewer.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/ImageViewer') + }, + 'Files.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Files') + }, + 'Editor.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Editor') + }, + 'Settings.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Settings') + } + } + }, + Desktop: { + type: 'directory', + deleteable: false, + permission: Permission.USER, + children: { + 'README.md': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('# Welcome to FlowOS!') + }, + 'Info.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/Info.app') + }, + 'Manager.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/Manager.app') + }, + 'Store.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/Store.app') + }, + 'TaskManager.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/TaskManager.app') + }, + 'Browser.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/Browser.app') + }, + 'ImageViewer.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/ImageViewer.app') + }, + 'Files.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/Files.app') + }, + 'Editor.lnk': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('/home/Applications/Editor.app') + } + } + }, + Pictures: { + type: 'directory', + deleteable: false, + permission: Permission.USER, + children: {} + }, + Videos: { + type: 'directory', + deleteable: false, + permission: Permission.USER, + children: {} + }, + Documents: { + type: 'directory', + deleteable: false, + permission: Permission.USER, + children: {} + }, + Music: { + type: 'directory', + deleteable: false, + permission: Permission.USER, + children: {} + } + } + }, + var: { + type: 'directory', + deleteable: false, + permission: Permission.SYSTEM, + children: {} + }, + etc: { + type: 'directory', + deleteable: false, + permission: Permission.SYSTEM, + children: { + flow: { + type: 'file', + deleteable: false, + permission: Permission.ELEVATED, + content: Buffer.from([ + 'SERVER=https://server.flow-works.me', + '24HOUR=FALSE' + ].join('\n')) + }, + hostname: { + type: 'file', + deleteable: false, + permission: Permission.ELEVATED, + content: Buffer.from('flow') + } + } + }, + opt: { + type: 'directory', + deleteable: false, + permission: Permission.SYSTEM, + children: { + apps: { + type: 'directory', + deleteable: false, + permission: Permission.SYSTEM, + children: {} + } + } + } + } + } +} + +export const setFileSystem = async (fileSystemObject: { root: Directory }): Promise => { + fileSystem = fileSystemObject +} + +export let db: IDBDatabase +let fileSystem: { root: Directory } +let kernel: Kernel, process: ProcessLib + +export const initializeDatabase = async (dbName: string): Promise => { + return await new Promise((resolve, reject) => { + const request = window.indexedDB.open(dbName) + + request.onupgradeneeded = (event: Event) => { + const target = event.target as IDBRequest + const db = target.result + db.createObjectStore('fs') + } + + request.onerror = (event: Event) => { + reject(new Error('[VirtualFS] Error opening database.')) + } + + request.onsuccess = () => { + db = request.result + resolve(true) + } + }) +} + +export const read = async (): Promise => { + const transaction = db.transaction(['fs'], 'readonly') + const store = transaction.objectStore('fs') + const getRequest = store.get('fs') + + return await new Promise((resolve, reject) => { + getRequest.onsuccess = () => { + resolve(getRequest.result) + } + + getRequest.onerror = () => { + reject(getRequest.error) + } + }) +} + +export const write = async (fileSystemObject: { root: Directory }): Promise => { + fileSystem = fileSystemObject + await save() +} + +const save = async (): Promise => { + const transaction = db.transaction(['fs'], 'readwrite') + const store = transaction.objectStore('fs') + const putRequest = store.put(fileSystem, 'fs') + + return await new Promise((resolve, reject) => { + putRequest.onsuccess = () => { + document.dispatchEvent(new CustomEvent('fs_update', {})) + resolve() + } + + putRequest.onerror = () => { + reject(putRequest.error) + } + }) +} + +const handlePermissions = async (path: string): Promise => { + let current + + current = (await navigatePath(path)).current + + if (current === undefined) current = (await navigatePathParent(path)).current + + if (current.permission === Permission.USER && current.permission > process.permission) { + const uac = await kernel.startExecutable('UserAccessControl', Permission.SYSTEM, { type: 'fs', process, path }) + if (uac.value === false) { + throw new Error(Errors.EACCES) + } + } + if (current.permission === Permission.ELEVATED && current.permission > process.permission) { + const uac = await kernel.startExecutable('UserAccessControl', Permission.SYSTEM, { type: 'fs', process, path }) + if (uac.value === false) { + throw new Error(Errors.EACCES) + } + } + if (current.permission === Permission.SYSTEM && current.permission > process.permission) throw new Error(Errors.EPERM) +} + +const navigatePath = async (path: string): Promise<{ current: Directory | File, parts: string[] }> => { + const parts = path.split('/').filter(x => x !== '') + let current = fileSystem.root + for (const part of parts) { + current = current.children[part] as Directory + } + return { current, parts } +} + +const navigatePathParent = async (path: string): Promise<{ current: Directory, parts: string[], filename: string }> => { + const parts = path.split('/').filter(x => x !== '') + const filename = parts.pop() as string + let current = fileSystem.root + for (const part of parts) { + current = current.children[part] as Directory + } + return { current, parts, filename } +} + +const VirtualFS: Library = { + config: { + name: 'VirtualFS', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k, p) => { + kernel = k + process = p + }, + data: { + unlink: async (path: string): Promise => { + const { current, filename } = await navigatePathParent(path) + + if (!current.children[filename].deleteable) throw new Error(Errors.EPERM) + await handlePermissions(path) + + Reflect.deleteProperty(current.children, filename) + + console.debug('unlink ' + path) + await save() + }, + readFile: async (path: string): Promise => { + const { current } = await navigatePath(path) + + await handlePermissions(path) + + if (current.type !== 'file') throw new Error(Errors.EISDIR) + + console.debug('read ' + path) + return current.content + }, + writeFile: async (path: string, content: string | Buffer): Promise => { + const { current, filename } = await navigatePathParent(path) + + let permission + + if (typeof current.children[filename] !== 'undefined') { + await handlePermissions(path) + permission = current.children[filename].permission + } else { + permission = Permission.USER + } + + current.children[filename] = { + type: 'file', + deleteable: true, + permission, + content: Buffer.from(content) + } + + console.debug('write ' + path) + await save() + }, + mkdir: async (path: string): Promise => { + const { current, filename } = await navigatePathParent(path) + + let permission + + if (typeof current.children[filename] !== 'undefined') { + await handlePermissions(path) + permission = current.children[filename].permission + } else { + permission = Permission.USER + } + + current.children[filename] = { + type: 'directory', + deleteable: true, + permission, + children: {} + } + + console.debug('mkdir ' + path) + await save() + }, + rmdir: async (path: string): Promise => { + const { current, filename } = await navigatePathParent(path) + + if (!current.deleteable) throw new Error(Errors.EPERM) + await handlePermissions(path) + + if (current.children[filename].type !== 'directory') throw new Error(Errors.ENOTDIR) + + Reflect.deleteProperty(current.children, filename) + + console.debug('rmdir ' + path) + await save() + }, + readdir: async (path: string): Promise => { + const { current } = await navigatePath(path) + + if (current.type === 'file') throw new Error(Errors.ENOTDIR) + const result = await Promise.all(Object.keys(current.children ?? {})) + + console.debug('readdir ' + path) + return result + }, + stat: async (path: string): Promise<{ isDirectory: () => boolean, isFile: () => boolean }> => { + const { current } = await navigatePath(path) + + console.debug('stat ' + path) + return { + isDirectory: () => current.type === 'directory', + isFile: () => current.type === 'file' + } + }, + rename: async (oldPath: string, newPath: string): Promise => { + const { current: oldCurrent, filename: oldFilename } = await navigatePathParent(oldPath) + const { current: newCurrent, filename: newFilename } = await navigatePathParent(newPath) + + if (!oldCurrent.deleteable) throw new Error(Errors.EPERM) + if (!newCurrent.deleteable) throw new Error(Errors.EPERM) + + await handlePermissions(oldPath) + await handlePermissions(newPath) + + newCurrent.children[newFilename] = oldCurrent.children[oldFilename] + Reflect.deleteProperty(oldCurrent.children, oldFilename) + + console.debug('rename ' + oldPath + ' -> ' + newPath) + await save() + }, + exists: async (path: string): Promise => { + console.debug('exists ' + path) + try { + const { current } = await navigatePath(path) + return current !== undefined + } catch (e) { + return false + } + } + } +} + +export default VirtualFS diff --git a/src/system/lib/WindowManager.ts b/src/system/lib/WindowManager.ts new file mode 100644 index 0000000..516678d --- /dev/null +++ b/src/system/lib/WindowManager.ts @@ -0,0 +1,90 @@ +import HTML from '../../HTML' +import FlowWindow from '../../structures/FlowWindow' +import ProcessLib from '../../structures/ProcessLib' +import { FlowWindowConfig, Library } from '../../types' + +const WindowManager: Library = { + config: { + name: 'WindowManager', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k, p) => { + document.addEventListener('app_closed', (e: any) => { + WindowManager.data.windows.find((win: FlowWindow) => { + if (win.process.token === e.detail.token) { + win.close() + return true + } + return false + }) + }) + }, + data: { + windowArea: new HTML('window-area'), + windows: [], + getHighestZIndex: () => { + const indexes = WindowManager.data.windows.map((win: FlowWindow) => { + return parseInt(win.element.style.zIndex) + }) + + const max = Math.max(...indexes) + + return max === -Infinity ? 0 : max + }, + createWindow: (config: FlowWindowConfig, process: ProcessLib) => { + const win = new FlowWindow(process, WindowManager.data, config) + const appOpenedEvent = { + detail: { + token: process.token, + proc: process.process, + win + } + } + document.dispatchEvent(new CustomEvent('app_opened', appOpenedEvent)) + WindowManager.data.windows.push(win) + WindowManager.data.windowArea.elm.appendChild(win.element) + return win + }, + createModal: async (title: string, text: string, process: ProcessLib) => { + const win = new FlowWindow(process, WindowManager.data, { + title, + icon: '', + width: 300, + height: 200, + canResize: false + }) + const appOpenedEvent = { + detail: { + token: process.token, + proc: process.process, + win + } + } + document.dispatchEvent(new CustomEvent('app_opened', appOpenedEvent)) + + const { Button } = await process.loadLibrary('lib/Components') + + return { + value: await new Promise((resolve) => { + new HTML('h3').text(title).appendTo(win.content) + new HTML('p').text(text).appendTo(win.content) + Button.new().text('Allow').appendTo(win.content).on('click', () => { + resolve(true) + win.close() + }) + Button.new().text('Deny').appendTo(win.content).on('click', () => { + resolve(false) + win.close() + }) + + WindowManager.data.windows.push(win) + WindowManager.data.windowArea.elm.appendChild(win.element) + }), + win + } + } + } +} + +export default WindowManager diff --git a/src/system/lib/XOR.ts b/src/system/lib/XOR.ts new file mode 100644 index 0000000..ca1c7cd --- /dev/null +++ b/src/system/lib/XOR.ts @@ -0,0 +1,46 @@ +import { Library } from '../../types' + +const XOR: Library = { + config: { + name: 'XOR', + type: 'library', + targetVer: '1.0.0-indev.0' + }, + init: (l, k, p) => {}, + data: { + randomMax: 100, + randomMin: -100, + + encode: (str: string): string => { + return encodeURIComponent( + str + .toString() + .split('') + .map((char, ind): string => { + let indCheck + if (ind % 2 === 0) { indCheck = false } else { indCheck = true } + + return indCheck ? String.fromCharCode(char.charCodeAt(0) ^ 2) : char + }) + .join('') + ) + }, + decode: (str: string): string => { + const [input, ...search] = str.split('?') + + return ( + decodeURIComponent(input) + .split('') + .map((char, ind): string => { + let indCheck + if (ind % 2 === 0) { indCheck = false } else { indCheck = true } + + return indCheck ? String.fromCharCode(char.charCodeAt(0) ^ 2) : char + }) + .join('') + ((search.length > 0) ? '?' + search.join('?') : '') + ) + } + } +} + +export default XOR diff --git a/src/types.ts b/src/types.ts index d85901c..dd951e7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,56 +1,64 @@ +import Kernel from './kernel' import FlowWindow from './structures/FlowWindow' - -export type AppOpenFunction = (data: any) => Promise -export type PluginRunFunction = (element: HTMLDivElement, config: any) => void | Promise +import LibraryLib from './structures/LibraryLib' +import ProcessLib from './structures/ProcessLib' export interface AppClosedEvent extends CustomEvent { detail: { - win: FlowWindow + token: string } } export interface AppOpenedEvent extends CustomEvent { detail: { - app: App + proc: Process + token: string win: FlowWindow } } -export interface BaseMeta { - name: string - description: string - pkg: string - version: string -} -export interface AppMeta extends BaseMeta { - icon: string -} - -export interface PluginMeta extends BaseMeta { - icon?: string -} - -export interface RepoAppMeta extends BaseMeta { - icon?: string +export interface Package { url: string + executable: Executable } -export interface Apps { - [key: string]: App +export interface Executable { + config: { + name: string + type: 'process' | 'library' + icon?: string + targetVer: string + } } -export interface Plugins { - [key: string]: Plugin +export type LibraryData = any +export interface Library extends Executable { + config: { + name: string + type: 'library' + targetVer: string + } + + init: (library: LibraryLib, kernel: Kernel, process: ProcessLib) => void + data: LibraryData } -export interface App { - meta: AppMeta - open: AppOpenFunction +export interface Process extends Executable { + config: { + name: string + type: 'process' + icon?: string + targetVer: string + } + + run: (process: ProcessLib) => Promise } -export interface Plugin { - meta: PluginMeta - run: PluginRunFunction +export interface RepoAppMeta { + name: string + icon?: string + targetVer: string + url: string } export interface FlowWindowConfig { @@ -65,28 +73,19 @@ export interface FlowWindowConfig { minWidth?: number minHeight?: number } - -export interface LoadedApp extends App { - builtin: boolean -} - -export interface LoadedPlugin extends Plugin { - builtin: boolean -} - -export interface PackageJSON { - version: string -} - -export interface FlowConfig { - SERVER_URL: string - HOSTNAME: string - USERNAME: string - '24HOUR_CLOCK': boolean -} - export interface RepoData { name: string id: string apps: RepoAppMeta[] } + +export interface ProcessInfo { + pid: number + name: string + token: string +} + +export interface KernelConfig { + SERVER: string + [key: string]: any +} diff --git a/vite.config.js b/vite.config.js index ff70d3f..e30b2d7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,8 +1,33 @@ import { defineConfig } from 'vite' import { nodePolyfills } from 'vite-plugin-node-polyfills' +import viteCompression from 'vite-plugin-compression' +import fs from 'fs' + +/** @type {import('vite').Plugin} */ +const hexLoader = { + name: 'hex-loader', + transform (code, id) { + const [path, query] = id.split('?') + if (query !== 'raw-hex') { return null } + + const data = fs.readFileSync(path) + const hex = data.toString('hex') + + return `export default '${hex}';` + } +} export default defineConfig({ plugins: [ - nodePolyfills() + hexLoader, + nodePolyfills(), + viteCompression({ + algorithm: 'gzip', + ext: '.gz', + deleteOriginFile: false, + threshold: 10240, + disable: false, + verbose: true + }) ] }) From 9a87964464ca9c788f1311487a8e18fd64d240c8 Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Tue, 16 Jan 2024 05:03:04 +0000 Subject: [PATCH 4/8] =?UTF-8?q?[=F0=9F=93=A6]=20Changed=20`main`=20propert?= =?UTF-8?q?y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 53b08c2..c19ef01 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "flowos", "version": "1.0.0-indev.0", "description": "The most aesthetic webOS.", - "main": "src/index.ts", + "main": "src/kernel.ts", "scripts": { "docs": "typedoc src/**", "test": "ts-standard", From 36201f4af1aa9ccab6b759688a4b502486202b90 Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Tue, 16 Jan 2024 05:47:17 +0000 Subject: [PATCH 5/8] =?UTF-8?q?[=F0=9F=93=87]=20Update=20typedoc=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- typedoc.config.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/typedoc.config.js b/typedoc.config.js index 8f922d7..d3f00ed 100644 --- a/typedoc.config.js +++ b/typedoc.config.js @@ -1,5 +1,8 @@ +/** @type {import('typedoc').TypeDocOptions} */ module.exports = { name: 'FlowOS', - plugin: ['typedoc-material-theme', 'typedoc-plugin-missing-exports'], - themeColor: '#1e1e2e' + plugin: ['typedoc-material-theme'], + themeColor: '#1e1e2e', + entryPoints: ['src/kernel.ts'], + entryPointStrategy: 'expand' } From 3402faf74e993fad593ee36c76a227fb2ddb25b9 Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Tue, 16 Jan 2024 05:49:49 +0000 Subject: [PATCH 6/8] =?UTF-8?q?[=F0=9F=94=A8]=20Mass=20refactor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/HTML.ts | 55 +++++++++----------------- src/kernel.ts | 48 ++++++++++------------- src/structures/ProcessLib.ts | 2 +- src/system/BootLoader.ts | 26 +++++++------ src/system/UserAccessControl.ts | 69 +++++++++++++++++---------------- src/system/apps/Browser.ts | 45 +++++++++------------ src/system/apps/Editor.ts | 18 ++++----- src/system/apps/Files.ts | 4 +- src/system/apps/ImageViewer.ts | 6 +-- src/system/apps/Store.ts | 4 +- src/system/apps/TaskManager.ts | 2 +- src/system/lib/SplashScreen.ts | 3 +- src/system/lib/StatusBar.ts | 34 ++++++++-------- src/system/lib/VirtualFS.ts | 37 +++++++++--------- src/system/lib/XOR.ts | 2 +- 15 files changed, 163 insertions(+), 192 deletions(-) diff --git a/src/HTML.ts b/src/HTML.ts index 8a35f69..5c766cc 100644 --- a/src/HTML.ts +++ b/src/HTML.ts @@ -6,11 +6,7 @@ export default class HTML { * @param elm The HTML element to be created or classified from. */ constructor (elm: string | HTMLElement) { - if (elm instanceof HTMLElement) { - this.elm = elm - } else { - this.elm = document.createElement(elm === '' ? 'div' : elm) - } + this.elm = elm instanceof HTMLElement ? elm : document.createElement(elm === '' ? 'div' : elm) } /** @@ -57,11 +53,7 @@ export default class HTML { * @returns a new HTML */ qs (query: string): HTML | null { - if (this.elm.querySelector(query) != null) { - return HTML.from(this.elm.querySelector(query) as HTMLElement) - } else { - return null - } + return this.elm.querySelector(query) != null ? HTML.from(this.elm.querySelector(query) as HTMLElement) : null } /** @@ -70,13 +62,11 @@ export default class HTML { * @returns a new HTML */ qsa (query: string): Array | null { - if (this.elm.querySelector(query) != null) { - return Array.from(this.elm.querySelectorAll(query)).map((e) => + return this.elm.querySelector(query) != null + ? Array.from(this.elm.querySelectorAll(query)).map((e) => HTML.from(e as HTMLElement) ) - } else { - return null - } + : null } /** @@ -95,8 +85,8 @@ export default class HTML { * @returns HTML */ class (...val: string[]): HTML { - for (let i = 0; i < val.length; i++) { - this.elm.classList.toggle(val[i]) + for (const element of val) { + this.elm.classList.toggle(element) } return this } @@ -107,8 +97,8 @@ export default class HTML { * @returns HTML */ classOn (...val: string[]): HTML { - for (let i = 0; i < val.length; i++) { - this.elm.classList.add(val[i]) + for (const element of val) { + this.elm.classList.add(element) } return this } @@ -119,8 +109,8 @@ export default class HTML { * @returns HTML */ classOff (...val: string[]): HTML { - for (let i = 0; i < val.length; i++) { - this.elm.classList.remove(val[i]) + for (const element of val) { + this.elm.classList.remove(element) } return this } @@ -234,10 +224,10 @@ export default class HTML { */ attr (obj: { [x: string]: any }): HTML { for (const key in obj) { - if (obj[key] !== null && obj[key] !== undefined) { - this.elm.setAttribute(key, obj[key]) - } else { + if (obj[key] == null) { this.elm.removeAttribute(key) + } else { + this.elm.setAttribute(key, obj[key]) } } return this @@ -296,8 +286,7 @@ export default class HTML { static from (elm: HTMLElement | string): HTML | null { if (typeof elm === 'string') { const element = HTML.qs(elm) - if (element === null) return null - else return element + return element === null ? null : element } else { return new HTML(elm) } @@ -309,11 +298,7 @@ export default class HTML { * @returns a new HTML */ static qs (query: string): HTML | null { - if (document.querySelector(query) != null) { - return HTML.from(document.querySelector(query) as HTMLElement) - } else { - return null - } + return document.querySelector(query) != null ? HTML.from(document.querySelector(query) as HTMLElement) : null } /** @@ -322,12 +307,10 @@ export default class HTML { * @returns a new HTML */ static qsa (query: string): Array | null { - if (document.querySelector(query) != null) { - return Array.from(document.querySelectorAll(query)).map((e) => + return document.querySelector(query) != null + ? Array.from(document.querySelectorAll(query)).map((e) => HTML.from(e as HTMLElement) ) - } else { - return null - } + : null } } diff --git a/src/kernel.ts b/src/kernel.ts index eed125d..89b8f4e 100644 --- a/src/kernel.ts +++ b/src/kernel.ts @@ -21,7 +21,7 @@ async function enableDebug (): Promise { return await Promise.resolve() } -if (params.get('debug') !== null && params.get('debug') !== undefined) { +if (params.get('debug') != null) { enableDebug().catch(e => console.error(e)) } @@ -69,7 +69,7 @@ export default class Kernel { executable = importedExecutable.default } catch { if (this.fs === undefined) throw new Error('Filesystem hasn\'t been initiated.') - const dataURL = 'data:text/javascript;base64,' + Buffer.from(await this.fs.readFile('/opt/' + url + '.js')).toString('base64') + const dataURL = `data:text/javascript;base64,${Buffer.from(await this.fs.readFile(`/opt/${url}.js`)).toString('base64')}` const importedExecutable = await import(dataURL) executable = importedExecutable.default } @@ -81,32 +81,26 @@ export default class Kernel { else if (this.packageList[executable.config.name].url !== url) throw new Error(`Package name conflict: ${executable.config.name}`) return await new Promise((resolve, reject) => { - switch (executable.config.type) { - case 'process': { - const executableProcess = executable as Process - console.group(`Starting ${url}`) - const pid = ProcLib.findEmptyPID(this) - const token = uuid() - const procLib = new ProcessLib(url, pid, token, permission, data, executableProcess, this) - this.processList.push({ - pid, - token, - name: executableProcess.config.name - }) + if (executable.config.type === 'process') { + const executableProcess = executable as Process + console.group(`Starting ${url}`) + const pid = ProcLib.findEmptyPID(this) + const token = uuid() + const procLib = new ProcessLib(url, pid, token, permission, data, executableProcess, this) + this.processList.push({ + pid, + token, + name: executableProcess.config.name + }) + document.dispatchEvent(new CustomEvent('update_process', {})) + executableProcess.run(procLib).then((value: any) => { + if (value !== undefined) procLib.kill().catch(e => console.error(e)) document.dispatchEvent(new CustomEvent('update_process', {})) - executableProcess.run(procLib).then((value: any) => { - if (value !== undefined) procLib.kill().catch(e => console.error(e)) - document.dispatchEvent(new CustomEvent('update_process', {})) - resolve({ procLib, value }) - }).catch(e => console.error(e)) - break - } - - default: { - reject(new Error(`Unknown executable type: ${executable.config.type as string}`)) - break - } + resolve({ procLib, value }) + }).catch(e => console.error(e)) + return } + reject(new Error(`Unknown executable type: ${executable.config.type as string}`)) }) } @@ -119,7 +113,7 @@ export default class Kernel { executable = importedExecutable.default } catch { if (this.fs === undefined) throw new Error('Filesystem hasn\'t been initiated.') - const dataURL = 'data:text/javascript;base64,' + Buffer.from(await this.fs.readFile('/opt/' + url + '.js')).toString('base64') + const dataURL = `data:text/javascript;base64,${Buffer.from(await this.fs.readFile(`/opt/${url}.js`)).toString('base64')}` const importedExecutable = await import(dataURL) executable = importedExecutable.default } diff --git a/src/structures/ProcessLib.ts b/src/structures/ProcessLib.ts index e2e6e3e..47e96c0 100644 --- a/src/structures/ProcessLib.ts +++ b/src/structures/ProcessLib.ts @@ -67,7 +67,7 @@ export default class ProcessLib { executable = importedExecutable.default } catch { if (this._kernel.fs === undefined) throw new Error('Filesystem hasn\'t been initiated.') - const dataURL = 'data:text/javascript;base64,' + Buffer.from(await this._kernel.fs.readFile('/opt/' + url + '.js')).toString('base64') + const dataURL = `data:text/javascript;base64,${Buffer.from(await this._kernel.fs.readFile(`/opt/${url}.js`)).toString('base64')}` const importedExecutable = await import(dataURL) executable = importedExecutable.default } diff --git a/src/system/BootLoader.ts b/src/system/BootLoader.ts index 27e923d..365cb02 100644 --- a/src/system/BootLoader.ts +++ b/src/system/BootLoader.ts @@ -33,7 +33,11 @@ const BootLoader: Process = { console.warn('Persistent storage is not supported.') } const fileSystem = await read() - fileSystem === undefined ? await write(defaultFS) : await setFileSystem(fileSystem) + if (fileSystem === undefined) { + await write(defaultFS) + } else { + await setFileSystem(fileSystem) + } const config = Buffer.from(await fs.readFile('/etc/flow')).toString() process.kernel.setFS(fs) @@ -46,7 +50,7 @@ const BootLoader: Process = { } try { - await navigator.serviceWorker.register('/uv-sw.js?url=' + encodeURIComponent(btoa(process.kernel.config.SERVER)) + '&e=' + uuid(), { + await navigator.serviceWorker.register(`/uv-sw.js?url=${encodeURIComponent(btoa(process.kernel.config.SERVER))}&e=${uuid()}`, { scope: '/service/' }) } catch (e) { @@ -81,7 +85,7 @@ const BootLoader: Process = { }).appendTo(apps) new HTML('img').attr({ src: executable.config.icon ?? nullIcon, - alt: executable.config.name + ' icon' + alt: `${executable.config.name} icon` }).appendTo(appElement) new HTML('div').text(executable.config.name).appendTo(appElement) }) @@ -102,7 +106,7 @@ const BootLoader: Process = { statusBar.element.html(`
space_dashboard
- ${/*
widgets
*/ ''} +
expand_less
@@ -111,9 +115,7 @@ const BootLoader: Process = { signal_cellular_4_bar
- ${/*
- notifications -
*/ ''} + `) setInterval((): any => { @@ -127,14 +129,14 @@ const BootLoader: Process = { }) if ('getBattery' in navigator) { - (navigator as any).getBattery().then(function (battery: any) { + (navigator as any).getBattery().then((battery: any) => { statusBar.updateBatteryIcon(battery) - battery.addEventListener('levelchange', function () { + battery.addEventListener('levelchange', () => { statusBar.updateBatteryIcon(battery) }) - battery.addEventListener('chargingchange', function () { + battery.addEventListener('chargingchange', () => { statusBar.updateBatteryIcon(battery) }) }) @@ -157,12 +159,12 @@ const BootLoader: Process = { }) } - setInterval((): any => ping(performance.now()), 10000) + setInterval((): any => ping(performance.now()), 10_000) document.addEventListener('app_opened', (e: AppOpenedEvent): void => { new HTML('app').appendMany( new HTML('img').attr({ - alt: e.detail.proc.config.name + ' icon', + alt: `${e.detail.proc.config.name} icon`, 'data-id': e.detail.token, src: e.detail.proc.config.icon ?? nullIcon }).on('click', () => { diff --git a/src/system/UserAccessControl.ts b/src/system/UserAccessControl.ts index 5f2cab3..593ccca 100644 --- a/src/system/UserAccessControl.ts +++ b/src/system/UserAccessControl.ts @@ -9,41 +9,42 @@ const UserAccessControl: Process = { targetVer: '1.0.0-indev.0' }, run: async (process) => { - if (Object.keys(process.data).length > 0) { - const initiator = process.data.process.process - const target = process.data.executable - return await new Promise((resolve) => { - process.loadLibrary('lib/WindowManager').then(async wm => { - let message - switch (process.data.type) { - case 'launch': { - message = `${initiator.config.name as string} wants to launch ${target.config.name as string}` - break - } - case 'kill': { - message = `${initiator.config.name as string} wants to kill ${process.data.name as string}` - break - } - case 'fs': { - message = `${initiator.config.name as string} wants to modify/access ${process.data.path as string}` - break - } - } - - wm.createModal('User Account Control', message, process) - .then(async ({ value, win }: { - value: boolean - win: FlowWindow - }) => { - if (value) { - resolve(true) - } else { - resolve(false) - } - }) - }).catch((e) => console.error(e)) - }) + if (Object.keys(process.data).length <= 0) { + return } + const initiator = process.data.process.process + const target = process.data.executable + return await new Promise((resolve) => { + process.loadLibrary('lib/WindowManager').then(async wm => { + let message + switch (process.data.type) { + case 'launch': { + message = `${initiator.config.name as string} wants to launch ${target.config.name as string}` + break + } + case 'kill': { + message = `${initiator.config.name as string} wants to kill ${process.data.name as string}` + break + } + case 'fs': { + message = `${initiator.config.name as string} wants to modify/access ${process.data.path as string}` + break + } + } + + wm.createModal('User Account Control', message, process) + .then(async ({ value, win }: { + value: boolean + win: FlowWindow + }) => { + if (value) { + resolve(true) + } else { + resolve(false) + } + }) + }).catch((e) => console.error(e)) + }) } } diff --git a/src/system/apps/Browser.ts b/src/system/apps/Browser.ts index efead69..973d379 100644 --- a/src/system/apps/Browser.ts +++ b/src/system/apps/Browser.ts @@ -92,12 +92,12 @@ const BrowserApp: Process = { } (this.header.querySelector('.title') as HTMLElement).innerText = 'Tab' this.iframe.src = (win.content.querySelector('input')?.value as string) - } else { - if (this === tabManager.activeTab) { - (win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_on' - } - this.iframe.src = `/service/${xor.encode(win.content.querySelector('input').value) as string}` + return } + if (this === tabManager.activeTab) { + (win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_on' + } + this.iframe.src = `/service/${xor.encode(win.content.querySelector('input').value) as string}` } } @@ -137,20 +137,21 @@ const BrowserApp: Process = { setActiveTab (tab: Tab): void { this.tabs.forEach((tab) => { - if (tab.active) { - tab.active = false - tab.iframe.style.display = 'none' - tab.header.classList.remove('active') + if (!tab.active) { + return } + tab.active = false + tab.iframe.style.display = 'none' + tab.header.classList.remove('active') }) - if (!tab.proxy) { + if (tab.proxy) { + try { (win.content.querySelector('.inp') as HTMLInputElement).value = xor.decode((tab.iframe.contentWindow as Window).location.href.split('/service/')[1]) } catch (e) { (win.content.querySelector('.inp') as HTMLInputElement).value = 'about:blank' } + (win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_on' + } else { (tab.header.querySelector('.title') as HTMLElement).textContent = 'Tab' try { (win.content.querySelector('.inp') as HTMLInputElement).value = (tab.iframe.contentWindow as Window).location.href } catch (e) { (win.content.querySelector('.inp') as HTMLInputElement).value = 'about:blank' } (win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_off' - } else { - try { (win.content.querySelector('.inp') as HTMLInputElement).value = xor.decode((tab.iframe.contentWindow as Window).location.href.split('/service/')[1]) } catch (e) { (win.content.querySelector('.inp') as HTMLInputElement).value = 'about:blank' } - (win.content.querySelector('.toggle') as HTMLElement).innerHTML = 'toggle_on' } tab.active = true @@ -166,11 +167,7 @@ const BrowserApp: Process = { win.content.querySelector('.inp')?.addEventListener('keydown', (event: KeyboardEvent) => { if (event.key === 'Enter') { - if (tabManager.activeTab.proxy) { - tabManager.activeTab.iframe.src = `/service/${xor.encode((win.content.querySelector('.inp') as HTMLInputElement).value) as string}` - } else { - tabManager.activeTab.iframe.src = (win.content.querySelector('.inp') as HTMLInputElement).value - } + tabManager.activeTab.iframe.src = tabManager.activeTab.proxy ? `/service/${xor.encode((win.content.querySelector('.inp') as HTMLInputElement).value) as string}` : (win.content.querySelector('.inp') as HTMLInputElement).value } }); @@ -195,18 +192,14 @@ const BrowserApp: Process = { } win.content.onfullscreenchange = () => { - if (document.fullscreenElement !== null) { - (win.content.querySelector('.fullscreen') as HTMLElement).innerHTML = 'fullscreen_exit' - } else { - (win.content.querySelector('.fullscreen') as HTMLElement).innerHTML = 'fullscreen' - } + (win.content.querySelector('.fullscreen') as HTMLElement).innerHTML = document.fullscreenElement !== null ? 'fullscreen_exit' : 'fullscreen' } (win.content.querySelector('.fullscreen') as HTMLElement).onclick = async () => { - if (document.fullscreenElement !== null) { - await document.exitFullscreen().catch(e => console.error) - } else { + if (document.fullscreenElement === null) { await win.content.requestFullscreen().catch((e: any) => console.error) + } else { + await document.exitFullscreen().catch(e => console.error) } } diff --git a/src/system/apps/Editor.ts b/src/system/apps/Editor.ts index b9f2187..94f0df4 100644 --- a/src/system/apps/Editor.ts +++ b/src/system/apps/Editor.ts @@ -59,7 +59,12 @@ const Editor: Process = { win.content.style.display = 'flex' win.content.style.flexDirection = 'column' - if (data != null) { + if (data == null) { + await process.launch('lib/FileManager') + setTimeout(() => { + win.close() + }, 10) + } else { const render = async (): Promise => { win.content.innerHTML = `
@@ -203,16 +208,11 @@ const Editor: Process = { document.addEventListener('fs_update', () => { render().catch(e => console.error(e)) }) - } else { - await process.launch('lib/FileManager') - setTimeout(() => { - win.close() - }, 10) } - } else { - await process.kill() - await process.launch('apps/Files') + return } + await process.kill() + await process.launch('apps/Files') } } diff --git a/src/system/apps/Files.ts b/src/system/apps/Files.ts index a7503d3..8e4b042 100644 --- a/src/system/apps/Files.ts +++ b/src/system/apps/Files.ts @@ -48,14 +48,14 @@ const Files: Process = { (win.content.querySelector('.file') as HTMLElement).onclick = async () => { const title: string | null | undefined = prompt('Enter file name') - if (title !== null && title !== undefined) { + if (title != null) { await fs.writeFile(`${dir}/${title}`, '') } } (win.content.querySelector('.folder') as HTMLElement).onclick = async () => { const title: string | null | undefined = prompt('Enter folder name') - if (title !== null && title !== undefined) { + if (title != null) { await fs.mkdir(`${dir}/${title}`, '') } } diff --git a/src/system/apps/ImageViewer.ts b/src/system/apps/ImageViewer.ts index 61553b0..499cf92 100644 --- a/src/system/apps/ImageViewer.ts +++ b/src/system/apps/ImageViewer.ts @@ -43,10 +43,10 @@ const ImageViewer: Process = { document.addEventListener('fs_update', () => { render().catch(e => console.error(e)) }) - } else { - await process.kill() - await process.launch('apps/Files') + return } + await process.kill() + await process.launch('apps/Files') } } diff --git a/src/system/apps/Store.ts b/src/system/apps/Store.ts index dc05597..59e6d66 100644 --- a/src/system/apps/Store.ts +++ b/src/system/apps/Store.ts @@ -25,12 +25,12 @@ const Store: Process = { win.content.style.background = 'var(--base)' - fetch(process.kernel.config.SERVER as string + '/apps/list/') + fetch(`${process.kernel.config.SERVER as string}/apps/list/`) .then(async (res) => await res.json()) .then(handle) .catch(e => console.error(e)) document.addEventListener('fs_update', () => { - fetch(process.kernel.config.SERVER as string + '/apps/list/') + fetch(`${process.kernel.config.SERVER as string}/apps/list/`) .then(async (res) => await res.json()) .then(handle) .catch(e => console.error(e)) diff --git a/src/system/apps/TaskManager.ts b/src/system/apps/TaskManager.ts index b995887..9f906e6 100644 --- a/src/system/apps/TaskManager.ts +++ b/src/system/apps/TaskManager.ts @@ -49,7 +49,7 @@ const TaskManager: Process = { }).appendTo(win.content) const render = (): void => { - const processList = process.kernel.processList + const { processList } = process.kernel table.html('') new HTML('thead').appendTo(table) diff --git a/src/system/lib/SplashScreen.ts b/src/system/lib/SplashScreen.ts index c60c61b..8e9ce9a 100644 --- a/src/system/lib/SplashScreen.ts +++ b/src/system/lib/SplashScreen.ts @@ -4,7 +4,8 @@ import FlowLogo from '../../assets/flow.png' import { Library } from '../../types' import LibraryLib from '../../structures/LibraryLib' -let library: LibraryLib, kernel: Kernel +let library: LibraryLib +let kernel: Kernel const SplashScreen: Library = { config: { diff --git a/src/system/lib/StatusBar.ts b/src/system/lib/StatusBar.ts index 9343dde..db2198e 100644 --- a/src/system/lib/StatusBar.ts +++ b/src/system/lib/StatusBar.ts @@ -29,24 +29,22 @@ const StatusBar: Library = { } else if (battery.level >= 0) { iconHTML = 'battery_charging_20' } - } else { - if (battery.level === 1) { - iconHTML = 'battery_full' - } else if (battery.level >= 0.6) { - iconHTML = 'battery_6_bar' - } else if (battery.level >= 0.5) { - iconHTML = 'battery_5_bar' - } else if (battery.level >= 0.4) { - iconHTML = 'battery_4_bar' - } else if (battery.level >= 0.3) { - iconHTML = 'battery_3_bar' - } else if (battery.level >= 0.2) { - iconHTML = 'battery_2_bar' - } else if (battery.level >= 0.1) { - iconHTML = 'battery_1_bar' - } else if (battery.level >= 0) { - iconHTML = 'battery_0_bar' - } + } else if (battery.level === 1) { + iconHTML = 'battery_full' + } else if (battery.level >= 0.6) { + iconHTML = 'battery_6_bar' + } else if (battery.level >= 0.5) { + iconHTML = 'battery_5_bar' + } else if (battery.level >= 0.4) { + iconHTML = 'battery_4_bar' + } else if (battery.level >= 0.3) { + iconHTML = 'battery_3_bar' + } else if (battery.level >= 0.2) { + iconHTML = 'battery_2_bar' + } else if (battery.level >= 0.1) { + iconHTML = 'battery_1_bar' + } else if (battery.level >= 0) { + iconHTML = 'battery_0_bar' } const batteryDiv = document.querySelector('div[data-toolbar-id="controls"] > .battery') diff --git a/src/system/lib/VirtualFS.ts b/src/system/lib/VirtualFS.ts index f8f5291..02fc73e 100644 --- a/src/system/lib/VirtualFS.ts +++ b/src/system/lib/VirtualFS.ts @@ -253,7 +253,8 @@ export const setFileSystem = async (fileSystemObject: { root: Directory }): Prom export let db: IDBDatabase let fileSystem: { root: Directory } -let kernel: Kernel, process: ProcessLib +let kernel: Kernel +let process: ProcessLib export const initializeDatabase = async (dbName: string): Promise => { return await new Promise((resolve, reject) => { @@ -315,9 +316,7 @@ const save = async (): Promise => { } const handlePermissions = async (path: string): Promise => { - let current - - current = (await navigatePath(path)).current + let { current } = (await navigatePath(path)) if (current === undefined) current = (await navigatePathParent(path)).current @@ -374,7 +373,7 @@ const VirtualFS: Library = { Reflect.deleteProperty(current.children, filename) - console.debug('unlink ' + path) + console.debug(`unlink ${path}`) await save() }, readFile: async (path: string): Promise => { @@ -384,7 +383,7 @@ const VirtualFS: Library = { if (current.type !== 'file') throw new Error(Errors.EISDIR) - console.debug('read ' + path) + console.debug(`read ${path}`) return current.content }, writeFile: async (path: string, content: string | Buffer): Promise => { @@ -392,11 +391,11 @@ const VirtualFS: Library = { let permission - if (typeof current.children[filename] !== 'undefined') { + if (typeof current.children[filename] === 'undefined') { + permission = Permission.USER + } else { await handlePermissions(path) permission = current.children[filename].permission - } else { - permission = Permission.USER } current.children[filename] = { @@ -406,7 +405,7 @@ const VirtualFS: Library = { content: Buffer.from(content) } - console.debug('write ' + path) + console.debug(`write ${path}`) await save() }, mkdir: async (path: string): Promise => { @@ -414,11 +413,11 @@ const VirtualFS: Library = { let permission - if (typeof current.children[filename] !== 'undefined') { + if (typeof current.children[filename] === 'undefined') { + permission = Permission.USER + } else { await handlePermissions(path) permission = current.children[filename].permission - } else { - permission = Permission.USER } current.children[filename] = { @@ -428,7 +427,7 @@ const VirtualFS: Library = { children: {} } - console.debug('mkdir ' + path) + console.debug(`mkdir ${path}`) await save() }, rmdir: async (path: string): Promise => { @@ -441,7 +440,7 @@ const VirtualFS: Library = { Reflect.deleteProperty(current.children, filename) - console.debug('rmdir ' + path) + console.debug(`rmdir ${path}`) await save() }, readdir: async (path: string): Promise => { @@ -450,13 +449,13 @@ const VirtualFS: Library = { if (current.type === 'file') throw new Error(Errors.ENOTDIR) const result = await Promise.all(Object.keys(current.children ?? {})) - console.debug('readdir ' + path) + console.debug(`readdir ${path}`) return result }, stat: async (path: string): Promise<{ isDirectory: () => boolean, isFile: () => boolean }> => { const { current } = await navigatePath(path) - console.debug('stat ' + path) + console.debug(`stat ${path}`) return { isDirectory: () => current.type === 'directory', isFile: () => current.type === 'file' @@ -475,11 +474,11 @@ const VirtualFS: Library = { newCurrent.children[newFilename] = oldCurrent.children[oldFilename] Reflect.deleteProperty(oldCurrent.children, oldFilename) - console.debug('rename ' + oldPath + ' -> ' + newPath) + console.debug(`rename ${oldPath} -> ${newPath}`) await save() }, exists: async (path: string): Promise => { - console.debug('exists ' + path) + console.debug(`exists ${path}`) try { const { current } = await navigatePath(path) return current !== undefined diff --git a/src/system/lib/XOR.ts b/src/system/lib/XOR.ts index ca1c7cd..63d2f20 100644 --- a/src/system/lib/XOR.ts +++ b/src/system/lib/XOR.ts @@ -37,7 +37,7 @@ const XOR: Library = { return indCheck ? String.fromCharCode(char.charCodeAt(0) ^ 2) : char }) - .join('') + ((search.length > 0) ? '?' + search.join('?') : '') + .join('') + ((search.length > 0) ? `?${search.join('?')}` : '') ) } } From 505c11804a09527f18073c854995357f63235354 Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Tue, 16 Jan 2024 05:51:25 +0000 Subject: [PATCH 7/8] =?UTF-8?q?[=E2=9E=95]=20Added=20`less`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 177 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 178 insertions(+) diff --git a/package-lock.json b/package-lock.json index e956061..b6ca8a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@types/node": "^20.11.3", "@types/uuid": "^9.0.5", "@types/web": "^0.0.117", + "less": "^4.2.0", "ts-standard": "^12.0.2", "typedoc": "^0.25.3", "typedoc-material-theme": "^1.0.2", @@ -1371,6 +1372,18 @@ "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", "dev": true }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", @@ -1594,6 +1607,19 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2782,6 +2808,19 @@ "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", "dev": true }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -2811,6 +2850,19 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3218,6 +3270,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -3353,6 +3411,38 @@ "json-buffer": "3.0.1" } }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3440,6 +3530,30 @@ "node": ">=12" } }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -3509,6 +3623,19 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -3578,6 +3705,23 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, "node_modules/node-stdlib-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.2.0.tgz", @@ -3871,6 +4015,15 @@ "node": ">=4" } }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -4137,6 +4290,13 @@ "react-is": "^16.13.1" } }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -4459,6 +4619,13 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "dev": true, + "optional": true + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -4578,6 +4745,16 @@ "node": ">=8" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", diff --git a/package.json b/package.json index c19ef01..c96c216 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@types/node": "^20.11.3", "@types/uuid": "^9.0.5", "@types/web": "^0.0.117", + "less": "^4.2.0", "ts-standard": "^12.0.2", "typedoc": "^0.25.3", "typedoc-material-theme": "^1.0.2", From cb30a0374aad8fb1d441c096f5c9fbd21ca25410 Mon Sep 17 00:00:00 2001 From: ThinLiquid Date: Tue, 16 Jan 2024 06:07:25 +0000 Subject: [PATCH 8/8] =?UTF-8?q?[=F0=9F=90=9B]=20Fixed=20file=20renaming=20?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/system/apps/Files.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/system/apps/Files.ts b/src/system/apps/Files.ts index 8e4b042..bbcba40 100644 --- a/src/system/apps/Files.ts +++ b/src/system/apps/Files.ts @@ -47,14 +47,14 @@ const Files: Process = { } (win.content.querySelector('.file') as HTMLElement).onclick = async () => { - const title: string | null | undefined = prompt('Enter file name') + const title = prompt('Enter file name') if (title != null) { await fs.writeFile(`${dir}/${title}`, '') } } (win.content.querySelector('.folder') as HTMLElement).onclick = async () => { - const title: string | null | undefined = prompt('Enter folder name') + const title = prompt('Enter folder name') if (title != null) { await fs.mkdir(`${dir}/${title}`, '') } @@ -73,8 +73,8 @@ const Files: Process = { element.innerHTML += `${icon} ${file}delete_foreveredit`; (element.querySelector('.rename') as HTMLElement).onclick = async () => { - const value = (prompt('Rename') as string) - if (value !== null || value !== undefined) { + const value = prompt('Rename') + if (value != null) { await fs.rename(dir + seperator + file, dir + seperator + value) } }