diff --git a/.gitignore b/.gitignore
index 2d08fce..6565849 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,10 @@ db.sqlite3
build/**
app/**
settings.json
-*config.json
+comic_config.json
+**/comic_config.json
+compiled/
+deploy-scripts/
-.pnpm-store/**
\ No newline at end of file
+.pnpm-store/**
+.env
\ No newline at end of file
diff --git a/app.ts b/app.ts
deleted file mode 100644
index 27c6636..0000000
--- a/app.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import { app, BrowserWindow, dialog, session } from "electron";
-import { ipcMain } from "electron";
-import { join } from "path";
-import { accessTokenName, getAdminAccessTokenValue, getAdminRefreshTokenValue, refreshTokenName } from "./src/login";
-import { UserAccessor } from "./src/model/mod";
-import { create_server } from "./src/server";
-import { get_setting } from "./src/SettingConfig";
-
-function registerChannel(cntr: UserAccessor) {
- ipcMain.handle("reset_password", async (event, username: string, password: string) => {
- const user = await cntr.findUser(username);
- if (user === undefined) {
- return false;
- }
- user.reset_password(password);
- return true;
- });
-}
-const setting = get_setting();
-if (!setting.cli) {
- let wnd: BrowserWindow | null = null;
-
- const createWindow = async () => {
- wnd = new BrowserWindow({
- width: 800,
- height: 600,
- center: true,
- useContentSize: true,
- webPreferences: {
- preload: join(__dirname, "preload.js"),
- contextIsolation: true,
- },
- });
- await wnd.loadURL(`data:text/html;base64,` + Buffer.from(loading_html).toString("base64"));
- // await wnd.loadURL('../loading.html');
- // set admin cookies.
- await session.defaultSession.cookies.set({
- url: `http://localhost:${setting.port}`,
- name: accessTokenName,
- value: getAdminAccessTokenValue(),
- httpOnly: true,
- secure: false,
- sameSite: "strict",
- });
- await session.defaultSession.cookies.set({
- url: `http://localhost:${setting.port}`,
- name: refreshTokenName,
- value: getAdminRefreshTokenValue(),
- httpOnly: true,
- secure: false,
- sameSite: "strict",
- });
- try {
- const server = await create_server();
- const app = server.start_server();
- registerChannel(server.userController);
- await wnd.loadURL(`http://localhost:${setting.port}`);
- } catch (e) {
- if (e instanceof Error) {
- await dialog.showMessageBox({
- type: "error",
- title: "error!",
- message: e.message,
- });
- } else {
- await dialog.showMessageBox({
- type: "error",
- title: "error!",
- message: String(e),
- });
- }
- }
- wnd.on("closed", () => {
- wnd = null;
- });
- };
-
- const isPrimary = app.requestSingleInstanceLock();
- if (!isPrimary) {
- app.quit(); // exit window
- app.exit();
- }
- app.on("second-instance", () => {
- if (wnd != null) {
- if (wnd.isMinimized()) {
- wnd.restore();
- }
- wnd.focus();
- }
- });
- app.on("ready", (event, info) => {
- createWindow();
- });
-
- app.on("window-all-closed", () => { // quit when all windows are closed
- if (process.platform != "darwin") app.quit(); // (except leave MacOS app active until Cmd+Q)
- });
-
- app.on("activate", () => { // re-recreate window when dock icon is clicked and no other windows open
- if (wnd == null) createWindow();
- });
-} else {
- (async () => {
- try {
- const server = await create_server();
- server.start_server();
- } catch (error) {
- console.log(error);
- }
- })();
-}
-const loading_html = `
-
-
-loading
-
-
-
-
-
- Loading...
-
-
-`;
diff --git a/biome.jsonc b/biome.jsonc
new file mode 100644
index 0000000..df0035c
--- /dev/null
+++ b/biome.jsonc
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://biomejs.dev/schemas/1.6.3/schema.json",
+ "organizeImports": {
+ "enabled": true
+ },
+ "formatter": {
+ "enabled": true,
+ "lineWidth": 120
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true
+ }
+ },
+ "vcs": {
+ "enabled": true,
+ "clientKind": "git",
+ "useIgnoreFile": true
+ }
+}
diff --git a/dprint.json b/dprint.json
deleted file mode 100644
index 3911cdd..0000000
--- a/dprint.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "incremental": true,
- "typescript": {
- "indentWidth": 2
- },
- "json": {
- },
- "markdown": {
- },
- "includes": ["**/*.{ts,tsx,js,jsx,cjs,mjs,json,md}"],
- "excludes": [
- "**/node_modules",
- "**/*-lock.json",
- "**/dist",
- "build/",
- "app/"
- ],
- "plugins": [
- "https://plugins.dprint.dev/typescript-0.84.4.wasm",
- "https://plugins.dprint.dev/json-0.17.2.wasm",
- "https://plugins.dprint.dev/markdown-0.15.2.wasm"
- ]
-}
diff --git a/gen_conf_schema.ts b/gen_conf_schema.ts
deleted file mode 100644
index 460665b..0000000
--- a/gen_conf_schema.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { promises } from "fs";
-const { readdir, writeFile } = promises;
-import { dirname, join } from "path";
-import { createGenerator } from "ts-json-schema-generator";
-
-async function genSchema(path: string, typename: string) {
- const gen = createGenerator({
- path: path,
- type: typename,
- tsconfig: "tsconfig.json",
- });
- const schema = gen.createSchema(typename);
- if (schema.definitions != undefined) {
- const definitions = schema.definitions;
- const definition = definitions[typename];
- if (typeof definition == "object") {
- let property = definition.properties;
- if (property) {
- property["$schema"] = {
- type: "string",
- };
- }
- }
- }
- const text = JSON.stringify(schema);
- await writeFile(join(dirname(path), `${typename}.schema.json`), text);
-}
-function capitalize(s: string) {
- return s.charAt(0).toUpperCase() + s.slice(1);
-}
-async function setToALL(path: string) {
- console.log(`scan ${path}`);
- const direntry = await readdir(path, { withFileTypes: true });
- const works = direntry.filter(x => x.isFile() && x.name.endsWith("Config.ts")).map(x => {
- const name = x.name;
- const m = /(.+)\.ts/.exec(name);
- if (m !== null) {
- const typename = m[1];
- return genSchema(join(path, typename), capitalize(typename));
- }
- });
- await Promise.all(works);
- const subdir = direntry.filter(x => x.isDirectory()).map(x => x.name);
- for (const x of subdir) {
- await setToALL(join(path, x));
- }
-}
-setToALL("src");
diff --git a/index.html b/index.html
deleted file mode 100644
index 48a8430..0000000
--- a/index.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- Ionian
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/knexfile.js b/knexfile.js
deleted file mode 100644
index 76f47c9..0000000
--- a/knexfile.js
+++ /dev/null
@@ -1,5 +0,0 @@
-require("ts-node").register();
-const { Knex } = require("./src/config");
-// Update with your config settings.
-
-module.exports = Knex.config;
diff --git a/migrations/initial.ts b/migrations/initial.ts
deleted file mode 100644
index 816926d..0000000
--- a/migrations/initial.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Knex } from "knex";
-
-export async function up(knex: Knex) {
- await knex.schema.createTable("schema_migration", (b) => {
- b.string("version");
- b.boolean("dirty");
- });
-
- await knex.schema.createTable("users", (b) => {
- b.string("username").primary().comment("user's login id");
- b.string("password_hash", 64).notNullable();
- b.string("password_salt", 64).notNullable();
- });
- await knex.schema.createTable("document", (b) => {
- b.increments("id").primary();
- b.string("title").notNullable();
- b.string("content_type", 16).notNullable();
- b.string("basepath", 256).notNullable().comment("directory path for resource");
- b.string("filename", 256).notNullable().comment("filename");
- b.string("content_hash").nullable();
- b.json("additional").nullable();
- b.integer("created_at").notNullable();
- b.integer("modified_at").notNullable();
- b.integer("deleted_at");
- b.index("content_type", "content_type_index");
- });
- await knex.schema.createTable("tags", (b) => {
- b.string("name").primary();
- b.text("description");
- });
- await knex.schema.createTable("doc_tag_relation", (b) => {
- b.integer("doc_id").unsigned().notNullable();
- b.string("tag_name").notNullable();
- b.foreign("doc_id").references("document.id");
- b.foreign("tag_name").references("tags.name");
- b.primary(["doc_id", "tag_name"]);
- });
- await knex.schema.createTable("permissions", b => {
- b.string("username").notNullable();
- b.string("name").notNullable();
- b.primary(["username", "name"]);
- b.foreign("username").references("users.username");
- });
- // create admin account.
- await knex.insert({
- username: "admin",
- password_hash: "unchecked",
- password_salt: "unchecked",
- }).into("users");
-}
-
-export async function down(knex: Knex) {
- throw new Error("Downward migrations are not supported. Restore from backup.");
-}
diff --git a/package.json b/package.json
index 2d0c444..d798872 100644
--- a/package.json
+++ b/package.json
@@ -1,86 +1,20 @@
{
- "name": "followed",
+ "name": "ionian",
"version": "1.0.0",
"description": "",
- "main": "build/app.js",
+ "main": "index.js",
"scripts": {
- "compile": "tsc",
- "compile:watch": "tsc -w",
- "build": "cd src/client && pnpm run build:prod",
- "build:watch": "cd src/client && pnpm run build:watch",
- "fmt": "dprint fmt",
- "app": "electron build/app.js",
- "app:build": "electron-builder",
- "app:pack": "electron-builder --dir",
- "app:build:win64": "electron-builder --win --x64",
- "app:pack:win64": "electron-builder --win --x64 --dir",
- "cliapp": "node build/app.js"
- },
- "build": {
- "asar": true,
- "files": [
- "build/**/*",
- "node_modules/**/*",
- "package.json"
- ],
- "extraFiles": [
- {
- "from": "dist/",
- "to": "dist/",
- "filter": [
- "**/*",
- "!**/*.map"
- ]
- },
- "index.html"
- ],
- "appId": "com.prelude.ionian.app",
- "productName": "Ionian",
- "win": {
- "target": [
- "zip"
- ]
- },
- "linux": {
- "target": [
- "zip"
- ]
- },
- "directories": {
- "output": "app/",
- "app": "."
- }
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "format": "biome format --write",
+ "lint": "biome lint"
},
+ "keywords": [],
+ "workspaces": [
+ "packages/*"
+ ],
"author": "",
- "license": "ISC",
- "dependencies": {
- "@louislam/sqlite3": "^6.0.1",
- "@types/koa-compose": "^3.2.5",
- "chokidar": "^3.5.3",
- "dprint": "^0.36.1",
- "jsonschema": "^1.4.1",
- "jsonwebtoken": "^8.5.1",
- "knex": "^0.95.15",
- "koa": "^2.13.4",
- "koa-bodyparser": "^4.3.0",
- "koa-compose": "^4.1.0",
- "koa-router": "^10.1.1",
- "natural-orderby": "^2.0.3",
- "node-stream-zip": "^1.15.0",
- "sqlite3": "^5.0.8",
- "tiny-async-pool": "^1.3.0"
- },
+ "license": "MIT",
"devDependencies": {
- "@types/jsonwebtoken": "^8.5.8",
- "@types/koa": "^2.13.4",
- "@types/koa-bodyparser": "^4.3.7",
- "@types/koa-router": "^7.4.4",
- "@types/node": "^14.18.21",
- "@types/tiny-async-pool": "^1.0.1",
- "electron": "^11.5.0",
- "electron-builder": "^22.14.13",
- "ts-json-schema-generator": "^0.82.0",
- "ts-node": "^9.1.1",
- "typescript": "^4.7.4"
+ "@biomejs/biome": "1.6.3"
}
-}
+}
\ No newline at end of file
diff --git a/packages/client/.eslintrc.cjs b/packages/client/.eslintrc.cjs
new file mode 100644
index 0000000..d6c9537
--- /dev/null
+++ b/packages/client/.eslintrc.cjs
@@ -0,0 +1,18 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parser: '@typescript-eslint/parser',
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+}
diff --git a/packages/client/.gitignore b/packages/client/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/packages/client/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/packages/client/README.md b/packages/client/README.md
new file mode 100644
index 0000000..0d6babe
--- /dev/null
+++ b/packages/client/README.md
@@ -0,0 +1,30 @@
+# React + TypeScript + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
+
+- Configure the top-level `parserOptions` property like this:
+
+```js
+export default {
+ // other rules...
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ project: ['./tsconfig.json', './tsconfig.node.json'],
+ tsconfigRootDir: __dirname,
+ },
+}
+```
+
+- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
+- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
+- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
diff --git a/packages/client/components.json b/packages/client/components.json
new file mode 100644
index 0000000..1cc471f
--- /dev/null
+++ b/packages/client/components.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.js",
+ "css": "src/index.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils"
+ }
+}
\ No newline at end of file
diff --git a/packages/client/index.html b/packages/client/index.html
new file mode 100644
index 0000000..ad1ff78
--- /dev/null
+++ b/packages/client/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Ionian
+
+
+
+
+
+
diff --git a/packages/client/package.json b/packages/client/package.json
new file mode 100644
index 0000000..4f70d99
--- /dev/null
+++ b/packages/client/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "client",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview",
+ "shadcn": "shadcn-ui"
+ },
+ "dependencies": {
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-popover": "^1.0.7",
+ "@radix-ui/react-radio-group": "^1.1.3",
+ "@radix-ui/react-separator": "^1.0.3",
+ "@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-tooltip": "^1.0.7",
+ "@tanstack/react-virtual": "^3.2.1",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.0",
+ "dbtype": "workspace:*",
+ "jotai": "^2.7.2",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-resizable-panels": "^2.0.16",
+ "swr": "^2.2.5",
+ "tailwind-merge": "^2.2.2",
+ "tailwindcss-animate": "^1.0.7",
+ "usehooks-ts": "^3.1.0",
+ "wouter": "^3.1.0"
+ },
+ "devDependencies": {
+ "@types/node": ">=20.0.0",
+ "@types/react": "^18.2.66",
+ "@types/react-dom": "^18.2.22",
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
+ "@typescript-eslint/parser": "^7.2.0",
+ "@vitejs/plugin-react-swc": "^3.5.0",
+ "autoprefixer": "^10.4.19",
+ "eslint": "^8.57.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.6",
+ "postcss": "^8.4.38",
+ "shadcn-ui": "^0.8.0",
+ "tailwindcss": "^3.4.3",
+ "typescript": "^5.2.2",
+ "vite": "^5.2.0"
+ }
+}
diff --git a/packages/client/postcss.config.js b/packages/client/postcss.config.js
new file mode 100644
index 0000000..2e7af2b
--- /dev/null
+++ b/packages/client/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/packages/client/public/vite.svg b/packages/client/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/packages/client/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/client/src/App.css b/packages/client/src/App.css
new file mode 100644
index 0000000..1ff976b
--- /dev/null
+++ b/packages/client/src/App.css
@@ -0,0 +1,13 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap');
+
+body {
+ margin: 0;
+ font-family: "Noto Sans KR", sans-serif;
+ font-optical-sizing: auto;
+ min-height: 100vh;
+}
+
+#root {
+ margin: 0;
+ min-height: 100vh;
+}
\ No newline at end of file
diff --git a/packages/client/src/App.tsx b/packages/client/src/App.tsx
new file mode 100644
index 0000000..45a6fe5
--- /dev/null
+++ b/packages/client/src/App.tsx
@@ -0,0 +1,49 @@
+import { Route, Switch, Redirect } from "wouter";
+import { useTernaryDarkMode } from "usehooks-ts";
+import { useEffect } from "react";
+
+import './App.css'
+
+import { TooltipProvider } from "./components/ui/tooltip.tsx";
+import Layout from "./components/layout/layout.tsx";
+
+import Gallery from "@/page/galleryPage.tsx";
+import NotFoundPage from "@/page/404.tsx";
+import LoginPage from "@/page/loginPage.tsx";
+import ProfilePage from "@/page/profilesPage.tsx";
+import ContentInfoPage from "@/page/contentInfoPage.tsx";
+import SettingPage from "@/page/settingPage.tsx";
+import ComicPage from "@/page/reader/comicPage.tsx";
+import DifferencePage from "./page/differencePage.tsx";
+
+const App = () => {
+ const { isDarkMode } = useTernaryDarkMode();
+
+ useEffect(() => {
+ if (isDarkMode) {
+ document.body.classList.add("dark");
+ }
+ else {
+ document.body.classList.remove("dark");
+ }
+ }, [isDarkMode]);
+
+ return (
+
+
+
+ } />
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default App
diff --git a/packages/client/src/assets/react.svg b/packages/client/src/assets/react.svg
new file mode 100644
index 0000000..6c87de9
--- /dev/null
+++ b/packages/client/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/client/src/components/Spinner.tsx b/packages/client/src/components/Spinner.tsx
new file mode 100644
index 0000000..4c3d960
--- /dev/null
+++ b/packages/client/src/components/Spinner.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+
+export function Spinner(props: { className?: string; }) {
+ const chars = ["⠋",
+ "⠙",
+ "⠹",
+ "⠸",
+ "⠼",
+ "⠴",
+ "⠦",
+ "⠧",
+ "⠇",
+ "⠏"
+ ];
+ const [index, setIndex] = React.useState(0);
+ React.useEffect(() => {
+ const interval = setInterval(() => {
+ setIndex((index + 1) % chars.length);
+ }, 80);
+ return () => clearInterval(interval);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [index]);
+
+ return {chars[index]};
+}
diff --git a/packages/client/src/components/gallery/DescItem.tsx b/packages/client/src/components/gallery/DescItem.tsx
new file mode 100644
index 0000000..566e889
--- /dev/null
+++ b/packages/client/src/components/gallery/DescItem.tsx
@@ -0,0 +1,26 @@
+import StyledLink from "@/components/gallery/StyledLink";
+import { cn } from "@/lib/utils";
+
+export function DescItem({ name, children, className }: {
+ name: string;
+ className?: string;
+ children?: React.ReactNode;
+}) {
+ return
+ {name}
+ {children}
+
;
+}
+export function DescTagItem({
+ items, name, className,
+}: {
+ name: string;
+ items: string[];
+ className?: string;
+}) {
+ return
+ {items.length === 0 ? "N/A" : items.map(
+ (x) => {x}
+ )}
+ ;
+}
diff --git a/packages/client/src/components/gallery/GalleryCard.tsx b/packages/client/src/components/gallery/GalleryCard.tsx
new file mode 100644
index 0000000..9381f02
--- /dev/null
+++ b/packages/client/src/components/gallery/GalleryCard.tsx
@@ -0,0 +1,90 @@
+import type { Document } from "dbtype/api";
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx";
+import TagBadge from "@/components/gallery/TagBadge.tsx";
+import { Fragment, useLayoutEffect, useRef, useState } from "react";
+import { LazyImage } from "./LazyImage.tsx";
+import StyledLink from "./StyledLink.tsx";
+import React from "react";
+
+function clipTagsWhenOverflow(tags: string[], limit: number) {
+ let l = 0;
+ for (let i = 0; i < tags.length; i++) {
+ l += tags[i].length;
+ if (l > limit) {
+ return tags.slice(0, i);
+ }
+ l += 1; // for space
+ }
+ return tags;
+}
+
+function GalleryCardImpl({
+ doc: x
+}: { doc: Document; }) {
+ const ref = useRef(null);
+ const [clipCharCount, setClipCharCount] = useState(200);
+ const isDeleted = x.deleted_at !== null;
+
+ const artists = x.tags.filter(x => x.startsWith("artist:")).map(x => x.replace("artist:", ""));
+ const groups = x.tags.filter(x => x.startsWith("group:")).map(x => x.replace("group:", ""));
+
+ const originalTags = x.tags.filter(x => !x.startsWith("artist:") && !x.startsWith("group:"));
+ const clippedTags = clipTagsWhenOverflow(originalTags, clipCharCount);
+
+ useLayoutEffect(() => {
+ const listener = () => {
+ if (ref.current) {
+ const { width } = ref.current.getBoundingClientRect();
+ const charWidth = 7; // rough estimate
+ const newClipCharCount = Math.floor(width / charWidth) * 3;
+ setClipCharCount(newClipCharCount);
+ }
+ };
+ listener();
+ window.addEventListener("resize", listener);
+ return () => {
+ window.removeEventListener("resize", listener);
+ };
+ }, []);
+
+ return
+ {isDeleted ?
+ Deleted
+
:
+
+
+ }
+
+
+
+
+ {x.title}
+
+
+
+ {artists.map((x, i) =>
+ {x}
+ {i + 1 < artists.length && , }
+ )}
+ {groups.length > 0 && {" | "}}
+ {groups.map((x, i) =>
+ {x}
+ {i + 1 < groups.length && , }
+
+ )}
+
+
+
+
+ {clippedTags.map(tag => )}
+ {clippedTags.length < originalTags.length && }
+
+
+
+ ;
+}
+
+export const GalleryCard = React.memo(GalleryCardImpl);
\ No newline at end of file
diff --git a/packages/client/src/components/gallery/LazyImage.tsx b/packages/client/src/components/gallery/LazyImage.tsx
new file mode 100644
index 0000000..fd6ea7c
--- /dev/null
+++ b/packages/client/src/components/gallery/LazyImage.tsx
@@ -0,0 +1,38 @@
+import { useEffect, useRef, useState } from "react";
+
+export function LazyImage({ src, alt, className }: { src: string; alt: string; className?: string; }) {
+ const ref = useRef(null);
+ const [loaded, setLoaded] = useState(false);
+
+ useEffect(() => {
+ if (ref.current) {
+ const observer = new IntersectionObserver((entries) => {
+ if (entries.some(x => x.isIntersecting)) {
+ setLoaded(true);
+ ref.current?.animate([
+ { opacity: 0 },
+ { opacity: 1 }
+ ], {
+ duration: 300,
+ easing: "ease-in-out"
+ });
+ observer.disconnect();
+ }
+ }, {
+ rootMargin: "200px",
+ threshold: 0
+ });
+ observer.observe(ref.current);
+ return () => {
+ observer.disconnect();
+ };
+ }
+ }, []);
+
+ return ;
+}
diff --git a/packages/client/src/components/gallery/StyledLink.tsx b/packages/client/src/components/gallery/StyledLink.tsx
new file mode 100644
index 0000000..b2e4458
--- /dev/null
+++ b/packages/client/src/components/gallery/StyledLink.tsx
@@ -0,0 +1,14 @@
+import { cn } from "@/lib/utils";
+import { Link } from "wouter";
+
+type StyledLinkProps = {
+ children?: React.ReactNode;
+ className?: string;
+ to: string;
+};
+
+export default function StyledLink({ children, className, ...rest }: StyledLinkProps) {
+ return {children}
+}
\ No newline at end of file
diff --git a/packages/client/src/components/gallery/TagBadge.tsx b/packages/client/src/components/gallery/TagBadge.tsx
new file mode 100644
index 0000000..a1ff5d1
--- /dev/null
+++ b/packages/client/src/components/gallery/TagBadge.tsx
@@ -0,0 +1,88 @@
+import { badgeVariants } from "@/components/ui/badge.tsx";
+import { Link } from "wouter";
+import { cn } from "@/lib/utils.ts";
+import { cva } from "class-variance-authority"
+
+enum TagKind {
+ Default = "default",
+ Type = "type",
+ Character = "character",
+ Series = "series",
+ Group = "group",
+ Artist = "artist",
+ Male = "male",
+ Female = "female",
+}
+
+type TagKindType = `${TagKind}`;
+
+export function getTagKind(tagname: string): TagKindType {
+ if (tagname.match(":") === null) {
+ return "default";
+ }
+ const prefix = tagname.split(":")[0];
+ return prefix as TagKindType;
+}
+
+export function toPrettyTagname(tagname: string): string {
+ const kind = getTagKind(tagname);
+ const name = tagname.slice(kind.length + 1);
+
+ switch (kind) {
+ case "male":
+ return `♂ ${name}`;
+ case "female":
+ return `♀ ${name}`;
+ case "artist":
+ return `🎨 ${name}`;
+ case "group":
+ return `🖿 ${name}`;
+ case "series":
+ return `📚 ${name}`
+ case "character":
+ return `👤 ${name}`;
+ case "default":
+ return tagname;
+ default:
+ return name;
+ }
+}
+
+interface TagBadgeProps {
+ tagname: string;
+ className?: string;
+ disabled?: boolean;
+}
+
+
+export const tagBadgeVariants = cva(
+ cn(badgeVariants({ variant: "default"}), "px-1"),
+ {
+ variants: {
+ variant: {
+ default: "bg-[#4a5568] hover:bg-[#718096]",
+ type: "bg-[#d53f8c] hover:bg-[#e24996]",
+ character: "bg-[#52952c] hover:bg-[#6cc24a]",
+ series: "bg-[#dc8f09] hover:bg-[#e69d17]",
+ group: "bg-[#805ad5] hover:bg-[#8b5cd6]",
+ artist: "bg-[#319795] hover:bg-[#38a89d]",
+ female: "bg-[#c21f58] hover:bg-[#db2d67]",
+ male: "bg-[#2a7bbf] hover:bg-[#3091e7]",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+);
+
+export default function TagBadge(props: TagBadgeProps) {
+ const { tagname } = props;
+ const kind = getTagKind(tagname);
+ return {toPrettyTagname(tagname)};
+}
\ No newline at end of file
diff --git a/packages/client/src/components/gallery/TagInput.tsx b/packages/client/src/components/gallery/TagInput.tsx
new file mode 100644
index 0000000..23774fb
--- /dev/null
+++ b/packages/client/src/components/gallery/TagInput.tsx
@@ -0,0 +1,182 @@
+import { cn } from "@/lib/utils";
+import { getTagKind, tagBadgeVariants } from "./TagBadge";
+import { useEffect, useRef, useState } from "react";
+import { Button } from "../ui/button";
+import { useOnClickOutside } from "usehooks-ts";
+import { useTags } from "@/hook/useTags";
+import { Skeleton } from "../ui/skeleton";
+
+interface TagsSelectListProps {
+ className?: string;
+ search?: string;
+ onSelect?: (tag: string) => void;
+ onFirstArrowUp?: () => void;
+}
+
+function TagsSelectList({
+ search = "",
+ onSelect,
+ onFirstArrowUp = () => { },
+}: TagsSelectListProps) {
+ const { data, isLoading } = useTags();
+ const candidates = data?.filter(s => s.name.startsWith(search));
+
+ return
+ {isLoading && <>
+
+
+
+ >}
+ {
+ candidates?.length === 0 && - No results
+ }
+ {candidates?.map((tag) => - onSelect?.(tag.name)}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") {
+ onSelect?.(tag.name);
+ }
+ if (e.key === "ArrowDown") {
+ const next = e.currentTarget.nextElementSibling as HTMLElement;
+ next?.focus();
+ e.preventDefault();
+ }
+ if (e.key === "ArrowUp") {
+ const prev = e.currentTarget.previousElementSibling as HTMLElement;
+ if (prev){
+ prev.focus();
+ }
+ else {
+ onFirstArrowUp();
+ }
+ e.preventDefault();
+ }
+ }}
+ onPointerMove={(e) => {
+ e.currentTarget.focus();
+ }}
+ >{tag.name}
)}
+
+}
+
+interface TagInputProps {
+ className?: string;
+ tags: string[];
+ onTagsChange: (tags: string[]) => void;
+ input: string;
+ onInputChange: (input: string) => void;
+}
+
+export default function TagInput({
+ className,
+ tags = [],
+ onTagsChange = () => { },
+ input = "",
+ onInputChange = () => { },
+}: TagInputProps) {
+ const inputRef = useRef(null);
+ const setTags = onTagsChange;
+ const setInput = onInputChange;
+ const [isFocused, setIsFocused] = useState(false);
+ const [openInfo, setOpenInfo] = useState<{
+ top: number;
+ left: number;
+ } | null>(null);
+ const autocompleteRef = useRef(null);
+ useOnClickOutside(autocompleteRef, () => {
+ setOpenInfo(null);
+ });
+ useEffect(() => {
+ const listener = (e: KeyboardEvent) => {
+ if (e.key === "Escape") {
+ setOpenInfo(null);
+ }
+ }
+ document.addEventListener("keyup", listener);
+ return () => {
+ document.removeEventListener("keyup", listener);
+ }
+ }, []);
+
+ return <>
+ {/* biome-ignore lint/a11y/useKeyWithClickEvents: input exist */}
+ inputRef.current?.focus()}
+ >
+
+ {tags.map((tag) => - {
+ setTags(tags.filter(x=>x!==tag));
+ }}>{tag}
)}
+
+
setIsFocused(true)} onBlur={() => setIsFocused(false)}
+ value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => {
+ if (e.key === "Enter") {
+ if (input.trim() === "") return;
+ setTags([...tags, input]);
+ setInput("");
+ setOpenInfo(null);
+ }
+ if (e.key === "Backspace" && input === "") {
+ setTags(tags.slice(0, -1));
+ setOpenInfo(null);
+ }
+ if (e.key === ":" || (e.ctrlKey && e.key === " ")) {
+ if (inputRef.current) {
+ const rect = inputRef.current.getBoundingClientRect();
+ setOpenInfo({
+ top: rect.bottom,
+ left: rect.left,
+ });
+ }
+ }
+ if (e.key === "Down" || e.key === "ArrowDown") {
+ if (openInfo && autocompleteRef.current) {
+ const firstChild = autocompleteRef.current.firstElementChild?.firstElementChild as HTMLElement;
+ firstChild?.focus();
+ e.preventDefault();
+ }
+ }
+ }}
+ />
+ {
+ openInfo &&
+ {
+ setTags([...tags, tag]);
+ setInput("");
+ setOpenInfo(null);
+ }}
+ onFirstArrowUp={() => {
+ inputRef.current?.focus();
+ }}
+ />
+
+ }
+ {
+ tags.length > 0 &&
+ }
+
+ >
+}
\ No newline at end of file
diff --git a/packages/client/src/components/layout/layout.tsx b/packages/client/src/components/layout/layout.tsx
new file mode 100644
index 0000000..1216fc8
--- /dev/null
+++ b/packages/client/src/components/layout/layout.tsx
@@ -0,0 +1,49 @@
+import { useLayoutEffect, useState } from "react";
+import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "../ui/resizable";
+import { NavList } from "./nav";
+
+
+interface LayoutProps {
+ children?: React.ReactNode;
+}
+
+export default function Layout({ children }: LayoutProps) {
+ const MIN_SIZE_IN_PIXELS = 70;
+ const [minSize, setMinSize] = useState(MIN_SIZE_IN_PIXELS);
+
+ useLayoutEffect(() => {
+ const panelGroup = document.querySelector('[data-panel-group-id="main"]');
+ const resizeHandles = document.querySelectorAll(
+ "[data-panel-resize-handle-id]"
+ );
+ if (!panelGroup || !resizeHandles) return;
+ const observer = new ResizeObserver(() => {
+ let width = panelGroup?.clientWidth;
+ if (!width) return;
+ width -= [...resizeHandles].reduce((acc, resizeHandle) => acc + resizeHandle.clientWidth, 0);
+ // Minimum size in pixels is a percentage of the PanelGroup's height,
+ // less the (fixed) height of the resize handles.
+ setMinSize((MIN_SIZE_IN_PIXELS / width) * 100);
+ });
+ observer.observe(panelGroup);
+ for (const resizeHandle of resizeHandles) {
+ observer.observe(resizeHandle);
+ }
+
+ return () => {
+ observer.disconnect();
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+ {children}
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/client/src/components/layout/nav.tsx b/packages/client/src/components/layout/nav.tsx
new file mode 100644
index 0000000..88f1c37
--- /dev/null
+++ b/packages/client/src/components/layout/nav.tsx
@@ -0,0 +1,78 @@
+import { Link } from "wouter"
+import { MagnifyingGlassIcon, GearIcon, ActivityLogIcon, ArchiveIcon, PersonIcon } from "@radix-ui/react-icons"
+import { Button, buttonVariants } from "@/components/ui/button.tsx"
+import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip.tsx"
+import { useLogin } from "@/state/user.ts";
+import { useNavItems } from "./navAtom";
+import { Separator } from "../ui/separator";
+
+interface NavItemProps {
+ icon: React.ReactNode;
+ to: string;
+ name: string;
+}
+
+export function NavItem({
+ icon,
+ to,
+ name
+}: NavItemProps) {
+ return
+
+
+ {icon}
+ {name}
+
+
+ {name}
+
+}
+
+interface NavItemButtonProps {
+ icon: React.ReactNode;
+ onClick: () => void;
+ name: string;
+ className?: string;
+}
+
+export function NavItemButton({
+ icon,
+ onClick,
+ name,
+ className
+}: NavItemButtonProps) {
+ return
+
+
+
+ {name}
+
+}
+
+export function NavList() {
+ const loginInfo = useLogin();
+ const navItems = useNavItems();
+
+ return
+}
\ No newline at end of file
diff --git a/packages/client/src/components/layout/navAtom.tsx b/packages/client/src/components/layout/navAtom.tsx
new file mode 100644
index 0000000..f0b23a6
--- /dev/null
+++ b/packages/client/src/components/layout/navAtom.tsx
@@ -0,0 +1,23 @@
+import { atom, useAtomValue, setAtomValue, getAtomState } from "@/lib/atom";
+import { useLayoutEffect } from "react";
+
+const NavItems = atom("NavItems", null);
+
+// eslint-disable-next-line react-refresh/only-export-components
+export function useNavItems() {
+ return useAtomValue(NavItems);
+}
+
+export function PageNavItem({items, children}:{items: React.ReactNode, children: React.ReactNode}) {
+ useLayoutEffect(() => {
+ const prev = getAtomState(NavItems).value;
+ const setter = setAtomValue(NavItems);
+ setter(items);
+ return () => {
+ setter(prev);
+ };
+ }, [items]);
+
+ return children;
+}
+
diff --git a/packages/client/src/components/ui/badge.tsx b/packages/client/src/components/ui/badge.tsx
new file mode 100644
index 0000000..3eb4c0d
--- /dev/null
+++ b/packages/client/src/components/ui/badge.tsx
@@ -0,0 +1,36 @@
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils.ts"
+
+const badgeVariants = cva(
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
+ secondary:
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ destructive:
+ "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
+ outline: "text-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+export interface BadgeProps
+ extends React.HTMLAttributes,
+ VariantProps {}
+
+function Badge({ className, variant, ...props }: BadgeProps) {
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/packages/client/src/components/ui/button.tsx b/packages/client/src/components/ui/button.tsx
new file mode 100644
index 0000000..5b05535
--- /dev/null
+++ b/packages/client/src/components/ui/button.tsx
@@ -0,0 +1,57 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils.ts"
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default:
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+ outline:
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-9 px-4 py-2",
+ sm: "h-8 rounded-md px-3 text-xs",
+ lg: "h-10 rounded-md px-8",
+ icon: "h-9 w-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button"
+ return (
+
+ )
+ }
+)
+Button.displayName = "Button"
+
+export { Button, buttonVariants }
diff --git a/packages/client/src/components/ui/card.tsx b/packages/client/src/components/ui/card.tsx
new file mode 100644
index 0000000..b751f76
--- /dev/null
+++ b/packages/client/src/components/ui/card.tsx
@@ -0,0 +1,76 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils.ts"
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+Card.displayName = "Card"
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardHeader.displayName = "CardHeader"
+
+const CardTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardTitle.displayName = "CardTitle"
+
+const CardDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardDescription.displayName = "CardDescription"
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardContent.displayName = "CardContent"
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardFooter.displayName = "CardFooter"
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
diff --git a/packages/client/src/components/ui/input.tsx b/packages/client/src/components/ui/input.tsx
new file mode 100644
index 0000000..0174a6b
--- /dev/null
+++ b/packages/client/src/components/ui/input.tsx
@@ -0,0 +1,25 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils.ts"
+
+export interface InputProps
+ extends React.InputHTMLAttributes {}
+
+const Input = React.forwardRef(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ )
+ }
+)
+Input.displayName = "Input"
+
+export { Input }
diff --git a/packages/client/src/components/ui/label.tsx b/packages/client/src/components/ui/label.tsx
new file mode 100644
index 0000000..ef29585
--- /dev/null
+++ b/packages/client/src/components/ui/label.tsx
@@ -0,0 +1,24 @@
+import * as React from "react"
+import * as LabelPrimitive from "@radix-ui/react-label"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils.ts"
+
+const labelVariants = cva(
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
+)
+
+const Label = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, ...props }, ref) => (
+
+))
+Label.displayName = LabelPrimitive.Root.displayName
+
+export { Label }
diff --git a/packages/client/src/components/ui/popover.tsx b/packages/client/src/components/ui/popover.tsx
new file mode 100644
index 0000000..d82e714
--- /dev/null
+++ b/packages/client/src/components/ui/popover.tsx
@@ -0,0 +1,31 @@
+import * as React from "react"
+import * as PopoverPrimitive from "@radix-ui/react-popover"
+
+import { cn } from "@/lib/utils"
+
+const Popover = PopoverPrimitive.Root
+
+const PopoverTrigger = PopoverPrimitive.Trigger
+
+const PopoverAnchor = PopoverPrimitive.Anchor
+
+const PopoverContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
+
+
+
+))
+PopoverContent.displayName = PopoverPrimitive.Content.displayName
+
+export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
diff --git a/packages/client/src/components/ui/radio-group.tsx b/packages/client/src/components/ui/radio-group.tsx
new file mode 100644
index 0000000..c939b06
--- /dev/null
+++ b/packages/client/src/components/ui/radio-group.tsx
@@ -0,0 +1,42 @@
+import * as React from "react"
+import { CheckIcon } from "@radix-ui/react-icons"
+import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
+
+import { cn } from "@/lib/utils"
+
+const RadioGroup = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => {
+ return (
+
+ )
+})
+RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
+
+const RadioGroupItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => {
+ return (
+
+
+
+
+
+ )
+})
+RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
+
+export { RadioGroup, RadioGroupItem }
diff --git a/packages/client/src/components/ui/resizable.tsx b/packages/client/src/components/ui/resizable.tsx
new file mode 100644
index 0000000..1cdd646
--- /dev/null
+++ b/packages/client/src/components/ui/resizable.tsx
@@ -0,0 +1,43 @@
+import { DragHandleDots2Icon } from "@radix-ui/react-icons"
+import * as ResizablePrimitive from "react-resizable-panels"
+
+import { cn } from "@/lib/utils.ts"
+
+const ResizablePanelGroup = ({
+ className,
+ ...props
+}: React.ComponentProps) => (
+
+)
+
+const ResizablePanel = ResizablePrimitive.Panel
+
+const ResizableHandle = ({
+ withHandle,
+ className,
+ ...props
+}: React.ComponentProps & {
+ withHandle?: boolean
+}) => (
+ div]:rotate-90",
+ className
+ )}
+ {...props}
+ >
+ {withHandle && (
+
+
+
+ )}
+
+)
+
+export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
diff --git a/packages/client/src/components/ui/separator.tsx b/packages/client/src/components/ui/separator.tsx
new file mode 100644
index 0000000..6d7f122
--- /dev/null
+++ b/packages/client/src/components/ui/separator.tsx
@@ -0,0 +1,29 @@
+import * as React from "react"
+import * as SeparatorPrimitive from "@radix-ui/react-separator"
+
+import { cn } from "@/lib/utils"
+
+const Separator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(
+ (
+ { className, orientation = "horizontal", decorative = true, ...props },
+ ref
+ ) => (
+
+ )
+)
+Separator.displayName = SeparatorPrimitive.Root.displayName
+
+export { Separator }
diff --git a/packages/client/src/components/ui/skeleton.tsx b/packages/client/src/components/ui/skeleton.tsx
new file mode 100644
index 0000000..7851593
--- /dev/null
+++ b/packages/client/src/components/ui/skeleton.tsx
@@ -0,0 +1,15 @@
+import { cn } from "@/lib/utils.ts"
+
+function Skeleton({
+ className,
+ ...props
+}: React.HTMLAttributes) {
+ return (
+
+ )
+}
+
+export { Skeleton }
diff --git a/packages/client/src/components/ui/tooltip.tsx b/packages/client/src/components/ui/tooltip.tsx
new file mode 100644
index 0000000..4737dd6
--- /dev/null
+++ b/packages/client/src/components/ui/tooltip.tsx
@@ -0,0 +1,28 @@
+import * as React from "react"
+import * as TooltipPrimitive from "@radix-ui/react-tooltip"
+
+import { cn } from "@/lib/utils.ts"
+
+const TooltipProvider = TooltipPrimitive.Provider
+
+const Tooltip = TooltipPrimitive.Root
+
+const TooltipTrigger = TooltipPrimitive.Trigger
+
+const TooltipContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, sideOffset = 4, ...props }, ref) => (
+
+))
+TooltipContent.displayName = TooltipPrimitive.Content.displayName
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
diff --git a/packages/client/src/hook/fetcher.ts b/packages/client/src/hook/fetcher.ts
new file mode 100644
index 0000000..d35738f
--- /dev/null
+++ b/packages/client/src/hook/fetcher.ts
@@ -0,0 +1,20 @@
+export const BASE_API_URL = import.meta.env.VITE_API_URL ?? window.location.origin;
+
+export function makeApiUrl(pathnameAndQueryparam: string) {
+ return new URL(pathnameAndQueryparam, BASE_API_URL).toString();
+}
+
+export class ApiError extends Error {
+ constructor(public readonly status: number, message: string) {
+ super(message);
+ }
+}
+
+export async function fetcher(url: string, init?: RequestInit) {
+ const u = makeApiUrl(url);
+ const res = await fetch(u, init);
+ if (!res.ok) {
+ throw new ApiError(res.status, await res.text());
+ }
+ return res.json();
+}
diff --git a/packages/client/src/hook/useDifference.ts b/packages/client/src/hook/useDifference.ts
new file mode 100644
index 0000000..627f628
--- /dev/null
+++ b/packages/client/src/hook/useDifference.ts
@@ -0,0 +1,38 @@
+import useSWR, { mutate } from "swr";
+import { fetcher } from "./fetcher";
+
+type FileDifference = {
+ type: string;
+ value: {
+ type: string;
+ path: string;
+ }[];
+};
+
+export function useDifferenceDoc() {
+ return useSWR("/api/diff/list", fetcher);
+}
+
+export async function commit(path: string, type: string) {
+ const data = await fetcher("/api/diff/commit", {
+ method: "POST",
+ body: JSON.stringify([{ path, type }]),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ mutate("/api/diff/list");
+ return data;
+}
+
+export async function commitAll(type: string) {
+ const data = await fetcher("/api/diff/commitall", {
+ method: "POST",
+ body: JSON.stringify({ type }),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ mutate("/api/diff/list");
+ return data;
+}
\ No newline at end of file
diff --git a/packages/client/src/hook/useGalleryDoc.ts b/packages/client/src/hook/useGalleryDoc.ts
new file mode 100644
index 0000000..54a7dce
--- /dev/null
+++ b/packages/client/src/hook/useGalleryDoc.ts
@@ -0,0 +1,7 @@
+import useSWR from "swr";
+import type { Document } from "dbtype/api";
+import { fetcher } from "./fetcher";
+
+export function useGalleryDoc(id: string) {
+ return useSWR(`/api/doc/${id}`, fetcher);
+}
\ No newline at end of file
diff --git a/packages/client/src/hook/useSearchGallery.ts b/packages/client/src/hook/useSearchGallery.ts
new file mode 100644
index 0000000..b8c1a7f
--- /dev/null
+++ b/packages/client/src/hook/useSearchGallery.ts
@@ -0,0 +1,62 @@
+import useSWRInifinite from "swr/infinite";
+import type { Document } from "dbtype/api";
+import { fetcher } from "./fetcher";
+import useSWR from "swr";
+
+interface SearchParams {
+ word?: string;
+ tags?: string[];
+ limit?: number;
+ cursor?: number;
+}
+
+function makeSearchParams({
+ word, tags, limit, cursor,
+}: SearchParams){
+ const search = new URLSearchParams();
+ if (word) search.set("word", word);
+ if (tags) {
+ for (const tag of tags){
+ search.append("allow_tag", tag);
+ }
+ }
+ if (limit) search.set("limit", limit.toString());
+ if (cursor) search.set("cursor", cursor.toString());
+ return search;
+}
+
+export function useSearchGallery(searchParams: SearchParams = {}) {
+ return useSWR(`/api/doc/search?${makeSearchParams(searchParams).toString()}`, fetcher);
+}
+
+export function useSearchGalleryInfinite(searchParams: SearchParams = {}) {
+ return useSWRInifinite<
+ {
+ data: Document[];
+ nextCursor: number | null;
+ startCursor: number | null;
+ hasMore: boolean;
+ }
+ >((index, previous) => {
+ if (!previous && index > 0) return null;
+ if (previous && !previous.hasMore) return null;
+ const search = makeSearchParams(searchParams)
+ if (index === 0) {
+ return `/api/doc/search?${search.toString()}`;
+ }
+ if (!previous || !previous.data) return null;
+ const last = previous.data[previous.data.length - 1];
+ search.set("cursor", last.id.toString());
+ return `/api/doc/search?${search.toString()}`;
+ }, async (url) => {
+ const limit = searchParams.limit;
+ const res = await fetcher(url);
+ return {
+ data: res,
+ startCursor: res.length === 0 ? null : res[0].id,
+ nextCursor: res.length === 0 ? null : res[res.length - 1].id,
+ hasMore: limit ? res.length === limit : (res.length === 20),
+ };
+ });
+}
+
diff --git a/packages/client/src/hook/useTags.ts b/packages/client/src/hook/useTags.ts
new file mode 100644
index 0000000..3141274
--- /dev/null
+++ b/packages/client/src/hook/useTags.ts
@@ -0,0 +1,9 @@
+import useSWR from "swr";
+import { fetcher } from "./fetcher";
+
+export function useTags() {
+ return useSWR<{
+ name: string;
+ description: string;
+ }[]>("/api/tags", fetcher);
+}
\ No newline at end of file
diff --git a/packages/client/src/index.css b/packages/client/src/index.css
new file mode 100644
index 0000000..e5b7c67
--- /dev/null
+++ b/packages/client/src/index.css
@@ -0,0 +1,76 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 0 0% 3.9%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 0 0% 3.9%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 0 0% 3.9%;
+
+ --primary: 0 0% 9%;
+ --primary-foreground: 0 0% 98%;
+
+ --secondary: 0 0% 96.1%;
+ --secondary-foreground: 0 0% 9%;
+
+ --muted: 0 0% 96.1%;
+ --muted-foreground: 0 0% 45.1%;
+
+ --accent: 0 0% 96.1%;
+ --accent-foreground: 0 0% 9%;
+
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 0 0% 98%;
+
+ --border: 0 0% 89.8%;
+ --input: 0 0% 89.8%;
+ --ring: 0 0% 3.9%;
+
+ --radius: 0.5rem;
+ }
+
+ .dark {
+ --background: 0 0% 3.9%;
+ --foreground: 0 0% 98%;
+
+ --card: 0 0% 3.9%;
+ --card-foreground: 0 0% 98%;
+
+ --popover: 0 0% 3.9%;
+ --popover-foreground: 0 0% 98%;
+
+ --primary: 0 0% 98%;
+ --primary-foreground: 0 0% 9%;
+
+ --secondary: 0 0% 14.9%;
+ --secondary-foreground: 0 0% 98%;
+
+ --muted: 0 0% 14.9%;
+ --muted-foreground: 0 0% 63.9%;
+
+ --accent: 0 0% 14.9%;
+ --accent-foreground: 0 0% 98%;
+
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 0 0% 98%;
+
+ --border: 0 0% 14.9%;
+ --input: 0 0% 14.9%;
+ --ring: 0 0% 83.1%;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
\ No newline at end of file
diff --git a/packages/client/src/lib/atom.ts b/packages/client/src/lib/atom.ts
new file mode 100644
index 0000000..526e725
--- /dev/null
+++ b/packages/client/src/lib/atom.ts
@@ -0,0 +1,70 @@
+import { useEffect, useReducer, useState } from "react";
+
+interface AtomState {
+ value: T;
+ listeners: Set<() => void>;
+}
+interface Atom {
+ key: string;
+ default: T;
+}
+
+const atomStateMap = new WeakMap, AtomState>();
+
+export function atom(key: string, defaultVal: T): Atom {
+ return { key, default: defaultVal };
+}
+
+export function getAtomState(atom: Atom): AtomState {
+ let atomState = atomStateMap.get(atom);
+ if (!atomState) {
+ atomState = {
+ value: atom.default,
+ listeners: new Set(),
+ };
+ atomStateMap.set(atom, atomState);
+ }
+ return atomState as AtomState;
+}
+
+export function useAtom(atom: Atom): [T, (val: T) => void] {
+ const state = getAtomState(atom);
+ const [, setState] = useState(state.value);
+ useEffect(() => {
+ const listener = () => setState(state.value);
+ state.listeners.add(listener);
+ return () => {
+ state.listeners.delete(listener);
+ };
+ }, [state]);
+ return [
+ state.value as T,
+ (val: T) => {
+ state.value = val;
+ // biome-ignore lint/complexity/noForEach: forEach is used to call each listener
+ state.listeners.forEach((listener) => listener());
+ },
+ ];
+}
+
+export function useAtomValue(atom: Atom): T {
+ const state = getAtomState(atom);
+ const update = useReducer((x) => x + 1, 0)[1];
+ useEffect(() => {
+ const listener = () => update();
+ state.listeners.add(listener);
+ return () => {
+ state.listeners.delete(listener);
+ };
+ }, [state, update]);
+ return state.value;
+}
+
+export function setAtomValue(atom: Atom): (val: T) => void {
+ const state = getAtomState(atom);
+ return (val: T) => {
+ state.value = val;
+ // biome-ignore lint/complexity/noForEach: forEach is used to call each listener
+ state.listeners.forEach((listener) => listener());
+ };
+}
\ No newline at end of file
diff --git a/packages/client/src/lib/classifyTags.tsx b/packages/client/src/lib/classifyTags.tsx
new file mode 100644
index 0000000..d72bea9
--- /dev/null
+++ b/packages/client/src/lib/classifyTags.tsx
@@ -0,0 +1,33 @@
+interface TagClassifyResult {
+ artist: string[];
+ group: string[];
+ series: string[];
+ type: string[];
+ character: string[];
+ rest: string[];
+}
+
+export function classifyTags(tags: string[]): TagClassifyResult {
+ const result = {
+ artist: [],
+ group: [],
+ series: [],
+ type: [],
+ character: [],
+ rest: [],
+ } as TagClassifyResult;
+ const tagKind = new Set(["artist", "group", "series", "type", "character"]);
+ for (const tag of tags) {
+ const split = tag.split(":");
+ if (split.length !== 2) {
+ continue;
+ }
+ const [prefix, name] = split;
+ if (tagKind.has(prefix)) {
+ result[prefix as keyof TagClassifyResult].push(name);
+ } else {
+ result.rest.push(tag);
+ }
+ }
+ return result;
+}
diff --git a/packages/client/src/lib/utils.ts b/packages/client/src/lib/utils.ts
new file mode 100644
index 0000000..d084cca
--- /dev/null
+++ b/packages/client/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/packages/client/src/main.tsx b/packages/client/src/main.tsx
new file mode 100644
index 0000000..e534213
--- /dev/null
+++ b/packages/client/src/main.tsx
@@ -0,0 +1,11 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App.tsx'
+import './index.css'
+
+// biome-ignore lint/style/noNonNullAssertion:
+ReactDOM.createRoot(document.getElementById('root')!).render(
+
+
+ ,
+)
diff --git a/packages/client/src/page/404.tsx b/packages/client/src/page/404.tsx
new file mode 100644
index 0000000..af25627
--- /dev/null
+++ b/packages/client/src/page/404.tsx
@@ -0,0 +1,9 @@
+export const NotFoundPage = () => {
+ return (
+
404 Not Found
+
찾을 수 없음
+
+ );
+};
+
+export default NotFoundPage;
\ No newline at end of file
diff --git a/packages/client/src/page/contentInfoPage.tsx b/packages/client/src/page/contentInfoPage.tsx
new file mode 100644
index 0000000..5bdb394
--- /dev/null
+++ b/packages/client/src/page/contentInfoPage.tsx
@@ -0,0 +1,82 @@
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
+import { useGalleryDoc } from "../hook/useGalleryDoc.ts";
+import TagBadge from "@/components/gallery/TagBadge";
+import StyledLink from "@/components/gallery/StyledLink";
+import { Link } from "wouter";
+import { classifyTags } from "../lib/classifyTags.tsx";
+import { DescTagItem, DescItem } from "../components/gallery/DescItem.tsx";
+
+export interface ContentInfoPageProps {
+ params: {
+ id: string;
+ };
+}
+
+export function ContentInfoPage({ params }: ContentInfoPageProps) {
+ const { data, error, isLoading } = useGalleryDoc(params.id);
+
+ if (isLoading) {
+ return Loading...
+ }
+
+ if (error) {
+ return Error: {String(error)}
+ }
+
+ if (!data) {
+ return Not found
+ }
+
+ const tags = data?.tags ?? [];
+ const classifiedTags = classifyTags(tags);
+
+ const contentLocation = `/doc/${params.id}/reader`;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ {data.title}
+
+
+
+
+ {classifiedTags.type[0] ?? "N/A"}
+
+
+
+
+
+
+
+
+
+ {new Date(data.created_at).toLocaleString()}
+ {new Date(data.modified_at).toLocaleString()}
+ {`${data.basepath}/${data.filename}`}
+ {JSON.stringify(data.additional)}
+
+
+
Tags
+
+ {classifiedTags.rest.map((tag) => )}
+
+
+
+
+
+ );
+}
+
+export default ContentInfoPage;
\ No newline at end of file
diff --git a/packages/client/src/page/differencePage.tsx b/packages/client/src/page/differencePage.tsx
new file mode 100644
index 0000000..0d49d9b
--- /dev/null
+++ b/packages/client/src/page/differencePage.tsx
@@ -0,0 +1,62 @@
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
+import { Separator } from "@/components/ui/separator";
+import { useDifferenceDoc, commit, commitAll } from "@/hook/useDifference";
+import { useLogin } from "@/state/user";
+import { Fragment } from "react/jsx-runtime";
+
+export function DifferencePage() {
+ const { data, isLoading, error } = useDifferenceDoc();
+ const userInfo = useLogin();
+
+ if (!userInfo) {
+ return
+
+ Not logged in
+
+
+ }
+
+ if (error) {
+ return Error: {String(error)}
+ }
+
+ return (
+
+
+
+
+ Difference
+ Scanned Files List
+
+
+
+ {isLoading && Loading...
}
+ {data?.map((c) => {
+ const x = c.value;
+ return (
+
+ {x.map((y) => (
+
+
{y.path}
+
+
+ ))}
+
+ )
+ })}
+
+
+
+ )
+}
+
+export default DifferencePage;
\ No newline at end of file
diff --git a/packages/client/src/page/galleryPage.tsx b/packages/client/src/page/galleryPage.tsx
new file mode 100644
index 0000000..ceb52d2
--- /dev/null
+++ b/packages/client/src/page/galleryPage.tsx
@@ -0,0 +1,141 @@
+import { useLocation, useSearch } from "wouter";
+import { Button } from "@/components/ui/button.tsx";
+import { GalleryCard } from "@/components/gallery/GalleryCard.tsx";
+import TagBadge from "@/components/gallery/TagBadge.tsx";
+import { useSearchGalleryInfinite } from "../hook/useSearchGallery.ts";
+import { Spinner } from "../components/Spinner.tsx";
+import TagInput from "@/components/gallery/TagInput.tsx";
+import { useEffect, useRef, useState } from "react";
+import { Separator } from "@/components/ui/separator.tsx";
+import { useVirtualizer } from "@tanstack/react-virtual";
+
+export default function Gallery() {
+ const search = useSearch();
+ const searchParams = new URLSearchParams(search);
+ const word = searchParams.get("word") ?? undefined;
+ const tags = searchParams.getAll("allow_tag") ?? undefined;
+ const limit = searchParams.get("limit");
+ const cursor = searchParams.get("cursor");
+ const { data, error, isLoading, size, setSize } = useSearchGalleryInfinite({
+ word, tags,
+ limit: limit ? Number.parseInt(limit) : undefined,
+ cursor: cursor ? Number.parseInt(cursor) : undefined
+ });
+ const parentRef = useRef(null);
+ const virtualizer = useVirtualizer({
+ count: size,
+ // biome-ignore lint/style/noNonNullAssertion:
+ getScrollElement: () => parentRef.current!,
+ estimateSize: (index) => {
+ if (!data) return 8;
+ const docs = data?.[index];
+ if (!docs) return 8;
+ return docs.data.length * (200 + 8) + 37 + 8;
+ },
+ overscan: 1,
+ });
+
+
+
+ const virtualItems = virtualizer.getVirtualItems();
+ useEffect(() => {
+ const lastItems = virtualItems.slice(-1);
+ if (lastItems.some(x => x.index >= size - 1)) {
+ const last = lastItems[0];
+ const docs = data?.[last.index];
+ if (docs?.hasMore) {
+ setSize(size + 1);
+ }
+ }
+ }, [virtualItems, setSize, size, data]);
+
+ useEffect(() => {
+ virtualizer.measure();
+ }, [virtualizer, data]);
+
+ if (isLoading) {
+ return Loading...
+ }
+ if (error) {
+ return Error: {String(error)}
+ }
+ if (!data) {
+ return No data
+ }
+
+
+ const isLoadingMore = data && size > 0 && (data[size - 1] === undefined);
+ return (
+
+ {(word || tags) &&
+
+ {word &&
Search: {word}}
+ {tags &&
Tags: }
+
+ }
+ {data?.length === 0 &&
No results
}
+
+ {// TODO: date based grouping
+ virtualItems.map((item) => {
+ const isLoaderRow = item.index === size - 1 && isLoadingMore;
+ if (isLoaderRow) {
+ return
+
+
;
+ }
+ const docs = data[item.index];
+ if (!docs) return null;
+ return
+ {docs.startCursor &&
+
Start with {docs.startCursor}
+
+ }
+ {docs?.data?.map((x) => {
+ return (
+
+ );
+ })}
+
+ })
+ }
+
+
+ );
+}
+
+function Search() {
+ const search = useSearch();
+ const [, navigate] = useLocation();
+ const searchParams = new URLSearchParams(search);
+ const [tags, setTags] = useState(searchParams.get("allow_tag")?.split(",") ?? []);
+ const [word, setWord] = useState(searchParams.get("word") ?? "");
+ return
+
+
+
;
+}
+
diff --git a/packages/client/src/page/loginPage.tsx b/packages/client/src/page/loginPage.tsx
new file mode 100644
index 0000000..882f16b
--- /dev/null
+++ b/packages/client/src/page/loginPage.tsx
@@ -0,0 +1,58 @@
+import { Button } from "@/components/ui/button.tsx";
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card.tsx";
+import { Input } from "@/components/ui/input.tsx";
+import { Label } from "@/components/ui/label.tsx";
+import { doLogin } from "@/state/user.ts";
+import { useState } from "react";
+import { useLocation } from "wouter";
+
+export function LoginForm() {
+ const [username, setUsername] = useState("");
+ const [password, setPassword] = useState("");
+ const [, setLocation] = useLocation();
+
+ return (
+
+
+ Login
+
+ Enter your email below to login to your account.
+
+
+
+
+
+ setUsername(e.target.value)}/>
+
+
+
+ setPassword(e.target.value)}/>
+
+
+
+
+
+
+ )
+}
+
+export function LoginPage() {
+ return (
+
+
+
+ )
+}
+
+export default LoginPage;
\ No newline at end of file
diff --git a/packages/client/src/page/profilesPage.tsx b/packages/client/src/page/profilesPage.tsx
new file mode 100644
index 0000000..8039a06
--- /dev/null
+++ b/packages/client/src/page/profilesPage.tsx
@@ -0,0 +1,34 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { useLogin } from "@/state/user";
+import { Redirect } from "wouter";
+
+export function ProfilePage() {
+ const userInfo = useLogin();
+ if (!userInfo) {
+ console.error("User session expired. Redirecting to login page.");
+ return ;
+ }
+ // TODO: Add a logout button
+ // TODO: Add a change password button
+ return (
+
+
+
+ Profile
+
+
+
+ Username
+ {userInfo.username}
+
+
+ Permission
+ {userInfo.permission.length > 1 ? userInfo.permission.join(",") : "N/A"}
+
+
+
+
+ )
+}
+
+export default ProfilePage;
\ No newline at end of file
diff --git a/packages/client/src/page/reader/comicPage.tsx b/packages/client/src/page/reader/comicPage.tsx
new file mode 100644
index 0000000..97c849c
--- /dev/null
+++ b/packages/client/src/page/reader/comicPage.tsx
@@ -0,0 +1,166 @@
+import { NavItem, NavItemButton } from "@/components/layout/nav";
+import { PageNavItem } from "@/components/layout/navAtom";
+import { Input } from "@/components/ui/input";
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
+import { useGalleryDoc } from "@/hook/useGalleryDoc.ts";
+import { cn } from "@/lib/utils";
+import { EnterFullScreenIcon, ExitFullScreenIcon, ExitIcon } from "@radix-ui/react-icons";
+import { useEventListener } from "usehooks-ts";
+import type { Document } from "dbtype/api";
+import { useCallback, useEffect, useRef, useState } from "react";
+
+interface ComicPageProps {
+ params: {
+ id: string;
+ };
+}
+
+function ComicViewer({
+ doc,
+ totalPage,
+ curPage,
+ onChangePage: setCurPage,
+}: {
+ doc: Document;
+ totalPage: number;
+ curPage: number;
+ onChangePage: (page: number) => void;
+}) {
+ const [fade, setFade] = useState(false);
+ const PageDown = useCallback((step: number) => setCurPage(Math.max(curPage - step, 0)), [curPage, setCurPage]);
+ const PageUp = useCallback((step: number) => setCurPage(Math.min(curPage + step, totalPage - 1)), [curPage, setCurPage, totalPage]);
+ const currentImageRef = useRef(null);
+
+ useEffect(() => {
+ const onKeyUp = (e: KeyboardEvent) => {
+ const step = e.shiftKey ? 10 : 1;
+ if (e.code === "ArrowLeft") {
+ PageDown(step);
+ } else if (e.code === "ArrowRight") {
+ PageUp(step);
+ }
+ };
+ window.addEventListener("keyup", onKeyUp);
+ return () => {
+ window.removeEventListener("keyup", onKeyUp);
+ };
+ }, [PageDown, PageUp]);
+
+ useEffect(() => {
+ if(currentImageRef.current){
+ if (curPage < 0 || curPage >= totalPage) {
+ return;
+ }
+ const img = new Image();
+ img.src = `/api/doc/${doc.id}/comic/${curPage}`;
+ if (img.complete) {
+ currentImageRef.current.src = img.src;
+ setFade(false);
+ return;
+ }
+ setFade(true);
+ const listener = () => {
+ // biome-ignore lint/style/noNonNullAssertion:
+ const currentImage = currentImageRef.current!;
+ currentImage.src = img.src;
+ setFade(false);
+ };
+ img.addEventListener("load", listener);
+ return () => {
+ img.removeEventListener("load", listener);
+ // abort loading
+ img.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAI=;';
+ // TODO: use web worker to abort loading image in the future
+ };
+ }
+ }, [curPage, doc.id, totalPage]);
+
+ return (
+
+
PageDown(1)} />
+
+
PageUp(1)} />
+
+ );
+}
+
+function clip(val: number, min: number, max: number): number {
+ return Math.max(min, Math.min(max, val));
+}
+
+function useFullScreen() {
+ const ref = useRef
(document.documentElement);
+ const [isFullScreen, setIsFullScreen] = useState(false);
+
+ const toggleFullScreen = useCallback(() => {
+ if (isFullScreen) {
+ document.exitFullscreen();
+ } else {
+ document.documentElement.requestFullscreen();
+ }
+ }, [isFullScreen]);
+
+ useEventListener("fullscreenchange", () => {
+ setIsFullScreen(!!document.fullscreenElement);
+ }, ref);
+ return { isFullScreen, toggleFullScreen };
+}
+
+export default function ComicPage({
+ params
+}: ComicPageProps) {
+ const { data, error, isLoading } = useGalleryDoc(params.id);
+ const [curPage, setCurPage] = useState(0);
+ const { isFullScreen, toggleFullScreen } = useFullScreen();
+ if (isLoading) {
+ // TODO: Add a loading spinner
+ return
+ Loading...
+
+ }
+ if (error) {
+ return Error: {String(error)}
+ }
+ if (!data) {
+ return Not found
+ }
+
+ if (data.content_type !== "comic") {
+ return Not a comic
+ }
+ if (!("page" in data.additional)) {
+ console.error(`invalid content : page read fail : ${JSON.stringify(data.additional)}`);
+ return Error. DB error. page restriction
+ }
+
+ return (
+
+ }/>
+ : } onClick={()=>{
+ toggleFullScreen();
+ }} />
+
+
+ {curPage + 1}/{data.additional.page as number}
+
+
+
+ setCurPage(clip(Number.parseInt(e.target.value) - 1,
+ 0,
+ (data.additional.page as number) - 1))} />
+
+
+ >}>
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/client/page/reader/thumbnail.css b/packages/client/src/page/reader/thumbnail.css
similarity index 100%
rename from src/client/page/reader/thumbnail.css
rename to packages/client/src/page/reader/thumbnail.css
diff --git a/packages/client/src/page/settingPage.tsx b/packages/client/src/page/settingPage.tsx
new file mode 100644
index 0000000..ef5deac
--- /dev/null
+++ b/packages/client/src/page/settingPage.tsx
@@ -0,0 +1,92 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { type TernaryDarkMode, useTernaryDarkMode, useMediaQuery } from "usehooks-ts";
+import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
+import { Label } from "@/components/ui/label";
+
+function LightModeView() {
+ return ;
+}
+
+function DarkModeView() {
+ return
+}
+
+export function SettingPage() {
+ const { setTernaryDarkMode, ternaryDarkMode } = useTernaryDarkMode();
+ const isSystemDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
+
+ return (
+
+
+
+ Settings
+
+
+
+
+
Appearance
+ Dark mode
+
+
setTernaryDarkMode(v as TernaryDarkMode)}
+ className="flex space-x-2 items-center"
+ >
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default SettingPage;
\ No newline at end of file
diff --git a/packages/client/src/state/user.ts b/packages/client/src/state/user.ts
new file mode 100644
index 0000000..8c9241c
--- /dev/null
+++ b/packages/client/src/state/user.ts
@@ -0,0 +1,116 @@
+import { atom, useAtomValue, setAtomValue } from "../lib/atom.ts";
+import { makeApiUrl } from "../hook/fetcher.ts";
+
+type LoginLocalStorage = {
+ username: string;
+ permission: string[];
+ accessExpired: number;
+};
+
+let localObj: LoginLocalStorage | null = null;
+function getUserSessions() {
+ if (localObj === null) {
+ const storagestr = localStorage.getItem("UserLoginContext") as string | null;
+ const storage = storagestr !== null ? (JSON.parse(storagestr) as LoginLocalStorage | null) : null;
+ localObj = storage;
+ }
+ if (localObj !== null && localObj.accessExpired > Math.floor(Date.now() / 1000)) {
+ return {
+ username: localObj.username,
+ permission: localObj.permission,
+ };
+ }
+ return null;
+}
+
+export async function refresh() {
+ const u = makeApiUrl("/api/user/refresh");
+ const res = await fetch(u, {
+ method: "POST",
+ credentials: "include",
+ });
+ if (res.status !== 200) throw new Error("Maybe Network Error");
+ const r = (await res.json()) as LoginLocalStorage & { refresh: boolean };
+ if (r.refresh) {
+ localObj = {
+ ...r
+ };
+ } else {
+ localObj = {
+ accessExpired: 0,
+ username: "",
+ permission: r.permission,
+ };
+ }
+ localStorage.setItem("UserLoginContext", JSON.stringify(localObj));
+ return {
+ username: r.username,
+ permission: r.permission,
+ };
+}
+
+export const doLogout = async () => {
+ const u = makeApiUrl("/api/user/logout");
+ const req = await fetch(u, {
+ method: "POST",
+ credentials: "include",
+ });
+ const setVal = setAtomValue(userLoginStateAtom);
+ try {
+ const res = await req.json();
+ localObj = {
+ accessExpired: 0,
+ username: "",
+ permission: res.permission,
+ };
+ window.localStorage.setItem("UserLoginContext", JSON.stringify(localObj));
+ setVal(localObj);
+ return {
+ username: localObj.username,
+ permission: localObj.permission,
+ };
+ } catch (error) {
+ console.error(`Server Error ${error}`);
+ return {
+ username: "",
+ permission: [],
+ };
+ }
+};
+export const doLogin = async (userLoginInfo: {
+ username: string;
+ password: string;
+}): Promise => {
+ const u = makeApiUrl("/api/user/login");
+ const res = await fetch(u, {
+ method: "POST",
+ body: JSON.stringify(userLoginInfo),
+ headers: { "content-type": "application/json" },
+ credentials: "include",
+ });
+ const b = await res.json();
+ if (res.status !== 200) {
+ return b.detail as string;
+ }
+ const setVal = setAtomValue(userLoginStateAtom);
+ localObj = b;
+ setVal(b);
+ window.localStorage.setItem("UserLoginContext", JSON.stringify(localObj));
+ return b;
+};
+
+
+export async function getInitialValue() {
+ const user = getUserSessions();
+ if (user) {
+ return user;
+ }
+ return refresh();
+}
+
+export const userLoginStateAtom = atom("userLoginState", getUserSessions());
+
+export function useLogin() {
+ const val = useAtomValue(userLoginStateAtom);
+ return val;
+}
\ No newline at end of file
diff --git a/packages/client/src/vite-env.d.ts b/packages/client/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/packages/client/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/packages/client/tailwind.config.js b/packages/client/tailwind.config.js
new file mode 100644
index 0000000..7cb7e37
--- /dev/null
+++ b/packages/client/tailwind.config.js
@@ -0,0 +1,77 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ darkMode: ["class"],
+ content: [
+ './pages/**/*.{ts,tsx}',
+ './components/**/*.{ts,tsx}',
+ './app/**/*.{ts,tsx}',
+ './src/**/*.{ts,tsx}',
+ ],
+ prefix: "",
+ theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
+ extend: {
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ "accordion-down": {
+ from: { height: "0" },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: "0" },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ },
+ },
+ },
+ plugins: [require("tailwindcss-animate")],
+}
\ No newline at end of file
diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json
new file mode 100644
index 0000000..0d28e1d
--- /dev/null
+++ b/packages/client/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ },
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/packages/client/tsconfig.node.json b/packages/client/tsconfig.node.json
new file mode 100644
index 0000000..97ede7e
--- /dev/null
+++ b/packages/client/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts
new file mode 100644
index 0000000..327a9e7
--- /dev/null
+++ b/packages/client/vite.config.ts
@@ -0,0 +1,20 @@
+import { defineConfig, loadEnv } from 'vite'
+import path from 'node:path'
+import react from '@vitejs/plugin-react-swc'
+
+// https://vitejs.dev/config/
+export default defineConfig(({ mode }) => {
+ const env = loadEnv(mode, process.cwd(), "");
+ return {
+ plugins: [react()],
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, './src'),
+ },
+ },
+ server: {
+ proxy: {
+ '/api': env.API_BASE_URL ?? 'http://localhost:8000',
+ }
+ }
+}})
diff --git a/packages/dbtype/api.ts b/packages/dbtype/api.ts
new file mode 100644
index 0000000..bc5e33b
--- /dev/null
+++ b/packages/dbtype/api.ts
@@ -0,0 +1,53 @@
+import type { JSONMap } from './jsonmap';
+
+export interface DocumentBody {
+ title: string;
+ content_type: string;
+ basepath: string;
+ filename: string;
+ modified_at: number;
+ content_hash: string | null;
+ additional: JSONMap;
+ tags: string[]; // eager loading
+}
+
+export interface Document extends DocumentBody {
+ readonly id: number;
+ readonly created_at: number;
+ readonly deleted_at: number | null;
+}
+
+export type QueryListOption = {
+ /**
+ * search word
+ */
+ word?: string;
+ allow_tag?: string[];
+ /**
+ * limit of list
+ * @default 20
+ */
+ limit?: number;
+ /**
+ * use offset if true, otherwise
+ * @default false
+ */
+ use_offset?: boolean;
+ /**
+ * cursor of documents
+ */
+ cursor?: number;
+ /**
+ * offset of documents
+ */
+ offset?: number;
+ /**
+ * tag eager loading
+ * @default true
+ */
+ eager_loading?: boolean;
+ /**
+ * content type
+ */
+ content_type?: string;
+};
\ No newline at end of file
diff --git a/src/types/json.ts b/packages/dbtype/jsonmap.ts
similarity index 100%
rename from src/types/json.ts
rename to packages/dbtype/jsonmap.ts
diff --git a/packages/dbtype/package.json b/packages/dbtype/package.json
new file mode 100644
index 0000000..47f24b7
--- /dev/null
+++ b/packages/dbtype/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "dbtype",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "@types/better-sqlite3": "^7.6.9",
+ "better-sqlite3": "^9.4.3",
+ "kysely": "^0.27.3",
+ "kysely-codegen": "^0.14.1"
+ }
+}
diff --git a/packages/dbtype/types.ts b/packages/dbtype/types.ts
new file mode 100644
index 0000000..3ea5ac5
--- /dev/null
+++ b/packages/dbtype/types.ts
@@ -0,0 +1,53 @@
+import type { ColumnType } from "kysely";
+
+export type Generated = T extends ColumnType
+ ? ColumnType
+ : ColumnType;
+
+export interface DocTagRelation {
+ doc_id: number;
+ tag_name: string;
+}
+
+export interface Document {
+ additional: string | null;
+ basepath: string;
+ content_hash: string | null;
+ content_type: string;
+ created_at: number;
+ deleted_at: number | null;
+ filename: string;
+ id: Generated;
+ modified_at: number;
+ title: string;
+}
+
+export interface Permissions {
+ name: string;
+ username: string;
+}
+
+export interface SchemaMigration {
+ dirty: number | null;
+ version: string | null;
+}
+
+export interface Tags {
+ description: string | null;
+ name: string;
+}
+
+export interface Users {
+ password_hash: string;
+ password_salt: string;
+ username: string | null;
+}
+
+export interface DB {
+ doc_tag_relation: DocTagRelation;
+ document: Document;
+ permissions: Permissions;
+ schema_migration: SchemaMigration;
+ tags: Tags;
+ users: Users;
+}
diff --git a/packages/server/app.ts b/packages/server/app.ts
new file mode 100644
index 0000000..baf6dea
--- /dev/null
+++ b/packages/server/app.ts
@@ -0,0 +1,7 @@
+import { create_server } from "./src/server";
+
+create_server().then((server) => {
+ server.start_server();
+}).catch((err) => {
+ console.error(err);
+});
\ No newline at end of file
diff --git a/packages/server/gen_conf_schema.ts b/packages/server/gen_conf_schema.ts
new file mode 100644
index 0000000..f5a02b6
--- /dev/null
+++ b/packages/server/gen_conf_schema.ts
@@ -0,0 +1,50 @@
+// import { promises } from "fs";
+// const { readdir, writeFile } = promises;
+// import { dirname, join } from "path";
+// import { createGenerator } from "ts-json-schema-generator";
+
+// async function genSchema(path: string, typename: string) {
+// const gen = createGenerator({
+// path: path,
+// type: typename,
+// tsconfig: "tsconfig.json",
+// });
+// const schema = gen.createSchema(typename);
+// if (schema.definitions != undefined) {
+// const definitions = schema.definitions;
+// const definition = definitions[typename];
+// if (typeof definition == "object") {
+// let property = definition.properties;
+// if (property) {
+// property["$schema"] = {
+// type: "string",
+// };
+// }
+// }
+// }
+// const text = JSON.stringify(schema);
+// await writeFile(join(dirname(path), `${typename}.schema.json`), text);
+// }
+// function capitalize(s: string) {
+// return s.charAt(0).toUpperCase() + s.slice(1);
+// }
+// async function setToALL(path: string) {
+// console.log(`scan ${path}`);
+// const direntry = await readdir(path, { withFileTypes: true });
+// const works = direntry
+// .filter((x) => x.isFile() && x.name.endsWith("Config.ts"))
+// .map((x) => {
+// const name = x.name;
+// const m = /(.+)\.ts/.exec(name);
+// if (m !== null) {
+// const typename = m[1];
+// return genSchema(join(path, typename), capitalize(typename));
+// }
+// });
+// await Promise.all(works);
+// const subdir = direntry.filter((x) => x.isDirectory()).map((x) => x.name);
+// for (const x of subdir) {
+// await setToALL(join(path, x));
+// }
+// }
+// setToALL("src");
diff --git a/packages/server/migrations/initial.ts b/packages/server/migrations/initial.ts
new file mode 100644
index 0000000..803da57
--- /dev/null
+++ b/packages/server/migrations/initial.ts
@@ -0,0 +1,56 @@
+import { Knex } from "knex";
+
+export async function up(knex: Knex) {
+ await knex.schema.createTable("schema_migration", (b) => {
+ b.string("version");
+ b.boolean("dirty");
+ });
+
+ await knex.schema.createTable("users", (b) => {
+ b.string("username").primary().comment("user's login id");
+ b.string("password_hash", 64).notNullable();
+ b.string("password_salt", 64).notNullable();
+ });
+ await knex.schema.createTable("document", (b) => {
+ b.increments("id").primary();
+ b.string("title").notNullable();
+ b.string("content_type", 16).notNullable();
+ b.string("basepath", 256).notNullable().comment("directory path for resource");
+ b.string("filename", 256).notNullable().comment("filename");
+ b.string("content_hash").nullable();
+ b.json("additional").nullable();
+ b.integer("created_at").notNullable();
+ b.integer("modified_at").notNullable();
+ b.integer("deleted_at");
+ b.index("content_type", "content_type_index");
+ });
+ await knex.schema.createTable("tags", (b) => {
+ b.string("name").primary();
+ b.text("description");
+ });
+ await knex.schema.createTable("doc_tag_relation", (b) => {
+ b.integer("doc_id").unsigned().notNullable();
+ b.string("tag_name").notNullable();
+ b.foreign("doc_id").references("document.id");
+ b.foreign("tag_name").references("tags.name");
+ b.primary(["doc_id", "tag_name"]);
+ });
+ await knex.schema.createTable("permissions", (b) => {
+ b.string("username").notNullable();
+ b.string("name").notNullable();
+ b.primary(["username", "name"]);
+ b.foreign("username").references("users.username");
+ });
+ // create admin account.
+ await knex
+ .insert({
+ username: "admin",
+ password_hash: "unchecked",
+ password_salt: "unchecked",
+ })
+ .into("users");
+}
+
+export async function down(knex: Knex) {
+ throw new Error("Downward migrations are not supported. Restore from backup.");
+}
diff --git a/packages/server/package.json b/packages/server/package.json
new file mode 100644
index 0000000..bf3919d
--- /dev/null
+++ b/packages/server/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "followed",
+ "version": "1.0.0",
+ "description": "",
+ "main": "build/app.js",
+ "scripts": {
+ "compile": "swc src --out-dir compile",
+ "dev": "nodemon -r @swc-node/register --enable-source-maps --exec node app.ts",
+ "start": "node compile/app.js"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "@zip.js/zip.js": "^2.7.40",
+ "better-sqlite3": "^9.4.3",
+ "chokidar": "^3.6.0",
+ "dotenv": "^16.4.5",
+ "jsonwebtoken": "^8.5.1",
+ "koa": "^2.15.2",
+ "koa-bodyparser": "^4.4.1",
+ "koa-compose": "^4.1.0",
+ "koa-router": "^12.0.1",
+ "kysely": "^0.27.3",
+ "natural-orderby": "^2.0.3",
+ "tiny-async-pool": "^1.3.0"
+ },
+ "devDependencies": {
+ "@swc-node/register": "^1.9.0",
+ "@swc/cli": "^0.3.10",
+ "@swc/core": "^1.4.11",
+ "@types/better-sqlite3": "^7.6.9",
+ "@types/jsonwebtoken": "^8.5.9",
+ "@types/koa": "^2.15.0",
+ "@types/koa-bodyparser": "^4.3.12",
+ "@types/koa-compose": "^3.2.8",
+ "@types/koa-router": "^7.4.8",
+ "@types/node": ">=20.0.0",
+ "@types/tiny-async-pool": "^1.0.5",
+ "dbtype": "workspace:^",
+ "nodemon": "^3.1.0"
+ }
+}
diff --git a/packages/server/preload.ts b/packages/server/preload.ts
new file mode 100644
index 0000000..396815a
--- /dev/null
+++ b/packages/server/preload.ts
@@ -0,0 +1,7 @@
+// import { contextBridge, ipcRenderer } from "electron";
+
+// contextBridge.exposeInMainWorld("electron", {
+// passwordReset: async (username: string, toPw: string) => {
+// return await ipcRenderer.invoke("reset_password", username, toPw);
+// },
+// });
diff --git a/packages/server/src/SettingConfig.schema.json b/packages/server/src/SettingConfig.schema.json
new file mode 100644
index 0000000..c4c7d48
--- /dev/null
+++ b/packages/server/src/SettingConfig.schema.json
@@ -0,0 +1,51 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$ref": "#/definitions/SettingConfig",
+ "definitions": {
+ "SettingConfig": {
+ "type": "object",
+ "properties": {
+ "localmode": {
+ "type": "boolean",
+ "description": "if true, server will bind on '127.0.0.1' rather than '0.0.0.0'"
+ },
+ "guest": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Permission"
+ },
+ "description": "guest permission"
+ },
+ "jwt_secretkey": {
+ "type": "string",
+ "description": "JWT secret key. if you change its value, all access tokens are invalidated."
+ },
+ "port": {
+ "type": "number",
+ "description": "the port which running server is binding on."
+ },
+ "mode": {
+ "type": "string",
+ "enum": ["development", "production"]
+ },
+ "cli": {
+ "type": "boolean",
+ "description": "if true, do not show 'electron' window and show terminal only."
+ },
+ "forbid_remote_admin_login": {
+ "type": "boolean",
+ "description": "forbid to login admin from remote client. but, it do not invalidate access token. \r if you want to invalidate access token, change 'jwt_secretkey'."
+ },
+ "$schema": {
+ "type": "string"
+ }
+ },
+ "required": ["localmode", "guest", "jwt_secretkey", "port", "mode", "cli", "forbid_remote_admin_login"],
+ "additionalProperties": false
+ },
+ "Permission": {
+ "type": "string",
+ "enum": ["ModifyTag", "QueryContent", "ModifyTagDesc"]
+ }
+ }
+}
diff --git a/packages/server/src/SettingConfig.ts b/packages/server/src/SettingConfig.ts
new file mode 100644
index 0000000..a59944e
--- /dev/null
+++ b/packages/server/src/SettingConfig.ts
@@ -0,0 +1,80 @@
+import { randomBytes } from "node:crypto";
+import { existsSync, readFileSync, writeFileSync } from "node:fs";
+import type { Permission } from "./permission/permission";
+
+export interface SettingConfig {
+ /**
+ * if true, server will bind on '127.0.0.1' rather than '0.0.0.0'
+ */
+ localmode: boolean;
+ /**
+ * secure only
+ */
+ secure: boolean;
+
+ /**
+ * guest permission
+ */
+ guest: Permission[];
+ /**
+ * JWT secret key. if you change its value, all access tokens are invalidated.
+ */
+ jwt_secretkey: string;
+ /**
+ * the port which running server is binding on.
+ */
+ port: number;
+
+ mode: "development" | "production";
+ /**
+ * if true, do not show 'electron' window and show terminal only.
+ */
+ cli: boolean;
+ /** forbid to login admin from remote client. but, it do not invalidate access token.
+ * if you want to invalidate access token, change 'jwt_secretkey'. */
+ forbid_remote_admin_login: boolean;
+}
+const default_setting: SettingConfig = {
+ localmode: true,
+ secure: true,
+ guest: [],
+ jwt_secretkey: "itsRandom",
+ port: 8080,
+ mode: "production",
+ cli: false,
+ forbid_remote_admin_login: true,
+};
+let setting: null | SettingConfig = null;
+
+// biome-ignore lint/suspicious/noExplicitAny:
+const setEmptyToDefault = (target: any, default_table: SettingConfig) => {
+ let diff_occur = false;
+ for (const key in default_table) {
+ if (key === undefined || key in target) {
+ continue;
+ }
+ target[key] = default_table[key as keyof SettingConfig];
+ diff_occur = true;
+ }
+ return diff_occur;
+};
+
+export const read_setting_from_file = () => {
+ const ret = existsSync("settings.json") ? JSON.parse(readFileSync("settings.json", { encoding: "utf8" })) : {};
+ const partial_occur = setEmptyToDefault(ret, default_setting);
+ if (partial_occur) {
+ writeFileSync("settings.json", JSON.stringify(ret));
+ }
+ return ret as SettingConfig;
+};
+export function get_setting(): SettingConfig {
+ if (setting === null) {
+ setting = read_setting_from_file();
+ const env = process.env.NODE_ENV;
+ if (env !== undefined && env !== "production" && env !== "development") {
+ throw new Error('process unknown value in NODE_ENV: must be either "development" or "production"');
+ }
+ setting.mode = env ?? setting.mode;
+ }
+ return setting;
+}
diff --git a/packages/server/src/config.ts b/packages/server/src/config.ts
new file mode 100644
index 0000000..6807e05
--- /dev/null
+++ b/packages/server/src/config.ts
@@ -0,0 +1,22 @@
+import type { Knex as k } from "knex";
+
+export namespace Knex {
+ export const config: {
+ development: k.Config;
+ production: k.Config;
+ } = {
+ development: {
+ client: "sqlite3",
+ connection: {
+ filename: "./devdb.sqlite3",
+ },
+ debug: true,
+ },
+ production: {
+ client: "sqlite3",
+ connection: {
+ filename: "./db.sqlite3",
+ },
+ },
+ };
+}
diff --git a/packages/server/src/content/comic.ts b/packages/server/src/content/comic.ts
new file mode 100644
index 0000000..f42338e
--- /dev/null
+++ b/packages/server/src/content/comic.ts
@@ -0,0 +1,70 @@
+import { extname } from "node:path";
+import type { DocumentBody } from "dbtype/api";
+import { readZip } from "../util/zipwrap";
+import { type ContentConstructOption, createDefaultClass, registerContentReferrer } from "./file";
+import { TextWriter } from "@zip.js/zip.js";
+
+type ComicType = "doujinshi" | "artist cg" | "manga" | "western";
+interface ComicDesc {
+ title: string;
+ artist?: string[];
+ group?: string[];
+ series?: string[];
+ type: ComicType | [ComicType];
+ character?: string[];
+ tags?: string[];
+}
+const ImageExt = [".gif", ".png", ".jpeg", ".bmp", ".webp", ".jpg"];
+export class ComicReferrer extends createDefaultClass("comic") {
+ desc: ComicDesc | undefined;
+ pagenum: number;
+ additional: ContentConstructOption | undefined;
+ constructor(path: string, option?: ContentConstructOption) {
+ super(path);
+ this.additional = option;
+ this.pagenum = 0;
+ }
+ async initDesc(): Promise {
+ if (this.desc !== undefined) return;
+ const zip = await readZip(this.path);
+ const entries = await zip.reader.getEntries();
+ this.pagenum = entries.filter((x) => ImageExt.includes(extname(x.filename))).length;
+ const descEntry = entries.find(x=> x.filename === "desc.json");
+ if (descEntry === undefined) {
+ return;
+ }
+ if (descEntry.getData === undefined) {
+ throw new Error("entry.getData is undefined");
+ }
+ const textWriter = new TextWriter();
+ const data = (await descEntry.getData(textWriter));
+ this.desc = JSON.parse(data);
+ zip.reader.close()
+ .then(() => zip.handle.close());
+ }
+
+ async createDocumentBody(): Promise {
+ await this.initDesc();
+ const basebody = await super.createDocumentBody();
+ this.desc?.title;
+ if (this.desc === undefined) {
+ return basebody;
+ }
+ let tags: string[] = this.desc.tags ?? [];
+ tags = tags.concat(this.desc.artist?.map((x) => `artist:${x}`) ?? []);
+ tags = tags.concat(this.desc.character?.map((x) => `character:${x}`) ?? []);
+ tags = tags.concat(this.desc.group?.map((x) => `group:${x}`) ?? []);
+ tags = tags.concat(this.desc.series?.map((x) => `series:${x}`) ?? []);
+ const type = Array.isArray(this.desc.type) ? this.desc.type[0] : this.desc.type;
+ tags.push(`type:${type}`);
+ return {
+ ...basebody,
+ title: this.desc.title,
+ additional: {
+ page: this.pagenum,
+ },
+ tags: tags,
+ };
+ }
+}
+registerContentReferrer(ComicReferrer);
diff --git a/packages/server/src/content/file.ts b/packages/server/src/content/file.ts
new file mode 100644
index 0000000..21f4397
--- /dev/null
+++ b/packages/server/src/content/file.ts
@@ -0,0 +1,98 @@
+import { createHash } from "node:crypto";
+import { promises, type Stats } from "node:fs";
+import path, { extname } from "node:path";
+import type { DocumentBody } from "dbtype/api";
+/**
+ * content file or directory referrer
+ */
+export interface ContentFile {
+ getHash(): Promise;
+ createDocumentBody(): Promise;
+ readonly path: string;
+ readonly type: string;
+}
+export type ContentConstructOption = {
+ hash: string;
+};
+type ContentFileConstructor = (new (
+ path: string,
+ option?: ContentConstructOption,
+) => ContentFile) & {
+ content_type: string;
+};
+export const createDefaultClass = (type: string): ContentFileConstructor => {
+ const cons = class implements ContentFile {
+ readonly path: string;
+ // type = type;
+ static content_type = type;
+ protected hash: string | undefined;
+ protected stat: Stats | undefined;
+
+ protected getStat(){
+ return this.stat;
+ }
+
+ constructor(path: string, option?: ContentConstructOption) {
+ this.path = path;
+ this.hash = option?.hash;
+ this.stat = undefined;
+ }
+ async createDocumentBody(): Promise {
+ console.log(`createDocumentBody: ${this.path}`);
+ const { base, dir, name } = path.parse(this.path);
+
+ const ret = {
+ title: name,
+ basepath: dir,
+ additional: {},
+ content_type: cons.content_type,
+ filename: base,
+ tags: [],
+ content_hash: await this.getHash(),
+ modified_at: await this.getMtime(),
+ } as DocumentBody;
+ return ret;
+ }
+ get type(): string {
+ return cons.content_type;
+ }
+ async getHash(): Promise {
+ if (this.hash !== undefined) return this.hash;
+ this.stat = await promises.stat(this.path);
+ const hash = createHash("sha512");
+ hash.update(extname(this.path));
+ hash.update(this.stat.mode.toString());
+ // if(this.desc !== undefined)
+ // hash.update(JSON.stringify(this.desc));
+ hash.update(this.stat.size.toString());
+ this.hash = hash.digest("base64");
+ return this.hash;
+ }
+ async getMtime(): Promise {
+ const oldStat = this.getStat();
+ if (oldStat !== undefined) return oldStat.mtimeMs;
+ await this.getHash();
+ const newStat = this.getStat();
+ if (newStat === undefined) throw new Error("stat is undefined");
+ return newStat.mtimeMs;
+ }
+ };
+ return cons;
+};
+const ContstructorTable: { [k: string]: ContentFileConstructor } = {};
+export function registerContentReferrer(s: ContentFileConstructor) {
+ console.log(`registered content type: ${s.content_type}`);
+ ContstructorTable[s.content_type] = s;
+}
+export function createContentFile(type: string, path: string, option?: ContentConstructOption) {
+ const constructorMethod = ContstructorTable[type];
+ if (constructorMethod === undefined) {
+ console.log(`${type} are not in ${JSON.stringify(ContstructorTable)}`);
+ throw new Error("construction method of the content type is undefined");
+ }
+ return new constructorMethod(path, option);
+}
+export function getContentFileConstructor(type: string): ContentFileConstructor | undefined {
+ const ret = ContstructorTable[type];
+ return ret;
+}
diff --git a/src/content/mod.ts b/packages/server/src/content/mod.ts
similarity index 100%
rename from src/content/mod.ts
rename to packages/server/src/content/mod.ts
diff --git a/packages/server/src/content/video.ts b/packages/server/src/content/video.ts
new file mode 100644
index 0000000..c26cfd5
--- /dev/null
+++ b/packages/server/src/content/video.ts
@@ -0,0 +1,6 @@
+import { registerContentReferrer } from "./file";
+import { createDefaultClass } from "./file";
+
+export class VideoReferrer extends createDefaultClass("video") {
+}
+registerContentReferrer(VideoReferrer);
diff --git a/packages/server/src/database.ts b/packages/server/src/database.ts
new file mode 100644
index 0000000..997fe9f
--- /dev/null
+++ b/packages/server/src/database.ts
@@ -0,0 +1,26 @@
+import { existsSync } from "node:fs";
+import { get_setting } from "./SettingConfig";
+import { getKysely } from "./db/kysely";
+
+export async function connectDB() {
+ const kysely = getKysely();
+
+ let tries = 0;
+ for (;;) {
+ try {
+ console.log("try to connect db");
+ await kysely.selectNoFrom(eb=> eb.val(1).as("dummy")).execute();
+ console.log("connect success");
+ } catch (err) {
+ if (tries < 3) {
+ tries++;
+ console.error(`connection fail ${err} retry...`);
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ continue;
+ }
+ throw err;
+ }
+ break;
+ }
+ return kysely;
+}
diff --git a/packages/server/src/db/doc.ts b/packages/server/src/db/doc.ts
new file mode 100644
index 0000000..0afa8d2
--- /dev/null
+++ b/packages/server/src/db/doc.ts
@@ -0,0 +1,234 @@
+import { getKysely } from "./kysely";
+import { jsonArrayFrom } from "kysely/helpers/sqlite";
+import type { DocumentAccessor } from "../model/doc";
+import type {
+ Document,
+ QueryListOption,
+ DocumentBody
+} from "dbtype/api";
+import type { NotNull } from "kysely";
+import { MyParseJSONResultsPlugin } from "./plugin";
+
+export type DBTagContentRelation = {
+ doc_id: number;
+ tag_name: string;
+};
+
+class SqliteDocumentAccessor implements DocumentAccessor {
+ constructor(private kysely = getKysely()) {
+ }
+ async search(search_word: string): Promise {
+ throw new Error("Method not implemented.");
+ }
+ async addList(content_list: DocumentBody[]): Promise {
+ return await this.kysely.transaction().execute(async (trx) => {
+ // add tags
+ const tagCollected = new Set();
+ for (const content of content_list) {
+ for (const tag of content.tags) {
+ tagCollected.add(tag);
+ }
+ }
+ await trx.insertInto("tags")
+ .values(Array.from(tagCollected).map((x) => ({ name: x })))
+ .onConflict((oc) => oc.doNothing())
+ .execute();
+
+ const ids = await trx.insertInto("document")
+ .values(content_list.map((content) => {
+ const { tags, additional, ...rest } = content;
+ return {
+ additional: JSON.stringify(additional),
+ created_at: Date.now(),
+ ...rest,
+ };
+ }))
+ .returning("id")
+ .execute();
+ const id_lst = ids.map((x) => x.id);
+
+ const doc_tags = content_list.flatMap((content, index) => {
+ const { tags, ...rest } = content;
+ return tags.map((tag) => ({ doc_id: id_lst[index], tag_name: tag }));
+ });
+ await trx.insertInto("doc_tag_relation")
+ .values(doc_tags)
+ .execute();
+ return id_lst;
+ });
+ }
+ async add(c: DocumentBody) {
+ return await this.kysely.transaction().execute(async (trx) => {
+ const { tags, additional, ...rest } = c;
+ const id_lst = await trx.insertInto("document").values({
+ additional: JSON.stringify(additional),
+ created_at: Date.now(),
+ ...rest,
+ })
+ .returning("id")
+ .executeTakeFirst() as { id: number };
+ const id = id_lst.id;
+
+ // add tags
+ await trx.insertInto("tags")
+ .values(tags.map((x) => ({ name: x })))
+ // on conflict is supported in sqlite and postgresql.
+ .onConflict((oc) => oc.doNothing())
+ .execute();
+
+ if (tags.length > 0) {
+ await trx.insertInto("doc_tag_relation")
+ .values(tags.map((x) => ({ doc_id: id, tag_name: x })))
+ .execute();
+ }
+ return id;
+ });
+ }
+ async del(id: number) {
+ // delete tags
+ await this.kysely
+ .deleteFrom("doc_tag_relation")
+ .where("doc_id", "=", id)
+ .execute();
+ // delete document
+ const result = await this.kysely
+ .deleteFrom("document")
+ .where("id", "=", id)
+ .executeTakeFirst();
+ return result.numDeletedRows > 0;
+ }
+ async findById(id: number, tagload?: boolean): Promise {
+ const doc = await this.kysely.selectFrom("document")
+ .selectAll()
+ .where("id", "=", id)
+ .$if(tagload ?? false, (qb) =>
+ qb.select(eb => jsonArrayFrom(
+ eb.selectFrom("doc_tag_relation")
+ .select(["doc_tag_relation.tag_name"])
+ .whereRef("document.id", "=", "doc_tag_relation.doc_id")
+ .select("tag_name")
+ ).as("tags")).withPlugin(new MyParseJSONResultsPlugin("tags"))
+ )
+ .executeTakeFirst();
+ if (!doc) return undefined;
+
+ return {
+ ...doc,
+ content_hash: doc.content_hash ?? "",
+ additional: doc.additional !== null ? JSON.parse(doc.additional) : {},
+ tags: doc.tags?.map((x: { tag_name: string }) => x.tag_name) ?? [],
+ };
+ }
+ async findDeleted(content_type: string) {
+ const docs = await this.kysely
+ .selectFrom("document")
+ .selectAll()
+ .where("content_type", "=", content_type)
+ .where("deleted_at", "is not", null)
+ .$narrowType<{ deleted_at: NotNull }>()
+ .execute();
+ return docs.map((x) => ({
+ ...x,
+ tags: [],
+ content_hash: x.content_hash ?? "",
+ additional: {},
+ }));
+ }
+ async findList(option?: QueryListOption) {
+ const {
+ allow_tag = [],
+ eager_loading = true,
+ limit = 20,
+ use_offset = false,
+ offset = 0,
+ word,
+ content_type,
+ cursor,
+ } = option ?? {};
+
+ const result = await this.kysely
+ .selectFrom("document")
+ .selectAll()
+ .$if(allow_tag.length > 0, (qb) => {
+ return allow_tag.reduce((prevQb, tag, index) => {
+ return prevQb.innerJoin(`doc_tag_relation as tags_${index}`, `tags_${index}.doc_id`, "document.id")
+ .where(`tags_${index}.tag_name`, "=", tag);
+ }, qb) as unknown as typeof qb;
+ })
+ .$if(word !== undefined, (qb) => qb.where("title", "like", `%${word}%`))
+ .$if(content_type !== undefined, (qb) => qb.where("content_type", "=", content_type as string))
+ .$if(use_offset, (qb) => qb.offset(offset))
+ .$if(!use_offset && cursor !== undefined, (qb) => qb.where("id", "<", cursor as number))
+ .limit(limit)
+ .$if(eager_loading, (qb) => {
+ return qb.select(eb =>
+ eb.selectFrom(e =>
+ e.selectFrom("doc_tag_relation")
+ .select(["doc_tag_relation.tag_name"])
+ .whereRef("document.id", "=", "doc_tag_relation.doc_id")
+ .as("agg")
+ ).select(e => e.fn.agg("json_group_array", ["agg.tag_name"])
+ .as("tags_list")
+ ).as("tags")
+ )
+ })
+ .orderBy("id", "desc")
+ .execute();
+ return result.map((x) => ({
+ ...x,
+ content_hash: x.content_hash ?? "",
+ additional: x.additional !== null ? (JSON.parse(x.additional)) : {},
+ tags: JSON.parse(x.tags ?? "[]"), //?.map((x: { tag_name: string }) => x.tag_name) ?? [],
+ }));
+ }
+ async findByPath(path: string, filename?: string): Promise {
+ const results = await this.kysely
+ .selectFrom("document")
+ .selectAll()
+ .where("basepath", "=", path)
+ .$if(filename !== undefined, (qb) => qb.where("filename", "=", filename as string))
+ .execute();
+ return results.map((x) => ({
+ ...x,
+ content_hash: x.content_hash ?? "",
+ tags: [],
+ additional: {},
+ }));
+ }
+ async update(c: Partial & { id: number }) {
+ const { id, tags, additional, ...rest } = c;
+ const r = await this.kysely.updateTable("document")
+ .set({
+ ...rest,
+ modified_at: Date.now(),
+ additional: additional !== undefined ? JSON.stringify(additional) : undefined,
+ })
+ .where("id", "=", id)
+ .executeTakeFirst();
+ return r.numUpdatedRows > 0;
+ }
+ async addTag(c: Document, tag_name: string) {
+ if (c.tags.includes(tag_name)) return false;
+ await this.kysely.insertInto("tags")
+ .values({ name: tag_name })
+ .onConflict((oc) => oc.doNothing())
+ .execute();
+ await this.kysely.insertInto("doc_tag_relation")
+ .values({ tag_name: tag_name, doc_id: c.id })
+ .execute();
+ c.tags.push(tag_name);
+ return true;
+ }
+ async delTag(c: Document, tag_name: string) {
+ if (c.tags.includes(tag_name)) return false;
+ await this.kysely.deleteFrom("doc_tag_relation")
+ .where("tag_name", "=", tag_name)
+ .where("doc_id", "=", c.id)
+ .execute();
+ c.tags.splice(c.tags.indexOf(tag_name), 1);
+ return true;
+ }
+}
+export const createSqliteDocumentAccessor = (kysely = getKysely()): DocumentAccessor => {
+ return new SqliteDocumentAccessor(kysely);
+};
diff --git a/packages/server/src/db/kysely.ts b/packages/server/src/db/kysely.ts
new file mode 100644
index 0000000..31e1ba2
--- /dev/null
+++ b/packages/server/src/db/kysely.ts
@@ -0,0 +1,26 @@
+import { Kysely, ParseJSONResultsPlugin, SqliteDialect } from "kysely";
+import SqliteDatabase from "better-sqlite3";
+import type { DB } from "dbtype/types";
+
+export function createSqliteDialect() {
+ const url = process.env.DATABASE_URL;
+ if (!url) {
+ throw new Error("DATABASE_URL is not set");
+ }
+ const db = new SqliteDatabase(url);
+ return new SqliteDialect({
+ database: db,
+ });
+}
+
+// Create a new Kysely instance with a new SqliteDatabase instance
+let kysely: Kysely | null = null;
+export function getKysely() {
+ if (!kysely) {
+ kysely = new Kysely({
+ dialect: createSqliteDialect(),
+ // plugins: [new ParseJSONResultsPlugin()],
+ });
+ }
+ return kysely;
+}
\ No newline at end of file
diff --git a/src/db/mod.ts b/packages/server/src/db/mod.ts
similarity index 100%
rename from src/db/mod.ts
rename to packages/server/src/db/mod.ts
diff --git a/packages/server/src/db/plugin.ts b/packages/server/src/db/plugin.ts
new file mode 100644
index 0000000..5574973
--- /dev/null
+++ b/packages/server/src/db/plugin.ts
@@ -0,0 +1,24 @@
+import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode, UnknownRow } from "kysely";
+
+export class MyParseJSONResultsPlugin implements KyselyPlugin {
+
+ constructor(private readonly itemPath: string) { }
+
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode {
+ // do nothing
+ return args.node;
+ }
+ async transformResult(args: PluginTransformResultArgs): Promise> {
+ return {
+ ...args.result,
+ rows: args.result.rows.map((row) => {
+ const newRow = { ...row };
+ const item = newRow[this.itemPath];
+ if (typeof item === "string") {
+ newRow[this.itemPath] = JSON.parse(item);
+ }
+ return newRow;
+ })
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/server/src/db/tag.ts b/packages/server/src/db/tag.ts
new file mode 100644
index 0000000..35ff2cf
--- /dev/null
+++ b/packages/server/src/db/tag.ts
@@ -0,0 +1,65 @@
+import { getKysely } from "./kysely";
+import { jsonArrayFrom } from "kysely/helpers/sqlite";
+import type { Tag, TagAccessor, TagCount } from "../model/tag";
+import type { DBTagContentRelation } from "./doc";
+
+class SqliteTagAccessor implements TagAccessor {
+
+ constructor(private kysely = getKysely()) {
+ }
+ async getAllTagCount(): Promise {
+ const result = await this.kysely
+ .selectFrom("doc_tag_relation")
+ .select("tag_name")
+ .select(qb => qb.fn.count("doc_id").as("occurs"))
+ .groupBy("tag_name")
+ .execute();
+ return result;
+ }
+ async getAllTagList(): Promise {
+ return (await this.kysely.selectFrom("tags")
+ .selectAll()
+ .execute()
+ ).map((x) => ({
+ name: x.name,
+ description: x.description ?? undefined,
+ }));
+ }
+ async getTagByName(name: string) {
+ const result = await this.kysely
+ .selectFrom("tags")
+ .selectAll()
+ .where("name", "=", name)
+ .executeTakeFirst();
+ if (result === undefined) {
+ return undefined;
+ }
+ return {
+ name: result.name,
+ description: result.description ?? undefined,
+ };
+ }
+ async addTag(tag: Tag) {
+ const result = await this.kysely.insertInto("tags")
+ .values([tag])
+ .onConflict((oc) => oc.doNothing())
+ .executeTakeFirst();
+ return (result.numInsertedOrUpdatedRows ?? 0n) > 0;
+ }
+ async delTag(name: string) {
+ const result = await this.kysely.deleteFrom("tags")
+ .where("name", "=", name)
+ .executeTakeFirst();
+ return (result.numDeletedRows ?? 0n) > 0;
+ }
+ async updateTag(name: string, desc: string) {
+ const result = await this.kysely.updateTable("tags")
+ .set({ description: desc })
+ .where("name", "=", name)
+ .executeTakeFirst();
+ return (result.numUpdatedRows ?? 0n) > 0;
+ }
+}
+export const createSqliteTagController = (kysely = getKysely()): TagAccessor => {
+ return new SqliteTagAccessor(kysely);
+};
diff --git a/packages/server/src/db/user.ts b/packages/server/src/db/user.ts
new file mode 100644
index 0000000..ba2c899
--- /dev/null
+++ b/packages/server/src/db/user.ts
@@ -0,0 +1,87 @@
+import { getKysely } from "./kysely";
+import { type IUser, Password, type UserAccessor, type UserCreateInput } from "../model/user";
+
+class SqliteUser implements IUser {
+ readonly username: string;
+ readonly password: Password;
+
+ constructor(username: string, pw: Password, private kysely = getKysely()) {
+ this.username = username;
+ this.password = pw;
+ }
+ async reset_password(password: string) {
+ this.password.set_password(password);
+ await this.kysely
+ .updateTable("users")
+ .where("username", "=", this.username)
+ .set({ password_hash: this.password.hash, password_salt: this.password.salt })
+ .execute();
+ }
+ async get_permissions() {
+ const permissions = await this.kysely
+ .selectFrom("permissions")
+ .selectAll()
+ .where("username", "=", this.username)
+ .execute();
+ return permissions.map((x) => x.name);
+ }
+ async add(name: string) {
+ const result = await this.kysely
+ .insertInto("permissions")
+ .values({ username: this.username, name })
+ .onConflict((oc) => oc.doNothing())
+ .executeTakeFirst();
+ return (result.numInsertedOrUpdatedRows ?? 0n) > 0;
+ }
+ async remove(name: string) {
+ const result = await this.kysely
+ .deleteFrom("permissions")
+ .where("username", "=", this.username)
+ .where("name", "=", name)
+ .executeTakeFirst();
+ return (result.numDeletedRows ?? 0n) > 0;
+ }
+}
+
+export const createSqliteUserController = (kysely = getKysely()): UserAccessor => {
+ const createUser = async (input: UserCreateInput) => {
+ if (undefined !== (await findUser(input.username))) {
+ return undefined;
+ }
+ const user = new SqliteUser(input.username, new Password(input.password), kysely);
+ await kysely
+ .insertInto("users")
+ .values({ username: user.username, password_hash: user.password.hash, password_salt: user.password.salt })
+ .execute();
+ return user;
+ };
+ const findUser = async (id: string) => {
+ const user = await kysely
+ .selectFrom("users")
+ .selectAll()
+ .where("username", "=", id)
+ .executeTakeFirst();
+ if (!user) return undefined;
+ if (!user.password_hash || !user.password_salt) {
+ throw new Error("password hash or salt is missing");
+ }
+ if (user.username === null) {
+ throw new Error("username is null");
+ }
+ return new SqliteUser(user.username, new Password({
+ hash: user.password_hash,
+ salt: user.password_salt
+ }), kysely);
+ };
+ const delUser = async (id: string) => {
+ const result = await kysely.deleteFrom("users")
+ .where("username", "=", id)
+ .executeTakeFirst();
+ return (result.numDeletedRows ?? 0n) > 0;
+ };
+ return {
+ createUser: createUser,
+ findUser: findUser,
+ delUser: delUser,
+ };
+};
diff --git a/packages/server/src/diff/content_handler.ts b/packages/server/src/diff/content_handler.ts
new file mode 100644
index 0000000..d0e0cc6
--- /dev/null
+++ b/packages/server/src/diff/content_handler.ts
@@ -0,0 +1,121 @@
+import { basename, dirname, join as pathjoin } from "node:path";
+import { ContentFile, createContentFile } from "../content/mod";
+import type { Document, DocumentAccessor } from "../model/mod";
+import { ContentList } from "./content_list";
+import type { IDiffWatcher } from "./watcher";
+
+// refactoring needed.
+export class ContentDiffHandler {
+ /** content file list waiting to add */
+ waiting_list: ContentList;
+ /** deleted contents */
+ tombstone: Map; // hash, contentfile
+ doc_cntr: DocumentAccessor;
+ /** content type of handle */
+ content_type: string;
+ constructor(cntr: DocumentAccessor, content_type: string) {
+ this.waiting_list = new ContentList();
+ this.tombstone = new Map();
+ this.doc_cntr = cntr;
+ this.content_type = content_type;
+ }
+ async setup() {
+ const deleted = await this.doc_cntr.findDeleted(this.content_type);
+ for (const it of deleted) {
+ this.tombstone.set(it.content_hash, it);
+ }
+ }
+ register(diff: IDiffWatcher) {
+ diff
+ .on("create", (path) => this.OnCreated(path))
+ .on("delete", (path) => this.OnDeleted(path))
+ .on("change", (prev, cur) => this.OnChanged(prev, cur));
+ }
+ private async OnDeleted(cpath: string) {
+ const basepath = dirname(cpath);
+ const filename = basename(cpath);
+ console.log("deleted ", cpath);
+ // if it wait to add, delete it from waiting list.
+ if (this.waiting_list.hasByPath(cpath)) {
+ this.waiting_list.deleteByPath(cpath);
+ return;
+ }
+ const dbc = await this.doc_cntr.findByPath(basepath, filename);
+ // when there is no related content in db, ignore.
+ if (dbc.length === 0) {
+ console.log("its not in waiting_list and db!!!: ", cpath);
+ return;
+ }
+ const content_hash = dbc[0].content_hash;
+ // When a path is changed, it takes into account when the
+ // creation event occurs first and the deletion occurs, not
+ // the change event.
+ const cf = this.waiting_list.getByHash(content_hash);
+ if (cf) {
+ // if a path is changed, update the changed path.
+ console.log("update path from", cpath, "to", cf.path);
+ const newFilename = basename(cf.path);
+ const newBasepath = dirname(cf.path);
+ this.waiting_list.deleteByHash(content_hash);
+ await this.doc_cntr.update({
+ id: dbc[0].id,
+ deleted_at: null,
+ filename: newFilename,
+ basepath: newBasepath,
+ });
+ return;
+ }
+ // invalidate db and add it to tombstone.
+ await this.doc_cntr.update({
+ id: dbc[0].id,
+ deleted_at: Date.now(),
+ });
+ this.tombstone.set(dbc[0].content_hash, dbc[0]);
+ }
+ private async OnCreated(cpath: string) {
+ const basepath = dirname(cpath);
+ const filename = basename(cpath);
+ console.log("createContentFile", cpath);
+ const content = createContentFile(this.content_type, cpath);
+ const hash = await content.getHash();
+ const c = this.tombstone.get(hash);
+ if (c !== undefined) {
+ await this.doc_cntr.update({
+ id: c.id,
+ deleted_at: null,
+ filename: filename,
+ basepath: basepath,
+ });
+ }
+ if (this.waiting_list.hasByHash(hash)) {
+ console.log("Hash Conflict!!!");
+ }
+ this.waiting_list.set(content);
+ }
+ private async OnChanged(prev_path: string, cur_path: string) {
+ const prev_basepath = dirname(prev_path);
+ const prev_filename = basename(prev_path);
+ const cur_basepath = dirname(cur_path);
+ const cur_filename = basename(cur_path);
+ console.log("modify", cur_path, "from", prev_path);
+ const c = this.waiting_list.getByPath(prev_path);
+ if (c !== undefined) {
+ await this.waiting_list.delete(c);
+ const content = createContentFile(this.content_type, cur_path);
+ await this.waiting_list.set(content);
+ return;
+ }
+ const doc = await this.doc_cntr.findByPath(prev_basepath, prev_filename);
+
+ if (doc.length === 0) {
+ await this.OnCreated(cur_path);
+ return;
+ }
+
+ await this.doc_cntr.update({
+ ...doc[0],
+ basepath: cur_basepath,
+ filename: cur_filename,
+ });
+ }
+}
diff --git a/packages/server/src/diff/content_list.ts b/packages/server/src/diff/content_list.ts
new file mode 100644
index 0000000..9e3f7f8
--- /dev/null
+++ b/packages/server/src/diff/content_list.ts
@@ -0,0 +1,59 @@
+import type { ContentFile } from "../content/mod";
+
+export class ContentList {
+ /** path map */
+ private cl: Map;
+ /** hash map */
+ private hl: Map;
+
+ constructor() {
+ this.cl = new Map();
+ this.hl = new Map();
+ }
+ hasByHash(s: string) {
+ return this.hl.has(s);
+ }
+ hasByPath(p: string) {
+ return this.cl.has(p);
+ }
+ getByHash(s: string) {
+ return this.hl.get(s);
+ }
+ getByPath(p: string) {
+ return this.cl.get(p);
+ }
+ async set(c: ContentFile) {
+ const path = c.path;
+ const hash = await c.getHash();
+ this.cl.set(path, c);
+ this.hl.set(hash, c);
+ }
+ /** delete content file */
+ async delete(c: ContentFile) {
+ const hash = await c.getHash();
+ let r = true;
+ r = this.cl.delete(c.path) && r;
+ r = this.hl.delete(hash) && r;
+ return r;
+ }
+ async deleteByPath(p: string) {
+ const o = this.getByPath(p);
+ if (o === undefined) return false;
+ return await this.delete(o);
+ }
+ deleteByHash(s: string) {
+ const o = this.getByHash(s);
+ if (o === undefined) return false;
+ let r = true;
+ r = this.cl.delete(o.path) && r;
+ r = this.hl.delete(s) && r;
+ return r;
+ }
+ clear() {
+ this.cl.clear();
+ this.hl.clear();
+ }
+ getAll() {
+ return [...this.cl.values()];
+ }
+}
diff --git a/packages/server/src/diff/diff.ts b/packages/server/src/diff/diff.ts
new file mode 100644
index 0000000..3f69f50
--- /dev/null
+++ b/packages/server/src/diff/diff.ts
@@ -0,0 +1,46 @@
+import asyncPool from "tiny-async-pool";
+import type { DocumentAccessor } from "../model/doc";
+import { ContentDiffHandler } from "./content_handler";
+import type { IDiffWatcher } from "./watcher";
+
+export class DiffManager {
+ watching: { [content_type: string]: ContentDiffHandler };
+ doc_cntr: DocumentAccessor;
+ constructor(contorller: DocumentAccessor) {
+ this.watching = {};
+ this.doc_cntr = contorller;
+ }
+ async register(content_type: string, watcher: IDiffWatcher) {
+ if (this.watching[content_type] === undefined) {
+ this.watching[content_type] = new ContentDiffHandler(this.doc_cntr, content_type);
+ }
+ this.watching[content_type].register(watcher);
+ await watcher.setup(this.doc_cntr);
+ }
+ async commit(type: string, path: string) {
+ const list = this.watching[type].waiting_list;
+ const c = list.getByPath(path);
+ if (c === undefined) {
+ throw new Error("path is not exist");
+ }
+ await list.delete(c);
+ console.log(`commit: ${c.path} ${c.type}`);
+ const body = await c.createDocumentBody();
+ const id = await this.doc_cntr.add(body);
+ return id;
+ }
+ async commitAll(type: string) {
+ const list = this.watching[type].waiting_list;
+ const contentFiles = list.getAll();
+ list.clear();
+ const bodies = await asyncPool(30, contentFiles, async (x) => await x.createDocumentBody());
+ const ids = await this.doc_cntr.addList(bodies);
+ return ids;
+ }
+ getAdded() {
+ return Object.keys(this.watching).map((x) => ({
+ type: x,
+ value: this.watching[x].waiting_list.getAll(),
+ }));
+ }
+}
diff --git a/src/diff/mod.ts b/packages/server/src/diff/mod.ts
similarity index 100%
rename from src/diff/mod.ts
rename to packages/server/src/diff/mod.ts
diff --git a/packages/server/src/diff/router.ts b/packages/server/src/diff/router.ts
new file mode 100644
index 0000000..41ab912
--- /dev/null
+++ b/packages/server/src/diff/router.ts
@@ -0,0 +1,85 @@
+import type Koa from "koa";
+import Router from "koa-router";
+import type { ContentFile } from "../content/mod";
+import { AdminOnlyMiddleware } from "../permission/permission";
+import { sendError } from "../route/error_handler";
+import type { DiffManager } from "./diff";
+
+function content_file_to_return(x: ContentFile) {
+ return { path: x.path, type: x.type };
+}
+
+export const getAdded = (diffmgr: DiffManager) => (ctx: Koa.Context, next: Koa.Next) => {
+ const ret = diffmgr.getAdded();
+ ctx.body = ret.map((x) => ({
+ type: x.type,
+ value: x.value.map((x) => ({ path: x.path, type: x.type })),
+ }));
+ ctx.type = "json";
+};
+
+type PostAddedBody = {
+ type: string;
+ path: string;
+}[];
+
+function checkPostAddedBody(body: unknown): body is PostAddedBody {
+ if (Array.isArray(body)) {
+ return body.map((x) => "type" in x && "path" in x).every((x) => x);
+ }
+ return false;
+}
+
+export const postAdded = (diffmgr: DiffManager) => async (ctx: Router.IRouterContext, next: Koa.Next) => {
+ const reqbody = ctx.request.body;
+ if (!checkPostAddedBody(reqbody)) {
+ sendError(400, "format exception");
+ return;
+ }
+ const allWork = reqbody.map((op) => diffmgr.commit(op.type, op.path));
+ const results = await Promise.all(allWork);
+ ctx.body = {
+ ok: true,
+ docs: results,
+ };
+ ctx.type = "json";
+ await next();
+};
+export const postAddedAll = (diffmgr: DiffManager) => async (ctx: Router.IRouterContext, next: Koa.Next) => {
+ if (!ctx.is("json")) {
+ sendError(400, "format exception");
+ return;
+ }
+ const reqbody = ctx.request.body as Record;
+ if (!("type" in reqbody)) {
+ sendError(400, 'format exception: there is no "type"');
+ return;
+ }
+ const t = reqbody.type;
+ if (typeof t !== "string") {
+ sendError(400, 'format exception: invalid type of "type"');
+ return;
+ }
+ await diffmgr.commitAll(t);
+ ctx.body = {
+ ok: true,
+ };
+ ctx.type = "json";
+ await next();
+};
+/*
+export const getNotWatched = (diffmgr : DiffManager)=> (ctx:Router.IRouterContext,next:Koa.Next)=>{
+ ctx.body = {
+ added: diffmgr.added.map(content_file_to_return),
+ deleted: diffmgr.deleted.map(content_file_to_return),
+ };
+ ctx.type = 'json';
+}*/
+
+export function createDiffRouter(diffmgr: DiffManager) {
+ const ret = new Router();
+ ret.get("/list", AdminOnlyMiddleware, getAdded(diffmgr));
+ ret.post("/commit", AdminOnlyMiddleware, postAdded(diffmgr));
+ ret.post("/commitall", AdminOnlyMiddleware, postAddedAll(diffmgr));
+ return ret;
+}
diff --git a/packages/server/src/diff/watcher.ts b/packages/server/src/diff/watcher.ts
new file mode 100644
index 0000000..70b01c8
--- /dev/null
+++ b/packages/server/src/diff/watcher.ts
@@ -0,0 +1,25 @@
+import type event from "node:events";
+import { FSWatcher, watch } from "node:fs";
+import { promises } from "node:fs";
+import { join } from "node:path";
+import type { DocumentAccessor } from "../model/doc";
+
+const readdir = promises.readdir;
+
+export interface DiffWatcherEvent {
+ create: (path: string) => void;
+ delete: (path: string) => void;
+ change: (prev_path: string, cur_path: string) => void;
+}
+
+export interface IDiffWatcher extends event.EventEmitter {
+ on(event: U, listener: DiffWatcherEvent[U]): this;
+ emit(event: U, ...arg: Parameters): boolean;
+ setup(cntr: DocumentAccessor): Promise;
+}
+
+export function linkWatcher(fromWatcher: IDiffWatcher, toWatcher: IDiffWatcher) {
+ fromWatcher.on("create", (p) => toWatcher.emit("create", p));
+ fromWatcher.on("delete", (p) => toWatcher.emit("delete", p));
+ fromWatcher.on("change", (p, c) => toWatcher.emit("change", p, c));
+}
diff --git a/packages/server/src/diff/watcher/ComicConfig.schema.json b/packages/server/src/diff/watcher/ComicConfig.schema.json
new file mode 100644
index 0000000..bd7b2ec
--- /dev/null
+++ b/packages/server/src/diff/watcher/ComicConfig.schema.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$ref": "#/definitions/ComicConfig",
+ "definitions": {
+ "ComicConfig": {
+ "type": "object",
+ "properties": { "watch": { "type": "array", "items": { "type": "string" } }, "$schema": { "type": "string" } },
+ "required": ["watch"],
+ "additionalProperties": false
+ }
+ }
+}
diff --git a/src/diff/watcher/ComicConfig.ts b/packages/server/src/diff/watcher/ComicConfig.ts
similarity index 92%
rename from src/diff/watcher/ComicConfig.ts
rename to packages/server/src/diff/watcher/ComicConfig.ts
index 0ff864c..3cc93ea 100644
--- a/src/diff/watcher/ComicConfig.ts
+++ b/packages/server/src/diff/watcher/ComicConfig.ts
@@ -1,7 +1,7 @@
import { ConfigManager } from "../../util/configRW";
import ComicSchema from "./ComicConfig.schema.json";
export interface ComicConfig {
- watch: string[];
+ watch: string[];
}
export const ComicConfig = new ConfigManager("comic_config.json", { watch: [] }, ComicSchema);
diff --git a/packages/server/src/diff/watcher/comic_watcher.ts b/packages/server/src/diff/watcher/comic_watcher.ts
new file mode 100644
index 0000000..96f5273
--- /dev/null
+++ b/packages/server/src/diff/watcher/comic_watcher.ts
@@ -0,0 +1,13 @@
+import { ComicConfig } from "./ComicConfig";
+import { WatcherCompositer } from "./compositer";
+import { RecursiveWatcher } from "./recursive_watcher";
+import { WatcherFilter } from "./watcher_filter";
+
+const createComicWatcherBase = (path: string) => {
+ return new WatcherFilter(new RecursiveWatcher(path), (x) => x.endsWith(".zip"));
+};
+export const createComicWatcher = () => {
+ const file = ComicConfig.get_config_file();
+ console.log(`register comic ${file.watch.join(",")}`);
+ return new WatcherCompositer(file.watch.map((path) => createComicWatcherBase(path)));
+};
diff --git a/packages/server/src/diff/watcher/common_watcher.ts b/packages/server/src/diff/watcher/common_watcher.ts
new file mode 100644
index 0000000..2782660
--- /dev/null
+++ b/packages/server/src/diff/watcher/common_watcher.ts
@@ -0,0 +1,44 @@
+import event from "node:events";
+import { type FSWatcher, promises, watch } from "node:fs";
+import { join } from "node:path";
+import type { DocumentAccessor } from "../../model/doc";
+import type { DiffWatcherEvent, IDiffWatcher } from "../watcher";
+import { setupHelp } from "./util";
+
+const { readdir } = promises;
+
+export class CommonDiffWatcher extends event.EventEmitter implements IDiffWatcher {
+ on(event: U, listener: DiffWatcherEvent[U]): this {
+ return super.on(event, listener);
+ }
+ emit(event: U, ...arg: Parameters): boolean {
+ return super.emit(event, ...arg);
+ }
+ private _path: string;
+ private _watcher: FSWatcher;
+
+ constructor(path: string) {
+ super();
+ this._path = path;
+ this._watcher = watch(this._path, { persistent: true, recursive: false }, async (eventType, filename) => {
+ if (eventType === "rename") {
+ const cur = await readdir(this._path);
+ // add
+ if (cur.includes(filename)) {
+ this.emit("create", join(this.path, filename));
+ } else {
+ this.emit("delete", join(this.path, filename));
+ }
+ }
+ });
+ }
+ async setup(cntr: DocumentAccessor): Promise {
+ await setupHelp(this, this.path, cntr);
+ }
+ public get path() {
+ return this._path;
+ }
+ watchClose() {
+ this._watcher.close();
+ }
+}
diff --git a/packages/server/src/diff/watcher/compositer.ts b/packages/server/src/diff/watcher/compositer.ts
new file mode 100644
index 0000000..b356f58
--- /dev/null
+++ b/packages/server/src/diff/watcher/compositer.ts
@@ -0,0 +1,23 @@
+import { EventEmitter } from "node:events";
+import type { DocumentAccessor } from "../../model/doc";
+import { type DiffWatcherEvent, type IDiffWatcher, linkWatcher } from "../watcher";
+
+export class WatcherCompositer extends EventEmitter implements IDiffWatcher {
+ refWatchers: IDiffWatcher[];
+ on(event: U, listener: DiffWatcherEvent[U]): this {
+ return super.on(event, listener);
+ }
+ emit(event: U, ...arg: Parameters): boolean {
+ return super.emit(event, ...arg);
+ }
+ constructor(refWatchers: IDiffWatcher[]) {
+ super();
+ this.refWatchers = refWatchers;
+ for (const refWatcher of this.refWatchers) {
+ linkWatcher(refWatcher, this);
+ }
+ }
+ async setup(cntr: DocumentAccessor): Promise {
+ await Promise.all(this.refWatchers.map((x) => x.setup(cntr)));
+ }
+}
diff --git a/packages/server/src/diff/watcher/recursive_watcher.ts b/packages/server/src/diff/watcher/recursive_watcher.ts
new file mode 100644
index 0000000..14fe70d
--- /dev/null
+++ b/packages/server/src/diff/watcher/recursive_watcher.ts
@@ -0,0 +1,67 @@
+import { type FSWatcher, watch } from "chokidar";
+import { EventEmitter } from "node:events";
+import type { DocumentAccessor } from "../../model/doc";
+import type { DiffWatcherEvent, IDiffWatcher } from "../watcher";
+import { setupRecursive } from "./util";
+
+type RecursiveWatcherOption = {
+ /** @default true */
+ watchFile?: boolean;
+ /** @default false */
+ watchDir?: boolean;
+};
+
+export class RecursiveWatcher extends EventEmitter implements IDiffWatcher {
+ on(event: U, listener: DiffWatcherEvent[U]): this {
+ return super.on(event, listener);
+ }
+ emit(event: U, ...arg: Parameters): boolean {
+ return super.emit(event, ...arg);
+ }
+ readonly path: string;
+ private watcher: FSWatcher;
+
+ constructor(
+ path: string,
+ option: RecursiveWatcherOption = {
+ watchDir: false,
+ watchFile: true,
+ },
+ ) {
+ super();
+ this.path = path;
+ this.watcher = watch(path, {
+ persistent: true,
+ ignoreInitial: true,
+ depth: 100,
+ });
+ option.watchFile ??= true;
+ if (option.watchFile) {
+ this.watcher
+ .on("add", (path) => {
+ const cpath = path;
+ // console.log("add ", cpath);
+ this.emit("create", cpath);
+ })
+ .on("unlink", (path) => {
+ const cpath = path;
+ // console.log("unlink ", cpath);
+ this.emit("delete", cpath);
+ });
+ }
+ if (option.watchDir) {
+ this.watcher
+ .on("addDir", (path) => {
+ const cpath = path;
+ this.emit("create", cpath);
+ })
+ .on("unlinkDir", (path) => {
+ const cpath = path;
+ this.emit("delete", cpath);
+ });
+ }
+ }
+ async setup(cntr: DocumentAccessor): Promise {
+ await setupRecursive(this, this.path, cntr);
+ }
+}
diff --git a/packages/server/src/diff/watcher/util.ts b/packages/server/src/diff/watcher/util.ts
new file mode 100644
index 0000000..7e136f0
--- /dev/null
+++ b/packages/server/src/diff/watcher/util.ts
@@ -0,0 +1,37 @@
+import { promises } from "node:fs";
+import { join } from "node:path";
+const { readdir } = promises;
+import type { DocumentAccessor } from "../../model/doc";
+import type { IDiffWatcher } from "../watcher";
+
+function setupCommon(watcher: IDiffWatcher, basepath: string, initial_filenames: string[], cur: string[]) {
+ // Todo : reduce O(nm) to O(n+m) using hash map.
+ const added = cur.filter((x) => !initial_filenames.includes(x));
+ const deleted = initial_filenames.filter((x) => !cur.includes(x));
+ for (const it of added) {
+ const cpath = join(basepath, it);
+ watcher.emit("create", cpath);
+ }
+ for (const it of deleted) {
+ const cpath = join(basepath, it);
+ watcher.emit("delete", cpath);
+ }
+}
+export async function setupHelp(watcher: IDiffWatcher, basepath: string, cntr: DocumentAccessor) {
+ const initial_document = await cntr.findByPath(basepath);
+ const initial_filenames = initial_document.map((x) => x.filename);
+ const cur = await readdir(basepath);
+ setupCommon(watcher, basepath, initial_filenames, cur);
+}
+export async function setupRecursive(watcher: IDiffWatcher, basepath: string, cntr: DocumentAccessor) {
+ const initial_document = await cntr.findByPath(basepath);
+ const initial_filenames = initial_document.map((x) => x.filename);
+ const cur = await readdir(basepath, { withFileTypes: true });
+ setupCommon(
+ watcher,
+ basepath,
+ initial_filenames,
+ cur.map((x) => x.name),
+ );
+ await Promise.all([cur.filter((x) => x.isDirectory()).map((x) => setupHelp(watcher, join(basepath, x.name), cntr))]);
+}
diff --git a/packages/server/src/diff/watcher/watcher_filter.ts b/packages/server/src/diff/watcher/watcher_filter.ts
new file mode 100644
index 0000000..67d0fca
--- /dev/null
+++ b/packages/server/src/diff/watcher/watcher_filter.ts
@@ -0,0 +1,44 @@
+import { EventEmitter } from "node:events";
+import type { DocumentAccessor } from "../../model/doc";
+import { type DiffWatcherEvent, type IDiffWatcher, linkWatcher } from "../watcher";
+
+export class WatcherFilter extends EventEmitter implements IDiffWatcher {
+ refWatcher: IDiffWatcher;
+ filter: (filename: string) => boolean;
+ on(event: U, listener: DiffWatcherEvent[U]): this {
+ return super.on(event, listener);
+ }
+ /**
+ * emit event
+ * @param event
+ * @param arg
+ * @returns `true` if the event had listeners, `false` otherwise.
+ */
+ emit(event: U, ...arg: Parameters): boolean {
+ if (event === "change") {
+ const prev = arg[0];
+ const cur = arg[1] as string;
+ if (this.filter(prev)) {
+ if (this.filter(cur)) {
+ return super.emit("change", prev, cur);
+ }
+ return super.emit("delete", cur);
+ }
+ if (this.filter(cur)) {
+ return super.emit("create", cur);
+ }
+ return false;
+ }if (!this.filter(arg[0])) {
+ return false;
+ }return super.emit(event, ...arg);
+ }
+ constructor(refWatcher: IDiffWatcher, filter: (filename: string) => boolean) {
+ super();
+ this.refWatcher = refWatcher;
+ this.filter = filter;
+ linkWatcher(refWatcher, this);
+ }
+ setup(cntr: DocumentAccessor): Promise {
+ return this.refWatcher.setup(cntr);
+ }
+}
diff --git a/packages/server/src/login.ts b/packages/server/src/login.ts
new file mode 100644
index 0000000..1046d6f
--- /dev/null
+++ b/packages/server/src/login.ts
@@ -0,0 +1,240 @@
+import { sign, TokenExpiredError, verify } from "jsonwebtoken";
+import type Koa from "koa";
+import Router from "koa-router";
+import type { IUser, UserAccessor } from "./model/mod";
+import { sendError } from "./route/error_handler";
+import { get_setting } from "./SettingConfig";
+
+type PayloadInfo = {
+ username: string;
+ permission: string[];
+};
+
+export type UserState = {
+ user: PayloadInfo;
+};
+
+const isUserState = (obj: object | string): obj is PayloadInfo => {
+ if (typeof obj === "string") return false;
+ return "username" in obj && "permission" in obj && Array.isArray((obj as { permission: unknown }).permission);
+};
+type RefreshPayloadInfo = { username: string };
+const isRefreshToken = (obj: object | string): obj is RefreshPayloadInfo => {
+ if (typeof obj === "string") return false;
+ return "username" in obj && typeof (obj as { username: unknown }).username === "string";
+};
+
+export const accessTokenName = "access_token";
+export const refreshTokenName = "refresh_token";
+const accessExpiredTime = 60 * 60; // 1 hour
+const refreshExpiredTime = 60 * 60 * 24 * 14; // 14 day;
+
+export const getAdminAccessTokenValue = () => {
+ const { jwt_secretkey } = get_setting();
+ return publishAccessToken(jwt_secretkey, "admin", [], accessExpiredTime);
+};
+export const getAdminRefreshTokenValue = () => {
+ const { jwt_secretkey } = get_setting();
+ return publishRefreshToken(jwt_secretkey, "admin", refreshExpiredTime);
+};
+const publishAccessToken = (secretKey: string, username: string, permission: string[], expiredtime: number) => {
+ const payload = sign(
+ {
+ username: username,
+ permission: permission,
+ },
+ secretKey,
+ { expiresIn: expiredtime },
+ );
+ return payload;
+};
+const publishRefreshToken = (secretKey: string, username: string, expiredtime: number) => {
+ const payload = sign({ username: username }, secretKey, { expiresIn: expiredtime });
+ return payload;
+};
+function setToken(ctx: Koa.Context, token_name: string, token_payload: string | null, expiredtime: number) {
+ const setting = get_setting();
+ if (token_payload === null && !ctx.cookies.get(token_name)) {
+ return;
+ }
+ ctx.cookies.set(token_name, token_payload, {
+ httpOnly: true,
+ secure: setting.secure,
+ sameSite: "strict",
+ expires: new Date(Date.now() + expiredtime * 1000),
+ });
+}
+export const createLoginMiddleware = (userController: UserAccessor) => async (ctx: Koa.Context, _next: Koa.Next) => {
+ const setting = get_setting();
+ const secretKey = setting.jwt_secretkey;
+ const body = ctx.request.body;
+ // check format
+ if (typeof body === "string" || !("username" in body) || !("password" in body)) {
+ return sendError(400, "invalid form : username or password is not found in query.");
+ }
+ const username = body.username;
+ const password = body.password;
+ // check type
+ if (typeof username !== "string" || typeof password !== "string") {
+ return sendError(400, "invalid form : username or password is not string");
+ }
+ // if admin login is forbidden?
+ if (username === "admin" && setting.forbid_remote_admin_login) {
+ return sendError(403, "forbidden remote admin login");
+ }
+ const user = await userController.findUser(username);
+ // username not exist
+ if (user === undefined) return sendError(401, "not authorized");
+ // password not matched
+ if (!user.password.check_password(password)) {
+ return sendError(401, "not authorized");
+ }
+ // create token
+ const userPermission = await user.get_permissions();
+ const payload = publishAccessToken(secretKey, user.username, userPermission, accessExpiredTime);
+ const payload2 = publishRefreshToken(secretKey, user.username, refreshExpiredTime);
+ setToken(ctx, accessTokenName, payload, accessExpiredTime);
+ setToken(ctx, refreshTokenName, payload2, refreshExpiredTime);
+ ctx.body = {
+ username: user.username,
+ permission: userPermission,
+ accessExpired: Math.floor(Date.now() / 1000) + accessExpiredTime,
+ };
+ console.log(`${username} logined`);
+ return;
+};
+
+export const LogoutMiddleware = (ctx: Koa.Context, next: Koa.Next) => {
+ const setting = get_setting();
+ ctx.cookies.set(accessTokenName, null);
+ ctx.cookies.set(refreshTokenName, null);
+ ctx.body = {
+ ok: true,
+ username: "",
+ permission: setting.guest,
+ };
+ return;
+};
+export const createUserMiddleWare =
+ (userController: UserAccessor) => async (ctx: Koa.ParameterizedContext, next: Koa.Next) => {
+ const refreshToken = refreshTokenHandler(userController);
+ const setting = get_setting();
+ const setGuest = async () => {
+ setToken(ctx, accessTokenName, null, 0);
+ setToken(ctx, refreshTokenName, null, 0);
+ ctx.state.user = { username: "", permission: setting.guest };
+ return await next();
+ };
+ return await refreshToken(ctx, setGuest, next);
+ };
+const refreshTokenHandler = (cntr: UserAccessor) => async (ctx: Koa.Context, fail: Koa.Next, next: Koa.Next) => {
+ const accessPayload = ctx.cookies.get(accessTokenName);
+ const setting = get_setting();
+ const secretKey = setting.jwt_secretkey;
+ if (accessPayload === undefined) {
+ return await checkRefreshAndUpdate();
+ }
+ try {
+ const o = verify(accessPayload, secretKey);
+ if (isUserState(o)) {
+ ctx.state.user = o;
+ return await next();
+ }
+ console.error("invalid token detected");
+ throw new Error("token form invalid");
+ } catch (e) {
+ if (e instanceof TokenExpiredError) {
+ return await checkRefreshAndUpdate();
+ }throw e;
+ }
+ async function checkRefreshAndUpdate() {
+ const refreshPayload = ctx.cookies.get(refreshTokenName);
+ if (refreshPayload === undefined) {
+ return await fail(); // refresh token doesn't exist
+ }
+ try {
+ const o = verify(refreshPayload, secretKey);
+ if (isRefreshToken(o)) {
+ const user = await cntr.findUser(o.username);
+ if (user === undefined) return await fail(); // already non-existence user
+ const perm = await user.get_permissions();
+ const payload = publishAccessToken(secretKey, user.username, perm, accessExpiredTime);
+ setToken(ctx, accessTokenName, payload, accessExpiredTime);
+ ctx.state.user = { username: o.username, permission: perm };
+ } else {
+ console.error("invalid token detected");
+ throw new Error("token form invalid");
+ }
+ } catch (e) {
+ if (e instanceof TokenExpiredError) {
+ // refresh token is expired.
+ return await fail();
+ }throw e;
+ }
+ return await next();
+ }
+};
+export const createRefreshTokenMiddleware = (cntr: UserAccessor) => async (ctx: Koa.Context, next: Koa.Next) => {
+ const handler = refreshTokenHandler(cntr);
+ await handler(ctx, fail, success);
+ async function fail() {
+ const user = ctx.state.user as PayloadInfo;
+ ctx.body = {
+ refresh: false,
+ ...user,
+ };
+ ctx.type = "json";
+ }
+ async function success() {
+ const user = ctx.state.user as PayloadInfo;
+ ctx.body = {
+ ...user,
+ refresh: true,
+ refreshExpired: Math.floor(Date.now() / 1000 + accessExpiredTime),
+ };
+ ctx.type = "json";
+ }
+};
+export const resetPasswordMiddleware = (cntr: UserAccessor) => async (ctx: Koa.Context, next: Koa.Next) => {
+ const body = ctx.request.body;
+ if (typeof body !== "object" || !("username" in body) || !("oldpassword" in body) || !("newpassword" in body)) {
+ return sendError(400, "request body is invalid format");
+ }
+ const username = body.username;
+ const oldpw = body.oldpassword;
+ const newpw = body.newpassword;
+ if (typeof username !== "string" || typeof oldpw !== "string" || typeof newpw !== "string") {
+ return sendError(400, "request body is invalid format");
+ }
+ const user = await cntr.findUser(username);
+ if (user === undefined) {
+ return sendError(403, "not authorized");
+ }
+ if (!user.password.check_password(oldpw)) {
+ return sendError(403, "not authorized");
+ }
+ user.reset_password(newpw);
+ ctx.body = { ok: true };
+ ctx.type = "json";
+};
+
+export function createLoginRouter(userController: UserAccessor) {
+ const router = new Router();
+ router.post("/login", createLoginMiddleware(userController));
+ router.post("/logout", LogoutMiddleware);
+ router.post("/refresh", createRefreshTokenMiddleware(userController));
+ router.post("/reset", resetPasswordMiddleware(userController));
+ return router;
+}
+
+export const getAdmin = async (cntr: UserAccessor) => {
+ const admin = await cntr.findUser("admin");
+ if (admin === undefined) {
+ throw new Error("initial process failed!"); // ???
+ }
+ return admin;
+};
+
+export const isAdminFirst = (admin: IUser) => {
+ return admin.password.hash === "unchecked" && admin.password.salt === "unchecked";
+};
diff --git a/packages/server/src/model/doc.ts b/packages/server/src/model/doc.ts
new file mode 100644
index 0000000..dab7cb0
--- /dev/null
+++ b/packages/server/src/model/doc.ts
@@ -0,0 +1,81 @@
+import { check_type } from "../util/type_check";
+import type {
+ DocumentBody,
+ Document,
+ QueryListOption
+} from "dbtype/api";
+
+export const MetaContentBody = {
+ title: "string",
+ content_type: "string",
+ basepath: "string",
+ filename: "string",
+ content_hash: "string",
+ additional: "object",
+ tags: "string[]",
+};
+
+export const isDocBody = (c: unknown): c is DocumentBody => {
+ return check_type(c, MetaContentBody);
+};
+
+export const isDoc = (c: unknown): c is Document => {
+ if (typeof c !== "object" || c === null) return false;
+ if ("id" in c && typeof c.id === "number") {
+ const { id, ...rest } = c;
+ return isDocBody(rest);
+ }
+ return false;
+};
+
+export interface DocumentAccessor {
+ /**
+ * find list by option
+ * @returns documents list
+ */
+ findList: (option?: QueryListOption) => Promise;
+ /**
+ * @returns document if exist, otherwise undefined
+ */
+ findById: (id: number, tagload?: boolean) => Promise;
+ /**
+ * find by base path and filename.
+ * if you call this function with filename, its return array length is 0 or 1.
+ */
+ findByPath: (basepath: string, filename?: string) => Promise;
+ /**
+ * find deleted content
+ */
+ findDeleted: (content_type: string) => Promise;
+ /**
+ * search by in document
+ */
+ search: (search_word: string) => Promise;
+ /**
+ * update document except tag.
+ */
+ update: (c: Partial & { id: number }) => Promise;
+ /**
+ * add document
+ */
+ add: (c: DocumentBody) => Promise;
+ /**
+ * add document list
+ */
+ addList: (content_list: DocumentBody[]) => Promise;
+ /**
+ * delete document
+ * @returns if it exists, return true.
+ */
+ del: (id: number) => Promise;
+ /**
+ * @param c Valid Document
+ * @param tagname tag name to add
+ * @returns if success, return true
+ */
+ addTag: (c: Document, tag_name: string) => Promise;
+ /**
+ * @returns if success, return true
+ */
+ delTag: (c: Document, tag_name: string) => Promise;
+}
diff --git a/src/model/mod.ts b/packages/server/src/model/mod.ts
similarity index 100%
rename from src/model/mod.ts
rename to packages/server/src/model/mod.ts
diff --git a/packages/server/src/model/tag.ts b/packages/server/src/model/tag.ts
new file mode 100644
index 0000000..ab3f985
--- /dev/null
+++ b/packages/server/src/model/tag.ts
@@ -0,0 +1,18 @@
+export interface Tag {
+ readonly name: string;
+ description?: string;
+}
+
+export interface TagCount {
+ tag_name: string;
+ occurs: number;
+}
+
+export interface TagAccessor {
+ getAllTagList: () => Promise;
+ getAllTagCount(): Promise;
+ getTagByName: (name: string) => Promise;
+ addTag: (tag: Tag) => Promise;
+ delTag: (name: string) => Promise;
+ updateTag: (name: string, tag: string) => Promise;
+}
diff --git a/packages/server/src/model/user.ts b/packages/server/src/model/user.ts
new file mode 100644
index 0000000..f4b8005
--- /dev/null
+++ b/packages/server/src/model/user.ts
@@ -0,0 +1,84 @@
+import { createHmac, randomBytes } from "node:crypto";
+
+function hashForPassword(salt: string, password: string) {
+ return createHmac("sha256", salt).update(password).digest("hex");
+}
+function createPasswordHashAndSalt(password: string): { salt: string; hash: string } {
+ const secret = randomBytes(32).toString("hex");
+ return {
+ salt: secret,
+ hash: hashForPassword(secret, password),
+ };
+}
+
+export class Password {
+ private _salt: string;
+ private _hash: string;
+ constructor(pw: string | { salt: string; hash: string }) {
+ const { salt, hash } = typeof pw === "string" ? createPasswordHashAndSalt(pw) : pw;
+ this._hash = hash;
+ this._salt = salt;
+ }
+ set_password(password: string) {
+ const { salt, hash } = createPasswordHashAndSalt(password);
+ this._hash = hash;
+ this._salt = salt;
+ }
+ check_password(password: string): boolean {
+ return this._hash === hashForPassword(this._salt, password);
+ }
+ get salt() {
+ return this._salt;
+ }
+ get hash() {
+ return this._hash;
+ }
+}
+
+export interface UserCreateInput {
+ username: string;
+ password: string;
+}
+
+export interface IUser {
+ readonly username: string;
+ readonly password: Password;
+ /**
+ * return user's permission list.
+ */
+ get_permissions(): Promise;
+ /**
+ * add permission
+ * @param name permission name to add
+ * @returns if `name` doesn't exist, return true
+ */
+ add(name: string): Promise;
+ /**
+ * remove permission
+ * @param name permission name to remove
+ * @returns if `name` exist, return true
+ */
+ remove(name: string): Promise;
+ /**
+ * reset password.
+ * @param password password to set
+ */
+ reset_password(password: string): Promise;
+}
+
+export interface UserAccessor {
+ /**
+ * create user
+ * @returns if user exist, return undefined
+ */
+ createUser: (input: UserCreateInput) => Promise;
+ /**
+ * find user
+ */
+ findUser: (username: string) => Promise;
+ /**
+ * remove user
+ * @returns if user exist, true
+ */
+ delUser: (username: string) => Promise;
+}
diff --git a/packages/server/src/permission/permission.ts b/packages/server/src/permission/permission.ts
new file mode 100644
index 0000000..8229316
--- /dev/null
+++ b/packages/server/src/permission/permission.ts
@@ -0,0 +1,59 @@
+import type Koa from "koa";
+import type { UserState } from "../login";
+import { sendError } from "../route/error_handler";
+
+export enum Permission {
+ // ========
+ // not implemented
+ // admin only
+ /** remove document */
+ // removeContent = 'removeContent',
+
+ /** upload document */
+ // uploadContent = 'uploadContent',
+
+ /** modify document except base path, filename, content_hash. but admin can modify all. */
+ // modifyContent = 'modifyContent',
+
+ /** add tag into document */
+ // addTagContent = 'addTagContent',
+ /** remove tag from document */
+ // removeTagContent = 'removeTagContent',
+ /** ModifyTagInDoc */
+ ModifyTag = "ModifyTag",
+
+ /** find documents with query */
+ // findAllContent = 'findAllContent',
+ /** find one document. */
+ // findOneContent = 'findOneContent',
+ /** view content*/
+ // viewContent = 'viewContent',
+ QueryContent = "QueryContent",
+
+ /** modify description about the one tag. */
+ modifyTagDesc = "ModifyTagDesc",
+}
+
+export const createPermissionCheckMiddleware =
+ (...permissions: string[]) =>
+ async (ctx: Koa.ParameterizedContext, next: Koa.Next) => {
+ const user = ctx.state.user;
+ if (user.username === "admin") {
+ return await next();
+ }
+ const user_permission = user.permission;
+ // if permissions is not subset of user permission
+ if (!permissions.map((p) => user_permission.includes(p)).every((x) => x)) {
+ if (user.username === "") {
+ return sendError(401, "you are guest. login needed.");
+ }return sendError(403, "do not have permission");
+ }
+ await next();
+ };
+export const AdminOnlyMiddleware = async (ctx: Koa.ParameterizedContext, next: Koa.Next) => {
+ const user = ctx.state.user;
+ if (user.username !== "admin") {
+ return sendError(403, "admin only");
+ }
+ await next();
+};
diff --git a/packages/server/src/route/all.ts b/packages/server/src/route/all.ts
new file mode 100644
index 0000000..49724ef
--- /dev/null
+++ b/packages/server/src/route/all.ts
@@ -0,0 +1,58 @@
+import type { DefaultContext, Middleware, Next, ParameterizedContext } from "koa";
+import compose from "koa-compose";
+import Router from "koa-router";
+import ComicRouter from "./comic";
+import type { ContentContext } from "./context";
+import VideoRouter from "./video";
+
+const table: { [s: string]: Router | undefined } = {
+ comic: new ComicRouter(),
+ video: new VideoRouter(),
+};
+const all_middleware =
+ (cont: string | undefined, restarg: string | undefined) =>
+ async (ctx: ParameterizedContext, next: Next) => {
+ if (cont === undefined) {
+ ctx.status = 404;
+ return;
+ }
+ if (ctx.state.location.type !== cont) {
+ console.error("not matched");
+ ctx.status = 404;
+ return;
+ }
+ const router = table[cont];
+ if (router === undefined) {
+ ctx.status = 404;
+ return;
+ }
+ const rest = `/${restarg ?? ""}`;
+ const result = router.match(rest, "GET");
+ if (!result.route) {
+ return await next();
+ }
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const chain = result.pathAndMethod.reduce((combination: Middleware[], cur) => {
+ combination.push(async (ctx, next) => {
+ const captures = cur.captures(rest);
+ ctx.params = cur.params(rest, captures);
+ ctx.request.params = ctx.params;
+ ctx.routerPath = cur.path;
+ return await next();
+ });
+ return combination.concat(cur.stack);
+ }, []);
+ return await compose(chain)(ctx, next);
+ };
+export class AllContentRouter extends Router {
+ constructor() {
+ super();
+ this.get("/:content_type", async (ctx, next) => {
+ return await all_middleware(ctx.params.content_type, undefined)(ctx, next);
+ });
+ this.get("/:content_type/:rest(.*)", async (ctx, next) => {
+ const cont = ctx.params.content_type as string;
+ return await all_middleware(cont, ctx.params.rest)(ctx, next);
+ });
+ }
+}
diff --git a/packages/server/src/route/comic.ts b/packages/server/src/route/comic.ts
new file mode 100644
index 0000000..cc05aaf
--- /dev/null
+++ b/packages/server/src/route/comic.ts
@@ -0,0 +1,135 @@
+import type { Context } from "koa";
+import Router from "koa-router";
+import { createReadableStreamFromZip, entriesByNaturalOrder, readZip } from "../util/zipwrap";
+import type { ContentContext } from "./context";
+import { since_last_modified } from "./util";
+import type { ZipReader } from "@zip.js/zip.js";
+import type { FileHandle } from "node:fs/promises";
+import { Readable } from "node:stream";
+
+/**
+ * zip stream cache.
+ */
+const ZipStreamCache = new Map,
+ handle: FileHandle,
+ refCount: number,
+}>();
+
+
+function markUseZip(path: string) {
+ const ret = ZipStreamCache.get(path);
+ if (ret) {
+ ret.refCount++;
+ }
+ return ret !== undefined;
+}
+
+async function acquireZip(path: string, marked = false) {
+ const ret = ZipStreamCache.get(path);
+ if (!ret) {
+ const obj = await readZip(path);
+ const check = ZipStreamCache.get(path);
+ if (check) {
+ check.refCount++;
+ // if the cache is updated, release the previous one.
+ releaseZip(path);
+ return check.reader;
+ }
+ // if the cache is not updated, set the new one.
+ ZipStreamCache.set(path, {
+ reader: obj.reader,
+ handle: obj.handle,
+ refCount: 1,
+ });
+ return obj.reader;
+ }
+ if (!marked) {
+ ret.refCount++;
+ }
+ return ret.reader;
+}
+
+function releaseZip(path: string) {
+ const obj = ZipStreamCache.get(path);
+ if (obj === undefined) {
+ console.warn(`warning! duplicate release at ${path}`);
+ return;
+ }
+ if (obj.refCount === 1) {
+ const { reader, handle } = obj;
+ reader.close().then(() => {
+ handle.close();
+ });
+ ZipStreamCache.delete(path);
+ } else {
+ obj.refCount--;
+ }
+}
+
+async function renderZipImage(ctx: Context, path: string, page: number) {
+ const image_ext = ["gif", "png", "jpeg", "bmp", "webp", "jpg"];
+ const marked = markUseZip(path);
+ const zip = await acquireZip(path, marked);
+ const entries = (await entriesByNaturalOrder(zip)).filter((x) => {
+ const ext = x.filename.split(".").pop();
+ return ext !== undefined && image_ext.includes(ext);
+ });
+ if (0 <= page && page < entries.length) {
+ const entry = entries[page];
+ const last_modified = entry.lastModDate;
+ if (since_last_modified(ctx, last_modified)) {
+ return;
+ }
+ const read_stream = await createReadableStreamFromZip(zip, entry);
+ const nodeReadableStream = new Readable();
+ nodeReadableStream._read = () => { };
+
+ read_stream.pipeTo(new WritableStream({
+ write(chunk) {
+ nodeReadableStream.push(chunk);
+ },
+ close() {
+ nodeReadableStream.push(null);
+ },
+ }));
+ nodeReadableStream.on("error", (err) => {
+ console.error("readalbe stream error",err);
+ setTimeout(()=>{
+ releaseZip(path)
+ },100);
+ });
+ nodeReadableStream.on("close", () => {
+ setTimeout(()=>{
+ releaseZip(path);
+ },100);
+ });
+
+ ctx.body = nodeReadableStream;
+ ctx.response.length = entry.uncompressedSize;
+ ctx.response.type = entry.filename.split(".").pop() as string;
+ ctx.status = 200;
+ ctx.set("Date", new Date().toUTCString());
+ ctx.set("Last-Modified", last_modified.toUTCString());
+ } else {
+ ctx.status = 404;
+ }
+}
+
+export class ComicRouter extends Router {
+ constructor() {
+ super();
+ this.get("/", async (ctx, next) => {
+ await renderZipImage(ctx, ctx.state.location.path, 0);
+ });
+ this.get("/:page(\\d+)", async (ctx, next) => {
+ const page = Number.parseInt(ctx.params.page);
+ await renderZipImage(ctx, ctx.state.location.path, page);
+ });
+ this.get("/thumbnail", async (ctx, next) => {
+ await renderZipImage(ctx, ctx.state.location.path, 0);
+ });
+ }
+}
+
+export default ComicRouter;
diff --git a/packages/server/src/route/contents.ts b/packages/server/src/route/contents.ts
new file mode 100644
index 0000000..9a2068f
--- /dev/null
+++ b/packages/server/src/route/contents.ts
@@ -0,0 +1,163 @@
+import type { Context, Next } from "koa";
+import Router from "koa-router";
+import { join } from "node:path";
+import type {
+ Document,
+ QueryListOption,
+} from "dbtype/api";
+import type { DocumentAccessor } from "../model/doc";
+import {
+ AdminOnlyMiddleware as AdminOnly,
+ createPermissionCheckMiddleware as PerCheck,
+ Permission as Per,
+} from "../permission/permission";
+import { AllContentRouter } from "./all";
+import type { ContentLocation } from "./context";
+import { sendError } from "./error_handler";
+import { ParseQueryArgString, ParseQueryArray, ParseQueryBoolean, ParseQueryNumber } from "./util";
+
+const ContentIDHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ const num = Number.parseInt(ctx.params.num);
+ const document = await controller.findById(num, true);
+ if (document === undefined) {
+ return sendError(404, "document does not exist.");
+ }
+ ctx.body = document;
+ ctx.type = "json";
+};
+const ContentTagIDHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ const num = Number.parseInt(ctx.params.num);
+ const document = await controller.findById(num, true);
+ if (document === undefined) {
+ return sendError(404, "document does not exist.");
+ }
+ ctx.body = document.tags;
+ ctx.type = "json";
+};
+const ContentQueryHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ const query_limit = ctx.query.limit;
+ const query_cursor = ctx.query.cursor;
+ const query_word = ctx.query.word;
+ const query_content_type = ctx.query.content_type;
+ const query_offset = ctx.query.offset;
+ const query_use_offset = ctx.query.use_offset;
+ if (Array.isArray(query_limit) ||Array.isArray(query_cursor) ||Array.isArray(query_word) ||Array.isArray(query_content_type) ||Array.isArray(query_offset) ||Array.isArray(query_use_offset)
+ ) {
+ return sendError(400, "paramter can not be array");
+ }
+ const limit = Math.min(ParseQueryNumber(query_limit) ?? 20, 100);
+ const cursor = ParseQueryNumber(query_cursor);
+ const word = ParseQueryArgString(query_word);
+ const content_type = ParseQueryArgString(query_content_type);
+ const offset = ParseQueryNumber(query_offset);
+ if (Number.isNaN(limit) || Number.isNaN(cursor) || Number.isNaN(offset)) {
+ return sendError(400, "parameter limit, cursor or offset is not a number");
+ }
+ const allow_tag = ParseQueryArray(ctx.query.allow_tag);
+ const [ok, use_offset] = ParseQueryBoolean(query_use_offset);
+ if (!ok) {
+ return sendError(400, "use_offset must be true or false.");
+ }
+ const option: QueryListOption = {
+ limit: limit,
+ allow_tag: allow_tag,
+ word: word,
+ cursor: cursor,
+ eager_loading: true,
+ offset: offset,
+ use_offset: use_offset,
+ content_type: content_type,
+ };
+ const document = await controller.findList(option);
+ ctx.body = document;
+ ctx.type = "json";
+};
+const UpdateContentHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ const num = Number.parseInt(ctx.params.num);
+
+ if (ctx.request.type !== "json") {
+ return sendError(400, "update fail. invalid document type: it is not json.");
+ }
+ if (typeof ctx.request.body !== "object") {
+ return sendError(400, "update fail. invalid argument: not");
+ }
+ const content_desc: Partial & { id: number } = {
+ id: num,
+ ...ctx.request.body,
+ };
+ const success = await controller.update(content_desc);
+ ctx.body = JSON.stringify(success);
+ ctx.type = "json";
+};
+
+const AddTagHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ let tag_name = ctx.params.tag;
+ const num = Number.parseInt(ctx.params.num);
+ if (typeof tag_name === "undefined") {
+ return sendError(400, "??? Unreachable");
+ }
+ tag_name = String(tag_name);
+ const c = await controller.findById(num);
+ if (c === undefined) {
+ return sendError(404);
+ }
+ const r = await controller.addTag(c, tag_name);
+ ctx.body = JSON.stringify(r);
+ ctx.type = "json";
+};
+const DelTagHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ let tag_name = ctx.params.tag;
+ const num = Number.parseInt(ctx.params.num);
+ if (typeof tag_name === "undefined") {
+ return sendError(400, "?? Unreachable");
+ }
+ tag_name = String(tag_name);
+ const c = await controller.findById(num);
+ if (c === undefined) {
+ return sendError(404);
+ }
+ const r = await controller.delTag(c, tag_name);
+ ctx.body = JSON.stringify(r);
+ ctx.type = "json";
+};
+const DeleteContentHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ const num = Number.parseInt(ctx.params.num);
+ const r = await controller.del(num);
+ ctx.body = JSON.stringify(r);
+ ctx.type = "json";
+};
+const ContentHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
+ const num = Number.parseInt(ctx.params.num);
+ const document = await controller.findById(num, true);
+ if (document === undefined) {
+ return sendError(404, "document does not exist.");
+ }
+ if (document.deleted_at !== null) {
+ return sendError(404, "document has been removed.");
+ }
+ const path = join(document.basepath, document.filename);
+ ctx.state.location = {
+ path: path,
+ type: document.content_type,
+ additional: document.additional,
+ } as ContentLocation;
+ await next();
+};
+
+export const getContentRouter = (controller: DocumentAccessor) => {
+ const ret = new Router();
+ ret.get("/search", PerCheck(Per.QueryContent), ContentQueryHandler(controller));
+ ret.get("/:num(\\d+)", PerCheck(Per.QueryContent), ContentIDHandler(controller));
+ ret.post("/:num(\\d+)", AdminOnly, UpdateContentHandler(controller));
+ // ret.use("/:num(\\d+)/:content_type");
+ // ret.post("/",AdminOnly,CreateContentHandler(controller));
+ ret.get("/:num(\\d+)/tags", PerCheck(Per.QueryContent), ContentTagIDHandler(controller));
+ ret.post("/:num(\\d+)/tags/:tag", PerCheck(Per.ModifyTag), AddTagHandler(controller));
+ ret.del("/:num(\\d+)/tags/:tag", PerCheck(Per.ModifyTag), DelTagHandler(controller));
+ ret.del("/:num(\\d+)", AdminOnly, DeleteContentHandler(controller));
+ ret.all("/:num(\\d+)/(.*)", PerCheck(Per.QueryContent), ContentHandler(controller));
+ ret.use("/:num(\\d+)", PerCheck(Per.QueryContent), new AllContentRouter().routes());
+ return ret;
+};
+
+export default getContentRouter;
diff --git a/packages/server/src/route/context.ts b/packages/server/src/route/context.ts
new file mode 100644
index 0000000..afd4874
--- /dev/null
+++ b/packages/server/src/route/context.ts
@@ -0,0 +1,8 @@
+export type ContentLocation = {
+ path: string;
+ type: string;
+ additional: object | undefined;
+};
+export interface ContentContext {
+ location: ContentLocation;
+}
diff --git a/packages/server/src/route/error_handler.ts b/packages/server/src/route/error_handler.ts
new file mode 100644
index 0000000..a329645
--- /dev/null
+++ b/packages/server/src/route/error_handler.ts
@@ -0,0 +1,49 @@
+import type { Context, Next } from "koa";
+
+export interface ErrorFormat {
+ code: number;
+ message: string;
+ detail?: string;
+}
+
+class ClientRequestError implements Error {
+ name: string;
+ message: string;
+ stack?: string | undefined;
+ code: number;
+
+ constructor(code: number, message: string) {
+ this.name = "client request error";
+ this.message = message;
+ this.code = code;
+ }
+}
+
+const code_to_message_table: { [key: number]: string | undefined } = {
+ 400: "BadRequest",
+ 404: "NotFound",
+};
+
+export const error_handler = async (ctx: Context, next: Next) => {
+ try {
+ await next();
+ } catch (err) {
+ if (err instanceof ClientRequestError) {
+ const body: ErrorFormat = {
+ code: err.code,
+ message: code_to_message_table[err.code] ?? "",
+ detail: err.message,
+ };
+ ctx.status = err.code;
+ ctx.body = body;
+ } else {
+ throw err;
+ }
+ }
+};
+
+export const sendError = (code: number, message?: string) => {
+ throw new ClientRequestError(code, message ?? "");
+};
+
+export default error_handler;
diff --git a/packages/server/src/route/tags.ts b/packages/server/src/route/tags.ts
new file mode 100644
index 0000000..da0f535
--- /dev/null
+++ b/packages/server/src/route/tags.ts
@@ -0,0 +1,29 @@
+import { type Context, Next } from "koa";
+import Router, { type RouterContext } from "koa-router";
+import type { TagAccessor } from "../model/tag";
+import { createPermissionCheckMiddleware as PerCheck, Permission } from "../permission/permission";
+import { sendError } from "./error_handler";
+
+export function getTagRounter(tagController: TagAccessor) {
+ const router = new Router();
+ router.get("/", PerCheck(Permission.QueryContent), async (ctx: Context) => {
+ if (ctx.query.withCount) {
+ const c = await tagController.getAllTagCount();
+ ctx.body = c;
+ } else {
+ const c = await tagController.getAllTagList();
+ ctx.body = c;
+ }
+ ctx.type = "json";
+ });
+ router.get("/:tag_name", PerCheck(Permission.QueryContent), async (ctx: RouterContext) => {
+ const tag_name = ctx.params.tag_name;
+ const c = await tagController.getTagByName(tag_name);
+ if (!c) {
+ sendError(404, "tags not found");
+ }
+ ctx.body = c;
+ ctx.type = "json";
+ });
+ return router;
+}
diff --git a/packages/server/src/route/util.ts b/packages/server/src/route/util.ts
new file mode 100644
index 0000000..bdc39f0
--- /dev/null
+++ b/packages/server/src/route/util.ts
@@ -0,0 +1,37 @@
+import type { Context } from "koa";
+
+export function ParseQueryNumber(s: string[] | string | undefined): number | undefined {
+ if (s === undefined) return undefined;
+ if (typeof s === "object") return undefined;
+ return Number.parseInt(s);
+}
+export function ParseQueryArray(s: string[] | string | undefined) {
+ const input = s ?? [];
+ const r = Array.isArray(input) ? input : [input];
+ return r.map((x) => decodeURIComponent(x));
+}
+export function ParseQueryArgString(s: string[] | string | undefined) {
+ if (typeof s === "object") return undefined;
+ return s === undefined ? s : decodeURIComponent(s);
+}
+export function ParseQueryBoolean(s: string[] | string | undefined): [boolean, boolean | undefined] {
+ let value: boolean | undefined;
+
+ if (s === "true") {
+ value = true;
+ } else if (s === "false") {
+ value = false;
+ } else if (s === undefined) {
+ value = undefined;
+ } else return [false, undefined];
+ return [true, value];
+}
+
+export function since_last_modified(ctx: Context, last_modified: Date): boolean {
+ const con = ctx.get("If-Modified-Since");
+ if (con === "") return false;
+ const mdate = new Date(con);
+ if (last_modified > mdate) return false;
+ ctx.status = 304;
+ return true;
+}
diff --git a/packages/server/src/route/video.ts b/packages/server/src/route/video.ts
new file mode 100644
index 0000000..198adc2
--- /dev/null
+++ b/packages/server/src/route/video.ts
@@ -0,0 +1,67 @@
+import { createReadStream, promises } from "node:fs";
+import type { Context } from "koa";
+import Router from "koa-router";
+import type { ContentContext } from "./context";
+
+export async function renderVideo(ctx: Context, path: string) {
+ const ext = path.trim().split(".").pop();
+ if (ext === undefined) {
+ // ctx.status = 404;
+ console.error(`${path}:${ext}`);
+ return;
+ }
+ ctx.response.type = ext;
+ const range_text = ctx.request.get("range");
+ const stat = await promises.stat(path);
+ let start = 0;
+ let end = 0;
+ ctx.set("Last-Modified", new Date(stat.mtime).toUTCString());
+ ctx.set("Date", new Date().toUTCString());
+ ctx.set("Accept-Ranges", "bytes");
+ if (range_text === "") {
+ end = 1024 * 512;
+ end = Math.min(end, stat.size - 1);
+ if (start > end) {
+ ctx.status = 416;
+ return;
+ }
+ ctx.status = 200;
+ ctx.length = stat.size;
+ const stream = createReadStream(path);
+ ctx.body = stream;
+ } else {
+ const m = range_text.match(/^bytes=(\d+)-(\d*)/);
+ if (m === null) {
+ ctx.status = 416;
+ return;
+ }
+ start = Number.parseInt(m[1]);
+ end = m[2].length > 0 ? Number.parseInt(m[2]) : start + 1024 * 1024;
+ end = Math.min(end, stat.size - 1);
+ if (start > end) {
+ ctx.status = 416;
+ return;
+ }
+ ctx.status = 206;
+ ctx.length = end - start + 1;
+ ctx.response.set("Content-Range", `bytes ${start}-${end}/${stat.size}`);
+ ctx.body = createReadStream(path, {
+ start: start,
+ end: end,
+ }); // inclusive range.
+ }
+}
+
+export class VideoRouter extends Router {
+ constructor() {
+ super();
+ this.get("/", async (ctx, next) => {
+ await renderVideo(ctx, ctx.state.location.path);
+ });
+ this.get("/thumbnail", async (ctx, next) => {
+ await renderVideo(ctx, ctx.state.location.path);
+ });
+ }
+}
+
+export default VideoRouter;
diff --git a/packages/server/src/search/indexer.ts b/packages/server/src/search/indexer.ts
new file mode 100644
index 0000000..3879b70
--- /dev/null
+++ b/packages/server/src/search/indexer.ts
@@ -0,0 +1,12 @@
+export interface PaginationOption {
+ cursor: number;
+ limit: number;
+}
+
+export interface IIndexer {
+ indexDoc(word: string, doc_id: number): boolean;
+ indexDoc(word: string[], doc_id: number): boolean;
+
+ getDoc(word: string, option?: PaginationOption): number[];
+ getDoc(word: string[], option?: PaginationOption): number[];
+}
diff --git a/packages/server/src/search/tokenizer.ts b/packages/server/src/search/tokenizer.ts
new file mode 100644
index 0000000..87d180e
--- /dev/null
+++ b/packages/server/src/search/tokenizer.ts
@@ -0,0 +1,9 @@
+export interface ITokenizer {
+ tokenize(s: string): string[];
+}
+
+export class DefaultTokenizer implements ITokenizer {
+ tokenize(s: string): string[] {
+ return s.split(" ");
+ }
+}
diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts
new file mode 100644
index 0000000..96b4a7a
--- /dev/null
+++ b/packages/server/src/server.ts
@@ -0,0 +1,256 @@
+import Koa from "koa";
+import Router from "koa-router";
+
+import { connectDB } from "./database";
+import { createDiffRouter, DiffManager } from "./diff/mod";
+import { get_setting, SettingConfig } from "./SettingConfig";
+
+import { createReadStream, readFileSync } from "node:fs";
+import bodyparser from "koa-bodyparser";
+import { createSqliteDocumentAccessor, createSqliteTagController, createSqliteUserController } from "./db/mod";
+import { createLoginRouter, createUserMiddleWare, getAdmin, isAdminFirst } from "./login";
+import getContentRouter from "./route/contents";
+import { error_handler } from "./route/error_handler";
+
+import { createInterface as createReadlineInterface } from "node:readline";
+import { createComicWatcher } from "./diff/watcher/comic_watcher";
+import type { DocumentAccessor, TagAccessor, UserAccessor } from "./model/mod";
+import { getTagRounter } from "./route/tags";
+
+import { config } from "dotenv";
+import { extname, join } from "node:path";
+config();
+
+class ServerApplication {
+ readonly userController: UserAccessor;
+ readonly documentController: DocumentAccessor;
+ readonly tagController: TagAccessor;
+ readonly diffManger: DiffManager;
+ readonly app: Koa;
+ private index_html: string;
+ private constructor(controller: {
+ userController: UserAccessor;
+ documentController: DocumentAccessor;
+ tagController: TagAccessor;
+ }) {
+ this.userController = controller.userController;
+ this.documentController = controller.documentController;
+ this.tagController = controller.tagController;
+
+ this.diffManger = new DiffManager(this.documentController);
+ this.app = new Koa();
+ this.index_html = readFileSync("dist/index.html", "utf-8");
+ }
+ private async setup() {
+ const setting = get_setting();
+ const app = this.app;
+
+ if (setting.cli) {
+ const userAdmin = await getAdmin(this.userController);
+ if (await isAdminFirst(userAdmin)) {
+ const rl = createReadlineInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
+ const pw = await new Promise((res: (data: string) => void, err) => {
+ rl.question("put admin password :", (data) => {
+ res(data);
+ });
+ });
+ rl.close();
+ userAdmin.reset_password(pw);
+ }
+ }
+ app.use(bodyparser());
+ app.use(error_handler);
+ app.use(createUserMiddleWare(this.userController));
+
+ const diff_router = createDiffRouter(this.diffManger);
+ this.diffManger.register("comic", createComicWatcher());
+
+ console.log("setup router");
+
+ const router = new Router();
+ router.use("/api/(.*)", async (ctx, next) => {
+ // For CORS
+ ctx.res.setHeader("access-control-allow-origin", "*");
+ await next();
+ });
+
+ router.use("/api/diff", diff_router.routes());
+ router.use("/api/diff", diff_router.allowedMethods());
+
+ const content_router = getContentRouter(this.documentController);
+ router.use("/api/doc", content_router.routes());
+ router.use("/api/doc", content_router.allowedMethods());
+
+ const tags_router = getTagRounter(this.tagController);
+ router.use("/api/tags", tags_router.allowedMethods());
+ router.use("/api/tags", tags_router.routes());
+
+ this.serve_with_meta_index(router);
+ this.serve_index(router);
+ this.serve_static_file(router);
+
+ const login_router = createLoginRouter(this.userController);
+ router.use("/api/user", login_router.routes());
+ router.use("/api/user", login_router.allowedMethods());
+
+ if (setting.mode === "development") {
+ let mm_count = 0;
+ app.use(async (ctx, next) => {
+ console.log(`=== Request No ${mm_count++} \t===`);
+ const ip = ctx.get("X-Real-IP").length > 0 ? ctx.get("X-Real-IP") : ctx.ip;
+ const fromClient = ctx.state.user.username === "" ? ip : ctx.state.user.username;
+ console.log(`${mm_count} ${fromClient} : ${ctx.method} ${ctx.url}`);
+ const start = Date.now();
+ await next();
+ const end = Date.now();
+ console.log(`${mm_count} ${fromClient} : ${ctx.method} ${ctx.url} ${ctx.status} ${end - start}ms`);
+ });
+ }
+ app.use(router.routes());
+ app.use(router.allowedMethods());
+ console.log("setup done");
+ }
+ private serve_index(router: Router) {
+ const serveindex = (url: string) => {
+ router.get(url, (ctx) => {
+ ctx.type = "html";
+ ctx.body = this.index_html;
+ const setting = get_setting();
+ ctx.set("x-content-type-options", "no-sniff");
+ if (setting.mode === "development") {
+ ctx.set("cache-control", "no-cache");
+ } else {
+ ctx.set("cache-control", "public, max-age=3600");
+ }
+ });
+ };
+ serveindex("/");
+ serveindex("/doc/:rest(.*)");
+ serveindex("/search");
+ serveindex("/login");
+ serveindex("/profile");
+ serveindex("/difference");
+ serveindex("/setting");
+ serveindex("/tags");
+ }
+ private serve_with_meta_index(router: Router) {
+ const DocMiddleware = async (ctx: Koa.ParameterizedContext) => {
+ const docId = Number.parseInt(ctx.params.id);
+ const doc = await this.documentController.findById(docId, true);
+ // biome-ignore lint/suspicious/noImplicitAnyLet:
+ let meta;
+ if (doc === undefined) {
+ ctx.status = 404;
+ meta = NotFoundContent();
+ } else {
+ ctx.status = 200;
+ meta = createOgTagContent(
+ doc.title,
+ doc.tags.join(", "),
+ `https://aeolian.prelude.duckdns.org/api/doc/${docId}/comic/thumbnail`,
+ );
+ }
+ const html = makeMetaTagInjectedHTML(this.index_html, meta);
+ serveHTML(ctx, html);
+ };
+ router.get("/doc/:id(\\d+)", DocMiddleware);
+
+ function NotFoundContent() {
+ return createOgTagContent("Not Found Doc", "Not Found", "");
+ }
+ function makeMetaTagInjectedHTML(html: string, tagContent: string) {
+ return html.replace("", tagContent);
+ }
+ function serveHTML(ctx: Koa.Context, file: string) {
+ ctx.type = "html";
+ ctx.body = file;
+ const setting = get_setting();
+ ctx.set("x-content-type-options", "no-sniff");
+ if (setting.mode === "development") {
+ ctx.set("cache-control", "no-cache");
+ } else {
+ ctx.set("cache-control", "public, max-age=3600");
+ }
+ }
+
+ function createMetaTagContent(key: string, value: string) {
+ return ``;
+ }
+ function createOgTagContent(title: string, description: string, image: string) {
+ return [
+ createMetaTagContent("og:title", title),
+ createMetaTagContent("og:type", "website"),
+ createMetaTagContent("og:description", description),
+ createMetaTagContent("og:image", image),
+ // createMetaTagContent("og:image:width","480"),
+ // createMetaTagContent("og:image","480"),
+ // createMetaTagContent("og:image:type","image/png"),
+ createMetaTagContent("twitter:card", "summary_large_image"),
+ createMetaTagContent("twitter:title", title),
+ createMetaTagContent("twitter:description", description),
+ createMetaTagContent("twitter:image", image),
+ ].join("\n");
+ }
+ }
+ private serve_static_file(router: Router) {
+ router.get("/assets/(.*)", async (ctx, next) => {
+ const setting = get_setting();
+ const ext = extname(ctx.path);
+ ctx.type = ext;
+ ctx.body = createReadStream(join("dist",`.${ctx.path}`));
+ ctx.set("x-content-type-options", "no-sniff");
+ if (setting.mode === "development") {
+ ctx.set("cache-control", "no-cache");
+ } else {
+ ctx.set("cache-control", "public, max-age=3600");
+ }
+ });
+ // const static_file_server = (path: string, type: string) => {
+ // router.get(`/${path}`, async (ctx, next) => {
+ // const setting = get_setting();
+ // ctx.type = type;
+ // ctx.body = createReadStream(path);
+ // ctx.set("x-content-type-options", "no-sniff");
+ // if (setting.mode === "development") {
+ // ctx.set("cache-control", "no-cache");
+ // } else {
+ // ctx.set("cache-control", "public, max-age=3600");
+ // }
+ // });
+ // };
+ // const setting = get_setting();
+ // static_file_server("dist/bundle.css", "css");
+ // static_file_server("dist/bundle.js", "js");
+ // if (setting.mode === "development") {
+ // static_file_server("dist/bundle.js.map", "text");
+ // static_file_server("dist/bundle.css.map", "text");
+ // }
+ }
+ start_server() {
+ const setting = get_setting();
+ // todo : support https
+ console.log(`listen on http://${setting.localmode ? "localhost" : "0.0.0.0"}:${setting.port}`);
+ return this.app.listen(setting.port, setting.localmode ? "127.0.0.1" : "0.0.0.0");
+ }
+ static async createServer() {
+ const setting = get_setting();
+ const db = await connectDB();
+
+ const app = new ServerApplication({
+ userController: createSqliteUserController(db),
+ documentController: createSqliteDocumentAccessor(db),
+ tagController: createSqliteTagController(db),
+ });
+ await app.setup();
+ return app;
+ }
+}
+
+export async function create_server() {
+ return await ServerApplication.createServer();
+}
+
+export default { create_server };
diff --git a/packages/server/src/types/json.ts b/packages/server/src/types/json.ts
new file mode 100644
index 0000000..b774877
--- /dev/null
+++ b/packages/server/src/types/json.ts
@@ -0,0 +1,4 @@
+export type JSONPrimitive = null | boolean | number | string;
+export interface JSONMap extends Record {}
+export interface JSONArray extends Array {}
+export type JSONType = JSONMap | JSONPrimitive | JSONArray;
diff --git a/packages/server/src/util/configRW.ts b/packages/server/src/util/configRW.ts
new file mode 100644
index 0000000..dd873ad
--- /dev/null
+++ b/packages/server/src/util/configRW.ts
@@ -0,0 +1,46 @@
+import { existsSync, promises as fs, readFileSync, writeFileSync } from "node:fs";
+
+export class ConfigManager {
+ path: string;
+ default_config: T;
+ config: T | null;
+ schema: object;
+ constructor(path: string, default_config: T, schema: object) {
+ this.path = path;
+ this.default_config = default_config;
+ this.config = null;
+ this.schema = schema;
+ }
+ get_config_file(): T {
+ if (this.config !== null) return this.config;
+ this.config = { ...this.read_config_file() };
+ return this.config;
+ }
+ private emptyToDefault(target: T) {
+ let occur = false;
+ for (const key in this.default_config) {
+ if (key === undefined || key in target) {
+ continue;
+ }
+ target[key] = this.default_config[key];
+ occur = true;
+ }
+ return occur;
+ }
+ read_config_file(): T {
+ if (!existsSync(this.path)) {
+ writeFileSync(this.path, JSON.stringify(this.default_config));
+ return this.default_config;
+ }
+ const ret = JSON.parse(readFileSync(this.path, { encoding: "utf8" }));
+ if (this.emptyToDefault(ret)) {
+ writeFileSync(this.path, JSON.stringify(ret));
+ }
+ return ret;
+ }
+ async write_config_file(new_config: T) {
+ this.config = new_config;
+ await fs.writeFile(`${this.path}.temp`, JSON.stringify(new_config));
+ await fs.rename(`${this.path}.temp`, this.path);
+ }
+}
diff --git a/packages/server/src/util/type_check.ts b/packages/server/src/util/type_check.ts
new file mode 100644
index 0000000..6ee6d50
--- /dev/null
+++ b/packages/server/src/util/type_check.ts
@@ -0,0 +1,17 @@
+export function check_type(obj: unknown, check_proto: Record): obj is T {
+ if (typeof obj !== "object" || obj === null) return false;
+ for (const it in check_proto) {
+ let defined = check_proto[it];
+ if (defined === undefined) return false;
+ defined = defined.trim();
+ if (defined.endsWith("[]")) {
+ if (!Array.isArray((obj as Record)[it])) {
+ return false;
+ }
+ // biome-ignore lint/suspicious/useValidTypeof:
+ } else if (defined !== typeof (obj as Record)[it]) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/packages/server/src/util/zipwrap.ts b/packages/server/src/util/zipwrap.ts
new file mode 100644
index 0000000..f32ab4f
--- /dev/null
+++ b/packages/server/src/util/zipwrap.ts
@@ -0,0 +1,54 @@
+import { type FileHandle, open } from "node:fs/promises";
+import { orderBy } from "natural-orderby";
+import { ZipReader, Reader, type Entry } from "@zip.js/zip.js";
+
+class FileReader extends Reader {
+ private fd: FileHandle;
+ constructor(fd: FileHandle) {
+ super(fd);
+ this.fd = fd;
+ }
+
+ async init(): Promise {
+ this.size = (await this.fd.stat()).size;
+ }
+ close(): void {
+ this.fd.close();
+ }
+
+ async readUint8Array(index: number, length: number): Promise {
+ const buffer = new Uint8Array(length);
+ const buf = await this.fd.read(buffer, 0, length, index);
+ if (buf.bytesRead !== length) {
+ console.error(`read error: ${buf.bytesRead} !== ${length}`);
+ throw new Error("read error");
+ }
+ return buffer;
+ }
+}
+
+export async function readZip(path: string): Promise<{
+ reader: ZipReader
+ handle: FileHandle
+}> {
+ const fd = await open(path, "r");
+ const reader = new ZipReader(new FileReader(fd), {
+ useCompressionStream: true,
+ preventClose: false,
+ });
+ return { reader, handle: fd };
+}
+export async function entriesByNaturalOrder(zip: ZipReader) {
+ const entries = await zip.getEntries();
+ const ret = orderBy(entries, (v) => v.filename);
+ return ret;
+}
+
+export async function createReadableStreamFromZip(_zip: ZipReader, entry: Entry): Promise {
+ if (entry.getData === undefined) {
+ throw new Error("entry.getData is undefined");
+ }
+ const stream = new TransformStream();
+ entry.getData(stream.writable);
+ return stream.readable;
+}
diff --git a/tsconfig.json b/packages/server/tsconfig.json
similarity index 98%
rename from tsconfig.json
rename to packages/server/tsconfig.json
index 4b13120..e824e11 100644
--- a/tsconfig.json
+++ b/packages/server/tsconfig.json
@@ -6,7 +6,7 @@
// "incremental": true, /* Enable incremental compilation */
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
- "lib": ["DOM", "ES6"], /* Specify library files to be included in the compilation. */
+ "lib": ["DOM", "ESNext"],
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
"jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9a70546..af296d6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,382 +1,2255 @@
-lockfileVersion: 5.4
+lockfileVersion: '6.0'
-specifiers:
- '@louislam/sqlite3': ^6.0.1
- '@types/jsonwebtoken': ^8.5.8
- '@types/koa': ^2.13.4
- '@types/koa-bodyparser': ^4.3.7
- '@types/koa-compose': ^3.2.5
- '@types/koa-router': ^7.4.4
- '@types/node': ^14.18.21
- '@types/tiny-async-pool': ^1.0.1
- chokidar: ^3.5.3
- dprint: ^0.36.1
- electron: ^11.5.0
- electron-builder: ^22.14.13
- jsonschema: ^1.4.1
- jsonwebtoken: ^8.5.1
- knex: ^0.95.15
- koa: ^2.13.4
- koa-bodyparser: ^4.3.0
- koa-compose: ^4.1.0
- koa-router: ^10.1.1
- natural-orderby: ^2.0.3
- node-stream-zip: ^1.15.0
- sqlite3: ^5.0.8
- tiny-async-pool: ^1.3.0
- ts-json-schema-generator: ^0.82.0
- ts-node: ^9.1.1
- typescript: ^4.7.4
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
-dependencies:
- '@louislam/sqlite3': 6.0.1
- '@types/koa-compose': 3.2.5
- chokidar: 3.5.3
- dprint: 0.36.1
- jsonschema: 1.4.1
- jsonwebtoken: 8.5.1
- knex: 0.95.15_sqlite3@5.0.8
- koa: 2.13.4
- koa-bodyparser: 4.3.0
- koa-compose: 4.1.0
- koa-router: 10.1.1
- natural-orderby: 2.0.3
- node-stream-zip: 1.15.0
- sqlite3: 5.0.8
- tiny-async-pool: 1.3.0
+importers:
-devDependencies:
- '@types/jsonwebtoken': 8.5.8
- '@types/koa': 2.13.4
- '@types/koa-bodyparser': 4.3.7
- '@types/koa-router': 7.4.4
- '@types/node': 14.18.21
- '@types/tiny-async-pool': 1.0.1
- electron: 11.5.0
- electron-builder: 22.14.13
- ts-json-schema-generator: 0.82.0
- ts-node: 9.1.1_typescript@4.7.4
- typescript: 4.7.4
+ .:
+ devDependencies:
+ '@biomejs/biome':
+ specifier: 1.6.3
+ version: 1.6.3
+
+ packages/client:
+ dependencies:
+ '@radix-ui/react-icons':
+ specifier: ^1.3.0
+ version: 1.3.0(react@18.2.0)
+ '@radix-ui/react-label':
+ specifier: ^2.0.2
+ version: 2.0.2(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-popover':
+ specifier: ^1.0.7
+ version: 1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-radio-group':
+ specifier: ^1.1.3
+ version: 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-separator':
+ specifier: ^1.0.3
+ version: 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-slot':
+ specifier: ^1.0.2
+ version: 1.0.2(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-tooltip':
+ specifier: ^1.0.7
+ version: 1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@tanstack/react-virtual':
+ specifier: ^3.2.1
+ version: 3.2.1(react-dom@18.2.0)(react@18.2.0)
+ class-variance-authority:
+ specifier: ^0.7.0
+ version: 0.7.0
+ clsx:
+ specifier: ^2.1.0
+ version: 2.1.0
+ dbtype:
+ specifier: workspace:*
+ version: link:../dbtype
+ jotai:
+ specifier: ^2.7.2
+ version: 2.7.2(@types/react@18.2.71)(react@18.2.0)
+ react:
+ specifier: ^18.2.0
+ version: 18.2.0
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.2.0(react@18.2.0)
+ react-resizable-panels:
+ specifier: ^2.0.16
+ version: 2.0.16(react-dom@18.2.0)(react@18.2.0)
+ swr:
+ specifier: ^2.2.5
+ version: 2.2.5(react@18.2.0)
+ tailwind-merge:
+ specifier: ^2.2.2
+ version: 2.2.2
+ tailwindcss-animate:
+ specifier: ^1.0.7
+ version: 1.0.7(tailwindcss@3.4.3)
+ usehooks-ts:
+ specifier: ^3.1.0
+ version: 3.1.0(react@18.2.0)
+ wouter:
+ specifier: ^3.1.0
+ version: 3.1.0(react@18.2.0)
+ devDependencies:
+ '@types/node':
+ specifier: '>=20.0.0'
+ version: 20.12.3
+ '@types/react':
+ specifier: ^18.2.66
+ version: 18.2.71
+ '@types/react-dom':
+ specifier: ^18.2.22
+ version: 18.2.22
+ '@typescript-eslint/eslint-plugin':
+ specifier: ^7.2.0
+ version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/parser':
+ specifier: ^7.2.0
+ version: 7.4.0(eslint@8.57.0)(typescript@5.4.3)
+ '@vitejs/plugin-react-swc':
+ specifier: ^3.5.0
+ version: 3.6.0(vite@5.2.6)
+ autoprefixer:
+ specifier: ^10.4.19
+ version: 10.4.19(postcss@8.4.38)
+ eslint:
+ specifier: ^8.57.0
+ version: 8.57.0
+ eslint-plugin-react-hooks:
+ specifier: ^4.6.0
+ version: 4.6.0(eslint@8.57.0)
+ eslint-plugin-react-refresh:
+ specifier: ^0.4.6
+ version: 0.4.6(eslint@8.57.0)
+ postcss:
+ specifier: ^8.4.38
+ version: 8.4.38
+ shadcn-ui:
+ specifier: ^0.8.0
+ version: 0.8.0(typescript@5.4.3)
+ tailwindcss:
+ specifier: ^3.4.3
+ version: 3.4.3
+ typescript:
+ specifier: ^5.2.2
+ version: 5.4.3
+ vite:
+ specifier: ^5.2.0
+ version: 5.2.6(@types/node@20.12.3)
+
+ packages/dbtype:
+ devDependencies:
+ '@types/better-sqlite3':
+ specifier: ^7.6.9
+ version: 7.6.9
+ better-sqlite3:
+ specifier: ^9.4.3
+ version: 9.4.3
+ kysely:
+ specifier: ^0.27.3
+ version: 0.27.3
+ kysely-codegen:
+ specifier: ^0.14.1
+ version: 0.14.1(better-sqlite3@9.4.3)(kysely@0.27.3)
+
+ packages/server:
+ dependencies:
+ '@zip.js/zip.js':
+ specifier: ^2.7.40
+ version: 2.7.40
+ better-sqlite3:
+ specifier: ^9.4.3
+ version: 9.4.3
+ chokidar:
+ specifier: ^3.6.0
+ version: 3.6.0
+ dotenv:
+ specifier: ^16.4.5
+ version: 16.4.5
+ jsonwebtoken:
+ specifier: ^8.5.1
+ version: 8.5.1
+ koa:
+ specifier: ^2.15.2
+ version: 2.15.2
+ koa-bodyparser:
+ specifier: ^4.4.1
+ version: 4.4.1
+ koa-compose:
+ specifier: ^4.1.0
+ version: 4.1.0
+ koa-router:
+ specifier: ^12.0.1
+ version: 12.0.1
+ kysely:
+ specifier: ^0.27.3
+ version: 0.27.3
+ natural-orderby:
+ specifier: ^2.0.3
+ version: 2.0.3
+ tiny-async-pool:
+ specifier: ^1.3.0
+ version: 1.3.0
+ devDependencies:
+ '@swc-node/register':
+ specifier: ^1.9.0
+ version: 1.9.0(@swc/core@1.4.11)(@swc/types@0.1.6)(typescript@5.4.3)
+ '@swc/cli':
+ specifier: ^0.3.10
+ version: 0.3.10(@swc/core@1.4.11)(chokidar@3.6.0)
+ '@swc/core':
+ specifier: ^1.4.11
+ version: 1.4.11
+ '@types/better-sqlite3':
+ specifier: ^7.6.9
+ version: 7.6.9
+ '@types/jsonwebtoken':
+ specifier: ^8.5.9
+ version: 8.5.9
+ '@types/koa':
+ specifier: ^2.15.0
+ version: 2.15.0
+ '@types/koa-bodyparser':
+ specifier: ^4.3.12
+ version: 4.3.12
+ '@types/koa-compose':
+ specifier: ^3.2.8
+ version: 3.2.8
+ '@types/koa-router':
+ specifier: ^7.4.8
+ version: 7.4.8
+ '@types/node':
+ specifier: '>=20.0.0'
+ version: 20.12.3
+ '@types/tiny-async-pool':
+ specifier: ^1.0.5
+ version: 1.0.5
+ dbtype:
+ specifier: workspace:^
+ version: link:../dbtype
+ nodemon:
+ specifier: ^3.1.0
+ version: 3.1.0
packages:
- /7zip-bin/5.1.1:
- resolution: {integrity: sha512-sAP4LldeWNz0lNzmTird3uWfFDWWTeg6V/MsmyyLR9X1idwKBWIgt/ZvinqQldJm3LecKEs1emkbquO6PCiLVQ==}
+ /@aashutoshrathi/word-wrap@1.2.6:
+ resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
+ engines: {node: '>=0.10.0'}
dev: true
- /@develar/schema-utils/2.6.5:
- resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==}
- engines: {node: '>= 8.9.0'}
+ /@alloc/quick-lru@5.2.0:
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
+
+ /@ampproject/remapping@2.3.0:
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
dependencies:
- ajv: 6.12.6
- ajv-keywords: 3.5.2_ajv@6.12.6
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
dev: true
- /@electron/get/1.14.1:
- resolution: {integrity: sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==}
- engines: {node: '>=8.6'}
+ /@antfu/ni@0.21.12:
+ resolution: {integrity: sha512-2aDL3WUv8hMJb2L3r/PIQWsTLyq7RQr3v9xD16fiz6O8ys1xEyLhhTOv8gxtZvJiTzjTF5pHoArvRdesGL1DMQ==}
+ hasBin: true
+ dev: true
+
+ /@babel/code-frame@7.24.2:
+ resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==}
+ engines: {node: '>=6.9.0'}
dependencies:
- debug: 4.3.4
- env-paths: 2.2.1
- fs-extra: 8.1.0
- got: 9.6.0
- progress: 2.0.3
- semver: 6.3.0
- sumchecker: 3.0.1
- optionalDependencies:
- global-agent: 3.0.0
- global-tunnel-ng: 2.7.1
+ '@babel/highlight': 7.24.2
+ picocolors: 1.0.0
+ dev: true
+
+ /@babel/compat-data@7.24.1:
+ resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/core@7.24.3:
+ resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.24.2
+ '@babel/generator': 7.24.1
+ '@babel/helper-compilation-targets': 7.23.6
+ '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3)
+ '@babel/helpers': 7.24.1
+ '@babel/parser': 7.24.1
+ '@babel/template': 7.24.0
+ '@babel/traverse': 7.24.1
+ '@babel/types': 7.24.0
+ convert-source-map: 2.0.0
+ debug: 4.3.4(supports-color@5.5.0)
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
transitivePeerDependencies:
- supports-color
dev: true
- /@electron/universal/1.0.5:
- resolution: {integrity: sha512-zX9O6+jr2NMyAdSkwEUlyltiI4/EBLu2Ls/VD3pUQdi3cAYeYfdQnT2AJJ38HE4QxLccbU13LSpccw1IWlkyag==}
- engines: {node: '>=8.6'}
+ /@babel/generator@7.24.1:
+ resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==}
+ engines: {node: '>=6.9.0'}
dependencies:
- '@malept/cross-spawn-promise': 1.1.1
- asar: 3.1.0
- debug: 4.3.4
- dir-compare: 2.4.0
- fs-extra: 9.1.0
+ '@babel/types': 7.24.0
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 2.5.2
+ dev: true
+
+ /@babel/helper-annotate-as-pure@7.22.5:
+ resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-compilation-targets@7.23.6:
+ resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/compat-data': 7.24.1
+ '@babel/helper-validator-option': 7.23.5
+ browserslist: 4.23.0
+ lru-cache: 5.1.1
+ semver: 6.3.1
+ dev: true
+
+ /@babel/helper-create-class-features-plugin@7.24.1(@babel/core@7.24.3):
+ resolution: {integrity: sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.24.3
+ '@babel/helper-annotate-as-pure': 7.22.5
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-function-name': 7.23.0
+ '@babel/helper-member-expression-to-functions': 7.23.0
+ '@babel/helper-optimise-call-expression': 7.22.5
+ '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.3)
+ '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.6
+ semver: 6.3.1
+ dev: true
+
+ /@babel/helper-environment-visitor@7.22.20:
+ resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-function-name@7.23.0:
+ resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.24.0
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-hoist-variables@7.22.5:
+ resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-member-expression-to-functions@7.23.0:
+ resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-module-imports@7.24.3:
+ resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3):
+ resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.24.3
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-module-imports': 7.24.3
+ '@babel/helper-simple-access': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.6
+ '@babel/helper-validator-identifier': 7.22.20
+ dev: true
+
+ /@babel/helper-optimise-call-expression@7.22.5:
+ resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-plugin-utils@7.24.0:
+ resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-replace-supers@7.24.1(@babel/core@7.24.3):
+ resolution: {integrity: sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.24.3
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-member-expression-to-functions': 7.23.0
+ '@babel/helper-optimise-call-expression': 7.22.5
+ dev: true
+
+ /@babel/helper-simple-access@7.22.5:
+ resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-skip-transparent-expression-wrappers@7.22.5:
+ resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-split-export-declaration@7.22.6:
+ resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/helper-string-parser@7.24.1:
+ resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-validator-identifier@7.22.20:
+ resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-validator-option@7.23.5:
+ resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helpers@7.24.1:
+ resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.24.0
+ '@babel/traverse': 7.24.1
+ '@babel/types': 7.24.0
transitivePeerDependencies:
- supports-color
dev: true
- /@gar/promisify/1.1.3:
- resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
- dev: false
- optional: true
-
- /@louislam/sqlite3/6.0.1:
- resolution: {integrity: sha512-QGLj5bjQ+O4YSPj/qxtEAArbIqW9wNzBUamlIcRbvFjFiNokItwdubqL2Gl5iX0q1mUn3Z6NoFO1rrAZ/qqlsA==}
- requiresBuild: true
- peerDependenciesMeta:
- node-gyp:
- optional: true
+ /@babel/highlight@7.24.2:
+ resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==}
+ engines: {node: '>=6.9.0'}
dependencies:
- '@mapbox/node-pre-gyp': 1.0.9
- node-addon-api: 3.2.1
- optionalDependencies:
- node-gyp: 8.4.1
- transitivePeerDependencies:
- - encoding
- - supports-color
- dev: false
-
- /@malept/cross-spawn-promise/1.1.1:
- resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==}
- engines: {node: '>= 10'}
- dependencies:
- cross-spawn: 7.0.3
+ '@babel/helper-validator-identifier': 7.22.20
+ chalk: 2.4.2
+ js-tokens: 4.0.0
+ picocolors: 1.0.0
dev: true
- /@malept/flatpak-bundler/0.4.0:
- resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==}
- engines: {node: '>= 10.0.0'}
- dependencies:
- debug: 4.3.4
- fs-extra: 9.1.0
- lodash: 4.17.21
- tmp-promise: 3.0.3
- transitivePeerDependencies:
- - supports-color
- dev: true
-
- /@mapbox/node-pre-gyp/1.0.9:
- resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==}
+ /@babel/parser@7.24.1:
+ resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==}
+ engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
- detect-libc: 2.0.1
- https-proxy-agent: 5.0.1
- make-dir: 3.1.0
- node-fetch: 2.6.7
- nopt: 5.0.0
- npmlog: 5.0.1
- rimraf: 3.0.2
- semver: 7.3.7
- tar: 6.1.11
- transitivePeerDependencies:
- - encoding
- - supports-color
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3):
+ resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.3
+ '@babel/helper-plugin-utils': 7.24.0
+ dev: true
+
+ /@babel/plugin-transform-typescript@7.24.1(@babel/core@7.24.3):
+ resolution: {integrity: sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.3
+ '@babel/helper-annotate-as-pure': 7.22.5
+ '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3)
+ '@babel/helper-plugin-utils': 7.24.0
+ '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.3)
+ dev: true
+
+ /@babel/runtime@7.24.1:
+ resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.14.1
dev: false
- /@npmcli/fs/1.1.1:
- resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==}
+ /@babel/template@7.24.0:
+ resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
+ engines: {node: '>=6.9.0'}
dependencies:
- '@gar/promisify': 1.1.3
- semver: 7.3.7
- dev: false
+ '@babel/code-frame': 7.24.2
+ '@babel/parser': 7.24.1
+ '@babel/types': 7.24.0
+ dev: true
+
+ /@babel/traverse@7.24.1:
+ resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.24.2
+ '@babel/generator': 7.24.1
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-function-name': 7.23.0
+ '@babel/helper-hoist-variables': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.6
+ '@babel/parser': 7.24.1
+ '@babel/types': 7.24.0
+ debug: 4.3.4(supports-color@5.5.0)
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/types@7.24.0:
+ resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-string-parser': 7.24.1
+ '@babel/helper-validator-identifier': 7.22.20
+ to-fast-properties: 2.0.0
+ dev: true
+
+ /@biomejs/biome@1.6.3:
+ resolution: {integrity: sha512-Xnp/TIpIcTnRA4LwerJuoGYQJEqwXtn5AL0U0OPXll/QGbAKmcUAfizU880xTwZRD4f53iceqODLDaD3wxYlIw==}
+ engines: {node: '>=14.*'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@biomejs/cli-darwin-arm64': 1.6.3
+ '@biomejs/cli-darwin-x64': 1.6.3
+ '@biomejs/cli-linux-arm64': 1.6.3
+ '@biomejs/cli-linux-arm64-musl': 1.6.3
+ '@biomejs/cli-linux-x64': 1.6.3
+ '@biomejs/cli-linux-x64-musl': 1.6.3
+ '@biomejs/cli-win32-arm64': 1.6.3
+ '@biomejs/cli-win32-x64': 1.6.3
+ dev: true
+
+ /@biomejs/cli-darwin-arm64@1.6.3:
+ resolution: {integrity: sha512-0E8PGu3/8HSkBJdtjno+niJE1ANS/12D7sPK65vw5lTBYmmaYwJdfclDp6XO0IAX7uVd3/YtXlsEua0SVrNt3Q==}
+ engines: {node: '>=14.*'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
optional: true
- /@npmcli/move-file/1.1.2:
- resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==}
+ /@biomejs/cli-darwin-x64@1.6.3:
+ resolution: {integrity: sha512-UWu0We/aIRtWXgJKe6ygWt2xR0yXs64BwWqtZbfxBojRn3jgW8UdFAkV5yiUOX3TQlsV6BZH1EQaUAVsccUeeA==}
+ engines: {node: '>=14.*'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@biomejs/cli-linux-arm64-musl@1.6.3:
+ resolution: {integrity: sha512-AntGCSfLN1nPcQj4VOk3X2JgnDw07DaPC8BuBmRcsRmn+7GPSWLllVN5awIKlRPZEbGJtSnLkTiDc5Bxw8OiuA==}
+ engines: {node: '>=14.*'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@biomejs/cli-linux-arm64@1.6.3:
+ resolution: {integrity: sha512-wFVkQw38kOssfnkbpSh6ums5TaElw3RAt5i/VZwHmgR2nQgE0fHXLO7HwIE9VBkOEdbiIFq+2PxvFIHuJF3z3Q==}
+ engines: {node: '>=14.*'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@biomejs/cli-linux-x64-musl@1.6.3:
+ resolution: {integrity: sha512-GelAvGsUwbxfFpKLG+7+dvDmbrfkGqn08sL8CMQrGnhjE1krAqHWiXQsjfmi0UMFdMsk7hbc4oSAP+1+mrXcHQ==}
+ engines: {node: '>=14.*'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@biomejs/cli-linux-x64@1.6.3:
+ resolution: {integrity: sha512-vyn8TQaTZg617hjqFitwGmb1St5XXvq6I3vmxU/QFalM74BryMSvYCrYWb2Yw/TkykdEwZTMGYp+SWHRb04fTg==}
+ engines: {node: '>=14.*'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@biomejs/cli-win32-arm64@1.6.3:
+ resolution: {integrity: sha512-Gx8N2Tixke6pAI1BniteCVZgUUmaFEDYosdWxoaCus15BZI/7RcBxhsRM0ZL/lC66StSQ8vHl8JBrrld1k570Q==}
+ engines: {node: '>=14.*'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@biomejs/cli-win32-x64@1.6.3:
+ resolution: {integrity: sha512-meungPJw64SqoR7LXY1wG7GC4+4wgpyThdFUMGXa6PCe0BLFOIOcZ9VMj9PstuczMPdgmt/BUMPsj25dK1VO8A==}
+ engines: {node: '>=14.*'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/aix-ppc64@0.20.2:
+ resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm64@0.20.2:
+ resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-arm@0.20.2:
+ resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/android-x64@0.20.2:
+ resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-arm64@0.20.2:
+ resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/darwin-x64@0.20.2:
+ resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-arm64@0.20.2:
+ resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/freebsd-x64@0.20.2:
+ resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm64@0.20.2:
+ resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-arm@0.20.2:
+ resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ia32@0.20.2:
+ resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-loong64@0.20.2:
+ resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-mips64el@0.20.2:
+ resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-ppc64@0.20.2:
+ resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-riscv64@0.20.2:
+ resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-s390x@0.20.2:
+ resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/linux-x64@0.20.2:
+ resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/netbsd-x64@0.20.2:
+ resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/openbsd-x64@0.20.2:
+ resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/sunos-x64@0.20.2:
+ resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-arm64@0.20.2:
+ resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-ia32@0.20.2:
+ resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@esbuild/win32-x64@0.20.2:
+ resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ dependencies:
+ eslint: 8.57.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@eslint-community/regexpp@4.10.0:
+ resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dev: true
+
+ /@eslint/eslintrc@2.1.4:
+ resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.4(supports-color@5.5.0)
+ espree: 9.6.1
+ globals: 13.24.0
+ ignore: 5.3.1
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@eslint/js@8.57.0:
+ resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@floating-ui/core@1.6.0:
+ resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==}
+ dependencies:
+ '@floating-ui/utils': 0.2.1
+ dev: false
+
+ /@floating-ui/dom@1.6.3:
+ resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==}
+ dependencies:
+ '@floating-ui/core': 1.6.0
+ '@floating-ui/utils': 0.2.1
+ dev: false
+
+ /@floating-ui/react-dom@2.0.8(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+ dependencies:
+ '@floating-ui/dom': 1.6.3
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@floating-ui/utils@0.2.1:
+ resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==}
+ dev: false
+
+ /@humanwhocodes/config-array@0.11.14:
+ resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 2.0.2
+ debug: 4.3.4(supports-color@5.5.0)
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@humanwhocodes/module-importer@1.0.1:
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+ dev: true
+
+ /@humanwhocodes/object-schema@2.0.2:
+ resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
+ dev: true
+
+ /@isaacs/cliui@8.0.2:
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: /string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: /strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: /wrap-ansi@7.0.0
+
+ /@jridgewell/gen-mapping@0.3.5:
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/trace-mapping': 0.3.25
+
+ /@jridgewell/resolve-uri@3.1.2:
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ /@jridgewell/set-array@1.2.1:
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ /@jridgewell/sourcemap-codec@1.4.15:
+ resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+
+ /@jridgewell/trace-mapping@0.3.25:
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.4.15
+
+ /@mole-inc/bin-wrapper@8.0.1:
+ resolution: {integrity: sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ bin-check: 4.1.0
+ bin-version-check: 5.1.0
+ content-disposition: 0.5.4
+ ext-name: 5.0.0
+ file-type: 17.1.6
+ filenamify: 5.1.1
+ got: 11.8.6
+ os-filter-obj: 2.0.0
+ dev: true
+
+ /@nodelib/fs.scandir@2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ /@nodelib/fs.stat@2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ /@nodelib/fs.walk@1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.17.1
+
+ /@pkgjs/parseargs@0.11.0:
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+ requiresBuild: true
+ optional: true
+
+ /@radix-ui/primitive@1.0.1:
+ resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
+ dependencies:
+ '@babel/runtime': 7.24.1
+ dev: false
+
+ /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-context@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-direction@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-icons@1.3.0(react@18.2.0):
+ resolution: {integrity: sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==}
+ peerDependencies:
+ react: ^16.x || ^17.x || ^18.x
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-id@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-label@2.0.2(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-id': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ aria-hidden: 1.2.4
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ react-remove-scroll: 2.5.5(@types/react@18.2.71)(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/rect': 1.0.1
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-radio-group@1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-x+yELayyefNeKeTx4fjK6j99Fs6c4qKm3aY38G3swQVTN6xMpsrbigC0uHs2L//g8q4qR7qOcww8430jJmi2ag==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-direction': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-direction': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-id': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-slot@1.0.2(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-id': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/rect': 1.0.1
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-use-size@1.0.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.71)(react@18.2.0)
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.1
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.71
+ '@types/react-dom': 18.2.22
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@radix-ui/rect@1.0.1:
+ resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
+ dependencies:
+ '@babel/runtime': 7.24.1
+ dev: false
+
+ /@rollup/rollup-android-arm-eabi@4.13.0:
+ resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-android-arm64@4.13.0:
+ resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-darwin-arm64@4.13.0:
+ resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-darwin-x64@4.13.0:
+ resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm-gnueabihf@4.13.0:
+ resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-gnu@4.13.0:
+ resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-musl@4.13.0:
+ resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-riscv64-gnu@4.13.0:
+ resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-gnu@4.13.0:
+ resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-musl@4.13.0:
+ resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-arm64-msvc@4.13.0:
+ resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-ia32-msvc@4.13.0:
+ resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-win32-x64-msvc@4.13.0:
+ resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@sindresorhus/is@4.6.0:
+ resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /@swc-node/core@1.13.0(@swc/core@1.4.11)(@swc/types@0.1.6):
+ resolution: {integrity: sha512-lFPD4nmy4ifAOVMChFjwlpXN5KQXvegqeyuzz1KQz42q1lf+cL3Qux1/GteGuZjh8HC+Rj1RdNrHpE/MCfJSTw==}
+ engines: {node: '>= 10'}
+ peerDependencies:
+ '@swc/core': '>= 1.3'
+ '@swc/types': '>= 0.1'
+ dependencies:
+ '@swc/core': 1.4.11
+ '@swc/types': 0.1.6
+ dev: true
+
+ /@swc-node/register@1.9.0(@swc/core@1.4.11)(@swc/types@0.1.6)(typescript@5.4.3):
+ resolution: {integrity: sha512-i0iYInD4q5v3xQC6bKvs0QtfUxu197CU5qKALmpxEqTYs7sIhQ7KFLe3kP+eAR4gRkJTvAgjQgrokXLN2jZrOw==}
+ peerDependencies:
+ '@swc/core': '>= 1.3'
+ typescript: '>= 4.3'
+ dependencies:
+ '@swc-node/core': 1.13.0(@swc/core@1.4.11)(@swc/types@0.1.6)
+ '@swc-node/sourcemap-support': 0.5.0
+ '@swc/core': 1.4.11
+ colorette: 2.0.20
+ debug: 4.3.4(supports-color@5.5.0)
+ pirates: 4.0.6
+ tslib: 2.6.2
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - '@swc/types'
+ - supports-color
+ dev: true
+
+ /@swc-node/sourcemap-support@0.5.0:
+ resolution: {integrity: sha512-fbhjL5G0YvFoWwNhWleuBUfotiX+USiA9oJqu9STFw+Hb0Cgnddn+HVS/K5fI45mn92e8V+cHD2jgFjk4w2T9Q==}
+ dependencies:
+ source-map-support: 0.5.21
+ tslib: 2.6.2
+ dev: true
+
+ /@swc/cli@0.3.10(@swc/core@1.4.11)(chokidar@3.6.0):
+ resolution: {integrity: sha512-YWfYo9kXdbmIuGwIPth9geKgb0KssCMTdZa44zAN5KoqcuCP2rTW9s60heQDSRNpbtCmUr7BKF1VivsoHXrvrQ==}
+ engines: {node: '>= 16.14.0'}
+ hasBin: true
+ peerDependencies:
+ '@swc/core': ^1.2.66
+ chokidar: ^3.5.1
+ peerDependenciesMeta:
+ chokidar:
+ optional: true
+ dependencies:
+ '@mole-inc/bin-wrapper': 8.0.1
+ '@swc/core': 1.4.11
+ '@swc/counter': 0.1.3
+ chokidar: 3.6.0
+ commander: 8.3.0
+ fast-glob: 3.3.2
+ minimatch: 9.0.3
+ piscina: 4.4.0
+ semver: 7.6.0
+ slash: 3.0.0
+ source-map: 0.7.4
+ dev: true
+
+ /@swc/core-darwin-arm64@1.4.11:
+ resolution: {integrity: sha512-C1j1Qp/IHSelVWdEnT7f0iONWxQz6FAqzjCF2iaL+0vFg4V5f2nlgrueY8vj5pNNzSGhrAlxsMxEIp4dj1MXkg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-darwin-x64@1.4.11:
+ resolution: {integrity: sha512-0TTy3Ni8ncgaMCchSQ7FK8ZXQLlamy0FXmGWbR58c+pVZWYZltYPTmheJUvVcR0H2+gPAymRKyfC0iLszDALjg==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-linux-arm-gnueabihf@1.4.11:
+ resolution: {integrity: sha512-XJLB71uw0rog4DjYAPxFGAuGCBQpgJDlPZZK6MTmZOvI/1t0+DelJ24IjHIxk500YYM26Yv47xPabqFPD7I2zQ==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-linux-arm64-gnu@1.4.11:
+ resolution: {integrity: sha512-vYQwzJvm/iu052d5Iw27UFALIN5xSrGkPZXxLNMHPySVko2QMNNBv35HLatkEQHbQ3X+VKSW9J9SkdtAvAVRAQ==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-linux-arm64-musl@1.4.11:
+ resolution: {integrity: sha512-eV+KduiRYUFjPsvbZuJ9aknQH9Tj0U2/G9oIZSzLx/18WsYi+upzHbgxmIIHJ2VJgfd7nN40RI/hMtxNsUzR/g==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-linux-x64-gnu@1.4.11:
+ resolution: {integrity: sha512-WA1iGXZ2HpqM1OR9VCQZJ8sQ1KP2or9O4bO8vWZo6HZJIeoQSo7aa9waaCLRpkZvkng1ct/TF/l6ymqSNFXIzQ==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-linux-x64-musl@1.4.11:
+ resolution: {integrity: sha512-UkVJToKf0owwQYRnGvjHAeYVDfeimCEcx0VQSbJoN7Iy0ckRZi7YPlmWJU31xtKvikE2bQWCOVe0qbSDqqcWXA==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-win32-arm64-msvc@1.4.11:
+ resolution: {integrity: sha512-35khwkyly7lF5NDSyvIrukBMzxPorgc5iTSDfVO/LvnmN5+fm4lTlrDr4tUfTdOhv3Emy7CsKlsNAeFRJ+Pm+w==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-win32-ia32-msvc@1.4.11:
+ resolution: {integrity: sha512-Wx8/6f0ufgQF2pbVPsJ2dAmFLwIOW+xBE5fxnb7VnEbGkTgP1qMDWiiAtD9rtvDSuODG3i1AEmAak/2HAc6i6A==}
+ engines: {node: '>=10'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core-win32-x64-msvc@1.4.11:
+ resolution: {integrity: sha512-0xRFW6K9UZQH2NVC/0pVB0GJXS45lY24f+6XaPBF1YnMHd8A8GoHl7ugyM5yNUTe2AKhSgk5fJV00EJt/XBtdQ==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@swc/core@1.4.11:
+ resolution: {integrity: sha512-WKEakMZxkVwRdgMN4AMJ9K5nysY8g8npgQPczmjBeNK5In7QEAZAJwnyccrWwJZU0XjVeHn2uj+XbOKdDW17rg==}
+ engines: {node: '>=10'}
+ requiresBuild: true
+ peerDependencies:
+ '@swc/helpers': ^0.5.0
+ peerDependenciesMeta:
+ '@swc/helpers':
+ optional: true
+ dependencies:
+ '@swc/counter': 0.1.3
+ '@swc/types': 0.1.6
+ optionalDependencies:
+ '@swc/core-darwin-arm64': 1.4.11
+ '@swc/core-darwin-x64': 1.4.11
+ '@swc/core-linux-arm-gnueabihf': 1.4.11
+ '@swc/core-linux-arm64-gnu': 1.4.11
+ '@swc/core-linux-arm64-musl': 1.4.11
+ '@swc/core-linux-x64-gnu': 1.4.11
+ '@swc/core-linux-x64-musl': 1.4.11
+ '@swc/core-win32-arm64-msvc': 1.4.11
+ '@swc/core-win32-ia32-msvc': 1.4.11
+ '@swc/core-win32-x64-msvc': 1.4.11
+ dev: true
+
+ /@swc/counter@0.1.3:
+ resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+ dev: true
+
+ /@swc/types@0.1.6:
+ resolution: {integrity: sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==}
+ dependencies:
+ '@swc/counter': 0.1.3
+ dev: true
+
+ /@szmarczak/http-timer@4.0.6:
+ resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
engines: {node: '>=10'}
dependencies:
- mkdirp: 1.0.4
- rimraf: 3.0.2
+ defer-to-connect: 2.0.1
+ dev: true
+
+ /@tanstack/react-virtual@3.2.1(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-i9Nt0ssIh2bSjomJZlr6Iq5usT/9+ewo2/fKHRNk6kjVKS8jrhXbnO8NEawarCuBx/efv0xpoUUKKGxa0cQb4Q==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ '@tanstack/virtual-core': 3.2.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
dev: false
- optional: true
- /@sindresorhus/is/0.14.0:
- resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==}
- engines: {node: '>=6'}
- dev: true
-
- /@szmarczak/http-timer/1.1.2:
- resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==}
- engines: {node: '>=6'}
- dependencies:
- defer-to-connect: 1.1.3
- dev: true
-
- /@tootallnate/once/1.1.2:
- resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}
- engines: {node: '>= 6'}
+ /@tanstack/virtual-core@3.2.1:
+ resolution: {integrity: sha512-nO0d4vRzsmpBQCJYyClNHPPoUMI4nXNfrm6IcCRL33ncWMoNVpURh9YebEHPw8KrtsP2VSJIHE4gf4XFGk1OGg==}
dev: false
- optional: true
- /@tootallnate/once/2.0.0:
- resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
- engines: {node: '>= 10'}
+ /@tokenizer/token@0.3.0:
+ resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
dev: true
- /@types/accepts/1.3.5:
- resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==}
+ /@ts-morph/common@0.19.0:
+ resolution: {integrity: sha512-Unz/WHmd4pGax91rdIKWi51wnVUW11QttMEPpBiBgIewnc9UQIX7UDLxr5vRlqeByXCwhkF6VabSsI0raWcyAQ==}
dependencies:
- '@types/node': 14.18.21
-
- /@types/body-parser/1.19.2:
- resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
- dependencies:
- '@types/connect': 3.4.35
- '@types/node': 14.18.21
-
- /@types/connect/3.4.35:
- resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
- dependencies:
- '@types/node': 14.18.21
-
- /@types/content-disposition/0.5.5:
- resolution: {integrity: sha512-v6LCdKfK6BwcqMo+wYW05rLS12S0ZO0Fl4w1h4aaZMD7bqT3gVUns6FvLJKGZHQmYn3SX55JWGpziwJRwVgutA==}
-
- /@types/cookies/0.7.7:
- resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==}
- dependencies:
- '@types/connect': 3.4.35
- '@types/express': 4.17.13
- '@types/keygrip': 1.0.2
- '@types/node': 14.18.21
-
- /@types/debug/4.1.7:
- resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
- dependencies:
- '@types/ms': 0.7.31
+ fast-glob: 3.3.2
+ minimatch: 7.4.6
+ mkdirp: 2.1.6
+ path-browserify: 1.0.1
dev: true
- /@types/express-serve-static-core/4.17.29:
- resolution: {integrity: sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==}
+ /@types/accepts@1.3.7:
+ resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==}
dependencies:
- '@types/node': 14.18.21
- '@types/qs': 6.9.7
- '@types/range-parser': 1.2.4
+ '@types/node': 20.12.3
+ dev: true
- /@types/express/4.17.13:
- resolution: {integrity: sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==}
+ /@types/better-sqlite3@7.6.9:
+ resolution: {integrity: sha512-FvktcujPDj9XKMJQWFcl2vVl7OdRIqsSRX9b0acWwTmwLK9CF2eqo/FRcmMLNpugKoX/avA6pb7TorDLmpgTnQ==}
dependencies:
- '@types/body-parser': 1.19.2
- '@types/express-serve-static-core': 4.17.29
- '@types/qs': 6.9.7
- '@types/serve-static': 1.13.10
+ '@types/node': 20.12.3
+ dev: true
- /@types/fs-extra/9.0.13:
- resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
+ /@types/body-parser@1.19.5:
+ resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
dependencies:
- '@types/node': 14.18.21
+ '@types/connect': 3.4.38
+ '@types/node': 20.12.3
dev: true
- /@types/glob/7.2.0:
- resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
- requiresBuild: true
+ /@types/cacheable-request@6.0.3:
+ resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
dependencies:
- '@types/minimatch': 3.0.5
- '@types/node': 14.18.21
- dev: true
- optional: true
-
- /@types/http-assert/1.5.3:
- resolution: {integrity: sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==}
-
- /@types/http-errors/1.8.2:
- resolution: {integrity: sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==}
-
- /@types/json-schema/7.0.11:
- resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
+ '@types/http-cache-semantics': 4.0.4
+ '@types/keyv': 3.1.4
+ '@types/node': 20.12.3
+ '@types/responselike': 1.0.3
dev: true
- /@types/jsonwebtoken/8.5.8:
- resolution: {integrity: sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==}
+ /@types/connect@3.4.38:
+ resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
dependencies:
- '@types/node': 14.18.21
+ '@types/node': 20.12.3
dev: true
- /@types/keygrip/1.0.2:
- resolution: {integrity: sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==}
+ /@types/content-disposition@0.5.8:
+ resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==}
+ dev: true
- /@types/koa-bodyparser/4.3.7:
- resolution: {integrity: sha512-21NhEp7LjZm4zbNV5alHHmrNY4J+S7B8lYTO6CzRL8ShTMnl20Gd14dRgVhAxraLaW5iZMofox+BycbuiDvj2Q==}
+ /@types/cookies@0.9.0:
+ resolution: {integrity: sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==}
dependencies:
- '@types/koa': 2.13.4
+ '@types/connect': 3.4.38
+ '@types/express': 4.17.21
+ '@types/keygrip': 1.0.6
+ '@types/node': 20.12.3
dev: true
- /@types/koa-compose/3.2.5:
- resolution: {integrity: sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==}
+ /@types/estree@1.0.5:
+ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+ dev: true
+
+ /@types/express-serve-static-core@4.17.43:
+ resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==}
dependencies:
- '@types/koa': 2.13.4
+ '@types/node': 20.12.3
+ '@types/qs': 6.9.14
+ '@types/range-parser': 1.2.7
+ '@types/send': 0.17.4
+ dev: true
- /@types/koa-router/7.4.4:
- resolution: {integrity: sha512-3dHlZ6CkhgcWeF6wafEUvyyqjWYfKmev3vy1PtOmr0mBc3wpXPU5E8fBBd4YQo5bRpHPfmwC5yDaX7s4jhIN6A==}
+ /@types/express@4.17.21:
+ resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
dependencies:
- '@types/koa': 2.13.4
+ '@types/body-parser': 1.19.5
+ '@types/express-serve-static-core': 4.17.43
+ '@types/qs': 6.9.14
+ '@types/serve-static': 1.15.5
dev: true
- /@types/koa/2.13.4:
- resolution: {integrity: sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw==}
+ /@types/http-assert@1.5.5:
+ resolution: {integrity: sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==}
+ dev: true
+
+ /@types/http-cache-semantics@4.0.4:
+ resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
+ dev: true
+
+ /@types/http-errors@2.0.4:
+ resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
+ dev: true
+
+ /@types/json-schema@7.0.15:
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ dev: true
+
+ /@types/jsonwebtoken@8.5.9:
+ resolution: {integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==}
dependencies:
- '@types/accepts': 1.3.5
- '@types/content-disposition': 0.5.5
- '@types/cookies': 0.7.7
- '@types/http-assert': 1.5.3
- '@types/http-errors': 1.8.2
- '@types/keygrip': 1.0.2
- '@types/koa-compose': 3.2.5
- '@types/node': 14.18.21
-
- /@types/mime/1.3.2:
- resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
-
- /@types/minimatch/3.0.5:
- resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==}
- dev: true
- optional: true
-
- /@types/ms/0.7.31:
- resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
+ '@types/node': 20.12.3
dev: true
- /@types/node/12.20.55:
- resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
+ /@types/keygrip@1.0.6:
+ resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
dev: true
- /@types/node/14.18.21:
- resolution: {integrity: sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q==}
-
- /@types/plist/3.0.2:
- resolution: {integrity: sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==}
- requiresBuild: true
+ /@types/keyv@3.1.4:
+ resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
- '@types/node': 14.18.21
- xmlbuilder: 15.1.1
+ '@types/node': 20.12.3
dev: true
- optional: true
- /@types/qs/6.9.7:
- resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
-
- /@types/range-parser/1.2.4:
- resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
-
- /@types/serve-static/1.13.10:
- resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==}
+ /@types/koa-bodyparser@4.3.12:
+ resolution: {integrity: sha512-hKMmRMVP889gPIdLZmmtou/BijaU1tHPyMNmcK7FAHAdATnRcGQQy78EqTTxLH1D4FTsrxIzklAQCso9oGoebQ==}
dependencies:
- '@types/mime': 1.3.2
- '@types/node': 14.18.21
-
- /@types/tiny-async-pool/1.0.1:
- resolution: {integrity: sha512-7msTTzXOAI9zS/u4DJLMAfAT/sz1laaZTFYVB83h0L78q4yB8RzRyxcqUlfkg12/hMC6G/cG//vbDwmdTpZ+gQ==}
+ '@types/koa': 2.15.0
dev: true
- /@types/verror/1.10.5:
- resolution: {integrity: sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==}
- requiresBuild: true
- dev: true
- optional: true
-
- /@types/yargs-parser/21.0.0:
- resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
- dev: true
-
- /@types/yargs/17.0.10:
- resolution: {integrity: sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==}
+ /@types/koa-compose@3.2.8:
+ resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==}
dependencies:
- '@types/yargs-parser': 21.0.0
+ '@types/koa': 2.15.0
dev: true
- /abbrev/1.1.1:
+ /@types/koa-router@7.4.8:
+ resolution: {integrity: sha512-SkWlv4F9f+l3WqYNQHnWjYnyTxYthqt8W9az2RTdQW7Ay8bc00iRZcrb8MC75iEfPqnGcg2csEl8tTG1NQPD4A==}
+ dependencies:
+ '@types/koa': 2.15.0
+ dev: true
+
+ /@types/koa@2.15.0:
+ resolution: {integrity: sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==}
+ dependencies:
+ '@types/accepts': 1.3.7
+ '@types/content-disposition': 0.5.8
+ '@types/cookies': 0.9.0
+ '@types/http-assert': 1.5.5
+ '@types/http-errors': 2.0.4
+ '@types/keygrip': 1.0.6
+ '@types/koa-compose': 3.2.8
+ '@types/node': 20.12.3
+ dev: true
+
+ /@types/mime@1.3.5:
+ resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
+ dev: true
+
+ /@types/mime@3.0.4:
+ resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==}
+ dev: true
+
+ /@types/node@20.12.3:
+ resolution: {integrity: sha512-sD+ia2ubTeWrOu+YMF+MTAB7E+O7qsMqAbMfW7DG3K1URwhZ5hN1pLlRVGbf4wDFzSfikL05M17EyorS86jShw==}
+ dependencies:
+ undici-types: 5.26.5
+ dev: true
+
+ /@types/prop-types@15.7.12:
+ resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
+
+ /@types/qs@6.9.14:
+ resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==}
+ dev: true
+
+ /@types/range-parser@1.2.7:
+ resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
+ dev: true
+
+ /@types/react-dom@18.2.22:
+ resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==}
+ dependencies:
+ '@types/react': 18.2.71
+
+ /@types/react@18.2.71:
+ resolution: {integrity: sha512-PxEsB9OjmQeYGffoWnYAd/r5FiJuUw2niFQHPc2v2idwh8wGPkkYzOHuinNJJY6NZqfoTCiOIizDOz38gYNsyw==}
+ dependencies:
+ '@types/prop-types': 15.7.12
+ '@types/scheduler': 0.23.0
+ csstype: 3.1.3
+
+ /@types/responselike@1.0.3:
+ resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
+ dependencies:
+ '@types/node': 20.12.3
+ dev: true
+
+ /@types/scheduler@0.23.0:
+ resolution: {integrity: sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==}
+
+ /@types/semver@7.5.8:
+ resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
+ dev: true
+
+ /@types/send@0.17.4:
+ resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
+ dependencies:
+ '@types/mime': 1.3.5
+ '@types/node': 20.12.3
+ dev: true
+
+ /@types/serve-static@1.15.5:
+ resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==}
+ dependencies:
+ '@types/http-errors': 2.0.4
+ '@types/mime': 3.0.4
+ '@types/node': 20.12.3
+ dev: true
+
+ /@types/tiny-async-pool@1.0.5:
+ resolution: {integrity: sha512-8hqr+s4rBthBtb+k02NXejl7BGVbj7CD/ZB2rMSvoSjXO52aXbtm9q/JEey5uDjzADs/zXEo7bU9iX+M6glAUA==}
+ dev: true
+
+ /@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^7.0.0
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@eslint-community/regexpp': 4.10.0
+ '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/scope-manager': 7.4.0
+ '@typescript-eslint/type-utils': 7.4.0(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.4.3)
+ '@typescript-eslint/visitor-keys': 7.4.0
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 8.57.0
+ graphemer: 1.4.0
+ ignore: 5.3.1
+ natural-compare: 1.4.0
+ semver: 7.6.0
+ ts-api-utils: 1.3.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/scope-manager': 7.4.0
+ '@typescript-eslint/types': 7.4.0
+ '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.4.3)
+ '@typescript-eslint/visitor-keys': 7.4.0
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 8.57.0
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/scope-manager@7.4.0:
+ resolution: {integrity: sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ dependencies:
+ '@typescript-eslint/types': 7.4.0
+ '@typescript-eslint/visitor-keys': 7.4.0
+ dev: true
+
+ /@typescript-eslint/type-utils@7.4.0(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.4.3)
+ '@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.4.3)
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 8.57.0
+ ts-api-utils: 1.3.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/types@7.4.0:
+ resolution: {integrity: sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ dev: true
+
+ /@typescript-eslint/typescript-estree@7.4.0(typescript@5.4.3):
+ resolution: {integrity: sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/types': 7.4.0
+ '@typescript-eslint/visitor-keys': 7.4.0
+ debug: 4.3.4(supports-color@5.5.0)
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.3
+ semver: 7.6.0
+ ts-api-utils: 1.3.0(typescript@5.4.3)
+ typescript: 5.4.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/utils@7.4.0(eslint@8.57.0)(typescript@5.4.3):
+ resolution: {integrity: sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@types/json-schema': 7.0.15
+ '@types/semver': 7.5.8
+ '@typescript-eslint/scope-manager': 7.4.0
+ '@typescript-eslint/types': 7.4.0
+ '@typescript-eslint/typescript-estree': 7.4.0(typescript@5.4.3)
+ eslint: 8.57.0
+ semver: 7.6.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /@typescript-eslint/visitor-keys@7.4.0:
+ resolution: {integrity: sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==}
+ engines: {node: ^18.18.0 || >=20.0.0}
+ dependencies:
+ '@typescript-eslint/types': 7.4.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@ungap/structured-clone@1.2.0:
+ resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+ dev: true
+
+ /@vitejs/plugin-react-swc@3.6.0(vite@5.2.6):
+ resolution: {integrity: sha512-XFRbsGgpGxGzEV5i5+vRiro1bwcIaZDIdBRP16qwm+jP68ue/S8FJTBEgOeojtVDYrbSua3XFp71kC8VJE6v+g==}
+ peerDependencies:
+ vite: ^4 || ^5
+ dependencies:
+ '@swc/core': 1.4.11
+ vite: 5.2.6(@types/node@20.12.3)
+ transitivePeerDependencies:
+ - '@swc/helpers'
+ dev: true
+
+ /@zip.js/zip.js@2.7.40:
+ resolution: {integrity: sha512-kSYwO0Wth6G66QM4CejZqG0nRhBsVVTaR18M/Ta8EcqcvaV0dYrnDDyKAstfy0V5+ejK4b9w5xc1W0ECATJTvA==}
+ engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'}
+ dev: false
+
+ /abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
- dev: false
+ dev: true
- /accepts/1.3.8:
+ /accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
dependencies:
@@ -384,44 +2257,30 @@ packages:
negotiator: 0.6.3
dev: false
- /agent-base/6.0.2:
- resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
- engines: {node: '>= 6.0.0'}
- dependencies:
- debug: 4.3.4
- transitivePeerDependencies:
- - supports-color
-
- /agentkeepalive/4.2.1:
- resolution: {integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==}
- engines: {node: '>= 8.0.0'}
- dependencies:
- debug: 4.3.4
- depd: 1.1.2
- humanize-ms: 1.2.1
- transitivePeerDependencies:
- - supports-color
- dev: false
- optional: true
-
- /aggregate-error/3.1.0:
- resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
- engines: {node: '>=8'}
- dependencies:
- clean-stack: 2.2.0
- indent-string: 4.0.0
- dev: false
- optional: true
-
- /ajv-keywords/3.5.2_ajv@6.12.6:
- resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
+ /acorn-jsx@5.3.2(acorn@8.11.3):
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
- ajv: ^6.9.1
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
- ajv: 6.12.6
+ acorn: 8.11.3
dev: true
- /ajv/6.12.6:
+ /acorn@8.11.3:
+ resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /agent-base@7.1.1:
+ resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
+ engines: {node: '>= 14'}
+ dependencies:
+ debug: 4.3.4(supports-color@5.5.0)
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies:
fast-deep-equal: 3.1.3
@@ -430,308 +2289,205 @@ packages:
uri-js: 4.4.1
dev: true
- /ansi-align/3.0.1:
- resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
- dependencies:
- string-width: 4.2.3
- dev: true
-
- /ansi-regex/5.0.1:
+ /ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
- /ansi-styles/4.3.0:
+ /ansi-regex@6.0.1:
+ resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+ engines: {node: '>=12'}
+
+ /ansi-styles@3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+ engines: {node: '>=4'}
+ dependencies:
+ color-convert: 1.9.3
+ dev: true
+
+ /ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
- dev: true
- /anymatch/3.1.2:
- resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
+ /ansi-styles@6.2.1:
+ resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ engines: {node: '>=12'}
+
+ /any-promise@1.3.0:
+ resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+
+ /anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
- dev: false
- /app-builder-bin/3.7.1:
- resolution: {integrity: sha512-ql93vEUq6WsstGXD+SBLSIQw6SNnhbDEM0swzgugytMxLp3rT24Ag/jcC80ZHxiPRTdew1niuR7P3/FCrDqIjw==}
+ /arch@2.2.0:
+ resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==}
dev: true
- /app-builder-lib/22.14.13:
- resolution: {integrity: sha512-SufmrtxU+D0Tn948fjEwAOlCN9757UXLkzzTWXMwZKR/5hisvgqeeBepWfphMIE6OkDGz0fbzEhL1P2Pty4XMg==}
- engines: {node: '>=14.0.0'}
- dependencies:
- '@develar/schema-utils': 2.6.5
- '@electron/universal': 1.0.5
- '@malept/flatpak-bundler': 0.4.0
- 7zip-bin: 5.1.1
- async-exit-hook: 2.0.1
- bluebird-lst: 1.0.9
- builder-util: 22.14.13
- builder-util-runtime: 8.9.2
- chromium-pickle-js: 0.2.0
- debug: 4.3.4
- ejs: 3.1.8
- electron-osx-sign: 0.5.0
- electron-publish: 22.14.13
- form-data: 4.0.0
- fs-extra: 10.1.0
- hosted-git-info: 4.1.0
- is-ci: 3.0.1
- isbinaryfile: 4.0.10
- js-yaml: 4.1.0
- lazy-val: 1.0.5
- minimatch: 3.1.2
- read-config-file: 6.2.0
- sanitize-filename: 1.6.3
- semver: 7.3.7
- temp-file: 3.4.0
- transitivePeerDependencies:
- - supports-color
- dev: true
+ /arg@5.0.2:
+ resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
- /aproba/2.0.0:
- resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
- dev: false
-
- /are-we-there-yet/2.0.0:
- resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
- engines: {node: '>=10'}
- dependencies:
- delegates: 1.0.0
- readable-stream: 3.6.0
- dev: false
-
- /are-we-there-yet/3.0.0:
- resolution: {integrity: sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16}
- dependencies:
- delegates: 1.0.0
- readable-stream: 3.6.0
- dev: false
- optional: true
-
- /arg/4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
- dev: true
-
- /argparse/2.0.1:
+ /argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
- /asar/3.1.0:
- resolution: {integrity: sha512-vyxPxP5arcAqN4F/ebHd/HhwnAiZtwhglvdmc7BR2f0ywbVNTOpSeyhLDbGXtE/y58hv1oC75TaNIXutnsOZsQ==}
- engines: {node: '>=10.12.0'}
- hasBin: true
- dependencies:
- chromium-pickle-js: 0.2.0
- commander: 5.1.0
- glob: 7.2.3
- minimatch: 3.1.2
- optionalDependencies:
- '@types/glob': 7.2.0
- dev: true
-
- /assert-plus/1.0.0:
- resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
- engines: {node: '>=0.8'}
- requiresBuild: true
- dev: true
- optional: true
-
- /astral-regex/2.0.0:
- resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
- engines: {node: '>=8'}
- requiresBuild: true
- dev: true
- optional: true
-
- /async-exit-hook/2.0.1:
- resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==}
- engines: {node: '>=0.12.0'}
- dev: true
-
- /async/3.2.4:
- resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
- dev: true
-
- /asynckit/0.4.0:
- resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
- dev: true
-
- /at-least-node/1.0.0:
- resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
- engines: {node: '>= 4.0.0'}
- dev: true
-
- /balanced-match/1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-
- /base64-js/1.5.1:
- resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
- requiresBuild: true
- dev: true
-
- /binary-extensions/2.2.0:
- resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
- engines: {node: '>=8'}
- dev: false
-
- /bluebird-lst/1.0.9:
- resolution: {integrity: sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==}
- dependencies:
- bluebird: 3.7.2
- dev: true
-
- /bluebird/3.7.2:
- resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
- dev: true
-
- /boolean/3.2.0:
- resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==}
- dev: true
- optional: true
-
- /boxen/5.1.2:
- resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
+ /aria-hidden@1.2.4:
+ resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
engines: {node: '>=10'}
dependencies:
- ansi-align: 3.0.1
- camelcase: 6.3.0
- chalk: 4.1.2
- cli-boxes: 2.2.1
- string-width: 4.2.3
- type-fest: 0.20.2
- widest-line: 3.1.0
- wrap-ansi: 7.0.0
+ tslib: 2.6.2
+ dev: false
+
+ /array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
dev: true
- /brace-expansion/1.1.11:
+ /ast-types@0.16.1:
+ resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
+ engines: {node: '>=4'}
+ dependencies:
+ tslib: 2.6.2
+ dev: true
+
+ /autoprefixer@10.4.19(postcss@8.4.38):
+ resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
+ engines: {node: ^10 || ^12 || >=14}
+ hasBin: true
+ peerDependencies:
+ postcss: ^8.1.0
+ dependencies:
+ browserslist: 4.23.0
+ caniuse-lite: 1.0.30001605
+ fraction.js: 4.3.7
+ normalize-range: 0.1.2
+ picocolors: 1.0.0
+ postcss: 8.4.38
+ postcss-value-parser: 4.2.0
+ dev: true
+
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ /base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+ /better-sqlite3@9.4.3:
+ resolution: {integrity: sha512-ud0bTmD9O3uWJGuXDltyj3R47Nz0OHX8iqPOT5PMspGqlu/qQFn+5S2eFBUCrySpavTjFXbi4EgrfVvPAHlImw==}
+ requiresBuild: true
+ dependencies:
+ bindings: 1.5.0
+ prebuild-install: 7.1.2
+
+ /bin-check@4.1.0:
+ resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==}
+ engines: {node: '>=4'}
+ dependencies:
+ execa: 0.7.0
+ executable: 4.1.1
+ dev: true
+
+ /bin-version-check@5.1.0:
+ resolution: {integrity: sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==}
+ engines: {node: '>=12'}
+ dependencies:
+ bin-version: 6.0.0
+ semver: 7.6.0
+ semver-truncate: 3.0.0
+ dev: true
+
+ /bin-version@6.0.0:
+ resolution: {integrity: sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==}
+ engines: {node: '>=12'}
+ dependencies:
+ execa: 5.1.1
+ find-versions: 5.1.0
+ dev: true
+
+ /binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
+ /bindings@1.5.0:
+ resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
+ dependencies:
+ file-uri-to-path: 1.0.0
+
+ /bl@4.1.0:
+ resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+ dependencies:
+ buffer: 5.7.1
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+
+ /bl@5.1.0:
+ resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==}
+ dependencies:
+ buffer: 6.0.3
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: true
+
+ /brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
+ dev: true
- /brace-expansion/2.0.1:
+ /brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
- dev: true
- /braces/3.0.2:
+ /braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
- dev: false
- /buffer-alloc-unsafe/1.1.0:
- resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==}
- dev: true
-
- /buffer-alloc/1.2.0:
- resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==}
+ /browserslist@4.23.0:
+ resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
dependencies:
- buffer-alloc-unsafe: 1.1.0
- buffer-fill: 1.0.0
+ caniuse-lite: 1.0.30001605
+ electron-to-chromium: 1.4.724
+ node-releases: 2.0.14
+ update-browserslist-db: 1.0.13(browserslist@4.23.0)
dev: true
- /buffer-crc32/0.2.13:
- resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
-
- /buffer-equal-constant-time/1.0.1:
+ /buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
dev: false
- /buffer-equal/1.0.0:
- resolution: {integrity: sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ==}
- engines: {node: '>=0.4.0'}
- dev: true
-
- /buffer-fill/1.0.0:
- resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==}
- dev: true
-
- /buffer-from/1.1.2:
+ /buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
- /buffer/5.7.1:
+ /buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
- requiresBuild: true
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+
+ /buffer@6.0.3:
+ resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: true
- optional: true
- /builder-util-runtime/8.9.2:
- resolution: {integrity: sha512-rhuKm5vh7E0aAmT6i8aoSfEjxzdYEFX7zDApK+eNgOhjofnWb74d9SRJv0H/8nsgOkos0TZ4zxW0P8J4N7xQ2A==}
- engines: {node: '>=12.0.0'}
- dependencies:
- debug: 4.3.4
- sax: 1.2.4
- transitivePeerDependencies:
- - supports-color
- dev: true
-
- /builder-util/22.14.13:
- resolution: {integrity: sha512-oePC/qrrUuerhmH5iaCJzPRAKlSBylrhzuAJmRQClTyWnZUv6jbaHh+VoHMbEiE661wrj2S2aV7/bQh12cj1OA==}
- dependencies:
- '@types/debug': 4.1.7
- '@types/fs-extra': 9.0.13
- 7zip-bin: 5.1.1
- app-builder-bin: 3.7.1
- bluebird-lst: 1.0.9
- builder-util-runtime: 8.9.2
- chalk: 4.1.2
- cross-spawn: 7.0.3
- debug: 4.3.4
- fs-extra: 10.1.0
- http-proxy-agent: 5.0.0
- https-proxy-agent: 5.0.1
- is-ci: 3.0.1
- js-yaml: 4.1.0
- source-map-support: 0.5.21
- stat-mode: 1.0.0
- temp-file: 3.4.0
- transitivePeerDependencies:
- - supports-color
- dev: true
-
- /bytes/3.1.2:
+ /bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
dev: false
- /cacache/15.3.0:
- resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==}
- engines: {node: '>= 10'}
- dependencies:
- '@npmcli/fs': 1.1.1
- '@npmcli/move-file': 1.1.2
- chownr: 2.0.0
- fs-minipass: 2.1.0
- glob: 7.2.3
- infer-owner: 1.0.4
- lru-cache: 6.0.0
- minipass: 3.3.3
- minipass-collect: 1.0.2
- minipass-flush: 1.0.5
- minipass-pipeline: 1.2.4
- mkdirp: 1.0.4
- p-map: 4.0.0
- promise-inflight: 1.0.1
- rimraf: 3.0.2
- ssri: 8.0.1
- tar: 6.1.11
- unique-filename: 1.1.1
- dev: false
- optional: true
-
- /cache-content-type/1.0.1:
+ /cache-content-type@1.0.1:
resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==}
engines: {node: '>= 6.0.0'}
dependencies:
@@ -739,32 +2495,58 @@ packages:
ylru: 1.3.2
dev: false
- /cacheable-request/6.1.0:
- resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==}
+ /cacheable-lookup@5.0.4:
+ resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
+ engines: {node: '>=10.6.0'}
+ dev: true
+
+ /cacheable-request@7.0.4:
+ resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
engines: {node: '>=8'}
dependencies:
- clone-response: 1.0.2
+ clone-response: 1.0.3
get-stream: 5.2.0
- http-cache-semantics: 4.1.0
- keyv: 3.1.0
+ http-cache-semantics: 4.1.1
+ keyv: 4.5.4
lowercase-keys: 2.0.0
- normalize-url: 4.5.1
- responselike: 1.0.2
+ normalize-url: 6.1.0
+ responselike: 2.0.1
dev: true
- /call-bind/1.0.2:
- resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+ /call-bind@1.0.7:
+ resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+ engines: {node: '>= 0.4'}
dependencies:
- function-bind: 1.1.1
- get-intrinsic: 1.1.2
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ set-function-length: 1.2.2
dev: false
- /camelcase/6.3.0:
- resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
- engines: {node: '>=10'}
+ /callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
dev: true
- /chalk/4.1.2:
+ /camelcase-css@2.0.1:
+ resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
+ engines: {node: '>= 6'}
+
+ /caniuse-lite@1.0.30001605:
+ resolution: {integrity: sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==}
+ dev: true
+
+ /chalk@2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ ansi-styles: 3.2.1
+ escape-string-regexp: 1.0.5
+ supports-color: 5.5.0
+ dev: true
+
+ /chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
dependencies:
@@ -772,11 +2554,16 @@ packages:
supports-color: 7.2.0
dev: true
- /chokidar/3.5.3:
- resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ /chalk@5.2.0:
+ resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ dev: true
+
+ /chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
dependencies:
- anymatch: 3.1.2
+ anymatch: 3.1.3
braces: 3.0.2
glob-parent: 5.1.2
is-binary-path: 2.1.0
@@ -784,250 +2571,186 @@ packages:
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
- fsevents: 2.3.2
+ fsevents: 2.3.3
+
+ /chownr@1.1.4:
+ resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+
+ /class-variance-authority@0.7.0:
+ resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==}
+ dependencies:
+ clsx: 2.0.0
dev: false
- /chownr/2.0.0:
- resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
- engines: {node: '>=10'}
- dev: false
-
- /chromium-pickle-js/0.2.0:
- resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==}
+ /cli-cursor@4.0.0:
+ resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ restore-cursor: 4.0.0
dev: true
- /ci-info/2.0.0:
- resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==}
- dev: true
-
- /ci-info/3.3.2:
- resolution: {integrity: sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==}
- dev: true
-
- /clean-stack/2.2.0:
- resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
- engines: {node: '>=6'}
- dev: false
- optional: true
-
- /cli-boxes/2.2.1:
- resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==}
+ /cli-spinners@2.9.2:
+ resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
engines: {node: '>=6'}
dev: true
- /cli-truncate/2.1.0:
- resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
- engines: {node: '>=8'}
- requiresBuild: true
- dependencies:
- slice-ansi: 3.0.0
- string-width: 4.2.3
- dev: true
- optional: true
+ /client-only@0.0.1:
+ resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
+ dev: false
- /cliui/7.0.4:
- resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
- dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 7.0.0
- dev: true
-
- /clone-response/1.0.2:
- resolution: {integrity: sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==}
+ /clone-response@1.0.3:
+ resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
dependencies:
mimic-response: 1.0.1
dev: true
- /co-body/6.1.0:
+ /clone@1.0.4:
+ resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
+ engines: {node: '>=0.8'}
+ dev: true
+
+ /clsx@2.0.0:
+ resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /clsx@2.1.0:
+ resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /co-body@6.1.0:
resolution: {integrity: sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==}
dependencies:
- inflation: 2.0.0
- qs: 6.10.5
- raw-body: 2.5.1
+ inflation: 2.1.0
+ qs: 6.12.0
+ raw-body: 2.5.2
type-is: 1.6.18
dev: false
- /co/4.6.0:
+ /co@4.6.0:
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
dev: false
- /color-convert/2.0.1:
+ /code-block-writer@12.0.0:
+ resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==}
+ dev: true
+
+ /color-convert@1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ dependencies:
+ color-name: 1.1.3
+ dev: true
+
+ /color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
+
+ /color-name@1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
dev: true
- /color-name/1.1.4:
+ /color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ /colorette@2.0.20:
+ resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
dev: true
- /color-support/1.1.3:
- resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
- hasBin: true
- dev: false
-
- /colorette/2.0.16:
- resolution: {integrity: sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==}
- dev: false
-
- /colors/1.0.3:
- resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==}
- engines: {node: '>=0.1.90'}
+ /commander@10.0.1:
+ resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
+ engines: {node: '>=14'}
dev: true
- /combined-stream/1.0.8:
- resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
- engines: {node: '>= 0.8'}
- dependencies:
- delayed-stream: 1.0.0
- dev: true
-
- /commander/2.9.0:
- resolution: {integrity: sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==}
- engines: {node: '>= 0.6.x'}
- dependencies:
- graceful-readlink: 1.0.1
- dev: true
-
- /commander/5.1.0:
- resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
+ /commander@4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
+
+ /commander@8.3.0:
+ resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
+ engines: {node: '>= 12'}
dev: true
- /commander/6.2.1:
- resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
- engines: {node: '>= 6'}
- dev: true
-
- /commander/7.2.0:
- resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
- engines: {node: '>= 10'}
- dev: false
-
- /compare-version/0.1.2:
- resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /concat-map/0.0.1:
+ /concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
- /concat-stream/1.6.2:
- resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
- engines: {'0': node >= 0.8}
- dependencies:
- buffer-from: 1.1.2
- inherits: 2.0.4
- readable-stream: 2.3.7
- typedarray: 0.0.6
dev: true
- /config-chain/1.1.13:
- resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
- dependencies:
- ini: 1.3.8
- proto-list: 1.2.4
- dev: true
- optional: true
-
- /configstore/5.0.1:
- resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==}
- engines: {node: '>=8'}
- dependencies:
- dot-prop: 5.3.0
- graceful-fs: 4.2.10
- make-dir: 3.1.0
- unique-string: 2.0.0
- write-file-atomic: 3.0.3
- xdg-basedir: 4.0.0
- dev: true
-
- /console-control-strings/1.1.0:
- resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
- dev: false
-
- /content-disposition/0.5.4:
+ /content-disposition@0.5.4:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
dependencies:
safe-buffer: 5.2.1
- dev: false
- /content-type/1.0.4:
- resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==}
+ /content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
dev: false
- /cookies/0.8.0:
- resolution: {integrity: sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==}
+ /convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ dev: true
+
+ /cookies@0.9.1:
+ resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}
engines: {node: '>= 0.8'}
dependencies:
depd: 2.0.0
keygrip: 1.1.0
dev: false
- /copy-to/2.0.1:
+ /copy-to@2.0.1:
resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==}
dev: false
- /core-util-is/1.0.2:
- resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
- requiresBuild: true
- dev: true
- optional: true
-
- /core-util-is/1.0.3:
- resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
- dev: true
-
- /crc/3.8.0:
- resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==}
- requiresBuild: true
+ /cosmiconfig@8.3.6(typescript@5.4.3):
+ resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ typescript: '>=4.9.5'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
dependencies:
- buffer: 5.7.1
- dev: true
- optional: true
-
- /create-require/1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ parse-json: 5.2.0
+ path-type: 4.0.0
+ typescript: 5.4.3
dev: true
- /cross-spawn/7.0.3:
+ /cross-spawn@5.1.0:
+ resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
+ dependencies:
+ lru-cache: 4.1.5
+ shebang-command: 1.2.0
+ which: 1.3.1
+ dev: true
+
+ /cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
+
+ /cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ /csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ /data-uri-to-buffer@4.0.1:
+ resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
+ engines: {node: '>= 12'}
dev: true
- /crypto-random-string/2.0.0:
- resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
- engines: {node: '>=8'}
- dev: true
-
- /debug/2.6.9:
- resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
- dependencies:
- ms: 2.0.0
- dev: true
-
- /debug/4.3.2:
- resolution: {integrity: sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.2
- dev: false
-
- /debug/4.3.4:
+ /debug@4.3.4(supports-color@5.5.0):
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
peerDependencies:
@@ -1037,463 +2760,632 @@ packages:
optional: true
dependencies:
ms: 2.1.2
+ supports-color: 5.5.0
- /decompress-response/3.3.0:
- resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==}
- engines: {node: '>=4'}
+ /decompress-response@6.0.0:
+ resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
+ engines: {node: '>=10'}
dependencies:
- mimic-response: 1.0.1
- dev: true
+ mimic-response: 3.1.0
- /deep-equal/1.0.1:
+ /deep-equal@1.0.1:
resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==}
dev: false
- /deep-extend/0.6.0:
+ /deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
+
+ /deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
- /defer-to-connect/1.1.3:
- resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==}
+ /defaults@1.0.4:
+ resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+ dependencies:
+ clone: 1.0.4
dev: true
- /define-properties/1.1.4:
- resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==}
+ /defer-to-connect@2.0.1:
+ resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'}
dependencies:
- has-property-descriptors: 1.0.0
- object-keys: 1.1.1
- dev: true
- optional: true
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ gopd: 1.0.1
+ dev: false
- /delayed-stream/1.0.0:
- resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
- engines: {node: '>=0.4.0'}
- dev: true
-
- /delegates/1.0.0:
+ /delegates@1.0.0:
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
dev: false
- /depd/1.1.2:
+ /depd@1.1.2:
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
engines: {node: '>= 0.6'}
dev: false
- /depd/2.0.0:
+ /depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
dev: false
- /destroy/1.2.0:
+ /destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
dev: false
- /detect-libc/2.0.1:
- resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==}
+ /detect-libc@2.0.3:
+ resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
engines: {node: '>=8'}
+
+ /detect-node-es@1.1.0:
+ resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
dev: false
- /detect-node/2.1.0:
- resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
- dev: true
- optional: true
+ /didyoumean@1.2.2:
+ resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
- /diff/4.0.2:
- resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
+ /diff@3.5.0:
+ resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==}
engines: {node: '>=0.3.1'}
dev: true
- /dir-compare/2.4.0:
- resolution: {integrity: sha512-l9hmu8x/rjVC9Z2zmGzkhOEowZvW7pmYws5CWHutg8u1JgvsKWMx7Q/UODeu4djLZ4FgW5besw5yvMQnBHzuCA==}
- hasBin: true
- dependencies:
- buffer-equal: 1.0.0
- colors: 1.0.3
- commander: 2.9.0
- minimatch: 3.0.4
+ /diff@5.2.0:
+ resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
+ engines: {node: '>=0.3.1'}
dev: true
- /dmg-builder/22.14.13:
- resolution: {integrity: sha512-xNOugB6AbIRETeU2uID15sUfjdZZcKdxK8xkFnwIggsM00PJ12JxpLNPTjcRoUnfwj3WrPjilrO64vRMwNItQg==}
- dependencies:
- app-builder-lib: 22.14.13
- builder-util: 22.14.13
- builder-util-runtime: 8.9.2
- fs-extra: 10.1.0
- iconv-lite: 0.6.3
- js-yaml: 4.1.0
- optionalDependencies:
- dmg-license: 1.0.11
- transitivePeerDependencies:
- - supports-color
- dev: true
-
- /dmg-license/1.0.11:
- resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==}
- engines: {node: '>=8'}
- os: [darwin]
- deprecated: 'Disk image license agreements are deprecated by Apple and will probably be removed in a future macOS release. Discussion at: https://github.com/argv-minus-one/dmg-license/issues/11'
- hasBin: true
- requiresBuild: true
- dependencies:
- '@types/plist': 3.0.2
- '@types/verror': 1.10.5
- ajv: 6.12.6
- crc: 3.8.0
- iconv-corefoundation: 1.1.7
- plist: 3.0.5
- smart-buffer: 4.2.0
- verror: 1.10.1
- dev: true
- optional: true
-
- /dot-prop/5.3.0:
- resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
+ /dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
dependencies:
- is-obj: 2.0.0
+ path-type: 4.0.0
dev: true
- /dotenv-expand/5.1.0:
- resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==}
- dev: true
+ /dlv@1.1.3:
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
- /dotenv/9.0.2:
- resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==}
- engines: {node: '>=10'}
- dev: true
-
- /dprint/0.36.1:
- resolution: {integrity: sha512-F8TaWlieYtJc4ktqr0tjNwg/HN4wNPTU6rTq29MdoIKXi9gQmh7Ibqr0oyW1hsLpqBuAXjjwEYIos9plYkwENQ==}
- hasBin: true
- requiresBuild: true
+ /doctrine@3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
dependencies:
- https-proxy-agent: 5.0.1
- yauzl: 2.10.0
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /duplexer3/0.1.4:
- resolution: {integrity: sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==}
+ esutils: 2.0.3
dev: true
- /ecdsa-sig-formatter/1.0.11:
+ /dotenv-expand@11.0.6:
+ resolution: {integrity: sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==}
+ engines: {node: '>=12'}
+ dependencies:
+ dotenv: 16.4.5
+ dev: true
+
+ /dotenv@16.4.5:
+ resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
+ engines: {node: '>=12'}
+
+ /eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+ /ecdsa-sig-formatter@1.0.11:
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
dependencies:
safe-buffer: 5.2.1
dev: false
- /ee-first/1.1.1:
+ /ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
dev: false
- /ejs/3.1.8:
- resolution: {integrity: sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==}
- engines: {node: '>=0.10.0'}
- hasBin: true
- dependencies:
- jake: 10.8.5
+ /electron-to-chromium@1.4.724:
+ resolution: {integrity: sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA==}
dev: true
- /electron-builder/22.14.13:
- resolution: {integrity: sha512-3fgLxqF2TXVKiUPeg74O4V3l0l3j7ERLazo8sUbRkApw0+4iVAf2BJkHsHMaXiigsgCoEzK/F4/rB5rne/VAnw==}
- engines: {node: '>=14.0.0'}
- hasBin: true
- dependencies:
- '@types/yargs': 17.0.10
- app-builder-lib: 22.14.13
- builder-util: 22.14.13
- builder-util-runtime: 8.9.2
- chalk: 4.1.2
- dmg-builder: 22.14.13
- fs-extra: 10.1.0
- is-ci: 3.0.1
- lazy-val: 1.0.5
- read-config-file: 6.2.0
- update-notifier: 5.1.0
- yargs: 17.5.1
- transitivePeerDependencies:
- - supports-color
- dev: true
-
- /electron-osx-sign/0.5.0:
- resolution: {integrity: sha512-icoRLHzFz/qxzDh/N4Pi2z4yVHurlsCAYQvsCSG7fCedJ4UJXBS6PoQyGH71IfcqKupcKeK7HX/NkyfG+v6vlQ==}
- engines: {node: '>=4.0.0'}
- hasBin: true
- dependencies:
- bluebird: 3.7.2
- compare-version: 0.1.2
- debug: 2.6.9
- isbinaryfile: 3.0.3
- minimist: 1.2.6
- plist: 3.0.5
- dev: true
-
- /electron-publish/22.14.13:
- resolution: {integrity: sha512-0oP3QiNj3e8ewOaEpEJV/o6Zrmy2VarVvZ/bH7kyO/S/aJf9x8vQsKVWpsdmSiZ5DJEHgarFIXrnO0ZQf0P9iQ==}
- dependencies:
- '@types/fs-extra': 9.0.13
- builder-util: 22.14.13
- builder-util-runtime: 8.9.2
- chalk: 4.1.2
- fs-extra: 10.1.0
- lazy-val: 1.0.5
- mime: 2.6.0
- transitivePeerDependencies:
- - supports-color
- dev: true
-
- /electron/11.5.0:
- resolution: {integrity: sha512-WjNDd6lGpxyiNjE3LhnFCAk/D9GIj1rU3GSDealVShhkkkPR3Vh4q8ErXGDl1OAO/faomVa10KoFPUN/pLbNxg==}
- engines: {node: '>= 8.6'}
- hasBin: true
- requiresBuild: true
- dependencies:
- '@electron/get': 1.14.1
- '@types/node': 12.20.55
- extract-zip: 1.7.0
- transitivePeerDependencies:
- - supports-color
- dev: true
-
- /emoji-regex/8.0.0:
+ /emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
- /encodeurl/1.0.2:
+ /emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ /encodeurl@1.0.2:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
-
- /encoding/0.1.13:
- resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
- requiresBuild: true
- dependencies:
- iconv-lite: 0.6.3
dev: false
- optional: true
- /end-of-stream/1.4.4:
+ /end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
dependencies:
once: 1.4.0
+
+ /error-ex@1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+ dependencies:
+ is-arrayish: 0.2.1
dev: true
- /env-paths/2.2.1:
- resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
- engines: {node: '>=6'}
-
- /err-code/2.0.3:
- resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
+ /es-define-property@1.0.0:
+ resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.4
dev: false
- optional: true
- /es6-error/4.1.1:
- resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
+ /es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+ dev: false
+
+ /esbuild@0.20.2:
+ resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.20.2
+ '@esbuild/android-arm': 0.20.2
+ '@esbuild/android-arm64': 0.20.2
+ '@esbuild/android-x64': 0.20.2
+ '@esbuild/darwin-arm64': 0.20.2
+ '@esbuild/darwin-x64': 0.20.2
+ '@esbuild/freebsd-arm64': 0.20.2
+ '@esbuild/freebsd-x64': 0.20.2
+ '@esbuild/linux-arm': 0.20.2
+ '@esbuild/linux-arm64': 0.20.2
+ '@esbuild/linux-ia32': 0.20.2
+ '@esbuild/linux-loong64': 0.20.2
+ '@esbuild/linux-mips64el': 0.20.2
+ '@esbuild/linux-ppc64': 0.20.2
+ '@esbuild/linux-riscv64': 0.20.2
+ '@esbuild/linux-s390x': 0.20.2
+ '@esbuild/linux-x64': 0.20.2
+ '@esbuild/netbsd-x64': 0.20.2
+ '@esbuild/openbsd-x64': 0.20.2
+ '@esbuild/sunos-x64': 0.20.2
+ '@esbuild/win32-arm64': 0.20.2
+ '@esbuild/win32-ia32': 0.20.2
+ '@esbuild/win32-x64': 0.20.2
dev: true
- optional: true
- /escalade/3.1.1:
- resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
+ /escalade@3.1.2:
+ resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
-
- /escape-goat/2.1.1:
- resolution: {integrity: sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==}
- engines: {node: '>=8'}
dev: true
- /escape-html/1.0.3:
+ /escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
dev: false
- /escape-string-regexp/4.0.0:
+ /escape-string-regexp@1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+ engines: {node: '>=0.8.0'}
+ dev: true
+
+ /escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
dev: true
- optional: true
- /esm/3.2.25:
- resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==}
- engines: {node: '>=6'}
- dev: false
+ /escape-string-regexp@5.0.0:
+ resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+ engines: {node: '>=12'}
+ dev: true
- /extract-zip/1.7.0:
- resolution: {integrity: sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==}
+ /eslint-plugin-react-hooks@4.6.0(eslint@8.57.0):
+ resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+ dependencies:
+ eslint: 8.57.0
+ dev: true
+
+ /eslint-plugin-react-refresh@0.4.6(eslint@8.57.0):
+ resolution: {integrity: sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA==}
+ peerDependencies:
+ eslint: '>=7'
+ dependencies:
+ eslint: 8.57.0
+ dev: true
+
+ /eslint-scope@7.2.2:
+ resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
+ /eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /eslint@8.57.0:
+ resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
- concat-stream: 1.6.2
- debug: 2.6.9
- mkdirp: 0.5.6
- yauzl: 2.10.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/regexpp': 4.10.0
+ '@eslint/eslintrc': 2.1.4
+ '@eslint/js': 8.57.0
+ '@humanwhocodes/config-array': 0.11.14
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ '@ungap/structured-clone': 1.2.0
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.4(supports-color@5.5.0)
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.5.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ globals: 13.24.0
+ graphemer: 1.4.0
+ ignore: 5.3.1
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ js-yaml: 4.1.0
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.3
+ strip-ansi: 6.0.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
dev: true
- /extsprintf/1.4.1:
- resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==}
- engines: {'0': node >=0.6.0}
- requiresBuild: true
+ /espree@9.6.1:
+ resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.11.3
+ acorn-jsx: 5.3.2(acorn@8.11.3)
+ eslint-visitor-keys: 3.4.3
dev: true
- optional: true
- /fast-deep-equal/3.1.3:
+ /esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /esquery@1.5.0:
+ resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /execa@0.7.0:
+ resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==}
+ engines: {node: '>=4'}
+ dependencies:
+ cross-spawn: 5.1.0
+ get-stream: 3.0.0
+ is-stream: 1.1.0
+ npm-run-path: 2.0.2
+ p-finally: 1.0.0
+ signal-exit: 3.0.7
+ strip-eof: 1.0.0
+ dev: true
+
+ /execa@5.1.1:
+ resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+ engines: {node: '>=10'}
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 6.0.1
+ human-signals: 2.1.0
+ is-stream: 2.0.1
+ merge-stream: 2.0.0
+ npm-run-path: 4.0.1
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ strip-final-newline: 2.0.0
+ dev: true
+
+ /execa@7.2.0:
+ resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
+ engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 6.0.1
+ human-signals: 4.3.1
+ is-stream: 3.0.0
+ merge-stream: 2.0.0
+ npm-run-path: 5.3.0
+ onetime: 6.0.0
+ signal-exit: 3.0.7
+ strip-final-newline: 3.0.0
+ dev: true
+
+ /executable@4.1.1:
+ resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==}
+ engines: {node: '>=4'}
+ dependencies:
+ pify: 2.3.0
+ dev: true
+
+ /expand-template@2.0.3:
+ resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
+ engines: {node: '>=6'}
+
+ /ext-list@2.2.2:
+ resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ mime-db: 1.52.0
+ dev: true
+
+ /ext-name@5.0.0:
+ resolution: {integrity: sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ ext-list: 2.2.2
+ sort-keys-length: 1.0.1
+ dev: true
+
+ /fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
- requiresBuild: true
dev: true
- /fast-json-stable-stringify/2.1.0:
+ /fast-glob@3.3.2:
+ resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.5
+
+ /fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: true
- /fd-slicer/1.1.0:
- resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
- dependencies:
- pend: 1.2.0
-
- /filelist/1.0.4:
- resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
- dependencies:
- minimatch: 5.1.0
+ /fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
dev: true
- /fill-range/7.0.1:
+ /fastq@1.17.1:
+ resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+ dependencies:
+ reusify: 1.0.4
+
+ /fetch-blob@3.2.0:
+ resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
+ engines: {node: ^12.20 || >= 14.13}
+ dependencies:
+ node-domexception: 1.0.0
+ web-streams-polyfill: 3.3.3
+ dev: true
+
+ /file-entry-cache@6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flat-cache: 3.2.0
+ dev: true
+
+ /file-type@17.1.6:
+ resolution: {integrity: sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ readable-web-to-node-stream: 3.0.2
+ strtok3: 7.0.0
+ token-types: 5.0.1
+ dev: true
+
+ /file-uri-to-path@1.0.0:
+ resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
+
+ /filename-reserved-regex@3.0.0:
+ resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /filenamify@5.1.1:
+ resolution: {integrity: sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==}
+ engines: {node: '>=12.20'}
+ dependencies:
+ filename-reserved-regex: 3.0.0
+ strip-outer: 2.0.0
+ trim-repeated: 2.0.0
+ dev: true
+
+ /fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
- dev: false
- /form-data/4.0.0:
- resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
- engines: {node: '>= 6'}
+ /find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
dependencies:
- asynckit: 0.4.0
- combined-stream: 1.0.8
- mime-types: 2.1.35
+ locate-path: 6.0.0
+ path-exists: 4.0.0
dev: true
- /fresh/0.5.2:
+ /find-versions@5.1.0:
+ resolution: {integrity: sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==}
+ engines: {node: '>=12'}
+ dependencies:
+ semver-regex: 4.0.5
+ dev: true
+
+ /flat-cache@3.2.0:
+ resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flatted: 3.3.1
+ keyv: 4.5.4
+ rimraf: 3.0.2
+ dev: true
+
+ /flatted@3.3.1:
+ resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
+ dev: true
+
+ /foreground-child@3.1.1:
+ resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+ engines: {node: '>=14'}
+ dependencies:
+ cross-spawn: 7.0.3
+ signal-exit: 4.1.0
+
+ /formdata-polyfill@4.0.10:
+ resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
+ engines: {node: '>=12.20.0'}
+ dependencies:
+ fetch-blob: 3.2.0
+ dev: true
+
+ /fraction.js@4.3.7:
+ resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+ dev: true
+
+ /fresh@0.5.2:
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
engines: {node: '>= 0.6'}
dev: false
- /fs-extra/10.1.0:
- resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
- engines: {node: '>=12'}
+ /fs-constants@1.0.0:
+ resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+
+ /fs-extra@11.2.0:
+ resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
+ engines: {node: '>=14.14'}
dependencies:
- graceful-fs: 4.2.10
+ graceful-fs: 4.2.11
jsonfile: 6.1.0
- universalify: 2.0.0
+ universalify: 2.0.1
dev: true
- /fs-extra/8.1.0:
- resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
- engines: {node: '>=6 <7 || >=8'}
- dependencies:
- graceful-fs: 4.2.10
- jsonfile: 4.0.0
- universalify: 0.1.2
- dev: true
-
- /fs-extra/9.1.0:
- resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
- engines: {node: '>=10'}
- dependencies:
- at-least-node: 1.0.0
- graceful-fs: 4.2.10
- jsonfile: 6.1.0
- universalify: 2.0.0
- dev: true
-
- /fs-minipass/2.1.0:
- resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
- engines: {node: '>= 8'}
- dependencies:
- minipass: 3.3.3
- dev: false
-
- /fs.realpath/1.0.0:
+ /fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ dev: true
- /fsevents/2.3.2:
- resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ /fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
- dev: false
optional: true
- /function-bind/1.1.1:
- resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
+ /function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
- /gauge/3.0.2:
- resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
- engines: {node: '>=10'}
- dependencies:
- aproba: 2.0.0
- color-support: 1.1.3
- console-control-strings: 1.1.0
- has-unicode: 2.0.1
- object-assign: 4.1.1
- signal-exit: 3.0.7
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wide-align: 1.1.5
- dev: false
-
- /gauge/4.0.4:
- resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- dependencies:
- aproba: 2.0.0
- color-support: 1.1.3
- console-control-strings: 1.1.0
- has-unicode: 2.0.1
- signal-exit: 3.0.7
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wide-align: 1.1.5
- dev: false
- optional: true
-
- /get-caller-file/2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
+ /gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
dev: true
- /get-intrinsic/1.1.2:
- resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==}
+ /get-intrinsic@1.2.4:
+ resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+ engines: {node: '>= 0.4'}
dependencies:
- function-bind: 1.1.1
- has: 1.0.3
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ has-proto: 1.0.3
has-symbols: 1.0.3
+ hasown: 2.0.2
+ dev: false
- /get-stream/4.1.0:
- resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
+ /get-nonce@1.0.1:
+ resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'}
- dependencies:
- pump: 3.0.0
+ dev: false
+
+ /get-stream@3.0.0:
+ resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==}
+ engines: {node: '>=4'}
dev: true
- /get-stream/5.2.0:
+ /get-stream@5.2.0:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
dependencies:
pump: 3.0.0
dev: true
- /getopts/2.2.5:
- resolution: {integrity: sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==}
- dev: false
+ /get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+ dev: true
- /glob-parent/5.1.2:
+ /git-diff@2.0.6:
+ resolution: {integrity: sha512-/Iu4prUrydE3Pb3lCBMbcSNIf81tgGt0W1ZwknnyF62t3tHmtiJTRj0f+1ZIhp3+Rh0ktz1pJVoa7ZXUCskivA==}
+ engines: {node: '>= 4.8.0'}
+ dependencies:
+ chalk: 2.4.2
+ diff: 3.5.0
+ loglevel: 1.9.1
+ shelljs: 0.8.5
+ shelljs.exec: 1.1.8
+ dev: true
+
+ /github-from-package@0.0.0:
+ resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
+
+ /glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
- dev: false
- /glob/7.2.3:
+ /glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+
+ /glob@10.3.12:
+ resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ foreground-child: 3.1.1
+ jackspeak: 2.3.6
+ minimatch: 9.0.3
+ minipass: 7.0.4
+ path-scurry: 1.10.2
+
+ /glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
fs.realpath: 1.0.0
@@ -1502,118 +3394,102 @@ packages:
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
-
- /global-agent/3.0.0:
- resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==}
- engines: {node: '>=10.0'}
- requiresBuild: true
- dependencies:
- boolean: 3.2.0
- es6-error: 4.1.1
- matcher: 3.0.0
- roarr: 2.15.4
- semver: 7.3.7
- serialize-error: 7.0.1
dev: true
- optional: true
- /global-dirs/3.0.0:
- resolution: {integrity: sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==}
+ /globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /globals@13.24.0:
+ resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.20.2
+ dev: true
+
+ /globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
dependencies:
- ini: 2.0.0
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ ignore: 5.3.1
+ merge2: 1.4.1
+ slash: 3.0.0
dev: true
- /global-tunnel-ng/2.7.1:
- resolution: {integrity: sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==}
- engines: {node: '>=0.10'}
- requiresBuild: true
+ /gopd@1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies:
- encodeurl: 1.0.2
- lodash: 4.17.21
- npm-conf: 1.1.3
- tunnel: 0.0.6
- dev: true
- optional: true
+ get-intrinsic: 1.2.4
+ dev: false
- /globalthis/1.0.3:
- resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
- engines: {node: '>= 0.4'}
+ /got@11.8.6:
+ resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
+ engines: {node: '>=10.19.0'}
dependencies:
- define-properties: 1.1.4
- dev: true
- optional: true
-
- /got/9.6.0:
- resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==}
- engines: {node: '>=8.6'}
- dependencies:
- '@sindresorhus/is': 0.14.0
- '@szmarczak/http-timer': 1.1.2
- cacheable-request: 6.1.0
- decompress-response: 3.3.0
- duplexer3: 0.1.4
- get-stream: 4.1.0
- lowercase-keys: 1.0.1
- mimic-response: 1.0.1
- p-cancelable: 1.1.0
- to-readable-stream: 1.0.0
- url-parse-lax: 3.0.0
+ '@sindresorhus/is': 4.6.0
+ '@szmarczak/http-timer': 4.0.6
+ '@types/cacheable-request': 6.0.3
+ '@types/responselike': 1.0.3
+ cacheable-lookup: 5.0.4
+ cacheable-request: 7.0.4
+ decompress-response: 6.0.0
+ http2-wrapper: 1.0.3
+ lowercase-keys: 2.0.0
+ p-cancelable: 2.1.1
+ responselike: 2.0.1
dev: true
- /graceful-fs/4.2.10:
- resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
-
- /graceful-readlink/1.0.1:
- resolution: {integrity: sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==}
+ /graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
dev: true
- /has-flag/4.0.0:
+ /graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ dev: true
+
+ /has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
+ /has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: true
- /has-property-descriptors/1.0.0:
- resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+ /has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
dependencies:
- get-intrinsic: 1.1.2
- dev: true
- optional: true
+ es-define-property: 1.0.0
+ dev: false
- /has-symbols/1.0.3:
+ /has-proto@1.0.3:
+ resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+ engines: {node: '>= 0.4'}
+ dev: false
+
+ /has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
+ dev: false
- /has-tostringtag/1.0.0:
- resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
+ /has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
dev: false
- /has-unicode/2.0.1:
- resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
- dev: false
-
- /has-yarn/2.1.0:
- resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==}
- engines: {node: '>=8'}
- dev: true
-
- /has/1.0.3:
- resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
- engines: {node: '>= 0.4.0'}
+ /hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
dependencies:
- function-bind: 1.1.1
+ function-bind: 1.1.2
- /hosted-git-info/4.1.0:
- resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
- engines: {node: '>=10'}
- dependencies:
- lru-cache: 6.0.0
- dev: true
-
- /http-assert/1.5.0:
+ /http-assert@1.5.0:
resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==}
engines: {node: '>= 0.8'}
dependencies:
@@ -1621,10 +3497,11 @@ packages:
http-errors: 1.8.1
dev: false
- /http-cache-semantics/4.1.0:
- resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==}
+ /http-cache-semantics@4.1.1:
+ resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
+ dev: true
- /http-errors/1.8.1:
+ /http-errors@1.8.1:
resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
engines: {node: '>= 0.6'}
dependencies:
@@ -1635,7 +3512,7 @@ packages:
toidentifier: 1.0.1
dev: false
- /http-errors/2.0.0:
+ /http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
dependencies:
@@ -1646,305 +3523,248 @@ packages:
toidentifier: 1.0.1
dev: false
- /http-proxy-agent/4.0.1:
- resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==}
- engines: {node: '>= 6'}
+ /http2-wrapper@1.0.3:
+ resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
+ engines: {node: '>=10.19.0'}
dependencies:
- '@tootallnate/once': 1.1.2
- agent-base: 6.0.2
- debug: 4.3.4
- transitivePeerDependencies:
- - supports-color
- dev: false
- optional: true
+ quick-lru: 5.1.1
+ resolve-alpn: 1.2.1
+ dev: true
- /http-proxy-agent/5.0.0:
- resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
- engines: {node: '>= 6'}
+ /https-proxy-agent@6.2.1:
+ resolution: {integrity: sha512-ONsE3+yfZF2caH5+bJlcddtWqNI3Gvs5A38+ngvljxaBiRXRswym2c7yf8UAeFpRFKjFNHIFEHqR/OLAWJzyiA==}
+ engines: {node: '>= 14'}
dependencies:
- '@tootallnate/once': 2.0.0
- agent-base: 6.0.2
- debug: 4.3.4
+ agent-base: 7.1.1
+ debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
dev: true
- /https-proxy-agent/5.0.1:
- resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
- engines: {node: '>= 6'}
- dependencies:
- agent-base: 6.0.2
- debug: 4.3.4
- transitivePeerDependencies:
- - supports-color
-
- /humanize-ms/1.2.1:
- resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
- dependencies:
- ms: 2.1.3
- dev: false
- optional: true
-
- /iconv-corefoundation/1.1.7:
- resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==}
- engines: {node: ^8.11.2 || >=10}
- os: [darwin]
- requiresBuild: true
- dependencies:
- cli-truncate: 2.1.0
- node-addon-api: 1.7.2
+ /human-signals@2.1.0:
+ resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+ engines: {node: '>=10.17.0'}
dev: true
- optional: true
- /iconv-lite/0.4.24:
+ /human-signals@4.3.1:
+ resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
+ engines: {node: '>=14.18.0'}
+ dev: true
+
+ /iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
dependencies:
safer-buffer: 2.1.2
dev: false
- /iconv-lite/0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
- dependencies:
- safer-buffer: 2.1.2
-
- /ieee754/1.2.1:
+ /ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
- requiresBuild: true
- dev: true
- optional: true
- /import-lazy/2.1.0:
- resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==}
- engines: {node: '>=4'}
+ /ignore-by-default@1.0.1:
+ resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
dev: true
- /imurmurhash/0.1.4:
+ /ignore@5.3.1:
+ resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+ dev: true
+
+ /imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ dev: true
- /indent-string/4.0.0:
- resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
- engines: {node: '>=8'}
- dev: false
- optional: true
-
- /infer-owner/1.0.4:
- resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
- dev: false
- optional: true
-
- /inflation/2.0.0:
- resolution: {integrity: sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==}
+ /inflation@2.1.0:
+ resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==}
engines: {node: '>= 0.8.0'}
dev: false
- /inflight/1.0.6:
+ /inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies:
once: 1.4.0
wrappy: 1.0.2
+ dev: true
- /inherits/2.0.4:
+ /inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- /ini/1.3.8:
+ /ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
- dev: true
- /ini/2.0.0:
- resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
- engines: {node: '>=10'}
- dev: true
-
- /interpret/2.2.0:
- resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==}
+ /interpret@1.4.0:
+ resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
engines: {node: '>= 0.10'}
+ dev: true
+
+ /invariant@2.2.4:
+ resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
+ dependencies:
+ loose-envify: 1.4.0
dev: false
- /ip/1.1.8:
- resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==}
- dev: false
- optional: true
+ /is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+ dev: true
- /is-binary-path/2.1.0:
+ /is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
dependencies:
- binary-extensions: 2.2.0
- dev: false
+ binary-extensions: 2.3.0
- /is-ci/2.0.0:
- resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==}
- hasBin: true
+ /is-core-module@2.13.1:
+ resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
dependencies:
- ci-info: 2.0.0
- dev: true
+ hasown: 2.0.2
- /is-ci/3.0.1:
- resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
- hasBin: true
- dependencies:
- ci-info: 3.3.2
- dev: true
-
- /is-core-module/2.9.0:
- resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==}
- dependencies:
- has: 1.0.3
- dev: false
-
- /is-extglob/2.1.1:
+ /is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
- dev: false
- /is-fullwidth-code-point/3.0.0:
+ /is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
- /is-generator-function/1.0.10:
+ /is-generator-function@1.0.10:
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
engines: {node: '>= 0.4'}
dependencies:
- has-tostringtag: 1.0.0
+ has-tostringtag: 1.0.2
dev: false
- /is-glob/4.0.3:
+ /is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
- dev: false
- /is-installed-globally/0.4.0:
- resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
- engines: {node: '>=10'}
- dependencies:
- global-dirs: 3.0.0
- is-path-inside: 3.0.3
+ /is-interactive@2.0.0:
+ resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==}
+ engines: {node: '>=12'}
dev: true
- /is-lambda/1.0.1:
- resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
- dev: false
- optional: true
-
- /is-npm/5.0.0:
- resolution: {integrity: sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==}
- engines: {node: '>=10'}
- dev: true
-
- /is-number/7.0.0:
+ /is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
- dev: false
- /is-obj/2.0.0:
- resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
- engines: {node: '>=8'}
- dev: true
-
- /is-path-inside/3.0.3:
+ /is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
dev: true
- /is-typedarray/1.0.0:
- resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+ /is-plain-obj@1.1.0:
+ resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
+ engines: {node: '>=0.10.0'}
dev: true
- /is-yarn-global/0.3.0:
- resolution: {integrity: sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==}
+ /is-stream@1.1.0:
+ resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
+ engines: {node: '>=0.10.0'}
dev: true
- /isarray/1.0.0:
- resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+ /is-stream@2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
dev: true
- /isbinaryfile/3.0.3:
- resolution: {integrity: sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==}
- engines: {node: '>=0.6.0'}
- dependencies:
- buffer-alloc: 1.2.0
+ /is-stream@3.0.0:
+ resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
- /isbinaryfile/4.0.10:
- resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==}
- engines: {node: '>= 8.0.0'}
+ /is-unicode-supported@1.3.0:
+ resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==}
+ engines: {node: '>=12'}
dev: true
- /isexe/2.0.0:
+ /isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- /jake/10.8.5:
- resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
- engines: {node: '>=10'}
- hasBin: true
+ /jackspeak@2.3.6:
+ resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
+ engines: {node: '>=14'}
dependencies:
- async: 3.2.4
- chalk: 4.1.2
- filelist: 1.0.4
- minimatch: 3.1.2
- dev: true
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
- /js-yaml/4.1.0:
+ /jiti@1.21.0:
+ resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
+ hasBin: true
+
+ /jotai@2.7.2(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-6Ft5kpNu8p93Ssf1Faoza3hYQZRIYp7rioK8MwTTFnbQKwUyZElwquPwl1h6U0uo9hC0jr+ghO3gcSjc6P35/Q==}
+ engines: {node: '>=12.20.0'}
+ peerDependencies:
+ '@types/react': '>=17.0.0'
+ react: '>=17.0.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ react:
+ optional: true
+ dependencies:
+ '@types/react': 18.2.71
+ react: 18.2.0
+ dev: false
+
+ /js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ /js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
dependencies:
argparse: 2.0.1
dev: true
- /json-buffer/3.0.0:
- resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==}
+ /jsesc@2.5.2:
+ resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+ engines: {node: '>=4'}
+ hasBin: true
dev: true
- /json-schema-traverse/0.4.1:
+ /json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ dev: true
+
+ /json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+ dev: true
+
+ /json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
- requiresBuild: true
dev: true
- /json-stable-stringify/1.0.1:
- resolution: {integrity: sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg==}
- dependencies:
- jsonify: 0.0.0
+ /json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
dev: true
- /json-stringify-safe/5.0.1:
- resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
- dev: true
- optional: true
-
- /json5/2.2.1:
- resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==}
+ /json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'}
hasBin: true
dev: true
- /jsonfile/4.0.0:
- resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
- optionalDependencies:
- graceful-fs: 4.2.10
- dev: true
-
- /jsonfile/6.1.0:
+ /jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
dependencies:
- universalify: 2.0.0
+ universalify: 2.0.1
optionalDependencies:
- graceful-fs: 4.2.10
+ graceful-fs: 4.2.11
dev: true
- /jsonify/0.0.0:
- resolution: {integrity: sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==}
- dev: true
-
- /jsonschema/1.4.1:
- resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==}
- dev: false
-
- /jsonwebtoken/8.5.1:
+ /jsonwebtoken@8.5.1:
resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==}
engines: {node: '>=4', npm: '>=1.4.28'}
dependencies:
@@ -1957,10 +3777,10 @@ packages:
lodash.isstring: 4.0.1
lodash.once: 4.1.1
ms: 2.1.3
- semver: 5.7.1
+ semver: 5.7.2
dev: false
- /jwa/1.4.1:
+ /jwa@1.4.1:
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
dependencies:
buffer-equal-constant-time: 1.0.1
@@ -1968,82 +3788,45 @@ packages:
safe-buffer: 5.2.1
dev: false
- /jws/3.2.2:
+ /jws@3.2.2:
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
dependencies:
jwa: 1.4.1
safe-buffer: 5.2.1
dev: false
- /keygrip/1.1.0:
+ /keygrip@1.1.0:
resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
engines: {node: '>= 0.6'}
dependencies:
tsscmp: 1.0.6
dev: false
- /keyv/3.1.0:
- resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==}
+ /keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
dependencies:
- json-buffer: 3.0.0
+ json-buffer: 3.0.1
dev: true
- /knex/0.95.15_sqlite3@5.0.8:
- resolution: {integrity: sha512-Loq6WgHaWlmL2bfZGWPsy4l8xw4pOE+tmLGkPG0auBppxpI0UcK+GYCycJcqz9W54f2LiGewkCVLBm3Wq4ur/w==}
- engines: {node: '>=10'}
- hasBin: true
- peerDependencies:
- mysql: '*'
- mysql2: '*'
- pg: '*'
- pg-native: '*'
- sqlite3: '*'
- tedious: '*'
- peerDependenciesMeta:
- mysql:
- optional: true
- mysql2:
- optional: true
- pg:
- optional: true
- pg-native:
- optional: true
- sqlite3:
- optional: true
- tedious:
- optional: true
- dependencies:
- colorette: 2.0.16
- commander: 7.2.0
- debug: 4.3.2
- escalade: 3.1.1
- esm: 3.2.25
- getopts: 2.2.5
- interpret: 2.2.0
- lodash: 4.17.21
- pg-connection-string: 2.5.0
- rechoir: 0.7.0
- resolve-from: 5.0.0
- sqlite3: 5.0.8
- tarn: 3.0.2
- tildify: 2.0.0
- transitivePeerDependencies:
- - supports-color
- dev: false
+ /kleur@3.0.3:
+ resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+ engines: {node: '>=6'}
+ dev: true
- /koa-bodyparser/4.3.0:
- resolution: {integrity: sha512-uyV8G29KAGwZc4q/0WUAjH+Tsmuv9ImfBUF2oZVyZtaeo0husInagyn/JH85xMSxM0hEk/mbCII5ubLDuqW/Rw==}
+ /koa-bodyparser@4.4.1:
+ resolution: {integrity: sha512-kBH3IYPMb+iAXnrxIhXnW+gXV8OTzCu8VPDqvcDHW9SQrbkHmqPQtiZwrltNmSq6/lpipHnT7k7PsjlVD7kK0w==}
engines: {node: '>=8.0.0'}
dependencies:
co-body: 6.1.0
copy-to: 2.0.1
+ type-is: 1.6.18
dev: false
- /koa-compose/4.1.0:
+ /koa-compose@4.1.0:
resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==}
dev: false
- /koa-convert/2.0.0:
+ /koa-convert@2.0.0:
resolution: {integrity: sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==}
engines: {node: '>= 10'}
dependencies:
@@ -2051,12 +3834,12 @@ packages:
koa-compose: 4.1.0
dev: false
- /koa-router/10.1.1:
- resolution: {integrity: sha512-z/OzxVjf5NyuNO3t9nJpx7e1oR3FSBAauiwXtMQu4ppcnuNZzTaQ4p21P8A6r2Es8uJJM339oc4oVW+qX7SqnQ==}
- engines: {node: '>= 8.0.0'}
+ /koa-router@12.0.1:
+ resolution: {integrity: sha512-gaDdj3GtzoLoeosacd50kBBTnnh3B9AYxDThQUo4sfUyXdOhY6ku1qyZKW88tQCRgc3Sw6ChXYXWZwwgjOxE0w==}
+ engines: {node: '>= 12'}
dependencies:
- debug: 4.3.4
- http-errors: 1.8.1
+ debug: 4.3.4(supports-color@5.5.0)
+ http-errors: 2.0.0
koa-compose: 4.1.0
methods: 1.1.2
path-to-regexp: 6.2.1
@@ -2064,16 +3847,16 @@ packages:
- supports-color
dev: false
- /koa/2.13.4:
- resolution: {integrity: sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==}
+ /koa@2.15.2:
+ resolution: {integrity: sha512-MXTeZH3M6AJ8ukW2QZ8wqO3Dcdfh2WRRmjCBkEP+NhKNCiqlO5RDqHmSnsyNrbRJrdjyvIGSJho4vQiWgQJSVA==}
engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4}
dependencies:
accepts: 1.3.8
cache-content-type: 1.0.1
content-disposition: 0.5.4
- content-type: 1.0.4
- cookies: 0.8.0
- debug: 4.3.4
+ content-type: 1.0.5
+ cookies: 0.9.1
+ debug: 4.3.4(supports-color@5.5.0)
delegates: 1.0.0
depd: 2.0.0
destroy: 1.2.0
@@ -2095,515 +3878,738 @@ packages:
- supports-color
dev: false
- /latest-version/5.1.0:
- resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==}
- engines: {node: '>=8'}
+ /kysely-codegen@0.14.1(better-sqlite3@9.4.3)(kysely@0.27.3):
+ resolution: {integrity: sha512-W6ULVWYnlBcGalHlKqw3ls0QjPl6n6z1xJ9ixPCh1lxDSbe98s4gjEbKC3hh8ZTCUTZSLSasi+QCii4AL/j7pw==}
+ hasBin: true
+ peerDependencies:
+ '@libsql/kysely-libsql': ^0.3.0
+ '@tediousjs/connection-string': ^0.5.0
+ better-sqlite3: '>=7.6.2'
+ kysely: ^0.27.0
+ kysely-bun-worker: ^0.5.3
+ mysql2: ^2.3.3 || ^3.0.0
+ pg: ^8.8.0
+ tarn: ^3.0.0
+ tedious: ^16.6.0 || ^17.0.0
+ peerDependenciesMeta:
+ '@libsql/kysely-libsql':
+ optional: true
+ '@tediousjs/connection-string':
+ optional: true
+ better-sqlite3:
+ optional: true
+ kysely-bun-worker:
+ optional: true
+ mysql2:
+ optional: true
+ pg:
+ optional: true
+ tarn:
+ optional: true
+ tedious:
+ optional: true
dependencies:
- package-json: 6.5.0
+ better-sqlite3: 9.4.3
+ chalk: 4.1.2
+ dotenv: 16.4.5
+ dotenv-expand: 11.0.6
+ git-diff: 2.0.6
+ kysely: 0.27.3
+ micromatch: 4.0.5
+ minimist: 1.2.8
dev: true
- /lazy-val/1.0.5:
- resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==}
+ /kysely@0.27.3:
+ resolution: {integrity: sha512-lG03Ru+XyOJFsjH3OMY6R/9U38IjDPfnOfDgO3ynhbDr+Dz8fak+X6L62vqu3iybQnj+lG84OttBuU9KY3L9kA==}
+ engines: {node: '>=14.0.0'}
+
+ /levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
dev: true
- /lodash.includes/4.3.0:
+ /lilconfig@2.1.0:
+ resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+ engines: {node: '>=10'}
+
+ /lilconfig@3.1.1:
+ resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
+ engines: {node: '>=14'}
+
+ /lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ /locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-locate: 5.0.0
+ dev: true
+
+ /lodash._reinterpolate@3.0.0:
+ resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==}
+ dev: true
+
+ /lodash.debounce@4.0.8:
+ resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+ dev: false
+
+ /lodash.includes@4.3.0:
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
dev: false
- /lodash.isboolean/3.0.3:
+ /lodash.isboolean@3.0.3:
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
dev: false
- /lodash.isinteger/4.0.4:
+ /lodash.isinteger@4.0.4:
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
dev: false
- /lodash.isnumber/3.0.3:
+ /lodash.isnumber@3.0.3:
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
dev: false
- /lodash.isplainobject/4.0.6:
+ /lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
dev: false
- /lodash.isstring/4.0.1:
+ /lodash.isstring@4.0.1:
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
dev: false
- /lodash.once/4.1.1:
+ /lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ dev: true
+
+ /lodash.once@4.1.1:
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
dev: false
- /lodash/4.17.21:
- resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
-
- /lowercase-keys/1.0.1:
- resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==}
- engines: {node: '>=0.10.0'}
+ /lodash.template@4.5.0:
+ resolution: {integrity: sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==}
+ dependencies:
+ lodash._reinterpolate: 3.0.0
+ lodash.templatesettings: 4.2.0
dev: true
- /lowercase-keys/2.0.0:
+ /lodash.templatesettings@4.2.0:
+ resolution: {integrity: sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==}
+ dependencies:
+ lodash._reinterpolate: 3.0.0
+ dev: true
+
+ /log-symbols@5.1.0:
+ resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==}
+ engines: {node: '>=12'}
+ dependencies:
+ chalk: 5.2.0
+ is-unicode-supported: 1.3.0
+ dev: true
+
+ /loglevel@1.9.1:
+ resolution: {integrity: sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==}
+ engines: {node: '>= 0.6.0'}
+ dev: true
+
+ /loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+ dependencies:
+ js-tokens: 4.0.0
+ dev: false
+
+ /lowercase-keys@2.0.0:
resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
engines: {node: '>=8'}
dev: true
- /lru-cache/6.0.0:
+ /lru-cache@10.2.0:
+ resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
+ engines: {node: 14 || >=16.14}
+
+ /lru-cache@4.1.5:
+ resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
+ dependencies:
+ pseudomap: 1.0.2
+ yallist: 2.1.2
+ dev: true
+
+ /lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ dependencies:
+ yallist: 3.1.1
+ dev: true
+
+ /lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
dependencies:
yallist: 4.0.0
- /make-dir/3.1.0:
- resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
- engines: {node: '>=8'}
- dependencies:
- semver: 6.3.0
-
- /make-error/1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
- dev: true
-
- /make-fetch-happen/9.1.0:
- resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==}
- engines: {node: '>= 10'}
- dependencies:
- agentkeepalive: 4.2.1
- cacache: 15.3.0
- http-cache-semantics: 4.1.0
- http-proxy-agent: 4.0.1
- https-proxy-agent: 5.0.1
- is-lambda: 1.0.1
- lru-cache: 6.0.0
- minipass: 3.3.3
- minipass-collect: 1.0.2
- minipass-fetch: 1.4.1
- minipass-flush: 1.0.5
- minipass-pipeline: 1.2.4
- negotiator: 0.6.3
- promise-retry: 2.0.1
- socks-proxy-agent: 6.2.1
- ssri: 8.0.1
- transitivePeerDependencies:
- - supports-color
- dev: false
- optional: true
-
- /matcher/3.0.0:
- resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==}
- engines: {node: '>=10'}
- dependencies:
- escape-string-regexp: 4.0.0
- dev: true
- optional: true
-
- /media-typer/0.3.0:
+ /media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
dev: false
- /methods/1.1.2:
+ /merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+ dev: true
+
+ /merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ /methods@1.1.2:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
engines: {node: '>= 0.6'}
dev: false
- /mime-db/1.52.0:
+ /micromatch@4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+
+ /mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
- /mime-types/2.1.35:
+ /mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
+ dev: false
- /mime/2.6.0:
- resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
- engines: {node: '>=4.0.0'}
- hasBin: true
+ /mimic-fn@2.1.0:
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+ engines: {node: '>=6'}
dev: true
- /mimic-response/1.0.1:
+ /mimic-fn@4.0.0:
+ resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /mimic-response@1.0.1:
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
engines: {node: '>=4'}
dev: true
- /minimatch/3.0.4:
- resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==}
+ /mimic-response@3.1.0:
+ resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
+ engines: {node: '>=10'}
+
+ /minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
dev: true
- /minimatch/3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
- dependencies:
- brace-expansion: 1.1.11
-
- /minimatch/5.1.0:
- resolution: {integrity: sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==}
+ /minimatch@7.4.6:
+ resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==}
engines: {node: '>=10'}
dependencies:
brace-expansion: 2.0.1
dev: true
- /minimist/1.2.6:
- resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
- dev: true
-
- /minipass-collect/1.0.2:
- resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
- engines: {node: '>= 8'}
+ /minimatch@9.0.3:
+ resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+ engines: {node: '>=16 || 14 >=14.17'}
dependencies:
- minipass: 3.3.3
- dev: false
- optional: true
+ brace-expansion: 2.0.1
- /minipass-fetch/1.4.1:
- resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==}
- engines: {node: '>=8'}
- dependencies:
- minipass: 3.3.3
- minipass-sized: 1.0.3
- minizlib: 2.1.2
- optionalDependencies:
- encoding: 0.1.13
- dev: false
- optional: true
+ /minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
- /minipass-flush/1.0.5:
- resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
- engines: {node: '>= 8'}
- dependencies:
- minipass: 3.3.3
- dev: false
- optional: true
+ /minipass@7.0.4:
+ resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
+ engines: {node: '>=16 || 14 >=14.17'}
- /minipass-pipeline/1.2.4:
- resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
- engines: {node: '>=8'}
- dependencies:
- minipass: 3.3.3
- dev: false
- optional: true
-
- /minipass-sized/1.0.3:
- resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
- engines: {node: '>=8'}
- dependencies:
- minipass: 3.3.3
- dev: false
- optional: true
-
- /minipass/3.3.3:
- resolution: {integrity: sha512-N0BOsdFAlNRfmwMhjAsLVWOk7Ljmeb39iqFlsV1At+jqRhSUP9yeof8FyJu4imaJiSUp8vQebWD/guZwGQC8iA==}
- engines: {node: '>=8'}
- dependencies:
- yallist: 4.0.0
+ /mitt@3.0.1:
+ resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
dev: false
- /minizlib/2.1.2:
- resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
- engines: {node: '>= 8'}
- dependencies:
- minipass: 3.3.3
- yallist: 4.0.0
- dev: false
+ /mkdirp-classic@0.5.3:
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
- /mkdirp/0.5.6:
- resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
- hasBin: true
- dependencies:
- minimist: 1.2.6
- dev: true
-
- /mkdirp/1.0.4:
- resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
+ /mkdirp@2.1.6:
+ resolution: {integrity: sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==}
engines: {node: '>=10'}
hasBin: true
- dev: false
-
- /ms/2.0.0:
- resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
dev: true
- /ms/2.1.2:
+ /ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
- /ms/2.1.3:
+ /ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
dev: false
- /natural-orderby/2.0.3:
+ /mz@2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+
+ /nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ /napi-build-utils@1.0.2:
+ resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
+
+ /natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ dev: true
+
+ /natural-orderby@2.0.3:
resolution: {integrity: sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==}
dev: false
- /negotiator/0.6.3:
+ /negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
dev: false
- /node-addon-api/1.7.2:
- resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==}
+ /nice-napi@1.0.2:
+ resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==}
+ os: ['!win32']
+ requiresBuild: true
+ dependencies:
+ node-addon-api: 3.2.1
+ node-gyp-build: 4.8.0
+ dev: true
+ optional: true
+
+ /node-abi@3.56.0:
+ resolution: {integrity: sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ semver: 7.6.0
+
+ /node-addon-api@3.2.1:
+ resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
requiresBuild: true
dev: true
optional: true
- /node-addon-api/3.2.1:
- resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
- dev: false
+ /node-domexception@1.0.0:
+ resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
+ engines: {node: '>=10.5.0'}
+ dev: true
- /node-addon-api/4.3.0:
- resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==}
- dev: false
-
- /node-fetch/2.6.7:
- resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
- engines: {node: 4.x || >=6.0.0}
- peerDependencies:
- encoding: ^0.1.0
- peerDependenciesMeta:
- encoding:
- optional: true
+ /node-fetch@3.3.2:
+ resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
- whatwg-url: 5.0.0
- dev: false
+ data-uri-to-buffer: 4.0.1
+ fetch-blob: 3.2.0
+ formdata-polyfill: 4.0.10
+ dev: true
- /node-gyp/8.4.1:
- resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==}
- engines: {node: '>= 10.12.0'}
+ /node-gyp-build@4.8.0:
+ resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==}
hasBin: true
requiresBuild: true
- dependencies:
- env-paths: 2.2.1
- glob: 7.2.3
- graceful-fs: 4.2.10
- make-fetch-happen: 9.1.0
- nopt: 5.0.0
- npmlog: 6.0.2
- rimraf: 3.0.2
- semver: 7.3.7
- tar: 6.1.11
- which: 2.0.2
- transitivePeerDependencies:
- - supports-color
- dev: false
+ dev: true
optional: true
- /node-stream-zip/1.15.0:
- resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==}
- engines: {node: '>=0.12.0'}
- dev: false
+ /node-releases@2.0.14:
+ resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+ dev: true
- /nopt/5.0.0:
- resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
- engines: {node: '>=6'}
+ /nodemon@3.1.0:
+ resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ chokidar: 3.6.0
+ debug: 4.3.4(supports-color@5.5.0)
+ ignore-by-default: 1.0.1
+ minimatch: 3.1.2
+ pstree.remy: 1.1.8
+ semver: 7.6.0
+ simple-update-notifier: 2.0.0
+ supports-color: 5.5.0
+ touch: 3.1.0
+ undefsafe: 2.0.5
+ dev: true
+
+ /nopt@1.0.10:
+ resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
hasBin: true
dependencies:
abbrev: 1.1.1
- dev: false
+ dev: true
- /normalize-path/3.0.0:
+ /normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
- dev: false
- /normalize-url/4.5.1:
- resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==}
- engines: {node: '>=8'}
+ /normalize-range@0.1.2:
+ resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+ engines: {node: '>=0.10.0'}
dev: true
- /npm-conf/1.1.3:
- resolution: {integrity: sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==}
+ /normalize-url@6.1.0:
+ resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /npm-run-path@2.0.2:
+ resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
engines: {node: '>=4'}
dependencies:
- config-chain: 1.1.13
- pify: 3.0.0
+ path-key: 2.0.1
dev: true
- optional: true
- /npmlog/5.0.1:
- resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
+ /npm-run-path@4.0.1:
+ resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+ engines: {node: '>=8'}
dependencies:
- are-we-there-yet: 2.0.0
- console-control-strings: 1.1.0
- gauge: 3.0.2
- set-blocking: 2.0.0
- dev: false
+ path-key: 3.1.1
+ dev: true
- /npmlog/6.0.2:
- resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ /npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
- are-we-there-yet: 3.0.0
- console-control-strings: 1.1.0
- gauge: 4.0.4
- set-blocking: 2.0.0
- dev: false
- optional: true
+ path-key: 4.0.0
+ dev: true
- /object-assign/4.1.1:
+ /object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
+
+ /object-hash@3.0.0:
+ resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
+ engines: {node: '>= 6'}
+
+ /object-inspect@1.13.1:
+ resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
dev: false
- /object-inspect/1.12.2:
- resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==}
- dev: false
-
- /object-keys/1.1.1:
- resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
- engines: {node: '>= 0.4'}
- dev: true
- optional: true
-
- /on-finished/2.4.1:
+ /on-finished@2.4.1:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
dependencies:
ee-first: 1.1.1
dev: false
- /once/1.4.0:
+ /once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
- /only/0.0.2:
+ /onetime@5.1.2:
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+ engines: {node: '>=6'}
+ dependencies:
+ mimic-fn: 2.1.0
+ dev: true
+
+ /onetime@6.0.0:
+ resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ mimic-fn: 4.0.0
+ dev: true
+
+ /only@0.0.2:
resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==}
dev: false
- /p-cancelable/1.1.0:
- resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==}
- engines: {node: '>=6'}
+ /optionator@0.9.3:
+ resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ '@aashutoshrathi/word-wrap': 1.2.6
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
dev: true
- /p-map/4.0.0:
- resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
+ /ora@6.3.1:
+ resolution: {integrity: sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ chalk: 5.2.0
+ cli-cursor: 4.0.0
+ cli-spinners: 2.9.2
+ is-interactive: 2.0.0
+ is-unicode-supported: 1.3.0
+ log-symbols: 5.1.0
+ stdin-discarder: 0.1.0
+ strip-ansi: 7.1.0
+ wcwidth: 1.0.1
+ dev: true
+
+ /os-filter-obj@2.0.0:
+ resolution: {integrity: sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==}
+ engines: {node: '>=4'}
+ dependencies:
+ arch: 2.2.0
+ dev: true
+
+ /p-cancelable@2.1.1:
+ resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /p-finally@1.0.0:
+ resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
dependencies:
- aggregate-error: 3.1.0
- dev: false
- optional: true
-
- /package-json/6.5.0:
- resolution: {integrity: sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==}
- engines: {node: '>=8'}
- dependencies:
- got: 9.6.0
- registry-auth-token: 4.2.2
- registry-url: 5.1.0
- semver: 6.3.0
+ yocto-queue: 0.1.0
dev: true
- /parseurl/1.3.3:
+ /p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-limit: 3.1.0
+ dev: true
+
+ /parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+ dependencies:
+ callsites: 3.1.0
+ dev: true
+
+ /parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/code-frame': 7.24.2
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+ dev: true
+
+ /parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
dev: false
- /path-is-absolute/1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
+ /path-browserify@1.0.1:
+ resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+ dev: true
- /path-key/3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ /path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
dev: true
- /path-parse/1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
- dev: false
+ /path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
- /path-to-regexp/6.2.1:
+ /path-key@2.0.1:
+ resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ /path-key@4.0.0:
+ resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ /path-scurry@1.10.2:
+ resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ lru-cache: 10.2.0
+ minipass: 7.0.4
+
+ /path-to-regexp@6.2.1:
resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
dev: false
- /pend/1.2.0:
- resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
+ /path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+ dev: true
- /pg-connection-string/2.5.0:
- resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==}
- dev: false
+ /peek-readable@5.0.0:
+ resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==}
+ engines: {node: '>=14.16'}
+ dev: true
- /picomatch/2.3.1:
+ /picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+
+ /picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
- dev: false
- /pify/3.0.0:
- resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==}
- engines: {node: '>=4'}
+ /pify@2.3.0:
+ resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
+ engines: {node: '>=0.10.0'}
+
+ /pirates@4.0.6:
+ resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
+ engines: {node: '>= 6'}
+
+ /piscina@4.4.0:
+ resolution: {integrity: sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==}
+ optionalDependencies:
+ nice-napi: 1.0.2
dev: true
- optional: true
- /plist/3.0.5:
- resolution: {integrity: sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==}
- engines: {node: '>=6'}
+ /postcss-import@15.1.0(postcss@8.4.38):
+ resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ postcss: ^8.0.0
dependencies:
- base64-js: 1.5.1
- xmlbuilder: 9.0.7
- dev: true
+ postcss: 8.4.38
+ postcss-value-parser: 4.2.0
+ read-cache: 1.0.0
+ resolve: 1.22.8
- /prepend-http/2.0.0:
- resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==}
+ /postcss-js@4.0.1(postcss@8.4.38):
+ resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
+ engines: {node: ^12 || ^14 || >= 16}
+ peerDependencies:
+ postcss: ^8.4.21
+ dependencies:
+ camelcase-css: 2.0.1
+ postcss: 8.4.38
+
+ /postcss-load-config@4.0.2(postcss@8.4.38):
+ resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ postcss: '>=8.0.9'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+ ts-node:
+ optional: true
+ dependencies:
+ lilconfig: 3.1.1
+ postcss: 8.4.38
+ yaml: 2.4.1
+
+ /postcss-nested@6.0.1(postcss@8.4.38):
+ resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.2.14
+ dependencies:
+ postcss: 8.4.38
+ postcss-selector-parser: 6.0.16
+
+ /postcss-selector-parser@6.0.16:
+ resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
engines: {node: '>=4'}
- dev: true
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
- /process-nextick-args/2.0.1:
- resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
- dev: true
+ /postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
- /progress/2.0.3:
- resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
- engines: {node: '>=0.4.0'}
- dev: true
+ /postcss@8.4.38:
+ resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.0
+ source-map-js: 1.2.0
- /promise-inflight/1.0.1:
- resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
- dev: false
- optional: true
-
- /promise-retry/2.0.1:
- resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
+ /prebuild-install@7.1.2:
+ resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==}
engines: {node: '>=10'}
+ hasBin: true
dependencies:
- err-code: 2.0.3
- retry: 0.12.0
- dev: false
- optional: true
+ detect-libc: 2.0.3
+ expand-template: 2.0.3
+ github-from-package: 0.0.0
+ minimist: 1.2.8
+ mkdirp-classic: 0.5.3
+ napi-build-utils: 1.0.2
+ node-abi: 3.56.0
+ pump: 3.0.0
+ rc: 1.2.8
+ simple-get: 4.0.1
+ tar-fs: 2.1.1
+ tunnel-agent: 0.6.0
- /proto-list/1.2.4:
- resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+ /prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
dev: true
- optional: true
- /pump/3.0.0:
+ /prompts@2.4.2:
+ resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
+ engines: {node: '>= 6'}
+ dependencies:
+ kleur: 3.0.3
+ sisteransi: 1.0.5
+ dev: true
+
+ /pseudomap@1.0.2:
+ resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
+ dev: true
+
+ /pstree.remy@1.1.8:
+ resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
+ dev: true
+
+ /pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
- dev: true
- /punycode/2.1.1:
- resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
+ /punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
- requiresBuild: true
dev: true
- /pupa/2.1.1:
- resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==}
- engines: {node: '>=8'}
- dependencies:
- escape-goat: 2.1.1
- dev: true
-
- /qs/6.10.5:
- resolution: {integrity: sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ==}
+ /qs@6.12.0:
+ resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==}
engines: {node: '>=0.6'}
dependencies:
- side-channel: 1.0.4
+ side-channel: 1.0.6
dev: false
- /raw-body/2.5.1:
- resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
+ /queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ /quick-lru@5.1.1:
+ resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /raw-body@2.5.2:
+ resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
engines: {node: '>= 0.8'}
dependencies:
bytes: 3.1.2
@@ -2612,309 +4618,438 @@ packages:
unpipe: 1.0.0
dev: false
- /rc/1.2.8:
+ /rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
- minimist: 1.2.6
+ minimist: 1.2.8
strip-json-comments: 2.0.1
- dev: true
- /read-config-file/6.2.0:
- resolution: {integrity: sha512-gx7Pgr5I56JtYz+WuqEbQHj/xWo+5Vwua2jhb1VwM4Wid5PqYmZ4i00ZB0YEGIfkVBsCv9UrjgyqCiQfS/Oosg==}
- engines: {node: '>=12.0.0'}
+ /react-dom@18.2.0(react@18.2.0):
+ resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
+ peerDependencies:
+ react: ^18.2.0
dependencies:
- dotenv: 9.0.2
- dotenv-expand: 5.1.0
- js-yaml: 4.1.0
- json5: 2.2.1
- lazy-val: 1.0.5
- dev: true
+ loose-envify: 1.4.0
+ react: 18.2.0
+ scheduler: 0.23.0
+ dev: false
- /readable-stream/2.3.7:
- resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==}
+ /react-remove-scroll-bar@2.3.6(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
dependencies:
- core-util-is: 1.0.3
- inherits: 2.0.4
- isarray: 1.0.0
- process-nextick-args: 2.0.1
- safe-buffer: 5.1.2
- string_decoder: 1.1.1
- util-deprecate: 1.0.2
- dev: true
+ '@types/react': 18.2.71
+ react: 18.2.0
+ react-style-singleton: 2.2.1(@types/react@18.2.71)(react@18.2.0)
+ tslib: 2.6.2
+ dev: false
- /readable-stream/3.6.0:
- resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
+ /react-remove-scroll@2.5.5(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.71
+ react: 18.2.0
+ react-remove-scroll-bar: 2.3.6(@types/react@18.2.71)(react@18.2.0)
+ react-style-singleton: 2.2.1(@types/react@18.2.71)(react@18.2.0)
+ tslib: 2.6.2
+ use-callback-ref: 1.3.2(@types/react@18.2.71)(react@18.2.0)
+ use-sidecar: 1.1.2(@types/react@18.2.71)(react@18.2.0)
+ dev: false
+
+ /react-resizable-panels@2.0.16(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-UrnxmTZaTnbCl/xIOX38ig35RicqGfLuqt2x5fytpNlQvCRuxyXZwIBEhmF+pmrEGxfajyXFBoCplNxLvhF0CQ==}
+ peerDependencies:
+ react: ^16.14.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /react-style-singleton@2.2.1(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.71
+ get-nonce: 1.0.1
+ invariant: 2.2.4
+ react: 18.2.0
+ tslib: 2.6.2
+ dev: false
+
+ /react@18.2.0:
+ resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ loose-envify: 1.4.0
+ dev: false
+
+ /read-cache@1.0.0:
+ resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
+ dependencies:
+ pify: 2.3.0
+
+ /readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
- dev: false
- /readdirp/3.6.0:
+ /readable-web-to-node-stream@3.0.2:
+ resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==}
+ engines: {node: '>=8'}
+ dependencies:
+ readable-stream: 3.6.2
+ dev: true
+
+ /readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.3.1
- dev: false
- /rechoir/0.7.0:
- resolution: {integrity: sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==}
+ /recast@0.23.6:
+ resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==}
+ engines: {node: '>= 4'}
+ dependencies:
+ ast-types: 0.16.1
+ esprima: 4.0.1
+ source-map: 0.6.1
+ tiny-invariant: 1.3.3
+ tslib: 2.6.2
+ dev: true
+
+ /rechoir@0.6.2:
+ resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
engines: {node: '>= 0.10'}
dependencies:
- resolve: 1.22.1
+ resolve: 1.22.8
+ dev: true
+
+ /regenerator-runtime@0.14.1:
+ resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
dev: false
- /registry-auth-token/4.2.2:
- resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==}
- engines: {node: '>=6.0.0'}
- dependencies:
- rc: 1.2.8
- dev: true
-
- /registry-url/5.1.0:
- resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==}
- engines: {node: '>=8'}
- dependencies:
- rc: 1.2.8
- dev: true
-
- /require-directory/2.1.1:
- resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /resolve-from/5.0.0:
- resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+ /regexparam@3.0.0:
+ resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==}
engines: {node: '>=8'}
dev: false
- /resolve/1.22.1:
- resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
+ /resolve-alpn@1.2.1:
+ resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
+ dev: true
+
+ /resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /resolve@1.22.8:
+ resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true
dependencies:
- is-core-module: 2.9.0
+ is-core-module: 2.13.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
- dev: false
- /responselike/1.0.2:
- resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==}
+ /responselike@2.0.1:
+ resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
dependencies:
- lowercase-keys: 1.0.1
+ lowercase-keys: 2.0.0
dev: true
- /retry/0.12.0:
- resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
- engines: {node: '>= 4'}
- dev: false
- optional: true
+ /restore-cursor@4.0.0:
+ resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ dev: true
- /rimraf/3.0.2:
+ /reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ /rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
dependencies:
glob: 7.2.3
+ dev: true
- /roarr/2.15.4:
- resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==}
- engines: {node: '>=8.0'}
+ /rollup@4.13.0:
+ resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
dependencies:
- boolean: 3.2.0
- detect-node: 2.1.0
- globalthis: 1.0.3
- json-stringify-safe: 5.0.1
- semver-compare: 1.0.0
- sprintf-js: 1.1.2
- dev: true
- optional: true
-
- /safe-buffer/5.1.2:
- resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+ '@types/estree': 1.0.5
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.13.0
+ '@rollup/rollup-android-arm64': 4.13.0
+ '@rollup/rollup-darwin-arm64': 4.13.0
+ '@rollup/rollup-darwin-x64': 4.13.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.13.0
+ '@rollup/rollup-linux-arm64-gnu': 4.13.0
+ '@rollup/rollup-linux-arm64-musl': 4.13.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.13.0
+ '@rollup/rollup-linux-x64-gnu': 4.13.0
+ '@rollup/rollup-linux-x64-musl': 4.13.0
+ '@rollup/rollup-win32-arm64-msvc': 4.13.0
+ '@rollup/rollup-win32-ia32-msvc': 4.13.0
+ '@rollup/rollup-win32-x64-msvc': 4.13.0
+ fsevents: 2.3.3
dev: true
- /safe-buffer/5.2.1:
+ /run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+
+ /safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
- dev: false
- /safer-buffer/2.1.2:
+ /safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ dev: false
- /sanitize-filename/1.6.3:
- resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==}
+ /scheduler@0.23.0:
+ resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
dependencies:
- truncate-utf8-bytes: 1.0.2
+ loose-envify: 1.4.0
+ dev: false
+
+ /semver-regex@4.0.5:
+ resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==}
+ engines: {node: '>=12'}
dev: true
- /sax/1.2.4:
- resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
- dev: true
-
- /semver-compare/1.0.0:
- resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==}
- dev: true
- optional: true
-
- /semver-diff/3.1.1:
- resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==}
- engines: {node: '>=8'}
+ /semver-truncate@3.0.0:
+ resolution: {integrity: sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==}
+ engines: {node: '>=12'}
dependencies:
- semver: 6.3.0
+ semver: 7.6.0
dev: true
- /semver/5.7.1:
- resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
+ /semver@5.7.2:
+ resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
hasBin: true
dev: false
- /semver/6.3.0:
- resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
+ /semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
+ dev: true
- /semver/7.3.7:
- resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==}
+ /semver@7.6.0:
+ resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
- /serialize-error/7.0.1:
- resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
- engines: {node: '>=10'}
+ /set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
dependencies:
- type-fest: 0.13.1
- dev: true
- optional: true
-
- /set-blocking/2.0.0:
- resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
dev: false
- /setprototypeof/1.2.0:
+ /setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
dev: false
- /shebang-command/2.0.0:
+ /shadcn-ui@0.8.0(typescript@5.4.3):
+ resolution: {integrity: sha512-avqRgjJ6PIQQXdfvoCAWQpyLTLk6oHhtU5DQKmLeYcgu1ZIsgMqA9MKWAkr0HpEdCAenCCZvFbvJ2C2m5ZXRiA==}
+ hasBin: true
+ dependencies:
+ '@antfu/ni': 0.21.12
+ '@babel/core': 7.24.3
+ '@babel/parser': 7.24.1
+ '@babel/plugin-transform-typescript': 7.24.1(@babel/core@7.24.3)
+ chalk: 5.2.0
+ commander: 10.0.1
+ cosmiconfig: 8.3.6(typescript@5.4.3)
+ diff: 5.2.0
+ execa: 7.2.0
+ fast-glob: 3.3.2
+ fs-extra: 11.2.0
+ https-proxy-agent: 6.2.1
+ lodash.template: 4.5.0
+ node-fetch: 3.3.2
+ ora: 6.3.1
+ prompts: 2.4.2
+ recast: 0.23.6
+ ts-morph: 18.0.0
+ tsconfig-paths: 4.2.0
+ zod: 3.22.4
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /shebang-command@1.2.0:
+ resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ shebang-regex: 1.0.0
+ dev: true
+
+ /shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
+
+ /shebang-regex@1.0.0:
+ resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
+ engines: {node: '>=0.10.0'}
dev: true
- /shebang-regex/3.0.0:
+ /shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
+
+ /shelljs.exec@1.1.8:
+ resolution: {integrity: sha512-vFILCw+lzUtiwBAHV8/Ex8JsFjelFMdhONIsgKNLgTzeRckp2AOYRQtHJE/9LhNvdMmE27AGtzWx0+DHpwIwSw==}
+ engines: {node: '>= 4.0.0'}
dev: true
- /side-channel/1.0.4:
- resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ /shelljs@0.8.5:
+ resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==}
+ engines: {node: '>=4'}
+ hasBin: true
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.1.2
- object-inspect: 1.12.2
+ glob: 7.2.3
+ interpret: 1.4.0
+ rechoir: 0.6.2
+ dev: true
+
+ /side-channel@1.0.6:
+ resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ object-inspect: 1.13.1
dev: false
- /signal-exit/3.0.7:
+ /signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
-
- /slice-ansi/3.0.0:
- resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
- engines: {node: '>=8'}
- requiresBuild: true
- dependencies:
- ansi-styles: 4.3.0
- astral-regex: 2.0.0
- is-fullwidth-code-point: 3.0.0
dev: true
- optional: true
- /smart-buffer/4.2.0:
- resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
- engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
- optional: true
+ /signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
- /socks-proxy-agent/6.2.1:
- resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==}
- engines: {node: '>= 10'}
+ /simple-concat@1.0.1:
+ resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
+
+ /simple-get@4.0.1:
+ resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
dependencies:
- agent-base: 6.0.2
- debug: 4.3.4
- socks: 2.6.2
- transitivePeerDependencies:
- - supports-color
- dev: false
- optional: true
+ decompress-response: 6.0.0
+ once: 1.4.0
+ simple-concat: 1.0.1
- /socks/2.6.2:
- resolution: {integrity: sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==}
- engines: {node: '>= 10.13.0', npm: '>= 3.0.0'}
+ /simple-update-notifier@2.0.0:
+ resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
+ engines: {node: '>=10'}
dependencies:
- ip: 1.1.8
- smart-buffer: 4.2.0
- dev: false
- optional: true
+ semver: 7.6.0
+ dev: true
- /source-map-support/0.5.21:
+ /sisteransi@1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+ dev: true
+
+ /slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /sort-keys-length@1.0.1:
+ resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ sort-keys: 1.1.2
+ dev: true
+
+ /sort-keys@1.1.2:
+ resolution: {integrity: sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-plain-obj: 1.1.0
+ dev: true
+
+ /source-map-js@1.2.0:
+ resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
+ engines: {node: '>=0.10.0'}
+
+ /source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
dev: true
- /source-map/0.6.1:
+ /source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
- /sprintf-js/1.1.2:
- resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
- dev: true
- optional: true
-
- /sqlite3/5.0.8:
- resolution: {integrity: sha512-f2ACsbSyb2D1qFFcqIXPfFscLtPVOWJr5GmUzYxf4W+0qelu5MWrR+FAQE1d5IUArEltBrzSDxDORG8P/IkqyQ==}
- requiresBuild: true
- peerDependenciesMeta:
- node-gyp:
- optional: true
- dependencies:
- '@mapbox/node-pre-gyp': 1.0.9
- node-addon-api: 4.3.0
- tar: 6.1.11
- optionalDependencies:
- node-gyp: 8.4.1
- transitivePeerDependencies:
- - encoding
- - supports-color
- dev: false
-
- /ssri/8.0.1:
- resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==}
+ /source-map@0.7.4:
+ resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
- dependencies:
- minipass: 3.3.3
- dev: false
- optional: true
-
- /stat-mode/1.0.0:
- resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==}
- engines: {node: '>= 6'}
dev: true
- /statuses/1.5.0:
+ /statuses@1.5.0:
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
engines: {node: '>= 0.6'}
dev: false
- /statuses/2.0.1:
+ /statuses@2.0.1:
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
engines: {node: '>= 0.8'}
dev: false
- /string-width/4.2.3:
+ /stdin-discarder@0.1.0:
+ resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ bl: 5.1.0
+ dev: true
+
+ /string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
dependencies:
@@ -2922,177 +5057,292 @@ packages:
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
- /string_decoder/1.1.1:
- resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+ /string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
dependencies:
- safe-buffer: 5.1.2
- dev: true
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
- /string_decoder/1.3.0:
+ /string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
- dev: false
- /strip-ansi/6.0.1:
+ /strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
- /strip-json-comments/2.0.1:
- resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
+ /strip-ansi@7.1.0:
+ resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-regex: 6.0.1
+
+ /strip-bom@3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /strip-eof@1.0.0:
+ resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
engines: {node: '>=0.10.0'}
dev: true
- /sumchecker/3.0.1:
- resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
- engines: {node: '>= 8.0'}
- dependencies:
- debug: 4.3.4
- transitivePeerDependencies:
- - supports-color
+ /strip-final-newline@2.0.0:
+ resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+ engines: {node: '>=6'}
dev: true
- /supports-color/7.2.0:
+ /strip-final-newline@3.0.0:
+ resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /strip-json-comments@2.0.1:
+ resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
+ engines: {node: '>=0.10.0'}
+
+ /strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /strip-outer@2.0.0:
+ resolution: {integrity: sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /strtok3@7.0.0:
+ resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ peek-readable: 5.0.0
+ dev: true
+
+ /sucrase@3.35.0:
+ resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ commander: 4.1.1
+ glob: 10.3.12
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.6
+ ts-interface-checker: 0.1.13
+
+ /supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: 3.0.0
+
+ /supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: true
- /supports-preserve-symlinks-flag/1.0.0:
+ /supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
- dev: false
- /tar/6.1.11:
- resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==}
- engines: {node: '>= 10'}
+ /swr@2.2.5(react@18.2.0):
+ resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==}
+ peerDependencies:
+ react: ^16.11.0 || ^17.0.0 || ^18.0.0
dependencies:
- chownr: 2.0.0
- fs-minipass: 2.1.0
- minipass: 3.3.3
- minizlib: 2.1.2
- mkdirp: 1.0.4
- yallist: 4.0.0
+ client-only: 0.0.1
+ react: 18.2.0
+ use-sync-external-store: 1.2.0(react@18.2.0)
dev: false
- /tarn/3.0.2:
- resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==}
- engines: {node: '>=8.0.0'}
- dev: false
-
- /temp-file/3.4.0:
- resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==}
+ /tailwind-merge@2.2.2:
+ resolution: {integrity: sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==}
dependencies:
- async-exit-hook: 2.0.1
- fs-extra: 10.1.0
+ '@babel/runtime': 7.24.1
+ dev: false
+
+ /tailwindcss-animate@1.0.7(tailwindcss@3.4.3):
+ resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
+ peerDependencies:
+ tailwindcss: '>=3.0.0 || insiders'
+ dependencies:
+ tailwindcss: 3.4.3
+ dev: false
+
+ /tailwindcss@3.4.3:
+ resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ arg: 5.0.2
+ chokidar: 3.6.0
+ didyoumean: 1.2.2
+ dlv: 1.1.3
+ fast-glob: 3.3.2
+ glob-parent: 6.0.2
+ is-glob: 4.0.3
+ jiti: 1.21.0
+ lilconfig: 2.1.0
+ micromatch: 4.0.5
+ normalize-path: 3.0.0
+ object-hash: 3.0.0
+ picocolors: 1.0.0
+ postcss: 8.4.38
+ postcss-import: 15.1.0(postcss@8.4.38)
+ postcss-js: 4.0.1(postcss@8.4.38)
+ postcss-load-config: 4.0.2(postcss@8.4.38)
+ postcss-nested: 6.0.1(postcss@8.4.38)
+ postcss-selector-parser: 6.0.16
+ resolve: 1.22.8
+ sucrase: 3.35.0
+ transitivePeerDependencies:
+ - ts-node
+
+ /tar-fs@2.1.1:
+ resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+ dependencies:
+ chownr: 1.1.4
+ mkdirp-classic: 0.5.3
+ pump: 3.0.0
+ tar-stream: 2.2.0
+
+ /tar-stream@2.2.0:
+ resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ bl: 4.1.0
+ end-of-stream: 1.4.4
+ fs-constants: 1.0.0
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+
+ /text-table@0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
- /tildify/2.0.0:
- resolution: {integrity: sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==}
- engines: {node: '>=8'}
- dev: false
+ /thenify-all@1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ thenify: 3.3.1
- /tiny-async-pool/1.3.0:
+ /thenify@3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ dependencies:
+ any-promise: 1.3.0
+
+ /tiny-async-pool@1.3.0:
resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==}
dependencies:
- semver: 5.7.1
+ semver: 5.7.2
dev: false
- /tmp-promise/3.0.3:
- resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
- dependencies:
- tmp: 0.2.1
+ /tiny-invariant@1.3.3:
+ resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
dev: true
- /tmp/0.2.1:
- resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
- engines: {node: '>=8.17.0'}
- dependencies:
- rimraf: 3.0.2
+ /to-fast-properties@2.0.0:
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+ engines: {node: '>=4'}
dev: true
- /to-readable-stream/1.0.0:
- resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==}
- engines: {node: '>=6'}
- dev: true
-
- /to-regex-range/5.0.1:
+ /to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
- dev: false
- /toidentifier/1.0.1:
+ /toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
dev: false
- /tr46/0.0.3:
- resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
- dev: false
-
- /truncate-utf8-bytes/1.0.2:
- resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
+ /token-types@5.0.1:
+ resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==}
+ engines: {node: '>=14.16'}
dependencies:
- utf8-byte-length: 1.0.4
+ '@tokenizer/token': 0.3.0
+ ieee754: 1.2.1
dev: true
- /ts-json-schema-generator/0.82.0:
- resolution: {integrity: sha512-g5/h3jmN7DqYTOx7OhTvWS638CJWzyoqlsKwe2eksvK8mnFHTnOZGvZITmPkRDPFUFwSUMo0J+Vm3A+Y8EDsEg==}
- engines: {node: '>=10.0.0'}
+ /touch@3.1.0:
+ resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
hasBin: true
dependencies:
- '@types/json-schema': 7.0.11
- commander: 6.2.1
- fast-json-stable-stringify: 2.1.0
- glob: 7.2.3
- json-stable-stringify: 1.0.1
- typescript: 4.1.6
+ nopt: 1.0.10
dev: true
- /ts-node/9.1.1_typescript@4.7.4:
- resolution: {integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==}
- engines: {node: '>=10.0.0'}
- hasBin: true
+ /trim-repeated@2.0.0:
+ resolution: {integrity: sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==}
+ engines: {node: '>=12'}
+ dependencies:
+ escape-string-regexp: 5.0.0
+ dev: true
+
+ /ts-api-utils@1.3.0(typescript@5.4.3):
+ resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
+ engines: {node: '>=16'}
peerDependencies:
- typescript: '>=2.7'
+ typescript: '>=4.2.0'
dependencies:
- arg: 4.1.3
- create-require: 1.1.1
- diff: 4.0.2
- make-error: 1.3.6
- source-map-support: 0.5.21
- typescript: 4.7.4
- yn: 3.1.1
+ typescript: 5.4.3
dev: true
- /tsscmp/1.0.6:
+ /ts-interface-checker@0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+
+ /ts-morph@18.0.0:
+ resolution: {integrity: sha512-Kg5u0mk19PIIe4islUI/HWRvm9bC1lHejK4S0oh1zaZ77TMZAEmQC0sHQYiu2RgCQFZKXz1fMVi/7nOOeirznA==}
+ dependencies:
+ '@ts-morph/common': 0.19.0
+ code-block-writer: 12.0.0
+ dev: true
+
+ /tsconfig-paths@4.2.0:
+ resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
+ engines: {node: '>=6'}
+ dependencies:
+ json5: 2.2.3
+ minimist: 1.2.8
+ strip-bom: 3.0.0
+ dev: true
+
+ /tslib@2.6.2:
+ resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+
+ /tsscmp@1.0.6:
resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==}
engines: {node: '>=0.6.x'}
dev: false
- /tunnel/0.0.6:
- resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
- engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
- dev: true
- optional: true
+ /tunnel-agent@0.6.0:
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+ dependencies:
+ safe-buffer: 5.2.1
- /type-fest/0.13.1:
- resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
- engines: {node: '>=10'}
+ /type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
dev: true
- optional: true
- /type-fest/0.20.2:
+ /type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
dev: true
- /type-is/1.6.18:
+ /type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
dependencies:
@@ -3100,229 +5350,221 @@ packages:
mime-types: 2.1.35
dev: false
- /typedarray-to-buffer/3.1.5:
- resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
- dependencies:
- is-typedarray: 1.0.0
- dev: true
-
- /typedarray/0.0.6:
- resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
- dev: true
-
- /typescript/4.1.6:
- resolution: {integrity: sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow==}
- engines: {node: '>=4.2.0'}
+ /typescript@5.4.3:
+ resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==}
+ engines: {node: '>=14.17'}
hasBin: true
dev: true
- /typescript/4.7.4:
- resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
- engines: {node: '>=4.2.0'}
- hasBin: true
+ /undefsafe@2.0.5:
+ resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
dev: true
- /unique-filename/1.1.1:
- resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==}
- dependencies:
- unique-slug: 2.0.2
- dev: false
- optional: true
-
- /unique-slug/2.0.2:
- resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==}
- dependencies:
- imurmurhash: 0.1.4
- dev: false
- optional: true
-
- /unique-string/2.0.0:
- resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
- engines: {node: '>=8'}
- dependencies:
- crypto-random-string: 2.0.0
+ /undici-types@5.26.5:
+ resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
dev: true
- /universalify/0.1.2:
- resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
- engines: {node: '>= 4.0.0'}
- dev: true
-
- /universalify/2.0.0:
- resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
+ /universalify@2.0.1:
+ resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
dev: true
- /unpipe/1.0.0:
+ /unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
dev: false
- /update-notifier/5.1.0:
- resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==}
- engines: {node: '>=10'}
+ /update-browserslist-db@1.0.13(browserslist@4.23.0):
+ resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
dependencies:
- boxen: 5.1.2
- chalk: 4.1.2
- configstore: 5.0.1
- has-yarn: 2.1.0
- import-lazy: 2.1.0
- is-ci: 2.0.0
- is-installed-globally: 0.4.0
- is-npm: 5.0.0
- is-yarn-global: 0.3.0
- latest-version: 5.1.0
- pupa: 2.1.1
- semver: 7.3.7
- semver-diff: 3.1.1
- xdg-basedir: 4.0.0
+ browserslist: 4.23.0
+ escalade: 3.1.2
+ picocolors: 1.0.0
dev: true
- /uri-js/4.4.1:
+ /uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
- requiresBuild: true
dependencies:
- punycode: 2.1.1
+ punycode: 2.3.1
dev: true
- /url-parse-lax/3.0.0:
- resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==}
- engines: {node: '>=4'}
+ /use-callback-ref@1.3.2(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
dependencies:
- prepend-http: 2.0.0
- dev: true
+ '@types/react': 18.2.71
+ react: 18.2.0
+ tslib: 2.6.2
+ dev: false
- /utf8-byte-length/1.0.4:
- resolution: {integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==}
- dev: true
+ /use-sidecar@1.1.2(@types/react@18.2.71)(react@18.2.0):
+ resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 18.2.71
+ detect-node-es: 1.1.0
+ react: 18.2.0
+ tslib: 2.6.2
+ dev: false
- /util-deprecate/1.0.2:
+ /use-sync-external-store@1.2.0(react@18.2.0):
+ resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /usehooks-ts@3.1.0(react@18.2.0):
+ resolution: {integrity: sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==}
+ engines: {node: '>=16.15.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18
+ dependencies:
+ lodash.debounce: 4.0.8
+ react: 18.2.0
+ dev: false
+
+ /util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
- /vary/1.1.2:
+ /vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
dev: false
- /verror/1.10.1:
- resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==}
- engines: {node: '>=0.6.0'}
- requiresBuild: true
+ /vite@5.2.6(@types/node@20.12.3):
+ resolution: {integrity: sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
dependencies:
- assert-plus: 1.0.0
- core-util-is: 1.0.2
- extsprintf: 1.4.1
+ '@types/node': 20.12.3
+ esbuild: 0.20.2
+ postcss: 8.4.38
+ rollup: 4.13.0
+ optionalDependencies:
+ fsevents: 2.3.3
dev: true
- optional: true
- /webidl-conversions/3.0.1:
- resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
- dev: false
-
- /whatwg-url/5.0.0:
- resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+ /wcwidth@1.0.1:
+ resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
dependencies:
- tr46: 0.0.3
- webidl-conversions: 3.0.1
- dev: false
+ defaults: 1.0.4
+ dev: true
- /which/2.0.2:
+ /web-streams-polyfill@3.3.3:
+ resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /which@1.3.1:
+ resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+ dev: true
+
+ /which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
- /wide-align/1.1.5:
- resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
+ /wouter@3.1.0(react@18.2.0):
+ resolution: {integrity: sha512-hou3w+12BMTBckdWdyJp/z7+kKcbdLDWfz6omSyrO6bbx4irNuQQyLDQkfSGXXJCxmglea3c8On9XFUkBSU8+Q==}
+ peerDependencies:
+ react: '>=16.8.0'
dependencies:
- string-width: 4.2.3
+ mitt: 3.0.1
+ react: 18.2.0
+ regexparam: 3.0.0
+ use-sync-external-store: 1.2.0(react@18.2.0)
dev: false
- /widest-line/3.1.0:
- resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==}
- engines: {node: '>=8'}
- dependencies:
- string-width: 4.2.3
- dev: true
-
- /wrap-ansi/7.0.0:
+ /wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
- dev: true
- /wrappy/1.0.2:
+ /wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+
+ /wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- /write-file-atomic/3.0.3:
- resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
- dependencies:
- imurmurhash: 0.1.4
- is-typedarray: 1.0.0
- signal-exit: 3.0.7
- typedarray-to-buffer: 3.1.5
+ /yallist@2.1.2:
+ resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
dev: true
- /xdg-basedir/4.0.0:
- resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==}
- engines: {node: '>=8'}
+ /yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
dev: true
- /xmlbuilder/15.1.1:
- resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
- engines: {node: '>=8.0'}
- requiresBuild: true
- dev: true
- optional: true
-
- /xmlbuilder/9.0.7:
- resolution: {integrity: sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==}
- engines: {node: '>=4.0'}
- requiresBuild: true
- dev: true
-
- /y18n/5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
- dev: true
-
- /yallist/4.0.0:
+ /yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
- /yargs-parser/21.0.1:
- resolution: {integrity: sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==}
- engines: {node: '>=12'}
- dev: true
+ /yaml@2.4.1:
+ resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==}
+ engines: {node: '>= 14'}
+ hasBin: true
- /yargs/17.5.1:
- resolution: {integrity: sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==}
- engines: {node: '>=12'}
- dependencies:
- cliui: 7.0.4
- escalade: 3.1.1
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- string-width: 4.2.3
- y18n: 5.0.8
- yargs-parser: 21.0.1
- dev: true
-
- /yauzl/2.10.0:
- resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
- dependencies:
- buffer-crc32: 0.2.13
- fd-slicer: 1.1.0
-
- /ylru/1.3.2:
+ /ylru@1.3.2:
resolution: {integrity: sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==}
engines: {node: '>= 4.0.0'}
dev: false
- /yn/3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
+ /yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /zod@3.22.4:
+ resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: true
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..4340350
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,2 @@
+packages:
+ - 'packages/*'
\ No newline at end of file
diff --git a/preload.ts b/preload.ts
deleted file mode 100644
index 05b82f8..0000000
--- a/preload.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { contextBridge, ipcRenderer } from "electron";
-
-contextBridge.exposeInMainWorld("electron", {
- passwordReset: async (username: string, toPw: string) => {
- return await ipcRenderer.invoke("reset_password", username, toPw);
- },
-});
diff --git a/src/SettingConfig.schema.json b/src/SettingConfig.schema.json
deleted file mode 100644
index 0ff349b..0000000
--- a/src/SettingConfig.schema.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "$ref": "#/definitions/SettingConfig",
- "definitions": {
- "SettingConfig": {
- "type": "object",
- "properties": {
- "localmode": {
- "type": "boolean",
- "description": "if true, server will bind on '127.0.0.1' rather than '0.0.0.0'"
- },
- "guest": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/Permission"
- },
- "description": "guest permission"
- },
- "jwt_secretkey": {
- "type": "string",
- "description": "JWT secret key. if you change its value, all access tokens are invalidated."
- },
- "port": {
- "type": "number",
- "description": "the port which running server is binding on."
- },
- "mode": {
- "type": "string",
- "enum": [
- "development",
- "production"
- ]
- },
- "cli": {
- "type": "boolean",
- "description": "if true, do not show 'electron' window and show terminal only."
- },
- "forbid_remote_admin_login": {
- "type": "boolean",
- "description": "forbid to login admin from remote client. but, it do not invalidate access token. \r if you want to invalidate access token, change 'jwt_secretkey'."
- },
- "$schema": {
- "type": "string"
- }
- },
- "required": [
- "localmode",
- "guest",
- "jwt_secretkey",
- "port",
- "mode",
- "cli",
- "forbid_remote_admin_login"
- ],
- "additionalProperties": false
- },
- "Permission": {
- "type": "string",
- "enum": [
- "ModifyTag",
- "QueryContent",
- "ModifyTagDesc"
- ]
- }
- }
-}
diff --git a/src/SettingConfig.ts b/src/SettingConfig.ts
deleted file mode 100644
index 0f8b080..0000000
--- a/src/SettingConfig.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { randomBytes } from "crypto";
-import { existsSync, readFileSync, writeFileSync } from "fs";
-import { Permission } from "./permission/permission";
-
-export interface SettingConfig {
- /**
- * if true, server will bind on '127.0.0.1' rather than '0.0.0.0'
- */
- localmode: boolean;
- /**
- * secure only
- */
- secure: boolean;
-
- /**
- * guest permission
- */
- guest: (Permission)[];
- /**
- * JWT secret key. if you change its value, all access tokens are invalidated.
- */
- jwt_secretkey: string;
- /**
- * the port which running server is binding on.
- */
- port: number;
-
- mode: "development" | "production";
- /**
- * if true, do not show 'electron' window and show terminal only.
- */
- cli: boolean;
- /** forbid to login admin from remote client. but, it do not invalidate access token.
- * if you want to invalidate access token, change 'jwt_secretkey'. */
- forbid_remote_admin_login: boolean;
-}
-const default_setting: SettingConfig = {
- localmode: true,
- secure: true,
- guest: [],
- jwt_secretkey: "itsRandom",
- port: 8080,
- mode: "production",
- cli: false,
- forbid_remote_admin_login: true,
-};
-let setting: null | SettingConfig = null;
-
-const setEmptyToDefault = (target: any, default_table: SettingConfig) => {
- let diff_occur = false;
- for (const key in default_table) {
- if (key === undefined || key in target) {
- continue;
- }
- target[key] = default_table[key as keyof SettingConfig];
- diff_occur = true;
- }
- return diff_occur;
-};
-
-export const read_setting_from_file = () => {
- let ret = existsSync("settings.json") ? JSON.parse(readFileSync("settings.json", { encoding: "utf8" })) : {};
- const partial_occur = setEmptyToDefault(ret, default_setting);
- if (partial_occur) {
- writeFileSync("settings.json", JSON.stringify(ret));
- }
- return ret as SettingConfig;
-};
-export function get_setting(): SettingConfig {
- if (setting === null) {
- setting = read_setting_from_file();
- const env = process.env.NODE_ENV;
- if (env !== undefined && (env != "production" && env != "development")) {
- throw new Error("process unknown value in NODE_ENV: must be either \"development\" or \"production\"");
- }
- setting.mode = env ?? setting.mode;
- }
- return setting;
-}
diff --git a/src/client/accessor/document.ts b/src/client/accessor/document.ts
deleted file mode 100644
index 21046b0..0000000
--- a/src/client/accessor/document.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import { Document, DocumentAccessor, DocumentBody, QueryListOption } from "../../model/doc";
-import { toQueryString } from "./util";
-const baseurl = "/api/doc";
-
-export * from "../../model/doc";
-
-export class FetchFailError extends Error {}
-
-export class ClientDocumentAccessor implements DocumentAccessor {
- search: (search_word: string) => Promise;
- addList: (content_list: DocumentBody[]) => Promise;
- async findByPath(basepath: string, filename?: string): Promise {
- throw new Error("not allowed");
- }
- async findDeleted(content_type: string): Promise {
- throw new Error("not allowed");
- }
- async findList(option?: QueryListOption | undefined): Promise {
- let res = await fetch(`${baseurl}/search?${option !== undefined ? toQueryString(option) : ""}`);
- if (res.status == 401) throw new FetchFailError("Unauthorized");
- if (res.status !== 200) throw new FetchFailError("findList Failed");
- let ret = await res.json();
- return ret;
- }
- async findById(id: number, tagload?: boolean | undefined): Promise {
- let res = await fetch(`${baseurl}/${id}`);
- if (res.status !== 200) throw new FetchFailError("findById Failed");
- let ret = await res.json();
- return ret;
- }
- /**
- * not implement
- */
- async findListByBasePath(basepath: string): Promise {
- throw new Error("not implement");
- return [];
- }
- async update(c: Partial & { id: number }): Promise {
- const { id, ...rest } = c;
- const res = await fetch(`${baseurl}/${id}`, {
- method: "POST",
- body: JSON.stringify(rest),
- headers: {
- "content-type": "application/json",
- },
- });
- const ret = await res.json();
- return ret;
- }
- async add(c: DocumentBody): Promise {
- throw new Error("not allow");
- const res = await fetch(`${baseurl}`, {
- method: "POST",
- body: JSON.stringify(c),
- headers: {
- "content-type": "application/json",
- },
- });
- const ret = await res.json();
- return ret;
- }
- async del(id: number): Promise {
- const res = await fetch(`${baseurl}/${id}`, {
- method: "DELETE",
- });
- const ret = await res.json();
- return ret;
- }
- async addTag(c: Document, tag_name: string): Promise {
- const { id, ...rest } = c;
- const res = await fetch(`${baseurl}/${id}/tags/${tag_name}`, {
- method: "POST",
- body: JSON.stringify(rest),
- headers: {
- "content-type": "application/json",
- },
- });
- const ret = await res.json();
- return ret;
- }
- async delTag(c: Document, tag_name: string): Promise {
- const { id, ...rest } = c;
- const res = await fetch(`${baseurl}/${id}/tags/${tag_name}`, {
- method: "DELETE",
- body: JSON.stringify(rest),
- headers: {
- "content-type": "application/json",
- },
- });
- const ret = await res.json();
- return ret;
- }
-}
-export const CDocumentAccessor = new ClientDocumentAccessor();
-export const makeThumbnailUrl = (x: Document) => {
- return `${baseurl}/${x.id}/${x.content_type}/thumbnail`;
-};
-
-export default CDocumentAccessor;
diff --git a/src/client/accessor/util.ts b/src/client/accessor/util.ts
deleted file mode 100644
index d2fa9ce..0000000
--- a/src/client/accessor/util.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-type Representable = string | number | boolean;
-
-type ToQueryStringA = {
- [name: string]: Representable | Representable[] | undefined;
-};
-
-export const toQueryString = (obj: ToQueryStringA) => {
- return Object.entries(obj)
- .filter((e): e is [string, Representable | Representable[]] => e[1] !== undefined)
- .map(e =>
- e[1] instanceof Array
- ? e[1].map(f => `${e[0]}=${(f)}`).join("&")
- : `${e[0]}=${(e[1])}`
- )
- .join("&");
-};
-export const QueryStringToMap = (query: string) => {
- const keyValue = query.slice(query.indexOf("?") + 1).split("&");
- const param: { [k: string]: string | string[] } = {};
- keyValue.forEach((p) => {
- const [k, v] = p.split("=");
- const pv = param[k];
- if (pv === undefined) {
- param[k] = v;
- } else if (typeof pv === "string") {
- param[k] = [pv, v];
- } else {
- pv.push(v);
- }
- });
- return param;
-};
diff --git a/src/client/app.tsx b/src/client/app.tsx
deleted file mode 100644
index e69a9ed..0000000
--- a/src/client/app.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { createTheme, ThemeProvider } from "@mui/material";
-import React, { createContext, useEffect, useRef, useState } from "react";
-import ReactDom from "react-dom";
-import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
-import {
- DifferencePage,
- DocumentAbout,
- Gallery,
- LoginPage,
- NotFoundPage,
- ProfilePage,
- ReaderPage,
- SettingPage,
- TagsPage,
-} from "./page/mod";
-import { getInitialValue, UserContext } from "./state";
-
-import "./css/style.css";
-
-const theme = createTheme();
-
-const App = () => {
- const [user, setUser] = useState("");
- const [userPermission, setUserPermission] = useState([]);
- (async () => {
- const { username, permission } = await getInitialValue();
- if (username !== user) {
- setUser(username);
- setUserPermission(permission);
- }
- })();
- // useEffect(()=>{});
- return (
-
-
-
-
- } />
- } />
- }>
- }>
- } />
- }>
- }>
- }>
- }>
- } />
-
-
-
-
- );
-};
-
-ReactDom.render(
- ,
- document.getElementById("root"),
-);
diff --git a/src/client/build.ts b/src/client/build.ts
deleted file mode 100644
index de54a07..0000000
--- a/src/client/build.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import esbuild from "esbuild";
-
-async function main() {
- try {
- const result = await esbuild.build({
- entryPoints: ["app.tsx"],
- bundle: true,
- outfile: "../../dist/bundle.js",
- platform: "browser",
- sourcemap: true,
- minify: true,
- target: ["chrome100", "firefox100"],
- watch: {
- onRebuild: async (err, _result) => {
- if (err) {
- console.error("watch build failed: ", err);
- } else {
- console.log("watch build success");
- }
- },
- },
- });
- console.log("watching...");
- return result;
- } catch (error) {
- console.error(error);
- process.exit(1);
- }
-}
-
-main().then((res) => {
-});
diff --git a/src/client/component/contentinfo.tsx b/src/client/component/contentinfo.tsx
deleted file mode 100644
index 8f699b9..0000000
--- a/src/client/component/contentinfo.tsx
+++ /dev/null
@@ -1,226 +0,0 @@
-import React, {} from "react";
-import { Link as RouterLink } from "react-router-dom";
-import { Document } from "../accessor/document";
-
-import { Box, Button, Grid, Link, Paper, Theme, Typography, useTheme } from "@mui/material";
-import { TagChip } from "../component/tagchip";
-import { ThumbnailContainer } from "../page/reader/reader";
-
-import DocumentAccessor from "../accessor/document";
-
-export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
-export const makeContentReaderUrl = (id: number) => `/doc/${id}/reader`;
-
-const useStyles = (theme: Theme) => ({
- thumbnail_content: {
- maxHeight: "400px",
- maxWidth: "min(400px, 100vw)",
- },
- tag_list: {
- display: "flex",
- justifyContent: "flex-start",
- flexWrap: "wrap",
- overflowY: "hidden",
- "& > *": {
- margin: theme.spacing(0.5),
- },
- },
- title: {
- marginLeft: theme.spacing(1),
- },
- infoContainer: {
- padding: theme.spacing(2),
- },
- subinfoContainer: {
- display: "grid",
- gridTemplateColumns: "100px auto",
- overflowY: "hidden",
- alignItems: "baseline",
- },
- short_subinfoContainer: {
- [theme.breakpoints.down("md")]: {
- display: "none",
- },
- },
- short_root: {
- overflowY: "hidden",
- display: "flex",
- flexDirection: "column",
- [theme.breakpoints.up("sm")]: {
- height: 200,
- flexDirection: "row",
- },
- },
- short_thumbnail_anchor: {
- background: "#272733",
- display: "flex",
- alignItems: "center",
- justifyContent: "center",
- [theme.breakpoints.up("sm")]: {
- width: theme.spacing(25),
- height: theme.spacing(25),
- flexShrink: 0,
- },
- },
- short_thumbnail_content: {
- maxWidth: "100%",
- maxHeight: "100%",
- },
-});
-
-export const ContentInfo = (props: {
- document: Document;
- children?: React.ReactNode;
- classes?: {
- root?: string;
- thumbnail_anchor?: string;
- thumbnail_content?: string;
- tag_list?: string;
- title?: string;
- infoContainer?: string;
- subinfoContainer?: string;
- };
- gallery?: string;
- short?: boolean;
-}) => {
- const theme = useTheme();
- const document = props.document;
- const url = props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id);
- return (
-
-
- {document.deleted_at === null
- ?
- : Deleted}
-
-
-
- {document.title}
-
-
- {props.short
- ? (
-
- {document.tags.map(x => (
-
- ))}
-
- )
- : (
-
- )}
-
- {document.deleted_at != null
- && (
-
- )}
-
-
- );
-};
-async function documentDelete(id: number) {
- const t = await DocumentAccessor.del(id);
- if (t) {
- alert("document deleted!");
- } else {
- alert("document already deleted.");
- }
-}
-
-function ComicDetailTag(prop: {
- tags: string[]; /*classes:{
- tag_list:string
-}*/
- path?: string;
- createdAt?: number;
- deletedAt?: number;
-}) {
- let allTag = prop.tags;
- const tagKind = ["artist", "group", "series", "type", "character"];
- let tagTable: { [kind: string]: string[] } = {};
- for (const kind of tagKind) {
- const tags = allTag.filter(x => x.startsWith(kind + ":")).map(x => x.slice(kind.length + 1));
- tagTable[kind] = tags;
- allTag = allTag.filter(x => !x.startsWith(kind + ":"));
- }
- return (
-
- {tagKind.map(key => (
-
-
- {key}
-
-
- {tagTable[key].length !== 0 ? tagTable[key].map((elem, i)=>{
- return <>
- {elem}
- {(i < tagTable[key].length - 1) ? ',' : ''}>
- }) : "N/A"}
-
-
- ))}
- {prop.path != undefined && (
- <>
-
- Path
-
-
- {prop.path}
-
- >
- )}
- {prop.createdAt != undefined && (
- <>
-
- CreatedAt
-
-
- {new Date(prop.createdAt).toUTCString()}
-
- >
- )}
- {prop.deletedAt != undefined && (
- <>
-
- DeletedAt
-
-
- {new Date(prop.deletedAt).toUTCString()}
-
- >
- )}
-
- Tags
-
-
- {allTag.map(x => )}
-
-
- );
-}
diff --git a/src/client/component/headline.tsx b/src/client/component/headline.tsx
deleted file mode 100644
index 248ada0..0000000
--- a/src/client/component/headline.tsx
+++ /dev/null
@@ -1,273 +0,0 @@
-import { AccountCircle, ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon } from "@mui/icons-material";
-import {
- AppBar,
- Button,
- CssBaseline,
- Divider,
- Drawer,
- Hidden,
- IconButton,
- InputBase,
- Link,
- List,
- ListItem,
- ListItemIcon,
- ListItemText,
- Menu,
- MenuItem,
- styled,
- Toolbar,
- Tooltip,
- Typography,
-} from "@mui/material";
-import { alpha, Theme, useTheme } from "@mui/material/styles";
-import React, { useContext, useState } from "react";
-
-import { Link as RouterLink, useNavigate } from "react-router-dom";
-import { doLogout, UserContext } from "../state";
-
-const drawerWidth = 270;
-
-const DrawerHeader = styled("div")(({ theme }) => ({
- ...theme.mixins.toolbar,
-}));
-
-const StyledDrawer = styled(Drawer)(({ theme }) => ({
- flexShrink: 0,
- whiteSpace: "nowrap",
- [theme.breakpoints.up("sm")]: {
- width: drawerWidth,
- },
-}));
-const StyledSearchBar = styled("div")(({ theme }) => ({
- position: "relative",
- borderRadius: theme.shape.borderRadius,
- backgroundColor: alpha(theme.palette.common.white, 0.15),
- "&:hover": {
- backgroundColor: alpha(theme.palette.common.white, 0.25),
- },
- marginLeft: 0,
- width: "100%",
- [theme.breakpoints.up("sm")]: {
- marginLeft: theme.spacing(1),
- width: "auto",
- },
-}));
-const StyledInputBase = styled(InputBase)(({ theme }) => ({
- color: "inherit",
- "& .MuiInputBase-input": {
- padding: theme.spacing(1, 1, 1, 0),
- // vertical padding + font size from searchIcon
- paddingLeft: `calc(1em + ${theme.spacing(4)})`,
- transition: theme.transitions.create("width"),
- width: "100%",
- [theme.breakpoints.up("sm")]: {
- width: "12ch",
- "&:focus": {
- width: "20ch",
- },
- },
- },
-}));
-
-const StyledNav = styled("nav")(({ theme }) => ({
- [theme.breakpoints.up("sm")]: {
- width: theme.spacing(7),
- },
-}));
-
-const closedMixin = (theme: Theme) => ({
- overflowX: "hidden",
- width: `calc(${theme.spacing(7)} + 1px)`,
-});
-
-export const Headline = (prop: {
- children?: React.ReactNode;
- classes?: {
- content?: string;
- toolbar?: string;
- };
- rightAppbar?: React.ReactNode;
- menu: React.ReactNode;
-}) => {
- const [v, setv] = useState(false);
- const [anchorEl, setAnchorEl] = React.useState(null);
- const theme = useTheme();
- const toggleV = () => setv(!v);
- const handleProfileMenuOpen = (e: React.MouseEvent) => setAnchorEl(e.currentTarget);
- const handleProfileMenuClose = () => setAnchorEl(null);
- const isProfileMenuOpened = Boolean(anchorEl);
- const menuId = "primary-search-account-menu";
- const user_ctx = useContext(UserContext);
- const isLogin = user_ctx.username !== "";
- const navigate = useNavigate();
- const [search, setSearch] = useState("");
-
- const renderProfileMenu = (
-
- );
- const drawer_contents = (
- <>
-
-
- {theme.direction === "ltr" ? : }
-
-
-
- {prop.menu}
- >
- );
-
- return (
-
-
-
-
-
-
-
-
- Ionian
-
-
- {prop.rightAppbar}
-
-
- navSearch(search)} />
-
- setSearch(e.target.value)}
- onKeyUp={(e) => {
- if (e.key === "Enter") {
- navSearch(search);
- }
- }}
- value={search}
- />
-
- {isLogin
- ? (
-
-
-
- )
- : }
-
-
- {renderProfileMenu}
-
-
-
- {drawer_contents}
-
-
-
-
- {drawer_contents}
-
-
-
-
{prop.children}
-
-
- );
- function navSearch(search: string) {
- let words = search.includes("&") ? search.split("&") : [search];
- words = words.map(w => w.trim())
- .map(w =>
- w.includes(":")
- ? `allow_tag=${w}`
- : `word=${encodeURIComponent(w)}`
- );
- navigate(`/search?${words.join("&")}`);
- }
-};
-
-export default Headline;
diff --git a/src/client/component/loading.tsx b/src/client/component/loading.tsx
deleted file mode 100644
index 6aa9172..0000000
--- a/src/client/component/loading.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Box, CircularProgress } from "@mui/material";
-import React from "react";
-
-export const LoadingCircle = () => {
- return (
-
-
-
- );
-};
diff --git a/src/client/component/mod.ts b/src/client/component/mod.ts
deleted file mode 100644
index a92d73a..0000000
--- a/src/client/component/mod.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from "./contentinfo";
-export * from "./headline";
-export * from "./loading";
-export * from "./navlist";
-export * from "./tagchip";
diff --git a/src/client/component/navlist.tsx b/src/client/component/navlist.tsx
deleted file mode 100644
index c7af904..0000000
--- a/src/client/component/navlist.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import {
- ArrowBack as ArrowBackIcon,
- Collections as CollectionIcon,
- Folder as FolderIcon,
- Home as HomeIcon,
- List as ListIcon,
- Settings as SettingIcon,
- VideoLibrary as VideoIcon,
-} from "@mui/icons-material";
-import { Divider, List, ListItem, ListItemIcon, ListItemText, Tooltip } from "@mui/material";
-import React from "react";
-import { Link as RouterLink } from "react-router-dom";
-
-export const NavItem = (props: { name: string; to: string; icon: React.ReactElement }) => {
- return (
-
-
-
- {props.icon}
-
-
-
-
- );
-};
-
-export const NavList = (props: { children?: React.ReactNode }) => {
- return (
-
- {props.children}
-
- );
-};
-
-export const BackItem = (props: { to?: string }) => {
- return } />;
-};
-
-export function CommonMenuList(props?: { url?: string }) {
- let url = props?.url ?? "";
- return (
-
- {url !== "" && (
- <>
-
- >
- )}
- } />
- }>
- } />
-
- } />
-
- }>
- } />
-
- );
-}
diff --git a/src/client/component/pagepad.tsx b/src/client/component/pagepad.tsx
deleted file mode 100644
index 93cf098..0000000
--- a/src/client/component/pagepad.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { styled } from "@mui/material";
-
-export const PagePad = styled("div")(({theme})=>({
- padding: theme.spacing(3)
-}))
\ No newline at end of file
diff --git a/src/client/component/tagchip.tsx b/src/client/component/tagchip.tsx
deleted file mode 100644
index 3e84519..0000000
--- a/src/client/component/tagchip.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import * as colors from "@mui/material/colors";
-import Chip, { ChipTypeMap } from "@mui/material/Chip";
-import { emphasize, styled, Theme, useTheme } from "@mui/material/styles";
-import React from "react";
-import { Link as RouterLink } from "react-router-dom";
-
-type TagChipStyleProp = {
- color: `rgba(${number},${number},${number},${number})` | `#${string}` | 'default';
-};
-
-const { blue, pink } = colors;
-const getTagColorName = (tagname: string): TagChipStyleProp['color'] => {
- if (tagname.startsWith("female")) {
- return pink[600];
- } else if (tagname.startsWith("male")) {
- return blue[600];
- } else return "default";
-};
-
-type ColorChipProp = Omit & TagChipStyleProp & {
- component?: React.ElementType;
- to?: string;
-};
-
-export const ColorChip = (props: ColorChipProp) => {
- const { color, ...rest } = props;
- const theme = useTheme();
-
- let newcolor = color;
- if (color === "default"){
- newcolor = "#ebebeb";
- }
- return ;
-};
-
-type TagChipProp = Omit & {
- tagname: string;
-};
-
-export const TagChip = (props: TagChipProp) => {
- const { tagname, label, clickable, ...rest } = props;
- const colorName = getTagColorName(tagname);
-
- let newlabel: React.ReactNode = label;
- if (typeof label === "string") {
- const female = "female:";
- const male = "male:";
- if (label.startsWith(female)) {
- newlabel = "♀ " + label.slice(female.length);
- } else if (label.startsWith(male)) {
- newlabel = "♂ " + label.slice(male.length);
- }
- }
-
- const inner = clickable
- ? (
-
- )
- : (
-
- );
- return inner;
-};
diff --git a/src/client/css/style.css b/src/client/css/style.css
deleted file mode 100644
index 257cfc8..0000000
--- a/src/client/css/style.css
+++ /dev/null
@@ -1,9 +0,0 @@
-body {
- margin: 0;
- padding: 0;
- font-family: sans-serif;
-}
-
-h1 {
- text-decoration: underline;
-}
\ No newline at end of file
diff --git a/src/client/package.json b/src/client/package.json
deleted file mode 100644
index 3831fab..0000000
--- a/src/client/package.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "ionian_client",
- "version": "0.0.1",
- "description": "client of ionian",
- "scripts": {
- "build:watch": "ts-node build.ts"
- },
- "dependencies": {
- "@emotion/react": "^11.9.0",
- "@emotion/styled": "^11.8.1",
- "@mui/icons-material": "^5.6.2",
- "@mui/material": "^5.6.2",
- "@mui/x-data-grid": "^5.12.3",
- "@types/react": "^18.0.5",
- "@types/react-dom": "^18.0.1",
- "react": "^18.0.0",
- "react-dom": "^18.0.0",
- "react-router-dom": "^6.3.0"
- },
- "devDependencies": {
- "esbuild": "^0.14.36",
- "ts-node": "^10.7.0"
- }
-}
diff --git a/src/client/page/404.tsx b/src/client/page/404.tsx
deleted file mode 100644
index 98e7d84..0000000
--- a/src/client/page/404.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Typography } from "@mui/material";
-import React from "react";
-import { CommonMenuList, Headline } from "../component/mod";
-import { PagePad } from "../component/pagepad";
-
-export const NotFoundPage = () => {
- const menu = CommonMenuList();
- return (
-
-
- 404 Not Found
-
-
- );
-};
diff --git a/src/client/page/contentinfo.tsx b/src/client/page/contentinfo.tsx
deleted file mode 100644
index 48756ee..0000000
--- a/src/client/page/contentinfo.tsx
+++ /dev/null
@@ -1,131 +0,0 @@
-import { IconButton, Theme, Typography } from "@mui/material";
-import FullscreenIcon from '@mui/icons-material/Fullscreen';
-import React, { useEffect, useRef, useState } from "react";
-import { Route, Routes, useLocation, useParams } from "react-router-dom";
-import DocumentAccessor, { Document } from "../accessor/document";
-import { LoadingCircle } from "../component/loading";
-import { CommonMenuList, ContentInfo, Headline } from "../component/mod";
-import { NotFoundPage } from "./404";
-import { getPresenter } from "./reader/reader";
-import { PagePad } from "../component/pagepad";
-
-export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
-export const makeComicReaderUrl = (id: number) => `/doc/${id}/reader`;
-
-type DocumentState = {
- doc: Document | undefined;
- notfound: boolean;
-};
-
-export function ReaderPage(props?: {}) {
- const location = useLocation();
- const match = useParams<{ id: string }>();
- if (match == null) {
- throw new Error("unreachable");
- }
- const id = Number.parseInt(match.id ?? "NaN");
- const [info, setInfo] = useState({ doc: undefined, notfound: false });
- const menu_list = (link?: string) => ;
- const fullScreenTargetRef = useRef(null);
-
- useEffect(() => {
- (async () => {
- if (!isNaN(id)) {
- const c = await DocumentAccessor.findById(id);
- setInfo({ doc: c, notfound: c === undefined });
- }
- })();
- }, []);
-
- if (isNaN(id)) {
- return (
-
- Oops. Invalid ID
-
- );
- } else if (info.notfound) {
- return (
-
- Content has been removed.
-
- );
- } else if (info.doc === undefined) {
- return (
-
-
-
- );
- } else {
- const ReaderPage = getPresenter(info.doc);
- return (
- {
- if (fullScreenTargetRef.current != null && document.fullscreenEnabled) {
- fullScreenTargetRef.current.requestFullscreen();
- }
- }}
- color="inherit">
-
- }>
-
-
- );
- }
-}
-
-export const DocumentAbout = (prop?: {}) => {
- const match = useParams<{ id: string }>();
- if (match == null) {
- throw new Error("unreachable");
- }
- const id = Number.parseInt(match.id ?? "NaN");
- const [info, setInfo] = useState({ doc: undefined, notfound: false });
- const menu_list = (link?: string) => ;
-
- useEffect(() => {
- (async () => {
- if (!isNaN(id)) {
- const c = await DocumentAccessor.findById(id);
- setInfo({ doc: c, notfound: c === undefined });
- }
- })();
- }, []);
-
- if (isNaN(id)) {
- return (
-
-
- Oops. Invalid ID
-
-
- );
- } else if (info.notfound) {
- return (
-
-
- Content has been removed.
-
-
- );
- } else if (info.doc === undefined) {
- return (
-
-
-
-
-
- );
- } else {
- return (
-
-
-
-
-
- );
- }
-};
diff --git a/src/client/page/difference.tsx b/src/client/page/difference.tsx
deleted file mode 100644
index 1cf82de..0000000
--- a/src/client/page/difference.tsx
+++ /dev/null
@@ -1,131 +0,0 @@
-import { Box, Button, Paper, Typography } from "@mui/material";
-import React, { useContext, useEffect, useState } from "react";
-import { CommonMenuList, Headline } from "../component/mod";
-import { UserContext } from "../state";
-import { PagePad } from "../component/pagepad";
-
-type FileDifference = {
- type: string;
- value: {
- type: string;
- path: string;
- }[];
-};
-
-function TypeDifference(prop: {
- content: FileDifference;
- onCommit: (v: { type: string; path: string }) => void;
- onCommitAll: (type: string) => void;
-}) {
- // const classes = useStyles();
- const x = prop.content;
- const [button_disable, set_disable] = useState(false);
-
- return (
-
-
- {x.type}
-
-
- {x.value.map(y => (
-
-
- {y.path}
-
- ))}
-
- );
-}
-
-export function DifferencePage() {
- const ctx = useContext(UserContext);
- // const classes = useStyles();
- const [diffList, setDiffList] = useState<
- FileDifference[]
- >([]);
- const doLoad = async () => {
- const list = await fetch("/api/diff/list");
- if (list.ok) {
- const inner = await list.json();
- setDiffList(inner);
- } else {
- // setDiffList([]);
- }
- };
- const Commit = async (x: { type: string; path: string }) => {
- const res = await fetch("/api/diff/commit", {
- method: "POST",
- body: JSON.stringify([{ ...x }]),
- headers: {
- "content-type": "application/json",
- },
- });
- const bb = await res.json();
- if (bb.ok) {
- doLoad();
- } else {
- console.error("fail to add document");
- }
- };
- const CommitAll = async (type: string) => {
- const res = await fetch("/api/diff/commitall", {
- method: "POST",
- body: JSON.stringify({ type: type }),
- headers: {
- "content-type": "application/json",
- },
- });
- const bb = await res.json();
- if (bb.ok) {
- doLoad();
- } else {
- console.error("fail to add document");
- }
- };
- useEffect(
- () => {
- doLoad();
- const i = setInterval(doLoad, 5000);
- return () => {
- clearInterval(i);
- };
- },
- [],
- );
- const menu = CommonMenuList();
- return (
-
-
- {(ctx.username == "admin")
- ? (
-
- {diffList.map(x => (
-
- ))}
-
- )
- : Not Allowed : please login as an admin}
-
-
- );
-}
diff --git a/src/client/page/gallery.tsx b/src/client/page/gallery.tsx
deleted file mode 100644
index 5a7e126..0000000
--- a/src/client/page/gallery.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import React, { useContext, useEffect, useState } from "react";
-import { CommonMenuList, ContentInfo, Headline, LoadingCircle, NavItem, NavList, TagChip } from "../component/mod";
-
-import { Box, Button, Chip, Pagination, Typography } from "@mui/material";
-import ContentAccessor, { Document, QueryListOption } from "../accessor/document";
-import { toQueryString } from "../accessor/util";
-
-import { useLocation } from "react-router-dom";
-import { QueryStringToMap } from "../accessor/util";
-import { useIsElementInViewport } from "./reader/reader";
-import { PagePad } from "../component/pagepad";
-
-export type GalleryProp = {
- option?: QueryListOption;
- diff: string;
-};
-type GalleryState = {
- documents: Document[] | undefined;
-};
-
-export const GalleryInfo = (props: GalleryProp) => {
- const [state, setState] = useState({ documents: undefined });
- const [error, setError] = useState(null);
- const [loadAll, setLoadAll] = useState(false);
- const { elementRef, isVisible: isLoadVisible } = useIsElementInViewport({});
-
- useEffect(() => {
- if (isLoadVisible && (!loadAll) && (state.documents != undefined)) {
- loadMore();
- }
- }, [isLoadVisible]);
-
- useEffect(() => {
- const abortController = new AbortController();
- console.log("load first", props.option);
- const load = async () => {
- try {
- const c = await ContentAccessor.findList(props.option);
- // todo : if c is undefined, retry to fetch 3 times. and show error message.
- setState({ documents: c });
- setLoadAll(c.length == 0);
- } catch (e) {
- if (e instanceof Error) {
- setError(e.message);
- } else {
- setError("unknown error");
- }
- }
- };
- load();
- }, [props.diff]);
- const queryString = toQueryString(props.option ?? {});
- if (state.documents === undefined && error == null) {
- return ;
- } else {
- return (
-
- {props.option !== undefined && props.diff !== "" && (
-
- search for
- {props.option.word !== undefined && (
-
- )}
- {props.option.content_type !== undefined && (
-
- )}
- {props.option.allow_tag !== undefined
- && props.option.allow_tag.map(x => (
-
- ))}
-
- )}
- {state.documents && state.documents.map(x => {
- return ;
- })}
- {error && Error : {error}}
-
- {state.documents ? state.documents.length : "null"} loaded...
-
-
-
- );
- }
- function loadMore() {
- let option = { ...props.option };
- console.log(elementRef);
- if (state.documents === undefined || state.documents.length === 0) {
- console.log("loadall");
- setLoadAll(true);
- return;
- }
- const prev_documents = state.documents;
- option.cursor = prev_documents[prev_documents.length - 1].id;
- console.log("load more", option);
- const load = async () => {
- const c = await ContentAccessor.findList(option);
- if (c.length === 0) {
- setLoadAll(true);
- } else {
- setState({ documents: [...prev_documents, ...c] });
- }
- };
- load();
- }
-};
-
-export const Gallery = () => {
- const location = useLocation();
- const query = QueryStringToMap(location.search);
- const menu_list = CommonMenuList({ url: location.search });
- let option: QueryListOption = query;
- option.allow_tag = typeof option.allow_tag === "string" ? [option.allow_tag] : option.allow_tag;
- option.limit = typeof query["limit"] === "string" ? parseInt(query["limit"]) : undefined;
- return (
-
-
-
-
-
- );
-};
diff --git a/src/client/page/login.tsx b/src/client/page/login.tsx
deleted file mode 100644
index 82d0720..0000000
--- a/src/client/page/login.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import {
- Button,
- Dialog,
- DialogActions,
- DialogContent,
- DialogContentText,
- DialogTitle,
- MenuList,
- Paper,
- TextField,
- Typography,
- useTheme,
-} from "@mui/material";
-import React, { useContext, useState } from "react";
-import { useNavigate } from "react-router-dom";
-import { CommonMenuList, Headline } from "../component/mod";
-import { UserContext } from "../state";
-import { doLogin as doSessionLogin } from "../state";
-import { PagePad } from "../component/pagepad";
-
-export const LoginPage = () => {
- const theme = useTheme();
- const [userLoginInfo, setUserLoginInfo] = useState({ username: "", password: "" });
- const [openDialog, setOpenDialog] = useState({ open: false, message: "" });
- const { setUsername, setPermission } = useContext(UserContext);
- const navigate = useNavigate();
- const handleDialogClose = () => {
- setOpenDialog({ ...openDialog, open: false });
- };
- const doLogin = async () => {
- try {
- const b = await doSessionLogin(userLoginInfo);
- if (typeof b === "string") {
- setOpenDialog({ open: true, message: b });
- return;
- }
- console.log(`login as ${b.username}`);
- setUsername(b.username);
- setPermission(b.permission);
- } catch (e) {
- if (e instanceof Error) {
- console.error(e);
- setOpenDialog({ open: true, message: e.message });
- } else console.error(e);
- return;
- }
- navigate("/");
- };
- const menu = CommonMenuList();
- return (
-
-
-
- Login
-
-
-
-
-
-
- );
-};
diff --git a/src/client/page/mod.ts b/src/client/page/mod.ts
deleted file mode 100644
index 47167f2..0000000
--- a/src/client/page/mod.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export * from "./404";
-export * from "./contentinfo";
-export * from "./difference";
-export * from "./gallery";
-export * from "./login";
-export * from "./profile";
-export * from "./setting";
-export * from "./tags";
diff --git a/src/client/page/profile.tsx b/src/client/page/profile.tsx
deleted file mode 100644
index 8df722e..0000000
--- a/src/client/page/profile.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-import {
- Button,
- Chip,
- Dialog,
- DialogActions,
- DialogContent,
- DialogContentText,
- DialogTitle,
- Divider,
- Grid,
- Paper,
- TextField,
- Theme,
- Typography,
-} from "@mui/material";
-import React, { useContext, useState } from "react";
-import { CommonMenuList, Headline } from "../component/mod";
-import { UserContext } from "../state";
-import { PagePad } from "../component/pagepad";
-
-const useStyles = (theme: Theme) => ({
- paper: {
- alignSelf: "center",
- padding: theme.spacing(2),
- },
- formfield: {
- display: "flex",
- flexFlow: "column",
- },
-});
-
-export function ProfilePage() {
- const userctx = useContext(UserContext);
- // const classes = useStyles();
- const menu = CommonMenuList();
- const [pw_open, set_pw_open] = useState(false);
- const [oldpw, setOldpw] = useState("");
- const [newpw, setNewpw] = useState("");
- const [newpwch, setNewpwch] = useState("");
- const [msg_dialog, set_msg_dialog] = useState({ opened: false, msg: "" });
- const permission_list = userctx.permission.map(p => );
- const isElectronContent = ((window["electron"] as any) !== undefined) as boolean;
- const handle_open = () => set_pw_open(true);
- const handle_close = () => {
- set_pw_open(false);
- setNewpw("");
- setNewpwch("");
- };
- const handle_ok = async () => {
- if (newpw != newpwch) {
- set_msg_dialog({ opened: true, msg: "password and password check is not equal." });
- handle_close();
- return;
- }
- if (isElectronContent) {
- const elec = window["electron"] as any;
- const success = elec.passwordReset(userctx.username, newpw);
- if (!success) {
- set_msg_dialog({ opened: true, msg: "user not exist." });
- }
- } else {
- const res = await fetch("/user/reset", {
- method: "POST",
- body: JSON.stringify({
- username: userctx.username,
- oldpassword: oldpw,
- newpassword: newpw,
- }),
- headers: {
- "content-type": "application/json",
- },
- });
- if (res.status != 200) {
- set_msg_dialog({ opened: true, msg: "failed to change password." });
- }
- }
- handle_close();
- };
- return (
-
-
-
-
-
-
- {userctx.username}
-
-
-
- Permission
-
-
- {permission_list.length == 0 ? "-" : permission_list}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/client/page/reader/comic.tsx b/src/client/page/reader/comic.tsx
deleted file mode 100644
index 70d7baf..0000000
--- a/src/client/page/reader/comic.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import { Typography, styled } from "@mui/material";
-import React, { RefObject, useEffect, useState } from "react";
-import { useSearchParams } from "react-router-dom";
-import { Document } from "../../accessor/document";
-
-type ComicType = "comic" | "artist cg" | "donjinshi" | "western";
-
-export type PresentableTag = {
- artist: string[];
- group: string[];
- series: string[];
- type: ComicType;
- character: string[];
- tags: string[];
-};
-
-const ViewMain = styled("div")(({ theme }) => ({
- overflow: "hidden",
- width: "100%",
- height: "calc(100vh - 64px)",
- position: "relative",
-}));
-const CurrentView = styled("img")(({theme})=>({
- maxWidth: "100%",
- maxHeight: "100%",
- top:"50%",
- left:"50%",
- transform: "translate(-50%,-50%)",
- position: "absolute"
-}));
-
-export const ComicReader = (props: { doc: Document,
- fullScreenTarget?: RefObject
}) => {
- const additional = props.doc.additional;
- const [searchParams, setSearchParams] = useSearchParams();
-
- const curPage = (parseInt(searchParams.get("page") ?? "0"));
- const setCurPage = (n: number) => {
- setSearchParams([
- ["page", n.toString()]
- ]);
- }
- if (isNaN(curPage)){
- return Error. Page number is not a number.
- }
- if (!("page" in additional)) {
- console.error("invalid content : page read fail : " + JSON.stringify(additional));
- return Error. DB error. page restriction;
- }
-
- const maxPage: number = additional["page"] as number;
- const PageDown = () => setCurPage(Math.max(curPage - 1, 0));
- const PageUp = () => setCurPage(Math.min(curPage + 1, maxPage - 1));
-
- const onKeyUp = (e: KeyboardEvent) => {
- console.log(`currently: ${curPage}/${maxPage}`)
- if (e.code === "ArrowLeft") {
- PageDown();
- } else if (e.code === "ArrowRight") {
- PageUp();
- }
- };
-
- useEffect(() => {
- document.addEventListener("keydown", onKeyUp);
- return () => {
- document.removeEventListener("keydown", onKeyUp);
- };
- }, [curPage]);
- // theme.mixins.toolbar.minHeight;
- return (
-
-
-
-
-
- );
-};
-
-export default ComicReader;
diff --git a/src/client/page/reader/reader.tsx b/src/client/page/reader/reader.tsx
deleted file mode 100644
index 16877d6..0000000
--- a/src/client/page/reader/reader.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { styled, Typography } from "@mui/material";
-import React from "react";
-import { Document, makeThumbnailUrl } from "../../accessor/document";
-import { ComicReader } from "./comic";
-import { VideoReader } from "./video";
-
-export interface PagePresenterProp {
- doc: Document;
- className?: string;
- fullScreenTarget?: React.RefObject;
-}
-interface PagePresenter {
- (prop: PagePresenterProp): JSX.Element;
-}
-
-export const getPresenter = (content: Document): PagePresenter => {
- switch (content.content_type) {
- case "comic":
- return ComicReader;
- case "video":
- return VideoReader;
- }
- return () => Not implemented reader;
-};
-const BackgroundDiv = styled("div")({
- height: "400px",
- width: "300px",
- backgroundColor: "#272733",
- display: "flex",
- alignItems: "center",
- justifyContent: "center",
-});
-
-import { useEffect, useRef, useState } from "react";
-import "./thumbnail.css";
-
-export function useIsElementInViewport(options?: IntersectionObserverInit) {
- const elementRef = useRef(null);
- const [isVisible, setIsVisible] = useState(false);
-
- const callback = (entries: IntersectionObserverEntry[]) => {
- const [entry] = entries;
- setIsVisible(entry.isIntersecting);
- };
-
- useEffect(() => {
- const observer = new IntersectionObserver(callback, options);
- elementRef.current && observer.observe(elementRef.current);
- return () => observer.disconnect();
- }, [elementRef, options]);
-
- return { elementRef, isVisible };
-}
-
-export function ThumbnailContainer(props: {
- content: Document;
- className?: string;
-}) {
- const { elementRef, isVisible } = useIsElementInViewport({});
- const [loaded, setLoaded] = useState(false);
- useEffect(() => {
- if (isVisible) {
- setLoaded(true);
- }
- }, [isVisible]);
- const style = {
- maxHeight: "400px",
- maxWidth: "min(400px, 100vw)",
- };
- const thumbnailurl = makeThumbnailUrl(props.content);
- if (props.content.content_type === "video") {
- return ;
- } else {return (
-
- {loaded && }
-
- );}
-}
diff --git a/src/client/page/reader/video.tsx b/src/client/page/reader/video.tsx
deleted file mode 100644
index af6d137..0000000
--- a/src/client/page/reader/video.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from "react";
-import { Document } from "../../accessor/document";
-
-export const VideoReader = (props: { doc: Document }) => {
- const id = props.doc.id;
- return (
-
- );
-};
diff --git a/src/client/page/setting.tsx b/src/client/page/setting.tsx
deleted file mode 100644
index a2d102b..0000000
--- a/src/client/page/setting.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Paper, Typography } from "@mui/material";
-import React from "react";
-import { CommonMenuList, Headline } from "../component/mod";
-import { PagePad } from "../component/pagepad";
-
-export const SettingPage = () => {
- const menu = CommonMenuList();
- return (
-
-
-
- Setting
-
-
-
- );
-};
diff --git a/src/client/page/tags.tsx b/src/client/page/tags.tsx
deleted file mode 100644
index 9c65cea..0000000
--- a/src/client/page/tags.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import { Box, Paper, Typography } from "@mui/material";
-import { DataGrid, GridColDef } from "@mui/x-data-grid";
-import React, { useEffect, useState } from "react";
-import { LoadingCircle } from "../component/loading";
-import { CommonMenuList, Headline } from "../component/mod";
-import { PagePad } from "../component/pagepad";
-
-type TagCount = {
- tag_name: string;
- occurs: number;
-};
-
-const tagTableColumn: GridColDef[] = [
- {
- field: "tag_name",
- headerName: "Tag Name",
- width: 200,
- },
- {
- field: "occurs",
- headerName: "Occurs",
- width: 100,
- type: "number",
- },
-];
-
-function TagTable() {
- const [data, setData] = useState();
- const [error, setErrorMsg] = useState(undefined);
- const isLoading = data === undefined;
-
- useEffect(() => {
- loadData();
- }, []);
-
- if (isLoading) {
- return ;
- }
- if (error !== undefined) {
- return {error};
- }
- return (
-
-
- t.tag_name}>
-
-
- );
-
- async function loadData() {
- try {
- const res = await fetch("/api/tags?withCount=true");
- const data = await res.json();
- setData(data);
- } catch (e) {
- setData([]);
- if (e instanceof Error) {
- setErrorMsg(e.message);
- } else {
- console.log(e);
- setErrorMsg("");
- }
- }
- }
-}
-
-export const TagsPage = () => {
- const menu = CommonMenuList();
- return (
-
-
-
-
-
- );
-};
diff --git a/src/client/pnpm-lock.yaml b/src/client/pnpm-lock.yaml
deleted file mode 100644
index f8f0e79..0000000
--- a/src/client/pnpm-lock.yaml
+++ /dev/null
@@ -1,1421 +0,0 @@
-lockfileVersion: '6.0'
-
-dependencies:
- '@emotion/react':
- specifier: ^11.9.0
- version: 11.9.3(@babel/core@7.22.1)(@types/react@18.0.12)(react@18.1.0)
- '@emotion/styled':
- specifier: ^11.8.1
- version: 11.9.3(@babel/core@7.22.1)(@emotion/react@11.9.3)(@types/react@18.0.12)(react@18.1.0)
- '@mui/icons-material':
- specifier: ^5.6.2
- version: 5.8.3(@mui/material@5.8.3)(@types/react@18.0.12)(react@18.1.0)
- '@mui/material':
- specifier: ^5.6.2
- version: 5.8.3(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.12)(react-dom@18.1.0)(react@18.1.0)
- '@mui/x-data-grid':
- specifier: ^5.12.3
- version: 5.12.3(@mui/material@5.8.3)(@mui/system@5.8.3)(react-dom@18.1.0)(react@18.1.0)
- '@types/react':
- specifier: ^18.0.5
- version: 18.0.12
- '@types/react-dom':
- specifier: ^18.0.1
- version: 18.0.5
- react:
- specifier: ^18.0.0
- version: 18.1.0
- react-dom:
- specifier: ^18.0.0
- version: 18.1.0(react@18.1.0)
- react-router-dom:
- specifier: ^6.3.0
- version: 6.3.0(react-dom@18.1.0)(react@18.1.0)
-
-devDependencies:
- esbuild:
- specifier: ^0.14.36
- version: 0.14.43
- ts-node:
- specifier: ^10.7.0
- version: 10.8.1(@types/node@20.2.5)(typescript@5.0.4)
-
-packages:
-
- /@ampproject/remapping@2.2.1:
- resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
- engines: {node: '>=6.0.0'}
- dependencies:
- '@jridgewell/gen-mapping': 0.3.3
- '@jridgewell/trace-mapping': 0.3.9
- dev: false
-
- /@babel/code-frame@7.16.7:
- resolution: {integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/highlight': 7.17.12
- dev: false
-
- /@babel/code-frame@7.21.4:
- resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/highlight': 7.18.6
- dev: false
-
- /@babel/compat-data@7.22.3:
- resolution: {integrity: sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /@babel/core@7.22.1:
- resolution: {integrity: sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@ampproject/remapping': 2.2.1
- '@babel/code-frame': 7.21.4
- '@babel/generator': 7.22.3
- '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1)
- '@babel/helper-module-transforms': 7.22.1
- '@babel/helpers': 7.22.3
- '@babel/parser': 7.22.4
- '@babel/template': 7.21.9
- '@babel/traverse': 7.22.4
- '@babel/types': 7.22.4
- convert-source-map: 1.8.0
- debug: 4.3.4
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.0
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /@babel/generator@7.22.3:
- resolution: {integrity: sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.22.4
- '@jridgewell/gen-mapping': 0.3.3
- '@jridgewell/trace-mapping': 0.3.18
- jsesc: 2.5.2
- dev: false
-
- /@babel/helper-compilation-targets@7.22.1(@babel/core@7.22.1):
- resolution: {integrity: sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
- dependencies:
- '@babel/compat-data': 7.22.3
- '@babel/core': 7.22.1
- '@babel/helper-validator-option': 7.21.0
- browserslist: 4.21.7
- lru-cache: 5.1.1
- semver: 6.3.0
- dev: false
-
- /@babel/helper-environment-visitor@7.22.1:
- resolution: {integrity: sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /@babel/helper-function-name@7.21.0:
- resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/template': 7.21.9
- '@babel/types': 7.22.4
- dev: false
-
- /@babel/helper-hoist-variables@7.18.6:
- resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.22.4
- dev: false
-
- /@babel/helper-module-imports@7.16.7:
- resolution: {integrity: sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.18.4
- dev: false
-
- /@babel/helper-module-imports@7.21.4:
- resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.22.4
- dev: false
-
- /@babel/helper-module-transforms@7.22.1:
- resolution: {integrity: sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/helper-environment-visitor': 7.22.1
- '@babel/helper-module-imports': 7.21.4
- '@babel/helper-simple-access': 7.21.5
- '@babel/helper-split-export-declaration': 7.18.6
- '@babel/helper-validator-identifier': 7.19.1
- '@babel/template': 7.21.9
- '@babel/traverse': 7.22.4
- '@babel/types': 7.22.4
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /@babel/helper-plugin-utils@7.17.12:
- resolution: {integrity: sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /@babel/helper-simple-access@7.21.5:
- resolution: {integrity: sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.22.4
- dev: false
-
- /@babel/helper-split-export-declaration@7.18.6:
- resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.22.4
- dev: false
-
- /@babel/helper-string-parser@7.21.5:
- resolution: {integrity: sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /@babel/helper-validator-identifier@7.16.7:
- resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /@babel/helper-validator-identifier@7.19.1:
- resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /@babel/helper-validator-option@7.21.0:
- resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /@babel/helpers@7.22.3:
- resolution: {integrity: sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/template': 7.21.9
- '@babel/traverse': 7.22.4
- '@babel/types': 7.22.4
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /@babel/highlight@7.17.12:
- resolution: {integrity: sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/helper-validator-identifier': 7.16.7
- chalk: 2.4.2
- js-tokens: 4.0.0
- dev: false
-
- /@babel/highlight@7.18.6:
- resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/helper-validator-identifier': 7.19.1
- chalk: 2.4.2
- js-tokens: 4.0.0
- dev: false
-
- /@babel/parser@7.22.4:
- resolution: {integrity: sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==}
- engines: {node: '>=6.0.0'}
- hasBin: true
- dependencies:
- '@babel/types': 7.22.4
- dev: false
-
- /@babel/plugin-syntax-jsx@7.17.12(@babel/core@7.22.1):
- resolution: {integrity: sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
- dependencies:
- '@babel/core': 7.22.1
- '@babel/helper-plugin-utils': 7.17.12
- dev: false
-
- /@babel/runtime@7.18.3:
- resolution: {integrity: sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==}
- engines: {node: '>=6.9.0'}
- dependencies:
- regenerator-runtime: 0.13.9
- dev: false
-
- /@babel/template@7.21.9:
- resolution: {integrity: sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/code-frame': 7.21.4
- '@babel/parser': 7.22.4
- '@babel/types': 7.22.4
- dev: false
-
- /@babel/traverse@7.22.4:
- resolution: {integrity: sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/code-frame': 7.21.4
- '@babel/generator': 7.22.3
- '@babel/helper-environment-visitor': 7.22.1
- '@babel/helper-function-name': 7.21.0
- '@babel/helper-hoist-variables': 7.18.6
- '@babel/helper-split-export-declaration': 7.18.6
- '@babel/parser': 7.22.4
- '@babel/types': 7.22.4
- debug: 4.3.4
- globals: 11.12.0
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /@babel/types@7.18.4:
- resolution: {integrity: sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/helper-validator-identifier': 7.16.7
- to-fast-properties: 2.0.0
- dev: false
-
- /@babel/types@7.22.4:
- resolution: {integrity: sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/helper-string-parser': 7.21.5
- '@babel/helper-validator-identifier': 7.19.1
- to-fast-properties: 2.0.0
- dev: false
-
- /@cspotcode/source-map-support@0.8.1:
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
- dependencies:
- '@jridgewell/trace-mapping': 0.3.9
- dev: true
-
- /@emotion/babel-plugin@11.9.2(@babel/core@7.22.1):
- resolution: {integrity: sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==}
- peerDependencies:
- '@babel/core': ^7.0.0
- dependencies:
- '@babel/core': 7.22.1
- '@babel/helper-module-imports': 7.16.7
- '@babel/plugin-syntax-jsx': 7.17.12(@babel/core@7.22.1)
- '@babel/runtime': 7.18.3
- '@emotion/hash': 0.8.0
- '@emotion/memoize': 0.7.5
- '@emotion/serialize': 1.0.4
- babel-plugin-macros: 2.8.0
- convert-source-map: 1.8.0
- escape-string-regexp: 4.0.0
- find-root: 1.1.0
- source-map: 0.5.7
- stylis: 4.0.13
- dev: false
-
- /@emotion/cache@11.9.3:
- resolution: {integrity: sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==}
- dependencies:
- '@emotion/memoize': 0.7.5
- '@emotion/sheet': 1.1.1
- '@emotion/utils': 1.1.0
- '@emotion/weak-memoize': 0.2.5
- stylis: 4.0.13
- dev: false
-
- /@emotion/hash@0.8.0:
- resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
- dev: false
-
- /@emotion/is-prop-valid@1.1.3:
- resolution: {integrity: sha512-RFg04p6C+1uO19uG8N+vqanzKqiM9eeV1LDOG3bmkYmuOj7NbKNlFC/4EZq5gnwAIlcC/jOT24f8Td0iax2SXA==}
- dependencies:
- '@emotion/memoize': 0.7.5
- dev: false
-
- /@emotion/memoize@0.7.5:
- resolution: {integrity: sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==}
- dev: false
-
- /@emotion/react@11.9.3(@babel/core@7.22.1)(@types/react@18.0.12)(react@18.1.0):
- resolution: {integrity: sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==}
- peerDependencies:
- '@babel/core': ^7.0.0
- '@types/react': '*'
- react: '>=16.8.0'
- peerDependenciesMeta:
- '@babel/core':
- optional: true
- '@types/react':
- optional: true
- dependencies:
- '@babel/core': 7.22.1
- '@babel/runtime': 7.18.3
- '@emotion/babel-plugin': 11.9.2(@babel/core@7.22.1)
- '@emotion/cache': 11.9.3
- '@emotion/serialize': 1.0.4
- '@emotion/utils': 1.1.0
- '@emotion/weak-memoize': 0.2.5
- '@types/react': 18.0.12
- hoist-non-react-statics: 3.3.2
- react: 18.1.0
- dev: false
-
- /@emotion/serialize@1.0.4:
- resolution: {integrity: sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==}
- dependencies:
- '@emotion/hash': 0.8.0
- '@emotion/memoize': 0.7.5
- '@emotion/unitless': 0.7.5
- '@emotion/utils': 1.1.0
- csstype: 3.1.0
- dev: false
-
- /@emotion/sheet@1.1.1:
- resolution: {integrity: sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA==}
- dev: false
-
- /@emotion/styled@11.9.3(@babel/core@7.22.1)(@emotion/react@11.9.3)(@types/react@18.0.12)(react@18.1.0):
- resolution: {integrity: sha512-o3sBNwbtoVz9v7WB1/Y/AmXl69YHmei2mrVnK7JgyBJ//Rst5yqPZCecEJlMlJrFeWHp+ki/54uN265V2pEcXA==}
- peerDependencies:
- '@babel/core': ^7.0.0
- '@emotion/react': ^11.0.0-rc.0
- '@types/react': '*'
- react: '>=16.8.0'
- peerDependenciesMeta:
- '@babel/core':
- optional: true
- '@types/react':
- optional: true
- dependencies:
- '@babel/core': 7.22.1
- '@babel/runtime': 7.18.3
- '@emotion/babel-plugin': 11.9.2(@babel/core@7.22.1)
- '@emotion/is-prop-valid': 1.1.3
- '@emotion/react': 11.9.3(@babel/core@7.22.1)(@types/react@18.0.12)(react@18.1.0)
- '@emotion/serialize': 1.0.4
- '@emotion/utils': 1.1.0
- '@types/react': 18.0.12
- react: 18.1.0
- dev: false
-
- /@emotion/unitless@0.7.5:
- resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
- dev: false
-
- /@emotion/utils@1.1.0:
- resolution: {integrity: sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==}
- dev: false
-
- /@emotion/weak-memoize@0.2.5:
- resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==}
- dev: false
-
- /@jridgewell/gen-mapping@0.3.3:
- resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
- engines: {node: '>=6.0.0'}
- dependencies:
- '@jridgewell/set-array': 1.1.2
- '@jridgewell/sourcemap-codec': 1.4.13
- '@jridgewell/trace-mapping': 0.3.18
- dev: false
-
- /@jridgewell/resolve-uri@3.0.7:
- resolution: {integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==}
- engines: {node: '>=6.0.0'}
-
- /@jridgewell/resolve-uri@3.1.0:
- resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
- engines: {node: '>=6.0.0'}
- dev: false
-
- /@jridgewell/set-array@1.1.2:
- resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
- engines: {node: '>=6.0.0'}
- dev: false
-
- /@jridgewell/sourcemap-codec@1.4.13:
- resolution: {integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==}
-
- /@jridgewell/sourcemap-codec@1.4.14:
- resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
- dev: false
-
- /@jridgewell/trace-mapping@0.3.18:
- resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
- dependencies:
- '@jridgewell/resolve-uri': 3.1.0
- '@jridgewell/sourcemap-codec': 1.4.14
- dev: false
-
- /@jridgewell/trace-mapping@0.3.9:
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
- dependencies:
- '@jridgewell/resolve-uri': 3.0.7
- '@jridgewell/sourcemap-codec': 1.4.13
-
- /@mui/base@5.0.0-alpha.84(@types/react@18.0.12)(react-dom@18.1.0)(react@18.1.0):
- resolution: {integrity: sha512-uDx+wGVytS+ZHiWHyzUyijY83GSIXJpzSJ0PGc/8/s+8nBzeHvaPKrAyJz15ASLr52hYRA6PQGqn0eRAsB7syQ==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@types/react': ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- react-dom: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
- dependencies:
- '@babel/runtime': 7.18.3
- '@emotion/is-prop-valid': 1.1.3
- '@mui/types': 7.1.3(@types/react@18.0.12)
- '@mui/utils': 5.8.0(react@18.1.0)
- '@popperjs/core': 2.11.5
- '@types/react': 18.0.12
- clsx: 1.1.1
- prop-types: 15.8.1
- react: 18.1.0
- react-dom: 18.1.0(react@18.1.0)
- react-is: 17.0.2
- dev: false
-
- /@mui/icons-material@5.8.3(@mui/material@5.8.3)(@types/react@18.0.12)(react@18.1.0):
- resolution: {integrity: sha512-dAdhimSLKOV0Q8FR7AYGEaCrTUh9OV7zU4Ueo5REoUt4cC3Vy+UBKDjZk66x5ezaYb63AFgQIFwtnZj3B/QDbQ==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@mui/material': ^5.0.0
- '@types/react': ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
- dependencies:
- '@babel/runtime': 7.18.3
- '@mui/material': 5.8.3(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.12)(react-dom@18.1.0)(react@18.1.0)
- '@types/react': 18.0.12
- react: 18.1.0
- dev: false
-
- /@mui/material@5.8.3(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.12)(react-dom@18.1.0)(react@18.1.0):
- resolution: {integrity: sha512-8UecY/W9SMtEZm5PMCUcMbujajVP6fobu0BgBPiIWwwWRblZVEzqprY6v1P2me7qCyrve4L4V/rqAKPKhVHOSg==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@emotion/react': ^11.5.0
- '@emotion/styled': ^11.3.0
- '@types/react': ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- react-dom: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- '@emotion/react':
- optional: true
- '@emotion/styled':
- optional: true
- '@types/react':
- optional: true
- dependencies:
- '@babel/runtime': 7.18.3
- '@emotion/react': 11.9.3(@babel/core@7.22.1)(@types/react@18.0.12)(react@18.1.0)
- '@emotion/styled': 11.9.3(@babel/core@7.22.1)(@emotion/react@11.9.3)(@types/react@18.0.12)(react@18.1.0)
- '@mui/base': 5.0.0-alpha.84(@types/react@18.0.12)(react-dom@18.1.0)(react@18.1.0)
- '@mui/system': 5.8.3(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.12)(react@18.1.0)
- '@mui/types': 7.1.3(@types/react@18.0.12)
- '@mui/utils': 5.8.0(react@18.1.0)
- '@types/react': 18.0.12
- '@types/react-transition-group': 4.4.4
- clsx: 1.1.1
- csstype: 3.1.0
- hoist-non-react-statics: 3.3.2
- prop-types: 15.8.1
- react: 18.1.0
- react-dom: 18.1.0(react@18.1.0)
- react-is: 17.0.2
- react-transition-group: 4.4.2(react-dom@18.1.0)(react@18.1.0)
- dev: false
-
- /@mui/private-theming@5.8.0(@types/react@18.0.12)(react@18.1.0):
- resolution: {integrity: sha512-MjRAneTmCKLR9u2S4jtjLUe6gpHxlbb4g2bqpDJ2PdwlvwsWIUzbc/gVB4dvccljXeWxr5G2M/Co2blXisvFIw==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@types/react': ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
- dependencies:
- '@babel/runtime': 7.18.3
- '@mui/utils': 5.8.0(react@18.1.0)
- '@types/react': 18.0.12
- prop-types: 15.8.1
- react: 18.1.0
- dev: false
-
- /@mui/styled-engine@5.8.0(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.1.0):
- resolution: {integrity: sha512-Q3spibB8/EgeMYHc+/o3RRTnAYkSl7ROCLhXJ830W8HZ2/iDiyYp16UcxKPurkXvLhUaILyofPVrP3Su2uKsAw==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@emotion/react': ^11.4.1
- '@emotion/styled': ^11.3.0
- react: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- '@emotion/react':
- optional: true
- '@emotion/styled':
- optional: true
- dependencies:
- '@babel/runtime': 7.18.3
- '@emotion/cache': 11.9.3
- '@emotion/react': 11.9.3(@babel/core@7.22.1)(@types/react@18.0.12)(react@18.1.0)
- '@emotion/styled': 11.9.3(@babel/core@7.22.1)(@emotion/react@11.9.3)(@types/react@18.0.12)(react@18.1.0)
- prop-types: 15.8.1
- react: 18.1.0
- dev: false
-
- /@mui/system@5.8.3(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.12)(react@18.1.0):
- resolution: {integrity: sha512-/tyGQcYqZT0nl98qV9XnGiedTO+V7VHc28k4POfhMJNedB1CRrwWRm767DeEdc5f/8CU2See3WD16ikP6pYiOA==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@emotion/react': ^11.5.0
- '@emotion/styled': ^11.3.0
- '@types/react': ^17.0.0 || ^18.0.0
- react: ^17.0.0 || ^18.0.0
- peerDependenciesMeta:
- '@emotion/react':
- optional: true
- '@emotion/styled':
- optional: true
- '@types/react':
- optional: true
- dependencies:
- '@babel/runtime': 7.18.3
- '@emotion/react': 11.9.3(@babel/core@7.22.1)(@types/react@18.0.12)(react@18.1.0)
- '@emotion/styled': 11.9.3(@babel/core@7.22.1)(@emotion/react@11.9.3)(@types/react@18.0.12)(react@18.1.0)
- '@mui/private-theming': 5.8.0(@types/react@18.0.12)(react@18.1.0)
- '@mui/styled-engine': 5.8.0(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.1.0)
- '@mui/types': 7.1.3(@types/react@18.0.12)
- '@mui/utils': 5.8.0(react@18.1.0)
- '@types/react': 18.0.12
- clsx: 1.1.1
- csstype: 3.1.0
- prop-types: 15.8.1
- react: 18.1.0
- dev: false
-
- /@mui/types@7.1.3(@types/react@18.0.12):
- resolution: {integrity: sha512-DDF0UhMBo4Uezlk+6QxrlDbchF79XG6Zs0zIewlR4c0Dt6GKVFfUtzPtHCH1tTbcSlq/L2bGEdiaoHBJ9Y1gSA==}
- peerDependencies:
- '@types/react': '*'
- peerDependenciesMeta:
- '@types/react':
- optional: true
- dependencies:
- '@types/react': 18.0.12
- dev: false
-
- /@mui/utils@5.8.0(react@18.1.0):
- resolution: {integrity: sha512-7LgUtCvz78676iC0wpTH7HizMdCrTphhBmRWimIMFrp5Ph6JbDFVuKS1CwYnWWxRyYKL0QzXrDL0lptAU90EXg==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- react: ^17.0.0 || ^18.0.0
- dependencies:
- '@babel/runtime': 7.18.3
- '@types/prop-types': 15.7.5
- '@types/react-is': 17.0.3
- prop-types: 15.8.1
- react: 18.1.0
- react-is: 17.0.2
- dev: false
-
- /@mui/x-data-grid@5.12.3(@mui/material@5.8.3)(@mui/system@5.8.3)(react-dom@18.1.0)(react@18.1.0):
- resolution: {integrity: sha512-57A2MkRR/uUNC/dECFV0YDJvi1Q+gQgmgw1OHmZ1uSnKh29PcHpswkdapO0LueLpxAy8tfH+fTtnnPDmYgJeUg==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- '@mui/material': ^5.4.1
- '@mui/system': ^5.4.1
- react: ^17.0.2 || ^18.0.0
- react-dom: ^17.0.2 || ^18.0.0
- dependencies:
- '@babel/runtime': 7.18.3
- '@mui/material': 5.8.3(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.12)(react-dom@18.1.0)(react@18.1.0)
- '@mui/system': 5.8.3(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.12)(react@18.1.0)
- '@mui/utils': 5.8.0(react@18.1.0)
- clsx: 1.1.1
- prop-types: 15.8.1
- react: 18.1.0
- react-dom: 18.1.0(react@18.1.0)
- reselect: 4.1.6
- dev: false
-
- /@popperjs/core@2.11.5:
- resolution: {integrity: sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==}
- dev: false
-
- /@tsconfig/node10@1.0.9:
- resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
- dev: true
-
- /@tsconfig/node12@1.0.10:
- resolution: {integrity: sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA==}
- dev: true
-
- /@tsconfig/node14@1.0.2:
- resolution: {integrity: sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg==}
- dev: true
-
- /@tsconfig/node16@1.0.3:
- resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==}
- dev: true
-
- /@types/node@20.2.5:
- resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==}
- dev: true
-
- /@types/parse-json@4.0.0:
- resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
- dev: false
-
- /@types/prop-types@15.7.5:
- resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
- dev: false
-
- /@types/react-dom@18.0.5:
- resolution: {integrity: sha512-OWPWTUrY/NIrjsAPkAk1wW9LZeIjSvkXRhclsFO8CZcZGCOg2G0YZy4ft+rOyYxy8B7ui5iZzi9OkDebZ7/QSA==}
- dependencies:
- '@types/react': 18.0.12
- dev: false
-
- /@types/react-is@17.0.3:
- resolution: {integrity: sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==}
- dependencies:
- '@types/react': 18.0.12
- dev: false
-
- /@types/react-transition-group@4.4.4:
- resolution: {integrity: sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==}
- dependencies:
- '@types/react': 18.0.12
- dev: false
-
- /@types/react@18.0.12:
- resolution: {integrity: sha512-duF1OTASSBQtcigUvhuiTB1Ya3OvSy+xORCiEf20H0P0lzx+/KeVsA99U5UjLXSbyo1DRJDlLKqTeM1ngosqtg==}
- dependencies:
- '@types/prop-types': 15.7.5
- '@types/scheduler': 0.16.2
- csstype: 3.1.0
- dev: false
-
- /@types/scheduler@0.16.2:
- resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
- dev: false
-
- /acorn-walk@8.2.0:
- resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
- engines: {node: '>=0.4.0'}
- dev: true
-
- /acorn@8.7.1:
- resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==}
- engines: {node: '>=0.4.0'}
- hasBin: true
- dev: true
-
- /ansi-styles@3.2.1:
- resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
- engines: {node: '>=4'}
- dependencies:
- color-convert: 1.9.3
- dev: false
-
- /arg@4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
- dev: true
-
- /babel-plugin-macros@2.8.0:
- resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==}
- dependencies:
- '@babel/runtime': 7.18.3
- cosmiconfig: 6.0.0
- resolve: 1.22.0
- dev: false
-
- /browserslist@4.21.7:
- resolution: {integrity: sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
- dependencies:
- caniuse-lite: 1.0.30001492
- electron-to-chromium: 1.4.415
- node-releases: 2.0.12
- update-browserslist-db: 1.0.11(browserslist@4.21.7)
- dev: false
-
- /callsites@3.1.0:
- resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
- engines: {node: '>=6'}
- dev: false
-
- /caniuse-lite@1.0.30001492:
- resolution: {integrity: sha512-2efF8SAZwgAX1FJr87KWhvuJxnGJKOnctQa8xLOskAXNXq8oiuqgl6u1kk3fFpsp3GgvzlRjiK1sl63hNtFADw==}
- dev: false
-
- /chalk@2.4.2:
- resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
- engines: {node: '>=4'}
- dependencies:
- ansi-styles: 3.2.1
- escape-string-regexp: 1.0.5
- supports-color: 5.5.0
- dev: false
-
- /clsx@1.1.1:
- resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==}
- engines: {node: '>=6'}
- dev: false
-
- /color-convert@1.9.3:
- resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
- dependencies:
- color-name: 1.1.3
- dev: false
-
- /color-name@1.1.3:
- resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
- dev: false
-
- /convert-source-map@1.8.0:
- resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==}
- dependencies:
- safe-buffer: 5.1.2
- dev: false
-
- /cosmiconfig@6.0.0:
- resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==}
- engines: {node: '>=8'}
- dependencies:
- '@types/parse-json': 4.0.0
- import-fresh: 3.3.0
- parse-json: 5.2.0
- path-type: 4.0.0
- yaml: 1.10.2
- dev: false
-
- /create-require@1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
- dev: true
-
- /csstype@3.1.0:
- resolution: {integrity: sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==}
- dev: false
-
- /debug@4.3.4:
- resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.2
- dev: false
-
- /diff@4.0.2:
- resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
- engines: {node: '>=0.3.1'}
- dev: true
-
- /dom-helpers@5.2.1:
- resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
- dependencies:
- '@babel/runtime': 7.18.3
- csstype: 3.1.0
- dev: false
-
- /electron-to-chromium@1.4.415:
- resolution: {integrity: sha512-3meOxxvyUOJVwa7cem6O2/MRPZ+FTzblSPSpG7biZoF9yOVrhCaS2l9C4jjW6YTm8uuEpmApuP0xQJSmUglfdg==}
- dev: false
-
- /error-ex@1.3.2:
- resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
- dependencies:
- is-arrayish: 0.2.1
- dev: false
-
- /esbuild-android-64@0.14.43:
- resolution: {integrity: sha512-kqFXAS72K6cNrB6RiM7YJ5lNvmWRDSlpi7ZuRZ1hu1S3w0zlwcoCxWAyM23LQUyZSs1PbjHgdbbfYAN8IGh6xg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-android-arm64@0.14.43:
- resolution: {integrity: sha512-bKS2BBFh+7XZY9rpjiHGRNA7LvWYbZWP87pLehggTG7tTaCDvj8qQGOU/OZSjCSKDYbgY7Q+oDw8RlYQ2Jt2BA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-darwin-64@0.14.43:
- resolution: {integrity: sha512-/3PSilx011ttoieRGkSZ0XV8zjBf2C9enV4ScMMbCT4dpx0mFhMOpFnCHkOK0pWGB8LklykFyHrWk2z6DENVUg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-darwin-arm64@0.14.43:
- resolution: {integrity: sha512-1HyFUKs8DMCBOvw1Qxpr5Vv/ThNcVIFb5xgXWK3pyT40WPvgYIiRTwJCvNs4l8i5qWF8/CK5bQxJVDjQvtv0Yw==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-freebsd-64@0.14.43:
- resolution: {integrity: sha512-FNWc05TPHYgaXjbPZO5/rJKSBslfG6BeMSs8GhwnqAKP56eEhvmzwnIz1QcC9cRVyO+IKqWNfmHFkCa1WJTULA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-freebsd-arm64@0.14.43:
- resolution: {integrity: sha512-amrYopclz3VohqisOPR6hA3GOWA3LZC1WDLnp21RhNmoERmJ/vLnOpnrG2P/Zao+/erKTCUqmrCIPVtj58DRoA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-32@0.14.43:
- resolution: {integrity: sha512-KoxoEra+9O3AKVvgDFvDkiuddCds6q71owSQEYwjtqRV7RwbPzKxJa6+uyzUulHcyGVq0g15K0oKG5CFBcvYDw==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-64@0.14.43:
- resolution: {integrity: sha512-EwINwGMyiJMgBby5/SbMqKcUhS5AYAZ2CpEBzSowsJPNBJEdhkCTtEjk757TN/wxgbu3QklqDM6KghY660QCUw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-arm64@0.14.43:
- resolution: {integrity: sha512-UlSpjMWllAc70zYbHxWuDS3FJytyuR/gHJYBr8BICcTNb/TSOYVBg6U7b3jZ3mILTrgzwJUHwhEwK18FZDouUQ==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-arm@0.14.43:
- resolution: {integrity: sha512-e6YzQUoDxxtyamuF12eVzzRC7bbEFSZohJ6igQB9tBqnNmIQY3fI6Cns3z2wxtbZ3f2o6idkD2fQnlvs2902Dg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-mips64le@0.14.43:
- resolution: {integrity: sha512-f+v8cInPEL1/SDP//CfSYzcDNgE4CY3xgDV81DWm3KAPWzhvxARrKxB1Pstf5mB56yAslJDxu7ryBUPX207EZA==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-ppc64le@0.14.43:
- resolution: {integrity: sha512-5wZYMDGAL/K2pqkdIsW+I4IR41kyfHr/QshJcNpUfK3RjB3VQcPWOaZmc+74rm4ZjVirYrtz+jWw0SgxtxRanA==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-riscv64@0.14.43:
- resolution: {integrity: sha512-lYcAOUxp85hC7lSjycJUVSmj4/9oEfSyXjb/ua9bNl8afonaduuqtw7hvKMoKuYnVwOCDw4RSfKpcnIRDWq+Bw==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-linux-s390x@0.14.43:
- resolution: {integrity: sha512-27e43ZhHvhFE4nM7HqtUbMRu37I/4eNSUbb8FGZWszV+uLzMIsHDwLoBiJmw7G9N+hrehNPeQ4F5Ujad0DrUKQ==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-netbsd-64@0.14.43:
- resolution: {integrity: sha512-2mH4QF6hHBn5zzAfxEI/2eBC0mspVsZ6UVo821LpAJKMvLJPBk3XJO5xwg7paDqSqpl7p6IRrAenW999AEfJhQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-openbsd-64@0.14.43:
- resolution: {integrity: sha512-ZhQpiZjvqCqO8jKdGp9+8k9E/EHSA+zIWOg+grwZasI9RoblqJ1QiZqqi7jfd6ZrrG1UFBNGe4m0NFxCFbMVbg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-sunos-64@0.14.43:
- resolution: {integrity: sha512-DgxSi9DaHReL9gYuul2rrQCAapgnCJkh3LSHPKsY26zytYppG0HgkgVF80zjIlvEsUbGBP/GHQzBtrezj/Zq1Q==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-windows-32@0.14.43:
- resolution: {integrity: sha512-Ih3+2O5oExiqm0mY6YYE5dR0o8+AspccQ3vIAtRodwFvhuyGLjb0Hbmzun/F3Lw19nuhPMu3sW2fqIJ5xBxByw==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-windows-64@0.14.43:
- resolution: {integrity: sha512-8NsuNfI8xwFuJbrCuI+aBqNTYkrWErejFO5aYM+yHqyHuL8mmepLS9EPzAzk8rvfaJrhN0+RvKWAcymViHOKEw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild-windows-arm64@0.14.43:
- resolution: {integrity: sha512-7ZlD7bo++kVRblJEoG+cepljkfP8bfuTPz5fIXzptwnPaFwGS6ahvfoYzY7WCf5v/1nX2X02HDraVItTgbHnKw==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /esbuild@0.14.43:
- resolution: {integrity: sha512-Uf94+kQmy/5jsFwKWiQB4hfo/RkM9Dh7b79p8yqd1tshULdr25G2szLz631NoH3s2ujnKEKVD16RmOxvCNKRFA==}
- engines: {node: '>=12'}
- hasBin: true
- requiresBuild: true
- optionalDependencies:
- esbuild-android-64: 0.14.43
- esbuild-android-arm64: 0.14.43
- esbuild-darwin-64: 0.14.43
- esbuild-darwin-arm64: 0.14.43
- esbuild-freebsd-64: 0.14.43
- esbuild-freebsd-arm64: 0.14.43
- esbuild-linux-32: 0.14.43
- esbuild-linux-64: 0.14.43
- esbuild-linux-arm: 0.14.43
- esbuild-linux-arm64: 0.14.43
- esbuild-linux-mips64le: 0.14.43
- esbuild-linux-ppc64le: 0.14.43
- esbuild-linux-riscv64: 0.14.43
- esbuild-linux-s390x: 0.14.43
- esbuild-netbsd-64: 0.14.43
- esbuild-openbsd-64: 0.14.43
- esbuild-sunos-64: 0.14.43
- esbuild-windows-32: 0.14.43
- esbuild-windows-64: 0.14.43
- esbuild-windows-arm64: 0.14.43
- dev: true
-
- /escalade@3.1.1:
- resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
- engines: {node: '>=6'}
- dev: false
-
- /escape-string-regexp@1.0.5:
- resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
- engines: {node: '>=0.8.0'}
- dev: false
-
- /escape-string-regexp@4.0.0:
- resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
- engines: {node: '>=10'}
- dev: false
-
- /find-root@1.1.0:
- resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
- dev: false
-
- /function-bind@1.1.1:
- resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
- dev: false
-
- /gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
- dev: false
-
- /globals@11.12.0:
- resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
- engines: {node: '>=4'}
- dev: false
-
- /has-flag@3.0.0:
- resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
- engines: {node: '>=4'}
- dev: false
-
- /has@1.0.3:
- resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
- engines: {node: '>= 0.4.0'}
- dependencies:
- function-bind: 1.1.1
- dev: false
-
- /history@5.3.0:
- resolution: {integrity: sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==}
- dependencies:
- '@babel/runtime': 7.18.3
- dev: false
-
- /hoist-non-react-statics@3.3.2:
- resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
- dependencies:
- react-is: 16.13.1
- dev: false
-
- /import-fresh@3.3.0:
- resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
- engines: {node: '>=6'}
- dependencies:
- parent-module: 1.0.1
- resolve-from: 4.0.0
- dev: false
-
- /is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
- dev: false
-
- /is-core-module@2.9.0:
- resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==}
- dependencies:
- has: 1.0.3
- dev: false
-
- /js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- dev: false
-
- /jsesc@2.5.2:
- resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
- engines: {node: '>=4'}
- hasBin: true
- dev: false
-
- /json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
- dev: false
-
- /json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
- dev: false
-
- /lines-and-columns@1.2.4:
- resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- dev: false
-
- /loose-envify@1.4.0:
- resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
- hasBin: true
- dependencies:
- js-tokens: 4.0.0
- dev: false
-
- /lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
- dependencies:
- yallist: 3.1.1
- dev: false
-
- /make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
- dev: true
-
- /ms@2.1.2:
- resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
- dev: false
-
- /node-releases@2.0.12:
- resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==}
- dev: false
-
- /object-assign@4.1.1:
- resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
- engines: {node: '>=0.10.0'}
- dev: false
-
- /parent-module@1.0.1:
- resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
- engines: {node: '>=6'}
- dependencies:
- callsites: 3.1.0
- dev: false
-
- /parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
- engines: {node: '>=8'}
- dependencies:
- '@babel/code-frame': 7.16.7
- error-ex: 1.3.2
- json-parse-even-better-errors: 2.3.1
- lines-and-columns: 1.2.4
- dev: false
-
- /path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
- dev: false
-
- /path-type@4.0.0:
- resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
- engines: {node: '>=8'}
- dev: false
-
- /picocolors@1.0.0:
- resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
- dev: false
-
- /prop-types@15.8.1:
- resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
- dependencies:
- loose-envify: 1.4.0
- object-assign: 4.1.1
- react-is: 16.13.1
- dev: false
-
- /react-dom@18.1.0(react@18.1.0):
- resolution: {integrity: sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==}
- peerDependencies:
- react: ^18.1.0
- dependencies:
- loose-envify: 1.4.0
- react: 18.1.0
- scheduler: 0.22.0
- dev: false
-
- /react-is@16.13.1:
- resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
- dev: false
-
- /react-is@17.0.2:
- resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
- dev: false
-
- /react-router-dom@6.3.0(react-dom@18.1.0)(react@18.1.0):
- resolution: {integrity: sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==}
- peerDependencies:
- react: '>=16.8'
- react-dom: '>=16.8'
- dependencies:
- history: 5.3.0
- react: 18.1.0
- react-dom: 18.1.0(react@18.1.0)
- react-router: 6.3.0(react@18.1.0)
- dev: false
-
- /react-router@6.3.0(react@18.1.0):
- resolution: {integrity: sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==}
- peerDependencies:
- react: '>=16.8'
- dependencies:
- history: 5.3.0
- react: 18.1.0
- dev: false
-
- /react-transition-group@4.4.2(react-dom@18.1.0)(react@18.1.0):
- resolution: {integrity: sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==}
- peerDependencies:
- react: '>=16.6.0'
- react-dom: '>=16.6.0'
- dependencies:
- '@babel/runtime': 7.18.3
- dom-helpers: 5.2.1
- loose-envify: 1.4.0
- prop-types: 15.8.1
- react: 18.1.0
- react-dom: 18.1.0(react@18.1.0)
- dev: false
-
- /react@18.1.0:
- resolution: {integrity: sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==}
- engines: {node: '>=0.10.0'}
- dependencies:
- loose-envify: 1.4.0
- dev: false
-
- /regenerator-runtime@0.13.9:
- resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
- dev: false
-
- /reselect@4.1.6:
- resolution: {integrity: sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==}
- dev: false
-
- /resolve-from@4.0.0:
- resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
- engines: {node: '>=4'}
- dev: false
-
- /resolve@1.22.0:
- resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==}
- hasBin: true
- dependencies:
- is-core-module: 2.9.0
- path-parse: 1.0.7
- supports-preserve-symlinks-flag: 1.0.0
- dev: false
-
- /safe-buffer@5.1.2:
- resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
- dev: false
-
- /scheduler@0.22.0:
- resolution: {integrity: sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==}
- dependencies:
- loose-envify: 1.4.0
- dev: false
-
- /semver@6.3.0:
- resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
- hasBin: true
- dev: false
-
- /source-map@0.5.7:
- resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
- engines: {node: '>=0.10.0'}
- dev: false
-
- /stylis@4.0.13:
- resolution: {integrity: sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==}
- dev: false
-
- /supports-color@5.5.0:
- resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
- engines: {node: '>=4'}
- dependencies:
- has-flag: 3.0.0
- dev: false
-
- /supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
- dev: false
-
- /to-fast-properties@2.0.0:
- resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
- engines: {node: '>=4'}
- dev: false
-
- /ts-node@10.8.1(@types/node@20.2.5)(typescript@5.0.4):
- resolution: {integrity: sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==}
- hasBin: true
- peerDependencies:
- '@swc/core': '>=1.2.50'
- '@swc/wasm': '>=1.2.50'
- '@types/node': '*'
- typescript: '>=2.7'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- '@swc/wasm':
- optional: true
- dependencies:
- '@cspotcode/source-map-support': 0.8.1
- '@tsconfig/node10': 1.0.9
- '@tsconfig/node12': 1.0.10
- '@tsconfig/node14': 1.0.2
- '@tsconfig/node16': 1.0.3
- '@types/node': 20.2.5
- acorn: 8.7.1
- acorn-walk: 8.2.0
- arg: 4.1.3
- create-require: 1.1.1
- diff: 4.0.2
- make-error: 1.3.6
- typescript: 5.0.4
- v8-compile-cache-lib: 3.0.1
- yn: 3.1.1
- dev: true
-
- /typescript@5.0.4:
- resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
- engines: {node: '>=12.20'}
- hasBin: true
- dev: true
-
- /update-browserslist-db@1.0.11(browserslist@4.21.7):
- resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
- dependencies:
- browserslist: 4.21.7
- escalade: 3.1.1
- picocolors: 1.0.0
- dev: false
-
- /v8-compile-cache-lib@3.0.1:
- resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
- dev: true
-
- /yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
- dev: false
-
- /yaml@1.10.2:
- resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
- engines: {node: '>= 6'}
- dev: false
-
- /yn@3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
- dev: true
diff --git a/src/client/state.tsx b/src/client/state.tsx
deleted file mode 100644
index ad9a74c..0000000
--- a/src/client/state.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import React, { createContext, useRef, useState } from "react";
-export const BackLinkContext = createContext({ backLink: "", setBackLink: (s: string) => {} });
-export const UserContext = createContext({
- username: "",
- permission: [] as string[],
- setUsername: (s: string) => {},
- setPermission: (permission: string[]) => {},
-});
-
-type LoginLocalStorage = {
- username: string;
- permission: string[];
- accessExpired: number;
-};
-
-let localObj: LoginLocalStorage | null = null;
-
-export const getInitialValue = async () => {
- if (localObj === null) {
- const storagestr = window.localStorage.getItem("UserLoginContext") as string | null;
- const storage = storagestr !== null ? JSON.parse(storagestr) as LoginLocalStorage | null : null;
- localObj = storage;
- }
- if (localObj !== null && localObj.accessExpired > Math.floor(Date.now() / 1000)) {
- return {
- username: localObj.username,
- permission: localObj.permission,
- };
- }
- const res = await fetch("/user/refresh", {
- method: "POST",
- });
- if (res.status !== 200) throw new Error("Maybe Network Error");
- const r = await res.json() as LoginLocalStorage & { refresh: boolean };
- if (r.refresh) {
- localObj = {
- username: r.username,
- permission: r.permission,
- accessExpired: r.accessExpired,
- };
- } else {
- localObj = {
- accessExpired: 0,
- username: "",
- permission: r.permission,
- };
- }
- window.localStorage.setItem("UserLoginContext", JSON.stringify(localObj));
- return {
- username: r.username,
- permission: r.permission,
- };
-};
-export const doLogout = async () => {
- const req = await fetch("/user/logout", {
- method: "POST",
- });
- try {
- const res = await req.json();
- localObj = {
- accessExpired: 0,
- username: "",
- permission: res["permission"],
- };
- window.localStorage.setItem("UserLoginContext", JSON.stringify(localObj));
- return {
- username: localObj.username,
- permission: localObj.permission,
- };
- } catch (error) {
- console.error(`Server Error ${error}`);
- return {
- username: "",
- permission: [],
- };
- }
-};
-export const doLogin = async (userLoginInfo: {
- username: string;
- password: string;
-}): Promise => {
- const res = await fetch("/user/login", {
- method: "POST",
- body: JSON.stringify(userLoginInfo),
- headers: { "content-type": "application/json" },
- });
- const b = await res.json();
- if (res.status !== 200) {
- return b.detail as string;
- }
- localObj = b;
- window.localStorage.setItem("UserLoginContext", JSON.stringify(localObj));
- return b;
-};
diff --git a/src/config.ts b/src/config.ts
deleted file mode 100644
index 583c834..0000000
--- a/src/config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Knex as k } from "knex";
-
-export namespace Knex {
- export const config: {
- development: k.Config;
- production: k.Config;
- } = {
- development: {
- client: "sqlite3",
- connection: {
- filename: "./devdb.sqlite3",
- },
- debug: true,
- },
- production: {
- client: "sqlite3",
- connection: {
- filename: "./db.sqlite3",
- },
- },
- };
-}
diff --git a/src/content/comic.ts b/src/content/comic.ts
deleted file mode 100644
index 0f0feb0..0000000
--- a/src/content/comic.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { extname } from "path";
-import { DocumentBody } from "../model/doc";
-import { readAllFromZip, readZip } from "../util/zipwrap";
-import { ContentConstructOption, ContentFile, createDefaultClass, registerContentReferrer } from "./file";
-
-type ComicType = "doujinshi" | "artist cg" | "manga" | "western";
-interface ComicDesc {
- title: string;
- artist?: string[];
- group?: string[];
- series?: string[];
- type: ComicType | [ComicType];
- character?: string[];
- tags?: string[];
-}
-const ImageExt = [".gif", ".png", ".jpeg", ".bmp", ".webp", ".jpg"];
-export class ComicReferrer extends createDefaultClass("comic") {
- desc: ComicDesc | undefined;
- pagenum: number;
- additional: ContentConstructOption | undefined;
- constructor(path: string, option?: ContentConstructOption) {
- super(path);
- this.additional = option;
- this.pagenum = 0;
- }
- async initDesc(): Promise {
- if (this.desc !== undefined) return;
- const zip = await readZip(this.path);
- const entries = await zip.entries();
- this.pagenum = Object.keys(entries).filter(x => ImageExt.includes(extname(x))).length;
- const entry = entries["desc.json"];
- if (entry === undefined) {
- return;
- }
- const data = (await readAllFromZip(zip, entry)).toString("utf-8");
- this.desc = JSON.parse(data);
- if (this.desc === undefined) {
- throw new Error(`JSON.parse is returning undefined. ${this.path} desc.json format error`);
- }
- }
-
- async createDocumentBody(): Promise {
- await this.initDesc();
- const basebody = await super.createDocumentBody();
- this.desc?.title;
- if (this.desc === undefined) {
- return basebody;
- }
- let tags: string[] = this.desc.tags ?? [];
- tags = tags.concat(this.desc.artist?.map(x => `artist:${x}`) ?? []);
- tags = tags.concat(this.desc.character?.map(x => `character:${x}`) ?? []);
- tags = tags.concat(this.desc.group?.map(x => `group:${x}`) ?? []);
- tags = tags.concat(this.desc.series?.map(x => `series:${x}`) ?? []);
- const type = this.desc.type instanceof Array ? this.desc.type[0] : this.desc.type;
- tags.push(`type:${type}`);
- return {
- ...basebody,
- title: this.desc.title,
- additional: {
- page: this.pagenum,
- },
- tags: tags,
- };
- }
-}
-registerContentReferrer(ComicReferrer);
diff --git a/src/content/file.ts b/src/content/file.ts
deleted file mode 100644
index e7b85e0..0000000
--- a/src/content/file.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { createHash } from "crypto";
-import { promises, Stats } from "fs";
-import { Context, DefaultContext, DefaultState, Middleware, Next } from "koa";
-import Router from "koa-router";
-import { extname } from "path";
-import path from "path";
-import { DocumentBody } from "../model/mod";
-/**
- * content file or directory referrer
- */
-export interface ContentFile {
- getHash(): Promise;
- createDocumentBody(): Promise;
- readonly path: string;
- readonly type: string;
-}
-export type ContentConstructOption = {
- hash: string;
-};
-type ContentFileConstructor = (new(path: string, option?: ContentConstructOption) => ContentFile) & {
- content_type: string;
-};
-export const createDefaultClass = (type: string): ContentFileConstructor => {
- let cons = class implements ContentFile {
- readonly path: string;
- // type = type;
- static content_type = type;
- protected hash: string | undefined;
- protected stat: Stats | undefined;
-
- constructor(path: string, option?: ContentConstructOption) {
- this.path = path;
- this.hash = option?.hash;
- this.stat = undefined;
- }
- async createDocumentBody(): Promise {
- const { base, dir, name } = path.parse(this.path);
-
- const ret = {
- title: name,
- basepath: dir,
- additional: {},
- content_type: cons.content_type,
- filename: base,
- tags: [],
- content_hash: await this.getHash(),
- modified_at: await this.getMtime(),
- } as DocumentBody;
- return ret;
- }
- get type(): string {
- return cons.content_type;
- }
- async getHash(): Promise {
- if (this.hash !== undefined) return this.hash;
- this.stat = await promises.stat(this.path);
- const hash = createHash("sha512");
- hash.update(extname(this.path));
- hash.update(this.stat.mode.toString());
- // if(this.desc !== undefined)
- // hash.update(JSON.stringify(this.desc));
- hash.update(this.stat.size.toString());
- this.hash = hash.digest("base64");
- return this.hash;
- }
- async getMtime(): Promise {
- if (this.stat !== undefined) return this.stat.mtimeMs;
- await this.getHash();
- return this.stat!.mtimeMs;
- }
- };
- return cons;
-};
-let ContstructorTable: { [k: string]: ContentFileConstructor } = {};
-export function registerContentReferrer(s: ContentFileConstructor) {
- console.log(`registered content type: ${s.content_type}`);
- ContstructorTable[s.content_type] = s;
-}
-export function createContentFile(type: string, path: string, option?: ContentConstructOption) {
- const constructorMethod = ContstructorTable[type];
- if (constructorMethod === undefined) {
- console.log(`${type} are not in ${JSON.stringify(ContstructorTable)}`);
- throw new Error("construction method of the content type is undefined");
- }
- return new constructorMethod(path, option);
-}
-export function getContentFileConstructor(type: string): ContentFileConstructor | undefined {
- const ret = ContstructorTable[type];
- return ret;
-}
diff --git a/src/content/video.ts b/src/content/video.ts
deleted file mode 100644
index d24e19f..0000000
--- a/src/content/video.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { ContentConstructOption, ContentFile, registerContentReferrer } from "./file";
-import { createDefaultClass } from "./file";
-
-export class VideoReferrer extends createDefaultClass("video") {
- constructor(path: string, desc?: ContentConstructOption) {
- super(path, desc);
- }
-}
-registerContentReferrer(VideoReferrer);
diff --git a/src/database.ts b/src/database.ts
deleted file mode 100644
index 285e726..0000000
--- a/src/database.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { existsSync } from "fs";
-import Knex from "knex";
-import { Knex as KnexConfig } from "./config";
-import { get_setting } from "./SettingConfig";
-
-export async function connectDB() {
- const env = get_setting().mode;
- const config = KnexConfig.config[env];
- if (!config.connection) {
- throw new Error("connection options required.");
- }
- const connection = config.connection;
- if (typeof connection === "string") {
- throw new Error("unknown connection options");
- }
- if (typeof connection === "function") {
- throw new Error("connection provider not supported...");
- }
- if (!("filename" in connection)) {
- throw new Error("sqlite3 config need");
- }
- const init_need = !existsSync(connection.filename);
- const knex = Knex(config);
- let tries = 0;
- for (;;) {
- try {
- console.log("try to connect db");
- await knex.raw("select 1 + 1;");
- console.log("connect success");
- } catch (err) {
- if (tries < 3) {
- tries++;
- console.error(`connection fail ${err} retry...`);
- continue;
- } else {
- throw err;
- }
- }
- break;
- }
- if (init_need) {
- console.log("first execute: initialize database...");
- const migrate = await import("../migrations/initial");
- await migrate.up(knex);
- }
- return knex;
-}
diff --git a/src/db/doc.ts b/src/db/doc.ts
deleted file mode 100644
index ef48898..0000000
--- a/src/db/doc.ts
+++ /dev/null
@@ -1,223 +0,0 @@
-import { Knex } from "knex";
-import { Document, DocumentAccessor, DocumentBody, QueryListOption } from "../model/doc";
-import { TagAccessor } from "../model/tag";
-import { createKnexTagController } from "./tag";
-
-export type DBTagContentRelation = {
- doc_id: number;
- tag_name: string;
-};
-
-class KnexDocumentAccessor implements DocumentAccessor {
- knex: Knex;
- tagController: TagAccessor;
- constructor(knex: Knex) {
- this.knex = knex;
- this.tagController = createKnexTagController(knex);
- }
- async search(search_word: string): Promise {
- throw new Error("Method not implemented.");
- const sw = `%${search_word}%`;
- const docs = await this.knex.select("*").from("document")
- .where("title", "like", sw);
- return docs;
- }
- async addList(content_list: DocumentBody[]): Promise {
- return await this.knex.transaction(async (trx) => {
- // add tags
- const tagCollected = new Set();
- content_list.map(x => x.tags).forEach((x) => {
- x.forEach(x => {
- tagCollected.add(x);
- });
- });
- const tagCollectPromiseList = [];
- const tagController = createKnexTagController(trx);
- for (const it of tagCollected) {
- const p = tagController.addTag({ name: it });
- tagCollectPromiseList.push(p);
- }
- await Promise.all(tagCollectPromiseList);
- // add for each contents
- const ret = [];
- for (const content of content_list) {
- const { tags, additional, ...rest } = content;
- const id_lst = await trx.insert({
- additional: JSON.stringify(additional),
- created_at: Date.now(),
- ...rest,
- }).into("document");
- const id = id_lst[0];
- if (tags.length > 0) {
- await trx.insert(tags.map(y => ({
- doc_id: id,
- tag_name: y,
- }))).into("doc_tag_relation");
- }
- ret.push(id);
- }
- return ret;
- });
- }
- async add(c: DocumentBody) {
- const { tags, additional, ...rest } = c;
- const id_lst = await this.knex.insert({
- additional: JSON.stringify(additional),
- created_at: Date.now(),
- ...rest,
- }).into("document");
- const id = id_lst[0];
- for (const it of tags) {
- this.tagController.addTag({ name: it });
- }
- if (tags.length > 0) {
- await this.knex.insert(
- tags.map(x => ({ doc_id: id, tag_name: x })),
- ).into("doc_tag_relation");
- }
- return id;
- }
- async del(id: number) {
- if (await this.findById(id) !== undefined) {
- await this.knex.delete().from("doc_tag_relation").where({ doc_id: id });
- await this.knex.delete().from("document").where({ id: id });
- return true;
- }
- return false;
- }
- async findById(id: number, tagload?: boolean): Promise {
- const s = await this.knex.select("*").from("document").where({ id: id });
- if (s.length === 0) return undefined;
- const first = s[0];
- let ret_tags: string[] = [];
- if (tagload === true) {
- const tags: DBTagContentRelation[] = await this.knex.select("*")
- .from("doc_tag_relation").where({ doc_id: first.id });
- ret_tags = tags.map(x => x.tag_name);
- }
- return {
- ...first,
- tags: ret_tags,
- additional: first.additional !== null ? JSON.parse(first.additional) : {},
- };
- }
- async findDeleted(content_type: string) {
- const s = await this.knex.select("*")
- .where({ content_type: content_type })
- .whereNotNull("update_at")
- .from("document");
- return s.map(x => ({
- ...x,
- tags: [],
- additional: {},
- }));
- }
- async findList(option?: QueryListOption) {
- option = option ?? {};
- const allow_tag = option.allow_tag ?? [];
- const eager_loading = option.eager_loading ?? true;
- const limit = option.limit ?? 20;
- const use_offset = option.use_offset ?? false;
- const offset = option.offset ?? 0;
- const word = option.word;
- const content_type = option.content_type;
- const cursor = option.cursor;
-
- const buildquery = () => {
- let query = this.knex.select("document.*");
- if (allow_tag.length > 0) {
- query = query.from("doc_tag_relation as tags_0");
- query = query.where("tags_0.tag_name", "=", allow_tag[0]);
- for (let index = 1; index < allow_tag.length; index++) {
- const element = allow_tag[index];
- query = query.innerJoin(
- `doc_tag_relation as tags_${index}`,
- `tags_${index}.doc_id`,
- "tags_0.doc_id",
- );
- query = query.where(`tags_${index}.tag_name`, "=", element);
- }
- query = query.innerJoin("document", "tags_0.doc_id", "document.id");
- } else {
- query = query.from("document");
- }
- if (word !== undefined) {
- // don't worry about sql injection.
- query = query.where("title", "like", `%${word}%`);
- }
- if (content_type !== undefined) {
- query = query.where("content_type", "=", content_type);
- }
- if (use_offset) {
- query = query.offset(offset);
- } else {
- if (cursor !== undefined) {
- query = query.where("id", "<", cursor);
- }
- }
- query = query.limit(limit);
- query = query.orderBy("id", "desc");
- return query;
- };
- let query = buildquery();
- // console.log(query.toSQL());
- let result: Document[] = await query;
- for (let i of result) {
- i.additional = JSON.parse((i.additional as unknown) as string);
- }
- if (eager_loading) {
- let idmap: { [index: number]: Document } = {};
- for (const r of result) {
- idmap[r.id] = r;
- r.tags = [];
- }
- let subquery = buildquery();
- let tagquery = this.knex.select("id", "doc_tag_relation.tag_name").from(subquery)
- .innerJoin("doc_tag_relation", "doc_tag_relation.doc_id", "id");
- // console.log(tagquery.toSQL());
- let tagresult: { id: number; tag_name: string }[] = await tagquery;
- for (const { id, tag_name } of tagresult) {
- idmap[id].tags.push(tag_name);
- }
- } else {
- result.forEach(v => {
- v.tags = [];
- });
- }
- return result;
- }
- async findByPath(path: string, filename?: string): Promise {
- const e = filename == undefined ? {} : { filename: filename };
- const results = await this.knex.select("*").from("document").where({ basepath: path, ...e });
- return results.map(x => ({
- ...x,
- tags: [],
- additional: {},
- }));
- }
- async update(c: Partial & { id: number }) {
- const { id, tags, ...rest } = c;
- if (await this.findById(id) !== undefined) {
- await this.knex.update(rest).where({ id: id }).from("document");
- return true;
- }
- return false;
- }
- async addTag(c: Document, tag_name: string) {
- if (c.tags.includes(tag_name)) return false;
- this.tagController.addTag({ name: tag_name });
- await this.knex.insert({ tag_name: tag_name, doc_id: c.id })
- .into("doc_tag_relation");
- c.tags.push(tag_name);
- return true;
- }
- async delTag(c: Document, tag_name: string) {
- if (c.tags.includes(tag_name)) return false;
- await this.knex.delete().where({ tag_name: tag_name, doc_id: c.id }).from("doc_tag_relation");
- c.tags.push(tag_name);
- return true;
- }
-}
-export const createKnexDocumentAccessor = (knex: Knex): DocumentAccessor => {
- return new KnexDocumentAccessor(knex);
-};
diff --git a/src/db/tag.ts b/src/db/tag.ts
deleted file mode 100644
index dae8909..0000000
--- a/src/db/tag.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { Knex } from "knex";
-import { Tag, TagAccessor, TagCount } from "../model/tag";
-import { DBTagContentRelation } from "./doc";
-
-type DBTags = {
- name: string;
- description?: string;
-};
-
-class KnexTagAccessor implements TagAccessor {
- knex: Knex;
- constructor(knex: Knex) {
- this.knex = knex;
- }
- async getAllTagCount(): Promise {
- const result = await this.knex("doc_tag_relation").select("tag_name")
- .count("*", { as: "occurs" }).groupBy("tag_name");
- return result;
- }
- async getAllTagList(onlyname?: boolean) {
- onlyname = onlyname ?? false;
- const t: DBTags[] = await this.knex.select(onlyname ? "*" : "name").from("tags");
- return t;
- }
- async getTagByName(name: string) {
- const t: DBTags[] = await this.knex.select("*").from("tags").where({ name: name });
- if (t.length === 0) return undefined;
- return t[0];
- }
- async addTag(tag: Tag) {
- if (await this.getTagByName(tag.name) === undefined) {
- await this.knex.insert({
- name: tag.name,
- description: tag.description === undefined ? "" : tag.description,
- }).into("tags");
- return true;
- }
- return false;
- }
- async delTag(name: string) {
- if (await this.getTagByName(name) !== undefined) {
- await this.knex.delete().where({ name: name }).from("tags");
- return true;
- }
- return false;
- }
- async updateTag(name: string, desc: string) {
- if (await this.getTagByName(name) !== undefined) {
- await this.knex.update({ description: desc }).where({ name: name }).from("tags");
- return true;
- }
- return false;
- }
-}
-export const createKnexTagController = (knex: Knex): TagAccessor => {
- return new KnexTagAccessor(knex);
-};
diff --git a/src/db/user.ts b/src/db/user.ts
deleted file mode 100644
index 1ff2f15..0000000
--- a/src/db/user.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import { Knex } from "knex";
-import { IUser, Password, UserAccessor, UserCreateInput } from "../model/user";
-
-type PermissionTable = {
- username: string;
- name: string;
-};
-type DBUser = {
- username: string;
- password_hash: string;
- password_salt: string;
-};
-class KnexUser implements IUser {
- private knex: Knex;
- readonly username: string;
- readonly password: Password;
-
- constructor(username: string, pw: Password, knex: Knex) {
- this.username = username;
- this.password = pw;
- this.knex = knex;
- }
- async reset_password(password: string) {
- this.password.set_password(password);
- await this.knex.from("users")
- .where({ username: this.username })
- .update({ password_hash: this.password.hash, password_salt: this.password.salt });
- }
- async get_permissions() {
- let b = (await this.knex.select("*").from("permissions")
- .where({ username: this.username })) as PermissionTable[];
- return b.map(x => x.name);
- }
- async add(name: string) {
- if (!(await this.get_permissions()).includes(name)) {
- const r = await this.knex.insert({
- username: this.username,
- name: name,
- }).into("permissions");
- return true;
- }
- return false;
- }
- async remove(name: string) {
- const r = await this.knex
- .from("permissions")
- .where({
- username: this.username,
- name: name,
- }).delete();
- return r !== 0;
- }
-}
-
-export const createKnexUserController = (knex: Knex): UserAccessor => {
- const createUserKnex = async (input: UserCreateInput) => {
- if (undefined !== (await findUserKenx(input.username))) {
- return undefined;
- }
- const user = new KnexUser(input.username, new Password(input.password), knex);
- await knex.insert({
- username: user.username,
- password_hash: user.password.hash,
- password_salt: user.password.salt,
- }).into("users");
- return user;
- };
- const findUserKenx = async (id: string) => {
- let user: DBUser[] = await knex.select("*").from("users").where({ username: id });
- if (user.length == 0) return undefined;
- const first = user[0];
- return new KnexUser(
- first.username,
- new Password({ hash: first.password_hash, salt: first.password_salt }),
- knex,
- );
- };
- const delUserKnex = async (id: string) => {
- let r = await knex.delete().from("users").where({ username: id });
- return r === 0;
- };
- return {
- createUser: createUserKnex,
- findUser: findUserKenx,
- delUser: delUserKnex,
- };
-};
diff --git a/src/diff/content_handler.ts b/src/diff/content_handler.ts
deleted file mode 100644
index 11ab44c..0000000
--- a/src/diff/content_handler.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-import { basename, dirname, join as pathjoin } from "path";
-import { ContentFile, createContentFile } from "../content/mod";
-import { Document, DocumentAccessor } from "../model/mod";
-import { ContentList } from "./content_list";
-import { IDiffWatcher } from "./watcher";
-
-// refactoring needed.
-export class ContentDiffHandler {
- /** content file list waiting to add */
- waiting_list: ContentList;
- /** deleted contents */
- tombstone: Map; // hash, contentfile
- doc_cntr: DocumentAccessor;
- /** content type of handle */
- content_type: string;
- constructor(cntr: DocumentAccessor, content_type: string) {
- this.waiting_list = new ContentList();
- this.tombstone = new Map();
- this.doc_cntr = cntr;
- this.content_type = content_type;
- }
- async setup() {
- const deleted = await this.doc_cntr.findDeleted(this.content_type);
- for (const it of deleted) {
- this.tombstone.set(it.content_hash, it);
- }
- }
- register(diff: IDiffWatcher) {
- diff.on("create", (path) => this.OnCreated(path))
- .on("delete", (path) => this.OnDeleted(path))
- .on("change", (prev, cur) => this.OnChanged(prev, cur));
- }
- private async OnDeleted(cpath: string) {
- const basepath = dirname(cpath);
- const filename = basename(cpath);
- console.log("deleted ", cpath);
- // if it wait to add, delete it from waiting list.
- if (this.waiting_list.hasByPath(cpath)) {
- this.waiting_list.deleteByPath(cpath);
- return;
- }
- const dbc = await this.doc_cntr.findByPath(basepath, filename);
- // when there is no related content in db, ignore.
- if (dbc.length === 0) {
- console.log("its not in waiting_list and db!!!: ", cpath);
- return;
- }
- const content_hash = dbc[0].content_hash;
- // When a path is changed, it takes into account when the
- // creation event occurs first and the deletion occurs, not
- // the change event.
- const cf = this.waiting_list.getByHash(content_hash);
- if (cf) {
- // if a path is changed, update the changed path.
- console.log("update path from", cpath, "to", cf.path);
- const newFilename = basename(cf.path);
- const newBasepath = dirname(cf.path);
- this.waiting_list.deleteByHash(content_hash);
- await this.doc_cntr.update({
- id: dbc[0].id,
- deleted_at: null,
- filename: newFilename,
- basepath: newBasepath,
- });
- return;
- }
- // invalidate db and add it to tombstone.
- await this.doc_cntr.update({
- id: dbc[0].id,
- deleted_at: Date.now(),
- });
- this.tombstone.set(dbc[0].content_hash, dbc[0]);
- }
- private async OnCreated(cpath: string) {
- const basepath = dirname(cpath);
- const filename = basename(cpath);
- console.log("createContentFile", cpath);
- const content = createContentFile(this.content_type, cpath);
- const hash = await content.getHash();
- const c = this.tombstone.get(hash);
- if (c !== undefined) {
- await this.doc_cntr.update({
- id: c.id,
- deleted_at: null,
- filename: filename,
- basepath: basepath,
- });
- }
- if (this.waiting_list.hasByHash(hash)) {
- console.log("Hash Conflict!!!");
- }
- this.waiting_list.set(content);
- }
- private async OnChanged(prev_path: string, cur_path: string) {
- const prev_basepath = dirname(prev_path);
- const prev_filename = basename(prev_path);
- const cur_basepath = dirname(cur_path);
- const cur_filename = basename(cur_path);
- console.log("modify", cur_path, "from", prev_path);
- const c = this.waiting_list.getByPath(prev_path);
- if (c !== undefined) {
- await this.waiting_list.delete(c);
- const content = createContentFile(this.content_type, cur_path);
- await this.waiting_list.set(content);
- return;
- }
- const doc = await this.doc_cntr.findByPath(prev_basepath, prev_filename);
-
- if (doc.length === 0) {
- await this.OnCreated(cur_path);
- return;
- }
-
- await this.doc_cntr.update({
- ...doc[0],
- basepath: cur_basepath,
- filename: cur_filename,
- });
- }
-}
diff --git a/src/diff/content_list.ts b/src/diff/content_list.ts
deleted file mode 100644
index 7a69cbd..0000000
--- a/src/diff/content_list.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { ContentFile } from "../content/mod";
-
-export class ContentList {
- /** path map */
- private cl: Map;
- /** hash map */
- private hl: Map;
-
- constructor() {
- this.cl = new Map();
- this.hl = new Map();
- }
- hasByHash(s: string) {
- return this.hl.has(s);
- }
- hasByPath(p: string) {
- return this.cl.has(p);
- }
- getByHash(s: string) {
- return this.hl.get(s);
- }
- getByPath(p: string) {
- return this.cl.get(p);
- }
- async set(c: ContentFile) {
- const path = c.path;
- const hash = await c.getHash();
- this.cl.set(path, c);
- this.hl.set(hash, c);
- }
- /** delete content file */
- async delete(c: ContentFile) {
- const hash = await c.getHash();
- let r = true;
- r = this.cl.delete(c.path) && r;
- r = this.hl.delete(hash) && r;
- return r;
- }
- async deleteByPath(p: string) {
- const o = this.getByPath(p);
- if (o === undefined) return false;
- return await this.delete(o);
- }
- deleteByHash(s: string) {
- const o = this.getByHash(s);
- if (o === undefined) return false;
- let r = true;
- r = this.cl.delete(o.path) && r;
- r = this.hl.delete(s) && r;
- return r;
- }
- clear() {
- this.cl.clear();
- this.hl.clear();
- }
- getAll() {
- return [...this.cl.values()];
- }
-}
diff --git a/src/diff/diff.ts b/src/diff/diff.ts
deleted file mode 100644
index c290ee3..0000000
--- a/src/diff/diff.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import asyncPool from "tiny-async-pool";
-import { DocumentAccessor } from "../model/doc";
-import { ContentDiffHandler } from "./content_handler";
-import { IDiffWatcher } from "./watcher";
-
-export class DiffManager {
- watching: { [content_type: string]: ContentDiffHandler };
- doc_cntr: DocumentAccessor;
- constructor(contorller: DocumentAccessor) {
- this.watching = {};
- this.doc_cntr = contorller;
- }
- async register(content_type: string, watcher: IDiffWatcher) {
- if (this.watching[content_type] === undefined) {
- this.watching[content_type] = new ContentDiffHandler(this.doc_cntr, content_type);
- }
- this.watching[content_type].register(watcher);
- await watcher.setup(this.doc_cntr);
- }
- async commit(type: string, path: string) {
- const list = this.watching[type].waiting_list;
- const c = list.getByPath(path);
- if (c === undefined) {
- throw new Error("path is not exist");
- }
- await list.delete(c);
- const body = await c.createDocumentBody();
- const id = await this.doc_cntr.add(body);
- return id;
- }
- async commitAll(type: string) {
- const list = this.watching[type].waiting_list;
- const contentFiles = list.getAll();
- list.clear();
- const bodies = await asyncPool(30, contentFiles, async (x) => await x.createDocumentBody());
- const ids = await this.doc_cntr.addList(bodies);
- return ids;
- }
- getAdded() {
- return Object.keys(this.watching).map(x => ({
- type: x,
- value: this.watching[x].waiting_list.getAll(),
- }));
- }
-}
diff --git a/src/diff/router.ts b/src/diff/router.ts
deleted file mode 100644
index 63dc3ee..0000000
--- a/src/diff/router.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import Koa from "koa";
-import Router from "koa-router";
-import { ContentFile } from "../content/mod";
-import { AdminOnlyMiddleware } from "../permission/permission";
-import { sendError } from "../route/error_handler";
-import { DiffManager } from "./diff";
-
-function content_file_to_return(x: ContentFile) {
- return { path: x.path, type: x.type };
-}
-
-export const getAdded = (diffmgr: DiffManager) => (ctx: Koa.Context, next: Koa.Next) => {
- const ret = diffmgr.getAdded();
- ctx.body = ret.map(x => ({
- type: x.type,
- value: x.value.map(x => ({ path: x.path, type: x.type })),
- }));
- ctx.type = "json";
-};
-
-type PostAddedBody = {
- type: string;
- path: string;
-}[];
-
-function checkPostAddedBody(body: any): body is PostAddedBody {
- if (body instanceof Array) {
- return body.map(x => "type" in x && "path" in x).every(x => x);
- }
- return false;
-}
-
-export const postAdded = (diffmgr: DiffManager) => async (ctx: Router.IRouterContext, next: Koa.Next) => {
- const reqbody = ctx.request.body;
- if (!checkPostAddedBody(reqbody)) {
- sendError(400, "format exception");
- return;
- }
- const allWork = reqbody.map(op => diffmgr.commit(op.type, op.path));
- const results = await Promise.all(allWork);
- ctx.body = {
- ok: true,
- docs: results,
- };
- ctx.type = "json";
-};
-export const postAddedAll = (diffmgr: DiffManager) => async (ctx: Router.IRouterContext, next: Koa.Next) => {
- if (!ctx.is("json")) {
- sendError(400, "format exception");
- return;
- }
- const reqbody = ctx.request.body as Record;
- if (!("type" in reqbody)) {
- sendError(400, "format exception: there is no \"type\"");
- return;
- }
- const t = reqbody["type"];
- if (typeof t !== "string") {
- sendError(400, "format exception: invalid type of \"type\"");
- return;
- }
- await diffmgr.commitAll(t);
- ctx.body = {
- ok: true,
- };
- ctx.type = "json";
-};
-/*
-export const getNotWatched = (diffmgr : DiffManager)=> (ctx:Router.IRouterContext,next:Koa.Next)=>{
- ctx.body = {
- added: diffmgr.added.map(content_file_to_return),
- deleted: diffmgr.deleted.map(content_file_to_return),
- };
- ctx.type = 'json';
-}*/
-
-export function createDiffRouter(diffmgr: DiffManager) {
- const ret = new Router();
- ret.get("/list", AdminOnlyMiddleware, getAdded(diffmgr));
- ret.post("/commit", AdminOnlyMiddleware, postAdded(diffmgr));
- ret.post("/commitall", AdminOnlyMiddleware, postAddedAll(diffmgr));
- return ret;
-}
diff --git a/src/diff/watcher.ts b/src/diff/watcher.ts
deleted file mode 100644
index f64604e..0000000
--- a/src/diff/watcher.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import event from "events";
-import { FSWatcher, watch } from "fs";
-import { promises } from "fs";
-import { join } from "path";
-import { DocumentAccessor } from "../model/doc";
-
-const readdir = promises.readdir;
-
-export interface DiffWatcherEvent {
- "create": (path: string) => void;
- "delete": (path: string) => void;
- "change": (prev_path: string, cur_path: string) => void;
-}
-
-export interface IDiffWatcher extends event.EventEmitter {
- on(event: U, listener: DiffWatcherEvent[U]): this;
- emit(event: U, ...arg: Parameters): boolean;
- setup(cntr: DocumentAccessor): Promise;
-}
-
-export function linkWatcher(fromWatcher: IDiffWatcher, toWatcher: IDiffWatcher) {
- fromWatcher.on("create", p => toWatcher.emit("create", p));
- fromWatcher.on("delete", p => toWatcher.emit("delete", p));
- fromWatcher.on("change", (p, c) => toWatcher.emit("change", p, c));
-}
diff --git a/src/diff/watcher/ComicConfig.schema.json b/src/diff/watcher/ComicConfig.schema.json
deleted file mode 100644
index 50196de..0000000
--- a/src/diff/watcher/ComicConfig.schema.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "$ref": "#/definitions/ComicConfig",
- "definitions": {
- "ComicConfig": {
- "type": "object",
- "properties": { "watch": { "type": "array", "items": { "type": "string" } }, "$schema": { "type": "string" } },
- "required": ["watch"],
- "additionalProperties": false
- }
- }
-}
diff --git a/src/diff/watcher/comic_watcher.ts b/src/diff/watcher/comic_watcher.ts
deleted file mode 100644
index ebad62b..0000000
--- a/src/diff/watcher/comic_watcher.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { EventEmitter } from "events";
-import { DocumentAccessor } from "../../model/doc";
-import { DiffWatcherEvent, IDiffWatcher } from "../watcher";
-import { ComicConfig } from "./ComicConfig";
-import { WatcherCompositer } from "./compositer";
-import { RecursiveWatcher } from "./recursive_watcher";
-import { WatcherFilter } from "./watcher_filter";
-
-const createComicWatcherBase = (path: string) => {
- return new WatcherFilter(new RecursiveWatcher(path), (x) => x.endsWith(".zip"));
-};
-export const createComicWatcher = () => {
- const file = ComicConfig.get_config_file();
- console.log(`register comic ${file.watch.join(",")}`);
- return new WatcherCompositer(file.watch.map(path => createComicWatcherBase(path)));
-};
diff --git a/src/diff/watcher/common_watcher.ts b/src/diff/watcher/common_watcher.ts
deleted file mode 100644
index 808645e..0000000
--- a/src/diff/watcher/common_watcher.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import event from "events";
-import { FSWatcher, promises, watch } from "fs";
-import { join } from "path";
-import { DocumentAccessor } from "../../model/doc";
-import { DiffWatcherEvent, IDiffWatcher } from "../watcher";
-import { setupHelp } from "./util";
-
-const { readdir } = promises;
-
-export class CommonDiffWatcher extends event.EventEmitter implements IDiffWatcher {
- on(event: U, listener: DiffWatcherEvent[U]): this {
- return super.on(event, listener);
- }
- emit(event: U, ...arg: Parameters): boolean {
- return super.emit(event, ...arg);
- }
- private _path: string;
- private _watcher: FSWatcher;
-
- constructor(path: string) {
- super();
- this._path = path;
- this._watcher = watch(this._path, { persistent: true, recursive: false }, async (eventType, filename) => {
- if (eventType === "rename") {
- const cur = await readdir(this._path);
- // add
- if (cur.includes(filename)) {
- this.emit("create", join(this.path, filename));
- } else {
- this.emit("delete", join(this.path, filename));
- }
- }
- });
- }
- async setup(cntr: DocumentAccessor): Promise {
- await setupHelp(this, this.path, cntr);
- }
- public get path() {
- return this._path;
- }
- watchClose() {
- this._watcher.close();
- }
-}
diff --git a/src/diff/watcher/compositer.ts b/src/diff/watcher/compositer.ts
deleted file mode 100644
index e621ab8..0000000
--- a/src/diff/watcher/compositer.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { EventEmitter } from "events";
-import { DocumentAccessor } from "../../model/doc";
-import { DiffWatcherEvent, IDiffWatcher, linkWatcher } from "../watcher";
-
-export class WatcherCompositer extends EventEmitter implements IDiffWatcher {
- refWatchers: IDiffWatcher[];
- on(event: U, listener: DiffWatcherEvent[U]): this {
- return super.on(event, listener);
- }
- emit(event: U, ...arg: Parameters): boolean {
- return super.emit(event, ...arg);
- }
- constructor(refWatchers: IDiffWatcher[]) {
- super();
- this.refWatchers = refWatchers;
- for (const refWatcher of this.refWatchers) {
- linkWatcher(refWatcher, this);
- }
- }
- async setup(cntr: DocumentAccessor): Promise {
- await Promise.all(this.refWatchers.map(x => x.setup(cntr)));
- }
-}
diff --git a/src/diff/watcher/recursive_watcher.ts b/src/diff/watcher/recursive_watcher.ts
deleted file mode 100644
index 6afadce..0000000
--- a/src/diff/watcher/recursive_watcher.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { FSWatcher, watch } from "chokidar";
-import { EventEmitter } from "events";
-import { join } from "path";
-import { DocumentAccessor } from "../../model/doc";
-import { DiffWatcherEvent, IDiffWatcher } from "../watcher";
-import { setupHelp, setupRecursive } from "./util";
-
-type RecursiveWatcherOption = {
- /** @default true */
- watchFile?: boolean;
- /** @default false */
- watchDir?: boolean;
-};
-
-export class RecursiveWatcher extends EventEmitter implements IDiffWatcher {
- on(event: U, listener: DiffWatcherEvent[U]): this {
- return super.on(event, listener);
- }
- emit(event: U, ...arg: Parameters): boolean {
- return super.emit(event, ...arg);
- }
- readonly path: string;
- private watcher: FSWatcher;
-
- constructor(path: string, option: RecursiveWatcherOption = {
- watchDir: false,
- watchFile: true,
- }) {
- super();
- this.path = path;
- this.watcher = watch(path, {
- persistent: true,
- ignoreInitial: true,
- depth: 100,
- });
- option.watchFile ??= true;
- if (option.watchFile) {
- this.watcher.on("add", path => {
- const cpath = path;
- // console.log("add ", cpath);
- this.emit("create", cpath);
- }).on("unlink", path => {
- const cpath = path;
- // console.log("unlink ", cpath);
- this.emit("delete", cpath);
- });
- }
- if (option.watchDir) {
- this.watcher.on("addDir", path => {
- const cpath = path;
- this.emit("create", cpath);
- }).on("unlinkDir", path => {
- const cpath = path;
- this.emit("delete", cpath);
- });
- }
- }
- async setup(cntr: DocumentAccessor): Promise {
- await setupRecursive(this, this.path, cntr);
- }
-}
diff --git a/src/diff/watcher/util.ts b/src/diff/watcher/util.ts
deleted file mode 100644
index 8e51d7f..0000000
--- a/src/diff/watcher/util.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { EventEmitter } from "events";
-import { promises } from "fs";
-import { join } from "path";
-const { readdir } = promises;
-import { DocumentAccessor } from "../../model/doc";
-import { IDiffWatcher } from "../watcher";
-
-function setupCommon(watcher: IDiffWatcher, basepath: string, initial_filenames: string[], cur: string[]) {
- // Todo : reduce O(nm) to O(n+m) using hash map.
- let added = cur.filter(x => !initial_filenames.includes(x));
- let deleted = initial_filenames.filter(x => !cur.includes(x));
- for (const it of added) {
- const cpath = join(basepath, it);
- watcher.emit("create", cpath);
- }
- for (const it of deleted) {
- const cpath = join(basepath, it);
- watcher.emit("delete", cpath);
- }
-}
-export async function setupHelp(watcher: IDiffWatcher, basepath: string, cntr: DocumentAccessor) {
- const initial_document = await cntr.findByPath(basepath);
- const initial_filenames = initial_document.map(x => x.filename);
- const cur = await readdir(basepath);
- setupCommon(watcher, basepath, initial_filenames, cur);
-}
-export async function setupRecursive(watcher: IDiffWatcher, basepath: string, cntr: DocumentAccessor) {
- const initial_document = await cntr.findByPath(basepath);
- const initial_filenames = initial_document.map(x => x.filename);
- const cur = await readdir(basepath, { withFileTypes: true });
- setupCommon(watcher, basepath, initial_filenames, cur.map(x => x.name));
- await Promise.all([
- cur.filter(x => x.isDirectory())
- .map(x => setupHelp(watcher, join(basepath, x.name), cntr)),
- ]);
-}
diff --git a/src/diff/watcher/watcher_filter.ts b/src/diff/watcher/watcher_filter.ts
deleted file mode 100644
index 381b807..0000000
--- a/src/diff/watcher/watcher_filter.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { EventEmitter } from "events";
-import { DocumentAccessor } from "../../model/doc";
-import { DiffWatcherEvent, IDiffWatcher, linkWatcher } from "../watcher";
-
-export class WatcherFilter extends EventEmitter implements IDiffWatcher {
- refWatcher: IDiffWatcher;
- filter: (filename: string) => boolean;
- on(event: U, listener: DiffWatcherEvent[U]): this {
- return super.on(event, listener);
- }
- /**
- * emit event
- * @param event
- * @param arg
- * @returns `true` if the event had listeners, `false` otherwise.
- */
- emit(event: U, ...arg: Parameters): boolean {
- if (event === "change") {
- const prev = arg[0];
- const cur = arg[1] as string;
- if (this.filter(prev)) {
- if (this.filter(cur)) {
- return super.emit("change", prev, cur);
- } else {
- return super.emit("delete", cur);
- }
- } else {
- if (this.filter(cur)) {
- return super.emit("create", cur);
- }
- }
- return false;
- } else if (!this.filter(arg[0])) {
- return false;
- } else return super.emit(event, ...arg);
- }
- constructor(refWatcher: IDiffWatcher, filter: (filename: string) => boolean) {
- super();
- this.refWatcher = refWatcher;
- this.filter = filter;
- linkWatcher(refWatcher, this);
- }
- setup(cntr: DocumentAccessor): Promise {
- return this.refWatcher.setup(cntr);
- }
-}
diff --git a/src/login.ts b/src/login.ts
deleted file mode 100644
index a3a1cbf..0000000
--- a/src/login.ts
+++ /dev/null
@@ -1,285 +0,0 @@
-import { request } from "http";
-import { decode, sign, TokenExpiredError, verify } from "jsonwebtoken";
-import Knex from "knex";
-import Koa from "koa";
-import Router from "koa-router";
-import { createKnexUserController } from "./db/mod";
-import { IUser, UserAccessor } from "./model/mod";
-import { sendError } from "./route/error_handler";
-import { get_setting } from "./SettingConfig";
-
-type PayloadInfo = {
- username: string;
- permission: string[];
-};
-
-export type UserState = {
- user: PayloadInfo;
-};
-
-const isUserState = (obj: object | string): obj is PayloadInfo => {
- if (typeof obj === "string") return false;
- return "username" in obj && "permission" in obj
- && (obj as { permission: unknown }).permission instanceof Array;
-};
-type RefreshPayloadInfo = { username: string };
-const isRefreshToken = (obj: object | string): obj is RefreshPayloadInfo => {
- if (typeof obj === "string") return false;
- return "username" in obj
- && typeof (obj as { username: unknown }).username === "string";
-};
-
-export const accessTokenName = "access_token";
-export const refreshTokenName = "refresh_token";
-const accessExpiredTime = 60 * 60; // 1 hour
-const refreshExpiredTime = 60 * 60 * 24 * 14; // 14 day;
-
-export const getAdminAccessTokenValue = () => {
- const { jwt_secretkey } = get_setting();
- return publishAccessToken(jwt_secretkey, "admin", [], accessExpiredTime);
-};
-export const getAdminRefreshTokenValue = () => {
- const { jwt_secretkey } = get_setting();
- return publishRefreshToken(jwt_secretkey, "admin", refreshExpiredTime);
-};
-const publishAccessToken = (
- secretKey: string,
- username: string,
- permission: string[],
- expiredtime: number,
-) => {
- const payload = sign(
- {
- username: username,
- permission: permission,
- },
- secretKey,
- { expiresIn: expiredtime },
- );
- return payload;
-};
-const publishRefreshToken = (
- secretKey: string,
- username: string,
- expiredtime: number,
-) => {
- const payload = sign(
- { username: username },
- secretKey,
- { expiresIn: expiredtime },
- );
- return payload;
-};
-function setToken(
- ctx: Koa.Context,
- token_name: string,
- token_payload: string | null,
- expiredtime: number,
-) {
- const setting = get_setting();
- if (token_payload === null && !!!ctx.cookies.get(token_name)) {
- return;
- }
- ctx.cookies.set(token_name, token_payload, {
- httpOnly: true,
- secure: setting.secure,
- sameSite: "strict",
- expires: new Date(Date.now() + expiredtime * 1000),
- });
-}
-export const createLoginMiddleware = (userController: UserAccessor) => async (ctx: Koa.Context, _next: Koa.Next) => {
- const setting = get_setting();
- const secretKey = setting.jwt_secretkey;
- const body = ctx.request.body;
- // check format
- if (typeof body == "string" || !("username" in body) || !("password" in body)) {
- return sendError(
- 400,
- "invalid form : username or password is not found in query.",
- );
- }
- const username = body["username"];
- const password = body["password"];
- // check type
- if (typeof username !== "string" || typeof password !== "string") {
- return sendError(
- 400,
- "invalid form : username or password is not string",
- );
- }
- // if admin login is forbidden?
- if (username === "admin" && setting.forbid_remote_admin_login) {
- return sendError(403, "forbidden remote admin login");
- }
- const user = await userController.findUser(username);
- // username not exist
- if (user === undefined) return sendError(401, "not authorized");
- // password not matched
- if (!user.password.check_password(password)) {
- return sendError(401, "not authorized");
- }
- // create token
- const userPermission = await user.get_permissions();
- const payload = publishAccessToken(
- secretKey,
- user.username,
- userPermission,
- accessExpiredTime,
- );
- const payload2 = publishRefreshToken(
- secretKey,
- user.username,
- refreshExpiredTime,
- );
- setToken(ctx, accessTokenName, payload, accessExpiredTime);
- setToken(ctx, refreshTokenName, payload2, refreshExpiredTime);
- ctx.body = {
- username: user.username,
- permission: userPermission,
- accessExpired: (Math.floor(Date.now() / 1000) + accessExpiredTime),
- };
- console.log(`${username} logined`);
- return;
-};
-
-export const LogoutMiddleware = (ctx: Koa.Context, next: Koa.Next) => {
- const setting = get_setting();
- ctx.cookies.set(accessTokenName, null);
- ctx.cookies.set(refreshTokenName, null);
- ctx.body = {
- ok: true,
- username: "",
- permission: setting.guest,
- };
- return;
-};
-export const createUserMiddleWare =
- (userController: UserAccessor) => async (ctx: Koa.ParameterizedContext, next: Koa.Next) => {
- const refreshToken = refreshTokenHandler(userController);
- const setting = get_setting();
- const setGuest = async () => {
- setToken(ctx, accessTokenName, null, 0);
- setToken(ctx, refreshTokenName, null, 0);
- ctx.state["user"] = { username: "", permission: setting.guest };
- return await next();
- };
- return await refreshToken(ctx, setGuest, next);
- };
-const refreshTokenHandler = (cntr: UserAccessor) => async (ctx: Koa.Context, fail: Koa.Next, next: Koa.Next) => {
- const accessPayload = ctx.cookies.get(accessTokenName);
- const setting = get_setting();
- const secretKey = setting.jwt_secretkey;
- if (accessPayload == undefined) {
- return await checkRefreshAndUpdate();
- }
- try {
- const o = verify(accessPayload, secretKey);
- if (isUserState(o)) {
- ctx.state.user = o;
- return await next();
- } else {
- console.error("invalid token detected");
- throw new Error("token form invalid");
- }
- } catch (e) {
- if (e instanceof TokenExpiredError) {
- return await checkRefreshAndUpdate();
- } else throw e;
- }
- async function checkRefreshAndUpdate() {
- const refreshPayload = ctx.cookies.get(refreshTokenName);
- if (refreshPayload === undefined) {
- return await fail(); // refresh token doesn't exist
- } else {
- try {
- const o = verify(refreshPayload, secretKey);
- if (isRefreshToken(o)) {
- const user = await cntr.findUser(o.username);
- if (user === undefined) return await fail(); // already non-existence user
- const perm = await user.get_permissions();
- const payload = publishAccessToken(
- secretKey,
- user.username,
- perm,
- accessExpiredTime,
- );
- setToken(ctx, accessTokenName, payload, accessExpiredTime);
- ctx.state.user = { username: o.username, permission: perm };
- } else {
- console.error("invalid token detected");
- throw new Error("token form invalid");
- }
- } catch (e) {
- if (e instanceof TokenExpiredError) { // refresh token is expired.
- return await fail();
- } else throw e;
- }
- }
- return await next();
- }
-};
-export const createRefreshTokenMiddleware = (cntr: UserAccessor) => async (ctx: Koa.Context, next: Koa.Next) => {
- const handler = refreshTokenHandler(cntr);
- await handler(ctx, fail, success);
- async function fail() {
- const user = ctx.state.user as PayloadInfo;
- ctx.body = {
- refresh: false,
- ...user,
- };
- ctx.type = "json";
- }
- async function success() {
- const user = ctx.state.user as PayloadInfo;
- ctx.body = {
- ...user,
- refresh: true,
- refreshExpired: Math.floor(Date.now() / 1000 + accessExpiredTime),
- };
- ctx.type = "json";
- }
-};
-export const resetPasswordMiddleware = (cntr: UserAccessor) => async (ctx: Koa.Context, next: Koa.Next) => {
- const body = ctx.request.body;
- if (typeof body !== "object" || !("username" in body) || !("oldpassword" in body) || !("newpassword" in body)) {
- return sendError(400, "request body is invalid format");
- }
- const username = body["username"];
- const oldpw = body["oldpassword"];
- const newpw = body["newpassword"];
- if (typeof username !== "string" || typeof oldpw !== "string" || typeof newpw !== "string") {
- return sendError(400, "request body is invalid format");
- }
- const user = await cntr.findUser(username);
- if (user === undefined) {
- return sendError(403, "not authorized");
- }
- if (!user.password.check_password(oldpw)) {
- return sendError(403, "not authorized");
- }
- user.reset_password(newpw);
- ctx.body = { ok: true };
- ctx.type = "json";
-};
-
-export function createLoginRouter(userController: UserAccessor) {
- const router = new Router();
- router.post("/login", createLoginMiddleware(userController));
- router.post("/logout", LogoutMiddleware);
- router.post("/refresh", createRefreshTokenMiddleware(userController));
- router.post("/reset", resetPasswordMiddleware(userController));
- return router;
-}
-
-export const getAdmin = async (cntr: UserAccessor) => {
- const admin = await cntr.findUser("admin");
- if (admin === undefined) {
- throw new Error("initial process failed!"); // ???
- }
- return admin;
-};
-
-export const isAdminFirst = (admin: IUser) => {
- return admin.password.hash === "unchecked"
- && admin.password.salt === "unchecked";
-};
diff --git a/src/model/doc.ts b/src/model/doc.ts
deleted file mode 100644
index 7954de0..0000000
--- a/src/model/doc.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import { JSONMap } from "../types/json";
-import { check_type } from "../util/type_check";
-import { TagAccessor } from "./tag";
-
-export interface DocumentBody {
- title: string;
- content_type: string;
- basepath: string;
- filename: string;
- modified_at: number;
- content_hash: string;
- additional: JSONMap;
- tags: string[]; // eager loading
-}
-
-export const MetaContentBody = {
- title: "string",
- content_type: "string",
- basepath: "string",
- filename: "string",
- content_hash: "string",
- additional: "object",
- tags: "string[]",
-};
-
-export const isDocBody = (c: any): c is DocumentBody => {
- return check_type(c, MetaContentBody);
-};
-
-export interface Document extends DocumentBody {
- readonly id: number;
- readonly created_at: number;
- readonly deleted_at: number | null;
-}
-
-export const isDoc = (c: any): c is Document => {
- if ("id" in c && typeof c["id"] === "number") {
- const { id, ...rest } = c;
- return isDocBody(rest);
- }
- return false;
-};
-
-export type QueryListOption = {
- /**
- * search word
- */
- word?: string;
- allow_tag?: string[];
- /**
- * limit of list
- * @default 20
- */
- limit?: number;
- /**
- * use offset if true, otherwise
- * @default false
- */
- use_offset?: boolean;
- /**
- * cursor of documents
- */
- cursor?: number;
- /**
- * offset of documents
- */
- offset?: number;
- /**
- * tag eager loading
- * @default true
- */
- eager_loading?: boolean;
- /**
- * content type
- */
- content_type?: string;
-};
-
-export interface DocumentAccessor {
- /**
- * find list by option
- * @returns documents list
- */
- findList: (option?: QueryListOption) => Promise;
- /**
- * @returns document if exist, otherwise undefined
- */
- findById: (id: number, tagload?: boolean) => Promise;
- /**
- * find by base path and filename.
- * if you call this function with filename, its return array length is 0 or 1.
- */
- findByPath: (basepath: string, filename?: string) => Promise;
- /**
- * find deleted content
- */
- findDeleted: (content_type: string) => Promise;
- /**
- * search by in document
- */
- search: (search_word: string) => Promise;
- /**
- * update document except tag.
- */
- update: (c: Partial & { id: number }) => Promise;
- /**
- * add document
- */
- add: (c: DocumentBody) => Promise;
- /**
- * add document list
- */
- addList: (content_list: DocumentBody[]) => Promise;
- /**
- * delete document
- * @returns if it exists, return true.
- */
- del: (id: number) => Promise;
- /**
- * @param c Valid Document
- * @param tagname tag name to add
- * @returns if success, return true
- */
- addTag: (c: Document, tag_name: string) => Promise;
- /**
- * @returns if success, return true
- */
- delTag: (c: Document, tag_name: string) => Promise;
-}
diff --git a/src/model/tag.ts b/src/model/tag.ts
deleted file mode 100644
index 74d945c..0000000
--- a/src/model/tag.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-export interface Tag {
- readonly name: string;
- description?: string;
-}
-
-export interface TagCount {
- tag_name: string;
- occurs: number;
-}
-
-export interface TagAccessor {
- getAllTagList: (onlyname?: boolean) => Promise;
- getAllTagCount(): Promise;
- getTagByName: (name: string) => Promise;
- addTag: (tag: Tag) => Promise;
- delTag: (name: string) => Promise;
- updateTag: (name: string, tag: string) => Promise;
-}
diff --git a/src/model/user.ts b/src/model/user.ts
deleted file mode 100644
index eb7c14b..0000000
--- a/src/model/user.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { createHmac, randomBytes } from "crypto";
-
-function hashForPassword(salt: string, password: string) {
- return createHmac("sha256", salt).update(password).digest("hex");
-}
-function createPasswordHashAndSalt(password: string): { salt: string; hash: string } {
- const secret = randomBytes(32).toString("hex");
- return {
- salt: secret,
- hash: hashForPassword(secret, password),
- };
-}
-
-export class Password {
- private _salt: string;
- private _hash: string;
- constructor(pw: string | { salt: string; hash: string }) {
- const { salt, hash } = typeof pw === "string" ? createPasswordHashAndSalt(pw) : pw;
- this._hash = hash;
- this._salt = salt;
- }
- set_password(password: string) {
- const { salt, hash } = createPasswordHashAndSalt(password);
- this._hash = hash;
- this._salt = salt;
- }
- check_password(password: string): boolean {
- return this._hash === hashForPassword(this._salt, password);
- }
- get salt() {
- return this._salt;
- }
- get hash() {
- return this._hash;
- }
-}
-
-export interface UserCreateInput {
- username: string;
- password: string;
-}
-
-export interface IUser {
- readonly username: string;
- readonly password: Password;
- /**
- * return user's permission list.
- */
- get_permissions(): Promise;
- /**
- * add permission
- * @param name permission name to add
- * @returns if `name` doesn't exist, return true
- */
- add(name: string): Promise;
- /**
- * remove permission
- * @param name permission name to remove
- * @returns if `name` exist, return true
- */
- remove(name: string): Promise;
- /**
- * reset password.
- * @param password password to set
- */
- reset_password(password: string): Promise;
-}
-
-export interface UserAccessor {
- /**
- * create user
- * @returns if user exist, return undefined
- */
- createUser: (input: UserCreateInput) => Promise;
- /**
- * find user
- */
- findUser: (username: string) => Promise;
- /**
- * remove user
- * @returns if user exist, true
- */
- delUser: (username: string) => Promise;
-}
diff --git a/src/permission/permission.ts b/src/permission/permission.ts
deleted file mode 100644
index 2d06225..0000000
--- a/src/permission/permission.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import Koa from "koa";
-import { UserState } from "../login";
-import { sendError } from "../route/error_handler";
-
-export enum Permission {
- // ========
- // not implemented
- // admin only
- /** remove document */
- // removeContent = 'removeContent',
-
- /** upload document */
- // uploadContent = 'uploadContent',
-
- /** modify document except base path, filename, content_hash. but admin can modify all. */
- // modifyContent = 'modifyContent',
-
- /** add tag into document */
- // addTagContent = 'addTagContent',
- /** remove tag from document */
- // removeTagContent = 'removeTagContent',
- /** ModifyTagInDoc */
- ModifyTag = "ModifyTag",
-
- /** find documents with query */
- // findAllContent = 'findAllContent',
- /** find one document. */
- // findOneContent = 'findOneContent',
- /** view content*/
- // viewContent = 'viewContent',
- QueryContent = "QueryContent",
-
- /** modify description about the one tag. */
- modifyTagDesc = "ModifyTagDesc",
-}
-
-export const createPermissionCheckMiddleware =
- (...permissions: string[]) => async (ctx: Koa.ParameterizedContext, next: Koa.Next) => {
- const user = ctx.state["user"];
- if (user.username === "admin") {
- return await next();
- }
- const user_permission = user.permission;
- // if permissions is not subset of user permission
- if (!permissions.map(p => user_permission.includes(p)).every(x => x)) {
- if (user.username === "") {
- return sendError(401, "you are guest. login needed.");
- } else return sendError(403, "do not have permission");
- }
- await next();
- };
-export const AdminOnlyMiddleware = async (ctx: Koa.ParameterizedContext, next: Koa.Next) => {
- const user = ctx.state["user"];
- if (user.username !== "admin") {
- return sendError(403, "admin only");
- }
- await next();
-};
diff --git a/src/route/all.ts b/src/route/all.ts
deleted file mode 100644
index 381226b..0000000
--- a/src/route/all.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { DefaultContext, Middleware, Next, ParameterizedContext } from "koa";
-import compose from "koa-compose";
-import Router, { IParamMiddleware } from "koa-router";
-import ComicRouter from "./comic";
-import { ContentContext } from "./context";
-import VideoRouter from "./video";
-
-const table: { [s: string]: Router | undefined } = {
- "comic": new ComicRouter(),
- "video": new VideoRouter(),
-};
-const all_middleware =
- (cont: string | undefined, restarg: string | undefined) =>
- async (ctx: ParameterizedContext, next: Next) => {
- if (cont == undefined) {
- ctx.status = 404;
- return;
- }
- if (ctx.state.location.type != cont) {
- console.error("not matched");
- ctx.status = 404;
- return;
- }
- const router = table[cont];
- if (router == undefined) {
- ctx.status = 404;
- return;
- }
- const rest = "/" + (restarg ?? "");
- const result = router.match(rest, "GET");
- if (!result.route) {
- return await next();
- }
- const chain = result.pathAndMethod.reduce((combination: Middleware[], cur) => {
- combination.push(async (ctx, next) => {
- const captures = cur.captures(rest);
- ctx.params = cur.params(rest, captures);
- ctx.request.params = ctx.params;
- ctx.routerPath = cur.path;
- return await next();
- });
- return combination.concat(cur.stack);
- }, []);
- return await compose(chain)(ctx, next);
- };
-export class AllContentRouter extends Router {
- constructor() {
- super();
- this.get("/:content_type", async (ctx, next) => {
- return await (all_middleware(ctx.params["content_type"], undefined))(ctx, next);
- });
- this.get("/:content_type/:rest(.*)", async (ctx, next) => {
- const cont = ctx.params["content_type"] as string;
- return await (all_middleware(cont, ctx.params["rest"]))(ctx, next);
- });
- }
-}
diff --git a/src/route/comic.ts b/src/route/comic.ts
deleted file mode 100644
index 875fd02..0000000
--- a/src/route/comic.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import { Context, DefaultContext, DefaultState, Next } from "koa";
-import Router from "koa-router";
-import { createReadableStreamFromZip, entriesByNaturalOrder, readZip, ZipAsync } from "../util/zipwrap";
-import { ContentContext } from "./context";
-import { since_last_modified } from "./util";
-
-/**
- * zip stream cache.
- */
-
-let ZipStreamCache: { [path: string]: [ZipAsync, number] } = {};
-
-async function acquireZip(path: string) {
- if (!(path in ZipStreamCache)) {
- const ret = await readZip(path);
- ZipStreamCache[path] = [ret, 1];
- // console.log(`acquire ${path} 1`);
- return ret;
- } else {
- const [ret, refCount] = ZipStreamCache[path];
- ZipStreamCache[path] = [ret, refCount + 1];
- // console.log(`acquire ${path} ${refCount + 1}`);
- return ret;
- }
-}
-
-function releaseZip(path: string) {
- const obj = ZipStreamCache[path];
- if (obj === undefined) throw new Error("error! key invalid");
- const [ref, refCount] = obj;
- // console.log(`release ${path} : ${refCount}`);
- if (refCount === 1) {
- ref.close();
- delete ZipStreamCache[path];
- } else {
- ZipStreamCache[path] = [ref, refCount - 1];
- }
-}
-
-async function renderZipImage(ctx: Context, path: string, page: number) {
- const image_ext = ["gif", "png", "jpeg", "bmp", "webp", "jpg"];
- // console.log(`opened ${page}`);
- let zip = await acquireZip(path);
- const entries = (await entriesByNaturalOrder(zip)).filter((x) => {
- const ext = x.name.split(".").pop();
- return ext !== undefined && image_ext.includes(ext);
- });
- if (0 <= page && page < entries.length) {
- const entry = entries[page];
- const last_modified = new Date(entry.time);
- if (since_last_modified(ctx, last_modified)) {
- return;
- }
- const read_stream = await createReadableStreamFromZip(zip, entry);
- /** Exceptions (ECONNRESET, ECONNABORTED) may be thrown when processing this request
- * for reasons such as when the browser unexpectedly closes the connection.
- * Once such an exception is raised, the stream is not properly destroyed,
- * so there is a problem with the zlib stream being accessed even after the stream is closed.
- * So it waits for 100 ms and releases it.
- * Additionaly, there is a risk of memory leak becuase zlib stream is not properly destroyed.
- * @todo modify function 'stream' in 'node-stream-zip' library to prevent memory leak */
- read_stream.once("close", () => {
- setTimeout(() => {
- releaseZip(path);
- }, 100);
- });
-
- ctx.body = read_stream;
- ctx.response.length = entry.size;
- // console.log(`${entry.name}'s ${page}:${entry.size}`);
- ctx.response.type = entry.name.split(".").pop() as string;
- ctx.status = 200;
- ctx.set("Date", new Date().toUTCString());
- ctx.set("Last-Modified", last_modified.toUTCString());
- } else {
- ctx.status = 404;
- }
-}
-
-export class ComicRouter extends Router {
- constructor() {
- super();
- this.get("/", async (ctx, next) => {
- await renderZipImage(ctx, ctx.state.location.path, 0);
- });
- this.get("/:page(\\d+)", async (ctx, next) => {
- const page = Number.parseInt(ctx.params["page"]);
- await renderZipImage(ctx, ctx.state.location.path, page);
- });
- this.get("/thumbnail", async (ctx, next) => {
- await renderZipImage(ctx, ctx.state.location.path, 0);
- });
- }
-}
-
-export default ComicRouter;
diff --git a/src/route/contents.ts b/src/route/contents.ts
deleted file mode 100644
index 1f737a1..0000000
--- a/src/route/contents.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-import { Context, Next } from "koa";
-import Router from "koa-router";
-import { join } from "path";
-import { Document, DocumentAccessor, isDocBody } from "../model/doc";
-import { QueryListOption } from "../model/doc";
-import {
- AdminOnlyMiddleware as AdminOnly,
- createPermissionCheckMiddleware as PerCheck,
- Permission as Per,
-} from "../permission/permission";
-import { AllContentRouter } from "./all";
-import { ContentLocation } from "./context";
-import { sendError } from "./error_handler";
-import { ParseQueryArgString, ParseQueryArray, ParseQueryBoolean, ParseQueryNumber } from "./util";
-
-const ContentIDHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- const num = Number.parseInt(ctx.params["num"]);
- let document = await controller.findById(num, true);
- if (document == undefined) {
- return sendError(404, "document does not exist.");
- }
- ctx.body = document;
- ctx.type = "json";
- console.log(document.additional);
-};
-const ContentTagIDHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- const num = Number.parseInt(ctx.params["num"]);
- let document = await controller.findById(num, true);
- if (document == undefined) {
- return sendError(404, "document does not exist.");
- }
- ctx.body = document.tags;
- ctx.type = "json";
-};
-const ContentQueryHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- let query_limit = ctx.query["limit"];
- let query_cursor = ctx.query["cursor"];
- let query_word = ctx.query["word"];
- let query_content_type = ctx.query["content_type"];
- let query_offset = ctx.query["offset"];
- let query_use_offset = ctx.query["use_offset"];
- if (
- query_limit instanceof Array
- || query_cursor instanceof Array
- || query_word instanceof Array
- || query_content_type instanceof Array
- || query_offset instanceof Array
- || query_use_offset instanceof Array
- ) {
- return sendError(400, "paramter can not be array");
- }
- const limit = ParseQueryNumber(query_limit);
- const cursor = ParseQueryNumber(query_cursor);
- const word = ParseQueryArgString(query_word);
- const content_type = ParseQueryArgString(query_content_type);
- const offset = ParseQueryNumber(query_offset);
- if (limit === NaN || cursor === NaN || offset === NaN) {
- return sendError(400, "parameter limit, cursor or offset is not a number");
- }
- const allow_tag = ParseQueryArray(ctx.query["allow_tag"]);
- const [ok, use_offset] = ParseQueryBoolean(query_use_offset);
- if (!ok) {
- return sendError(400, "use_offset must be true or false.");
- }
- const option: QueryListOption = {
- limit: limit,
- allow_tag: allow_tag,
- word: word,
- cursor: cursor,
- eager_loading: true,
- offset: offset,
- use_offset: use_offset,
- content_type: content_type,
- };
- let document = await controller.findList(option);
- ctx.body = document;
- ctx.type = "json";
-};
-const UpdateContentHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- const num = Number.parseInt(ctx.params["num"]);
-
- if (ctx.request.type !== "json") {
- return sendError(400, "update fail. invalid document type: it is not json.");
- }
- if (typeof ctx.request.body !== "object") {
- return sendError(400, "update fail. invalid argument: not");
- }
- const content_desc: Partial & { id: number } = {
- id: num,
- ...ctx.request.body,
- };
- const success = await controller.update(content_desc);
- ctx.body = JSON.stringify(success);
- ctx.type = "json";
-};
-
-const AddTagHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- let tag_name = ctx.params["tag"];
- const num = Number.parseInt(ctx.params["num"]);
- if (typeof tag_name === undefined) {
- return sendError(400, "??? Unreachable");
- }
- tag_name = String(tag_name);
- const c = await controller.findById(num);
- if (c === undefined) {
- return sendError(404);
- }
- const r = await controller.addTag(c, tag_name);
- ctx.body = JSON.stringify(r);
- ctx.type = "json";
-};
-const DelTagHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- let tag_name = ctx.params["tag"];
- const num = Number.parseInt(ctx.params["num"]);
- if (typeof tag_name === undefined) {
- return sendError(400, "?? Unreachable");
- }
- tag_name = String(tag_name);
- const c = await controller.findById(num);
- if (c === undefined) {
- return sendError(404);
- }
- const r = await controller.delTag(c, tag_name);
- ctx.body = JSON.stringify(r);
- ctx.type = "json";
-};
-const DeleteContentHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- const num = Number.parseInt(ctx.params["num"]);
- const r = await controller.del(num);
- ctx.body = JSON.stringify(r);
- ctx.type = "json";
-};
-const ContentHandler = (controller: DocumentAccessor) => async (ctx: Context, next: Next) => {
- const num = Number.parseInt(ctx.params["num"]);
- let document = await controller.findById(num, true);
- if (document == undefined) {
- return sendError(404, "document does not exist.");
- }
- if (document.deleted_at !== null) {
- return sendError(404, "document has been removed.");
- }
- const path = join(document.basepath, document.filename);
- ctx.state["location"] = {
- path: path,
- type: document.content_type,
- additional: document.additional,
- } as ContentLocation;
- await next();
-};
-
-export const getContentRouter = (controller: DocumentAccessor) => {
- const ret = new Router();
- ret.get("/search", PerCheck(Per.QueryContent), ContentQueryHandler(controller));
- ret.get("/:num(\\d+)", PerCheck(Per.QueryContent), ContentIDHandler(controller));
- ret.post("/:num(\\d+)", AdminOnly, UpdateContentHandler(controller));
- // ret.use("/:num(\\d+)/:content_type");
- // ret.post("/",AdminOnly,CreateContentHandler(controller));
- ret.get("/:num(\\d+)/tags", PerCheck(Per.QueryContent), ContentTagIDHandler(controller));
- ret.post("/:num(\\d+)/tags/:tag", PerCheck(Per.ModifyTag), AddTagHandler(controller));
- ret.del("/:num(\\d+)/tags/:tag", PerCheck(Per.ModifyTag), DelTagHandler(controller));
- ret.del("/:num(\\d+)", AdminOnly, DeleteContentHandler(controller));
- ret.all("/:num(\\d+)/(.*)", PerCheck(Per.QueryContent), ContentHandler(controller));
- ret.use("/:num(\\d+)", PerCheck(Per.QueryContent), (new AllContentRouter()).routes());
- return ret;
-};
-
-export default getContentRouter;
diff --git a/src/route/context.ts b/src/route/context.ts
deleted file mode 100644
index 19e44d9..0000000
--- a/src/route/context.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export type ContentLocation = {
- path: string;
- type: string;
- additional: object | undefined;
-};
-export interface ContentContext {
- location: ContentLocation;
-}
diff --git a/src/route/error_handler.ts b/src/route/error_handler.ts
deleted file mode 100644
index 5d3e84f..0000000
--- a/src/route/error_handler.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { Context, Next } from "koa";
-
-export interface ErrorFormat {
- code: number;
- message: string;
- detail?: string;
-}
-
-class ClientRequestError implements Error {
- name: string;
- message: string;
- stack?: string | undefined;
- code: number;
-
- constructor(code: number, message: string) {
- this.name = "client request error";
- this.message = message;
- this.code = code;
- }
-}
-
-const code_to_message_table: { [key: number]: string | undefined } = {
- 400: "BadRequest",
- 404: "NotFound",
-};
-
-export const error_handler = async (ctx: Context, next: Next) => {
- try {
- await next();
- } catch (err) {
- if (err instanceof ClientRequestError) {
- const body: ErrorFormat = {
- code: err.code,
- message: code_to_message_table[err.code] ?? "",
- detail: err.message,
- };
- ctx.status = err.code;
- ctx.body = body;
- } else {
- throw err;
- }
- }
-};
-
-export const sendError = (code: number, message?: string) => {
- throw new ClientRequestError(code, message ?? "");
-};
-
-export default error_handler;
diff --git a/src/route/tags.ts b/src/route/tags.ts
deleted file mode 100644
index aa86d67..0000000
--- a/src/route/tags.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Context, Next } from "koa";
-import Router, { RouterContext } from "koa-router";
-import { TagAccessor } from "../model/tag";
-import { createPermissionCheckMiddleware as PerCheck, Permission } from "../permission/permission";
-import { sendError } from "./error_handler";
-
-export function getTagRounter(tagController: TagAccessor) {
- let router = new Router();
- router.get("/", PerCheck(Permission.QueryContent), async (ctx: Context) => {
- if (ctx.query["withCount"]) {
- const c = await tagController.getAllTagCount();
- ctx.body = c;
- } else {
- const c = await tagController.getAllTagList();
- ctx.body = c;
- }
- ctx.type = "json";
- });
- router.get("/:tag_name", PerCheck(Permission.QueryContent), async (ctx: RouterContext) => {
- const tag_name = ctx.params["tag_name"];
- const c = await tagController.getTagByName(tag_name);
- if (!c) {
- sendError(404, "tags not found");
- }
- ctx.body = c;
- ctx.type = "json";
- });
- return router;
-}
diff --git a/src/route/util.ts b/src/route/util.ts
deleted file mode 100644
index 8a64a41..0000000
--- a/src/route/util.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Context } from "koa";
-
-export function ParseQueryNumber(s: string[] | string | undefined): number | undefined {
- if (s === undefined) return undefined;
- else if (typeof s === "object") return undefined;
- else return Number.parseInt(s);
-}
-export function ParseQueryArray(s: string[] | string | undefined) {
- s = s ?? [];
- const r = s instanceof Array ? s : [s];
- return r.map(x => decodeURIComponent(x));
-}
-export function ParseQueryArgString(s: string[] | string | undefined) {
- if (typeof s === "object") return undefined;
- return s === undefined ? s : decodeURIComponent(s);
-}
-export function ParseQueryBoolean(s: string[] | string | undefined): [boolean, boolean | undefined] {
- let value: boolean | undefined;
-
- if (s === "true") {
- value = true;
- } else if (s === "false") {
- value = false;
- } else if (s === undefined) {
- value = undefined;
- } else return [false, undefined];
- return [true, value];
-}
-
-export function since_last_modified(ctx: Context, last_modified: Date): boolean {
- const con = ctx.get("If-Modified-Since");
- if (con === "") return false;
- const mdate = new Date(con);
- if (last_modified > mdate) return false;
- ctx.status = 304;
- return true;
-}
diff --git a/src/route/video.ts b/src/route/video.ts
deleted file mode 100644
index f52499d..0000000
--- a/src/route/video.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { createReadStream, promises } from "fs";
-import { Context } from "koa";
-import Router from "koa-router";
-import { ContentContext } from "./context";
-
-export async function renderVideo(ctx: Context, path: string) {
- const ext = path.trim().split(".").pop();
- if (ext === undefined) {
- // ctx.status = 404;
- console.error(`${path}:${ext}`);
- return;
- }
- ctx.response.type = ext;
- const range_text = ctx.request.get("range");
- const stat = await promises.stat(path);
- let start = 0;
- let end = 0;
- ctx.set("Last-Modified", new Date(stat.mtime).toUTCString());
- ctx.set("Date", new Date().toUTCString());
- ctx.set("Accept-Ranges", "bytes");
- if (range_text === "") {
- end = 1024 * 512;
- end = Math.min(end, stat.size - 1);
- if (start > end) {
- ctx.status = 416;
- return;
- }
- ctx.status = 200;
- ctx.length = stat.size;
- let stream = createReadStream(path);
- ctx.body = stream;
- } else {
- const m = range_text.match(/^bytes=(\d+)-(\d*)/);
- if (m === null) {
- ctx.status = 416;
- return;
- }
- start = parseInt(m[1]);
- end = m[2].length > 0 ? parseInt(m[2]) : start + 1024 * 1024;
- end = Math.min(end, stat.size - 1);
- if (start > end) {
- ctx.status = 416;
- return;
- }
- ctx.status = 206;
- ctx.length = end - start + 1;
- ctx.response.set("Content-Range", `bytes ${start}-${end}/${stat.size}`);
- ctx.body = createReadStream(path, {
- start: start,
- end: end,
- }); // inclusive range.
- }
-}
-
-export class VideoRouter extends Router {
- constructor() {
- super();
- this.get("/", async (ctx, next) => {
- await renderVideo(ctx, ctx.state.location.path);
- });
- this.get("/thumbnail", async (ctx, next) => {
- await renderVideo(ctx, ctx.state.location.path);
- });
- }
-}
-
-export default VideoRouter;
diff --git a/src/search/indexer.ts b/src/search/indexer.ts
deleted file mode 100644
index f3c129b..0000000
--- a/src/search/indexer.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export interface PaginationOption {
- cursor: number;
- limit: number;
-}
-
-export interface IIndexer {
- indexDoc(word: string, doc_id: number): boolean;
- indexDoc(word: string[], doc_id: number): boolean;
-
- getDoc(word: string, option?: PaginationOption): number[];
- getDoc(word: string[], option?: PaginationOption): number[];
-}
diff --git a/src/search/tokenizer.ts b/src/search/tokenizer.ts
deleted file mode 100644
index cb7f8ad..0000000
--- a/src/search/tokenizer.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export interface ITokenizer {
- tokenize(s: string): string[];
-}
-
-export class DefaultTokenizer implements ITokenizer {
- tokenize(s: string): string[] {
- return s.split(" ");
- }
-}
diff --git a/src/server.ts b/src/server.ts
deleted file mode 100644
index 23590b0..0000000
--- a/src/server.ts
+++ /dev/null
@@ -1,237 +0,0 @@
-import Koa from "koa";
-import Router from "koa-router";
-
-import { connectDB } from "./database";
-import { createDiffRouter, DiffManager } from "./diff/mod";
-import { get_setting, SettingConfig } from "./SettingConfig";
-
-import { createReadStream, readFileSync } from "fs";
-import bodyparser from "koa-bodyparser";
-import { createKnexDocumentAccessor, createKnexTagController, createKnexUserController } from "./db/mod";
-import { createLoginRouter, createUserMiddleWare, getAdmin, isAdminFirst } from "./login";
-import getContentRouter from "./route/contents";
-import { error_handler } from "./route/error_handler";
-
-import { createInterface as createReadlineInterface } from "readline";
-import { createComicWatcher } from "./diff/watcher/comic_watcher";
-import { DocumentAccessor, TagAccessor, UserAccessor } from "./model/mod";
-import { getTagRounter } from "./route/tags";
-
-class ServerApplication {
- readonly userController: UserAccessor;
- readonly documentController: DocumentAccessor;
- readonly tagController: TagAccessor;
- readonly diffManger: DiffManager;
- readonly app: Koa;
- private index_html: string;
- private constructor(controller: {
- userController: UserAccessor;
- documentController: DocumentAccessor;
- tagController: TagAccessor;
- }) {
- this.userController = controller.userController;
- this.documentController = controller.documentController;
- this.tagController = controller.tagController;
-
- this.diffManger = new DiffManager(this.documentController);
- this.app = new Koa();
- this.index_html = readFileSync("index.html", "utf-8");
- }
- private async setup() {
- const setting = get_setting();
- const app = this.app;
-
- if (setting.cli) {
- const userAdmin = await getAdmin(this.userController);
- if (await isAdminFirst(userAdmin)) {
- const rl = createReadlineInterface({
- input: process.stdin,
- output: process.stdout,
- });
- const pw = await new Promise((res: (data: string) => void, err) => {
- rl.question("put admin password :", (data) => {
- res(data);
- });
- });
- rl.close();
- userAdmin.reset_password(pw);
- }
- }
- app.use(bodyparser());
- app.use(error_handler);
- app.use(createUserMiddleWare(this.userController));
-
- let diff_router = createDiffRouter(this.diffManger);
- this.diffManger.register("comic", createComicWatcher());
-
- console.log("setup router");
-
- let router = new Router();
- router.use("/api/(.*)", async (ctx, next) => {
- // For CORS
- ctx.res.setHeader("access-control-allow-origin", "*");
- await next();
- });
-
- router.use("/api/diff", diff_router.routes());
- router.use("/api/diff", diff_router.allowedMethods());
-
- const content_router = getContentRouter(this.documentController);
- router.use("/api/doc", content_router.routes());
- router.use("/api/doc", content_router.allowedMethods());
-
- const tags_router = getTagRounter(this.tagController);
- router.use("/api/tags", tags_router.allowedMethods());
- router.use("/api/tags", tags_router.routes());
-
- this.serve_with_meta_index(router);
- this.serve_index(router);
- this.serve_static_file(router);
-
- const login_router = createLoginRouter(this.userController);
- router.use("/user", login_router.routes());
- router.use("/user", login_router.allowedMethods());
-
- if (setting.mode == "development") {
- let mm_count = 0;
- app.use(async (ctx, next) => {
- console.log(`==========================${mm_count++}`);
- const ip = (ctx.get("X-Real-IP")) ?? ctx.ip;
- const fromClient = ctx.state["user"].username === "" ? ip : ctx.state["user"].username;
- console.log(`${fromClient} : ${ctx.method} ${ctx.url}`);
- await next();
- // console.log(`404`);
- });
- }
- app.use(router.routes());
- app.use(router.allowedMethods());
- console.log("setup done");
- }
- private serve_index(router: Router) {
- const serveindex = (url: string) => {
- router.get(url, (ctx) => {
- ctx.type = "html";
- ctx.body = this.index_html;
- const setting = get_setting();
- ctx.set("x-content-type-options", "no-sniff");
- if (setting.mode === "development") {
- ctx.set("cache-control", "no-cache");
- } else {
- ctx.set("cache-control", "public, max-age=3600");
- }
- });
- };
- serveindex("/");
- serveindex("/doc/:rest(.*)");
- serveindex("/search");
- serveindex("/login");
- serveindex("/profile");
- serveindex("/difference");
- serveindex("/setting");
- serveindex("/tags");
- }
- private serve_with_meta_index(router: Router) {
- const DocMiddleware = async (ctx: Koa.ParameterizedContext) => {
- const docId = Number.parseInt(ctx.params["id"]);
- const doc = await this.documentController.findById(docId, true);
- let meta;
- if (doc === undefined) {
- ctx.status = 404;
- meta = NotFoundContent();
- } else {
- ctx.status = 200;
- meta = createOgTagContent(
- doc.title,
- doc.tags.join(", "),
- `https://aeolian.prelude.duckdns.org/api/doc/${docId}/comic/thumbnail`,
- );
- }
- const html = makeMetaTagInjectedHTML(this.index_html, meta);
- serveHTML(ctx, html);
- };
- router.get("/doc/:id(\\d+)", DocMiddleware);
-
- function NotFoundContent() {
- return createOgTagContent("Not Found Doc", "Not Found", "");
- }
- function makeMetaTagInjectedHTML(html: string, tagContent: string) {
- return html.replace("", tagContent);
- }
- function serveHTML(ctx: Koa.Context, file: string) {
- ctx.type = "html";
- ctx.body = file;
- const setting = get_setting();
- ctx.set("x-content-type-options", "no-sniff");
- if (setting.mode === "development") {
- ctx.set("cache-control", "no-cache");
- } else {
- ctx.set("cache-control", "public, max-age=3600");
- }
- }
-
- function createMetaTagContent(key: string, value: string) {
- return ``;
- }
- function createOgTagContent(title: string, description: string, image: string) {
- return [
- createMetaTagContent("og:title", title),
- createMetaTagContent("og:type", "website"),
- createMetaTagContent("og:description", description),
- createMetaTagContent("og:image", image),
- // createMetaTagContent("og:image:width","480"),
- // createMetaTagContent("og:image","480"),
- // createMetaTagContent("og:image:type","image/png"),
- createMetaTagContent("twitter:card", "summary_large_image"),
- createMetaTagContent("twitter:title", title),
- createMetaTagContent("twitter:description", description),
- createMetaTagContent("twitter:image", image),
- ].join("\n");
- }
- }
- private serve_static_file(router: Router) {
- const static_file_server = (path: string, type: string) => {
- router.get("/" + path, async (ctx, next) => {
- const setting = get_setting();
- ctx.type = type;
- ctx.body = createReadStream(path);
- ctx.set("x-content-type-options", "no-sniff");
- if (setting.mode === "development") {
- ctx.set("cache-control", "no-cache");
- } else {
- ctx.set("cache-control", "public, max-age=3600");
- }
- });
- };
- const setting = get_setting();
- static_file_server("dist/bundle.css", "css");
- static_file_server("dist/bundle.js", "js");
- if (setting.mode === "development") {
- static_file_server("dist/bundle.js.map", "text");
- static_file_server("dist/bundle.css.map", "text");
- }
- }
- start_server() {
- let setting = get_setting();
- // todo : support https
- console.log(`listen on http://${setting.localmode ? "localhost" : "0.0.0.0"}:${setting.port}`);
- return this.app.listen(setting.port, setting.localmode ? "127.0.0.1" : "0.0.0.0");
- }
- static async createServer() {
- const setting = get_setting();
- let db = await connectDB();
-
- const app = new ServerApplication({
- userController: createKnexUserController(db),
- documentController: createKnexDocumentAccessor(db),
- tagController: createKnexTagController(db),
- });
- await app.setup();
- return app;
- }
-}
-
-export async function create_server() {
- return await ServerApplication.createServer();
-}
-
-export default { create_server };
diff --git a/src/types/db.d.ts b/src/types/db.d.ts
deleted file mode 100644
index 4e2fdda..0000000
--- a/src/types/db.d.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Knex } from "knex";
-
-declare module "knex" {
- interface Tables {
- tags: {
- name: string;
- description?: string;
- };
- users: {
- username: string;
- password_hash: string;
- password_salt: string;
- };
- document: {
- id: number;
- title: string;
- content_type: string;
- basepath: string;
- filename: string;
- created_at: number;
- deleted_at: number | null;
- content_hash: string;
- additional: string | null;
- };
- doc_tag_relation: {
- doc_id: number;
- tag_name: string;
- };
- permissions: {
- username: string;
- name: string;
- };
- }
-}
diff --git a/src/util/configRW.ts b/src/util/configRW.ts
deleted file mode 100644
index f0700f9..0000000
--- a/src/util/configRW.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { existsSync, promises as fs, readFileSync, writeFileSync } from "fs";
-import { validate } from "jsonschema";
-
-export class ConfigManager {
- path: string;
- default_config: T;
- config: T | null;
- schema: object;
- constructor(path: string, default_config: T, schema: object) {
- this.path = path;
- this.default_config = default_config;
- this.config = null;
- this.schema = schema;
- }
- get_config_file(): T {
- if (this.config !== null) return this.config;
- this.config = { ...this.read_config_file() };
- return this.config;
- }
- private emptyToDefault(target: T) {
- let occur = false;
- for (const key in this.default_config) {
- if (key === undefined || key in target) {
- continue;
- }
- target[key] = this.default_config[key];
- occur = true;
- }
- return occur;
- }
- read_config_file(): T {
- if (!existsSync(this.path)) {
- writeFileSync(this.path, JSON.stringify(this.default_config));
- return this.default_config;
- }
- const ret = JSON.parse(readFileSync(this.path, { encoding: "utf8" }));
- if (this.emptyToDefault(ret)) {
- writeFileSync(this.path, JSON.stringify(ret));
- }
- const result = validate(ret, this.schema);
- if (!result.valid) {
- throw new Error(result.toString());
- }
- return ret;
- }
- async write_config_file(new_config: T) {
- this.config = new_config;
- await fs.writeFile(`${this.path}.temp`, JSON.stringify(new_config));
- await fs.rename(`${this.path}.temp`, this.path);
- }
-}
diff --git a/src/util/type_check.ts b/src/util/type_check.ts
deleted file mode 100644
index c45a2b1..0000000
--- a/src/util/type_check.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export function check_type(obj: any, check_proto: Record): obj is T {
- for (const it in check_proto) {
- let defined = check_proto[it];
- if (defined === undefined) return false;
- defined = defined.trim();
- if (defined.endsWith("[]")) {
- if (!(obj[it] instanceof Array)) {
- return false;
- }
- } else if (defined !== typeof obj[it]) {
- return false;
- }
- }
- return true;
-}
diff --git a/src/util/zipwrap.ts b/src/util/zipwrap.ts
deleted file mode 100644
index 2de4529..0000000
--- a/src/util/zipwrap.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { ZipEntry } from "node-stream-zip";
-
-import { ReadStream } from "fs";
-import { orderBy } from "natural-orderby";
-import StreamZip from "node-stream-zip";
-
-export type ZipAsync = InstanceType;
-export async function readZip(path: string): Promise {
- return new StreamZip.async({
- file: path,
- storeEntries: true,
- });
-}
-export async function entriesByNaturalOrder(zip: ZipAsync) {
- const entries = await zip.entries();
- const ret = orderBy(Object.values(entries), v => v.name);
- return ret;
-}
-
-export async function createReadableStreamFromZip(zip: ZipAsync, entry: ZipEntry): Promise {
- return await zip.stream(entry);
-}
-export async function readAllFromZip(zip: ZipAsync, entry: ZipEntry): Promise {
- const stream = await createReadableStreamFromZip(zip, entry);
- const chunks: Uint8Array[] = [];
- return new Promise((resolve, reject) => {
- stream.on("data", (data) => {
- chunks.push(data);
- });
- stream.on("error", (err) => reject(err));
- stream.on("end", () => resolve(Buffer.concat(chunks)));
- });
-}