New: フロントエンドにL.jsを導入 / Fix: 初期設定前にserver-infoが利用できない問題 / Feat: manifest.json / Chg: isOwnerをisAdminに戻しました / Fix: UserRepositoryのschemaの記述順序を統一 / Feat: server-infoにサーバー名とサーバー説明を記載 / New: manifest.jsonをフロントエンドで読み込み / New: スクロールバーのスタイルを指定 / New: フォントを指定 / New: line-heightを指定 / New: tab-sizeを指定 / New: <label>のwidthをfit-contentとして指定 / New: CSS変数にアクセントカラーなどを追加 / New: <a>のcolorをaccent-colorとして指定 / Feat: ページのレイアウトを作成 / Feat: 各ページのヘッダーでタイトルを表示 / Feat: スマホUI / Feat: セットアップウィザードをフロントエンドに実装 / Feat: NotFoundページ / New: Button,Input,InputPassword,Toggle,Textareaコンポーネントを作成 / Feat: modal機能 / Chg: server-infoをrefに変更 / Fix: L.jsのsetup/initializationがsetup/initilizationになっていたtypoを修正
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
"@mikro-orm/postgresql": "^6.6.7",
|
"@mikro-orm/postgresql": "^6.6.7",
|
||||||
"@mikro-orm/reflection": "^6.6.7",
|
"@mikro-orm/reflection": "^6.6.7",
|
||||||
"@types/web-push": "^3.6.4",
|
"@types/web-push": "^3.6.4",
|
||||||
|
"lynqchat-js": "workspace:*",
|
||||||
"argon2": "^0.44.0",
|
"argon2": "^0.44.0",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"fastify": "^5.7.4",
|
"fastify": "^5.7.4",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import Authorization from "@/lib/auth";
|
|||||||
import { RequestContext } from "@mikro-orm/core";
|
import { RequestContext } from "@mikro-orm/core";
|
||||||
import { DatabaseError, ErrorBase } from "@/errors";
|
import { DatabaseError, ErrorBase } from "@/errors";
|
||||||
import { ConfigEntity } from "@/modules/entities/Config";
|
import { ConfigEntity } from "@/modules/entities/Config";
|
||||||
|
import type ApiMap from "lynqchat-js/1.0.0-alpha.0/map";
|
||||||
|
|
||||||
process.title = "LynqChat";
|
process.title = "LynqChat";
|
||||||
|
|
||||||
@@ -83,7 +84,8 @@ try {
|
|||||||
fastify.addHook("onRequest", async (req, res) => {
|
fastify.addHook("onRequest", async (req, res) => {
|
||||||
if (
|
if (
|
||||||
req.url.startsWith("/api") &&
|
req.url.startsWith("/api") &&
|
||||||
!req.url.startsWith("/api/setup")
|
!req.url.startsWith("/api/setup") &&
|
||||||
|
!req.url.startsWith("/api/server-info")
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const configCount = await fastify.orm.em.count(ConfigEntity);
|
const configCount = await fastify.orm.em.count(ConfigEntity);
|
||||||
@@ -123,6 +125,23 @@ try {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fastify.get("/manifest.json", async (req, res) => {
|
||||||
|
const serverInfo = await (await fastify.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: "/api/server-info",
|
||||||
|
})).json() as ApiMap["server-info"]["response"];
|
||||||
|
|
||||||
|
if (!serverInfo.success) {
|
||||||
|
return res.code(500).send(serverInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.send({
|
||||||
|
name: serverInfo.name ?? "LynqChat",
|
||||||
|
start_url: "/",
|
||||||
|
display: "standalone",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
await fastify.register(Routes, {
|
await fastify.register(Routes, {
|
||||||
prefix: "/api",
|
prefix: "/api",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export class UserEntity {
|
|||||||
type: "boolean",
|
type: "boolean",
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
isOwner: boolean = false;
|
isAdmin: boolean = false;
|
||||||
|
|
||||||
@Property({
|
@Property({
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export class UserRepository extends EntityRepository<UserEntity> {
|
|||||||
userid: z.string().trim().min(3).max(20),
|
userid: z.string().trim().min(3).max(20),
|
||||||
username: z.string().trim().min(3).max(30),
|
username: z.string().trim().min(3).max(30),
|
||||||
profile: z.string().max(4096).optional(),
|
profile: z.string().max(4096).optional(),
|
||||||
email: z.string().min(6).trim().max(254).regex(EmailRegex),
|
email: z.string().trim().min(6).max(254).regex(EmailRegex),
|
||||||
password: z.string().trim().min(8),
|
password: z.string().trim().min(8),
|
||||||
isAdmin: z.boolean(),
|
isAdmin: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,8 +14,13 @@ export default async function ServerInfo(fastify: FastifyInstance) {
|
|||||||
const configCount = await config.count();
|
const configCount = await config.count();
|
||||||
const userCount = await user.count();
|
const userCount = await user.count();
|
||||||
|
|
||||||
|
const serverName = await config.findOne({ name: "name" });
|
||||||
|
const serverDescription = await config.findOne({ name: "description" });
|
||||||
|
|
||||||
return res.send({
|
return res.send({
|
||||||
success: true,
|
success: true,
|
||||||
|
name: serverName?.value ?? null,
|
||||||
|
description: serverDescription?.value ?? null,
|
||||||
isInitialized: configCount > 0,
|
isInitialized: configCount > 0,
|
||||||
isFirstAdminExists: userCount > 0,
|
isFirstAdminExists: userCount > 0,
|
||||||
userCount,
|
userCount,
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>LynqChat</title>
|
<title>LynqChat</title>
|
||||||
<link rel="icon" href="/assets/lynqchat.svg" type="image/svg+xml">
|
<link rel="icon" href="/assets/lynqchat.svg" type="image/svg+xml" />
|
||||||
|
<link rel="manifest" href="/manifest.json" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -3,20 +3,23 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite dev --host",
|
||||||
"build": "vue-tsc -b && vite build",
|
"build": "vue-tsc -b && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dexie": "^4.3.0",
|
"@iconify/vue": "^5.0.0",
|
||||||
"vue": "^3.5.24",
|
"@unhead/vue": "3.0.0-beta.9",
|
||||||
"vue-router": "^5.0.2",
|
|
||||||
"lynqchat-js": "workspace:*",
|
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vue/tsconfig": "^0.8.1",
|
"@vue/tsconfig": "^0.8.1",
|
||||||
|
"dexie": "^4.3.0",
|
||||||
|
"lynqchat-js": "workspace:*",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"vite": "^8.0.0",
|
"vite": "^8.0.0",
|
||||||
"vue-tsc": "^3.1.4"
|
"vue": "^3.5.24",
|
||||||
|
"vue-router": "^5.0.2",
|
||||||
|
"vue-tsc": "^3.1.4",
|
||||||
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^24.10.1"
|
"@types/node": "^24.10.1"
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
:size="6"
|
:size="6"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div class="modals-container" />
|
||||||
|
|
||||||
<main class="layout">
|
<main class="layout">
|
||||||
<div class="left-menu">
|
<div class="left-menu">
|
||||||
<div>
|
<div>
|
||||||
@@ -12,10 +14,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="route-main">
|
<div class="content-main">
|
||||||
<RouterView
|
<div class="content-header">
|
||||||
:key="$route.fullPath"
|
{{
|
||||||
/>
|
$route.meta.title
|
||||||
|
?? (serverInfo.success
|
||||||
|
? serverInfo.name
|
||||||
|
: null)
|
||||||
|
?? "LynqChat"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="route-main">
|
||||||
|
<RouterView
|
||||||
|
:key="$route.fullPath"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
@@ -26,7 +40,7 @@ main.layout {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
width: 100dvw;
|
width: 100dvw;
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
padding: 1rem;
|
padding: 1.5rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +50,8 @@ main.layout {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-menu div {
|
.left-menu div {
|
||||||
@@ -44,26 +60,65 @@ main.layout {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
border-radius: 2rem;
|
border-radius: 2rem;
|
||||||
padding: 1rem;
|
padding: 1rem 1.5rem;
|
||||||
transition: all 100ms ease-in;
|
transition: background-color 250ms ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-menu div:hover {
|
.left-menu div:hover {
|
||||||
background-color: var(--border-color);
|
background-color: var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.route-main {
|
.content-main {
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
padding: 0.75rem;
|
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
overflow: hidden;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-header {
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom-left-radius: 1rem;
|
||||||
|
border-bottom-right-radius: 1rem;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
box-shadow: 0px 1px 10px var(--border-color);
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.route-main {
|
||||||
|
padding: 1.25rem;
|
||||||
|
padding-bottom: 0;
|
||||||
|
overflow: scroll;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.router-progress {
|
.router-progress {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0.5rem 0.5rem 0 auto;
|
inset: 0.5rem 0.5rem 0 auto;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modals-container {
|
||||||
|
z-index: 9998;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
.layout {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-menu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-main {
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -74,11 +129,15 @@ import serverInfo from "@/lib/account";
|
|||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
if (!serverInfo.success) {
|
if (!serverInfo.value.success) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serverInfo.isFirstAdminExists) {
|
if (!serverInfo.value.isInitialized) {
|
||||||
router.replace("/setup");
|
router.replace("/setup/initialization");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverInfo.value.isFirstAdminExists) {
|
||||||
|
router.replace("/setup/create-admin");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Icon
|
||||||
|
icon="line-md:question-circle"
|
||||||
|
width="8rem"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
name="ホームに戻る"
|
||||||
|
@click='$router.push("/")'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: fit-content;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Icon } from "@iconify/vue";
|
||||||
|
import Button from "@/components/Button.vue";
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
v-bind="$attrs"
|
||||||
|
:style="size"
|
||||||
|
:class='[
|
||||||
|
$attrs.class,
|
||||||
|
{ accent: color === "accent" },
|
||||||
|
]'
|
||||||
|
class="button"
|
||||||
|
>{{ name }}</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.button {
|
||||||
|
width: fit-content;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background-color: var(--bg-sub-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: var(--size);
|
||||||
|
border-radius: calc(var(--size) * 2);
|
||||||
|
padding: calc(var(--size) / 2.25) calc(var(--size) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.accent {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
color: var(--accent-in-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:disabled {
|
||||||
|
opacity: 50%;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
name: string;
|
||||||
|
color?: "default" | "accent";
|
||||||
|
size?: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const size = computed(() => ({
|
||||||
|
"--size": `${props.size ?? 1}rem`,
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<div class="input">
|
||||||
|
<label :for="id">{{ label }}</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="model"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:class="$attrs.class"
|
||||||
|
:id="id"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.input {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input input {
|
||||||
|
background-color: var(--bg-sub-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
outline: none;
|
||||||
|
padding: 0.6rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
transition: border 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input input:hover {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input input:focus {
|
||||||
|
border: 1px solid var(--accent-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useId } from "vue";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
label: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const model = defineModel<string>();
|
||||||
|
const id = useId();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<div class="input password">
|
||||||
|
<label :for="id">{{ label }}</label>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
v-model="model"
|
||||||
|
v-bind="$attrs"
|
||||||
|
autocomplete="new-password"
|
||||||
|
:class="$attrs.class"
|
||||||
|
:id="id"
|
||||||
|
:type='isVisible
|
||||||
|
? "text"
|
||||||
|
: "password"
|
||||||
|
'
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
v-show="isVisible"
|
||||||
|
icon="material-symbols:visibility"
|
||||||
|
width="1.25rem"
|
||||||
|
@click="changeVisible"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
v-show="!isVisible"
|
||||||
|
icon="material-symbols:visibility-off"
|
||||||
|
width="1.25rem"
|
||||||
|
@click="changeVisible"
|
||||||
|
/>
|
||||||
|
</input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.input.password {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.password label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.password div {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.password div input {
|
||||||
|
background-color: var(--bg-sub-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
outline: none;
|
||||||
|
padding: 0.6rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
transition: border 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.password div input:hover {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.password div input:focus {
|
||||||
|
border: 1px solid var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.password div svg {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
right: 1rem;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Icon } from "@iconify/vue";
|
||||||
|
import { ref, useId } from "vue";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
label: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const isVisible = ref<boolean>(false);
|
||||||
|
const model = defineModel<string>();
|
||||||
|
const id = useId();
|
||||||
|
|
||||||
|
const changeVisible = () => isVisible.value = !isVisible.value;
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div class="modal">
|
||||||
|
<Icon
|
||||||
|
icon="line-md:close-circle"
|
||||||
|
class="error-badge"
|
||||||
|
width="4rem"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span class="modal-title">問題が発生しました</span>
|
||||||
|
|
||||||
|
<p v-html="error" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
v-if="canClose"
|
||||||
|
name="閉じる"
|
||||||
|
color="accent"
|
||||||
|
@click='$emit("PleaseClose")'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-badge {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Icon } from "@iconify/vue";
|
||||||
|
import Button from "@/components/Button.vue";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
error: any;
|
||||||
|
canClose: boolean;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<div class="modal">
|
||||||
|
<Progress :size="16" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Progress from "@/components/Progress.vue";
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<div class="modal">
|
||||||
|
<Icon
|
||||||
|
icon="line-md:confirm-circle"
|
||||||
|
class="success-badge"
|
||||||
|
width="4rem"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
name="閉じる"
|
||||||
|
color="accent"
|
||||||
|
@click='$emit("PleaseClose")'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 4rem;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-badge {
|
||||||
|
color: var(--success-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Icon } from "@iconify/vue";
|
||||||
|
import Button from "@/components/Button.vue";
|
||||||
|
|
||||||
|
const emit = defineEmits();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
emit("PleaseClose");
|
||||||
|
}, 1000);
|
||||||
|
</script>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.progress {
|
.progress {
|
||||||
|
flex-shrink: 0;
|
||||||
border: v-bind(borderSize) solid #425C97;
|
border: v-bind(borderSize) solid #425C97;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
border-top: v-bind(borderSize) solid #ffffff;
|
border-top: v-bind(borderSize) solid #ffffff;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="textarea">
|
||||||
|
<label :for="id">{{ label }}</label>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
v-model="model"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:class="$attrs.class"
|
||||||
|
:id="id"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.textarea {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea textarea {
|
||||||
|
background-color: var(--bg-sub-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 1rem;
|
||||||
|
resize: vertical;
|
||||||
|
field-sizing: content;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
outline: none;
|
||||||
|
padding: 0.6rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
transition: border 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea textarea:hover {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea textarea:focus {
|
||||||
|
border: 1px solid var(--accent-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useId } from "vue";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
label: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const model = defineModel<string>();
|
||||||
|
const id = useId();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="toggle"
|
||||||
|
:class="{ isRow: isRow }"
|
||||||
|
:style="size"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p>{{ description }}</p>
|
||||||
|
|
||||||
|
<label :for="id">{{ label }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
v-model="model"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:class="$attrs.class"
|
||||||
|
:id="id"
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.toggle {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle.isRow {
|
||||||
|
width: fit-content;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
gap: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle.isRow div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle div label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
margin: auto 0;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle.isRow div label {
|
||||||
|
font-size: 1rem;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
--height: calc(var(--size) + var(--size) / 4 * 1.3 * 2);
|
||||||
|
height: var(--height);
|
||||||
|
line-height: var(--height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle input {
|
||||||
|
appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: var(--bg-sub-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
padding: calc(var(--size) / 4 * 1.3);
|
||||||
|
width: calc(var(--size) * 2);
|
||||||
|
height: calc(var(--size));
|
||||||
|
box-sizing: content-box;
|
||||||
|
outline: none;
|
||||||
|
border-radius: var(--size);
|
||||||
|
transition: border 200ms ease-out, background-color 100ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle input:checked {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle input::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
transition: transform 100ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle input:checked::after {
|
||||||
|
transform: translateX(var(--size));
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle div p {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle.isRow div p {
|
||||||
|
display: inherit;
|
||||||
|
color: var(--text-sub-color);
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, useId } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
label: string;
|
||||||
|
size?: number;
|
||||||
|
isRow?: boolean;
|
||||||
|
description?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const model = defineModel<boolean>();
|
||||||
|
|
||||||
|
const id = useId();
|
||||||
|
const size = computed(() => ({
|
||||||
|
"--size": `${props.size ?? 1}rem`,
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
@@ -1,13 +1,23 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=BIZ+UDPGothic&display=swap");
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--bg-color: #ffffff;
|
--bg-color: #ffffff;
|
||||||
|
--bg-sub-color: #f1f1f1;
|
||||||
--text-color: #000000;
|
--text-color: #000000;
|
||||||
|
--text-sub-color: #595959;
|
||||||
--border-color: #e0e0e0;
|
--border-color: #e0e0e0;
|
||||||
|
--error-color: #ff0000;
|
||||||
|
--success-color: #00ff00;
|
||||||
|
--accent-color: #3ad0a1;
|
||||||
|
--accent-in-text-color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root {
|
||||||
--bg-color: #1b1b1b;
|
--bg-color: #1b1b1b;
|
||||||
|
--bg-sub-color: #252525;
|
||||||
--text-color: #ffffff;
|
--text-color: #ffffff;
|
||||||
|
--text-sub-color: #a4a4a4;
|
||||||
--border-color: #2c2c2c;
|
--border-color: #2c2c2c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,12 +25,45 @@
|
|||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: var(--accent-color) var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
color: var(--accent-in-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
width: 100dvw;
|
width: 100dvw;
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
font-family: "BIZ UDPGothic", sans-serif;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
tab-size: 2;
|
||||||
background-color: var(--bg-color);
|
background-color: var(--bg-color);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
border-radius: 2rem;
|
||||||
|
padding: 3rem 6rem;
|
||||||
|
width: fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
max-width: 90dvw;
|
||||||
|
max-height: 90dvh;
|
||||||
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
import client from "@/lib/client";
|
import client from "@/lib/client";
|
||||||
|
import type ApiMap from "lynqchat-js/1.0.0-alpha.0/map";
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
const serverInfo = await client.request("server-info");
|
let serverInfo = ref<ApiMap["server-info"]["response"]>(await client.request("server-info"));
|
||||||
|
|
||||||
|
export const reloadServerInfo = async () => {
|
||||||
|
serverInfo.value = await client.request("server-info");
|
||||||
|
}
|
||||||
|
|
||||||
export default serverInfo;
|
export default serverInfo;
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { createApp, h, ref, type Component } from "vue";
|
||||||
|
|
||||||
|
const layer = ref<number>(0);
|
||||||
|
|
||||||
|
export const createModal = <T extends Component>(data: {
|
||||||
|
component: T,
|
||||||
|
style?: Record<string, string>,
|
||||||
|
props?: Record<string, ((...args: any[]) => any) | any>,
|
||||||
|
onClose?: () => void
|
||||||
|
}) => {
|
||||||
|
layer.value++
|
||||||
|
const newContainer = document.createElement("div");
|
||||||
|
for (const [key, value] of Object.entries({
|
||||||
|
...data.style,
|
||||||
|
transform: `translateZ(${layer.value})`,
|
||||||
|
position: "fixed",
|
||||||
|
inset: "0",
|
||||||
|
display: "flex",
|
||||||
|
"justify-content": "center",
|
||||||
|
"align-items": "center",
|
||||||
|
width: "100dvw",
|
||||||
|
height: "100dvh",
|
||||||
|
"background-color": "#00000080",
|
||||||
|
})) {
|
||||||
|
newContainer.style.setProperty(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = document.querySelector(".modals-container")!
|
||||||
|
.appendChild(newContainer);
|
||||||
|
|
||||||
|
let app: ReturnType<typeof createApp>;
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
data.onClose?.();
|
||||||
|
layer.value--;
|
||||||
|
app.unmount();
|
||||||
|
container.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
app = createApp({
|
||||||
|
render() {
|
||||||
|
return h(data.component, {
|
||||||
|
...data.props,
|
||||||
|
onPleaseClose: close,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
app.mount(container);
|
||||||
|
|
||||||
|
return close;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import type { SafeParseReturnType } from "zod/v3";
|
||||||
|
|
||||||
|
export const getIssueFromPath = (path: string, result: SafeParseReturnType<any, any>) => {
|
||||||
|
const filtered = result.error?.issues.filter(issue => issue.path.join(".") === path);
|
||||||
|
const issue = (filtered ?? [])[0];
|
||||||
|
|
||||||
|
return issue;
|
||||||
|
}
|
||||||
@@ -1,30 +1,69 @@
|
|||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
import { createRouter, createWebHistory } from "vue-router";
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
import routerStatus from "@/lib/router";
|
import routerStatus from "@/lib/router";
|
||||||
|
import { createHead } from "@unhead/vue/client";
|
||||||
|
import serverInfo from "@/lib/account";
|
||||||
|
|
||||||
import "@/global.css";
|
import "@/global.css";
|
||||||
import Layout from "@/Layout.vue";
|
import Layout from "@/Layout.vue";
|
||||||
|
|
||||||
const app = createApp(Layout);
|
const app = createApp(Layout);
|
||||||
|
|
||||||
|
app.use(createHead());
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
|
meta: {
|
||||||
|
title: "ホーム",
|
||||||
|
},
|
||||||
component: () => import("@/routes/index.vue"),
|
component: () => import("@/routes/index.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/setup",
|
path: "/setup",
|
||||||
component: () => import("@/routes/setup.vue"),
|
redirect: "/setup/initialization",
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
path: "/setup/initialization",
|
||||||
|
meta: {
|
||||||
|
title: "初期設定",
|
||||||
|
},
|
||||||
|
component: () => import("@/routes/setup/initialization.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/setup/create-admin",
|
||||||
|
meta: {
|
||||||
|
title: "管理者アカウントの作成",
|
||||||
|
},
|
||||||
|
component: () => import("@/routes/setup/create-admin.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/:NotFound(.*)*",
|
||||||
|
meta: {
|
||||||
|
title: "お探しのページは見つかりませんでした。",
|
||||||
|
},
|
||||||
|
component: () => import("@/NotFound.vue"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
router.beforeEach(() => {
|
router.beforeEach(() => {
|
||||||
routerStatus.isLoad = true;
|
routerStatus.isLoad = true;
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
router.afterEach(() => {
|
router.afterEach((to) => {
|
||||||
|
const title = to.meta.title;
|
||||||
|
|
||||||
|
let serverName = "LynqChat";
|
||||||
|
|
||||||
|
if (serverInfo.value.success && serverInfo.value.name) {
|
||||||
|
serverName = serverInfo.value.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.title = title
|
||||||
|
? `${title} | ${serverName}`
|
||||||
|
: serverName;
|
||||||
routerStatus.isLoad = false;
|
routerStatus.isLoad = false;
|
||||||
});
|
});
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
<template>
|
|
||||||
<h1>Welcome setup wizard!!</h1>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import serverInfo from "@/lib/account";
|
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
if (!serverInfo.success) {
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverInfo.isFirstAdminExists) {
|
|
||||||
router.replace("/");
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
<template>
|
||||||
|
<div class="welcome">
|
||||||
|
<p><!--
|
||||||
|
-->ここでは、LynqChatの管理者アカウントの作成を行います。<!--
|
||||||
|
-->管理者アカウントはサーバーに1つだけです。<!--
|
||||||
|
-->今後、特権ユーザーを増やしたい場合は、柔軟に権限を設定できます。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form novalidate @submit="submit">
|
||||||
|
<Input
|
||||||
|
label="ユーザーID"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="userid"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="input-issue"
|
||||||
|
v-if="useridIssue"
|
||||||
|
>
|
||||||
|
<Icon icon="material-symbols:error-outline-rounded" />
|
||||||
|
{{ useridIssue.message }}
|
||||||
|
</span>
|
||||||
|
</Input>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="メールアドレス"
|
||||||
|
type="email"
|
||||||
|
autocomplete="email"
|
||||||
|
v-model="email"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="input-issue"
|
||||||
|
v-if="emailIssue"
|
||||||
|
>
|
||||||
|
<Icon icon="material-symbols:error-outline-rounded" />
|
||||||
|
{{ emailIssue.message }}
|
||||||
|
</span>
|
||||||
|
</Input>
|
||||||
|
|
||||||
|
<InputPassword
|
||||||
|
label="パスワード"
|
||||||
|
v-model="password"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="input-issue"
|
||||||
|
v-if="passwordIssue"
|
||||||
|
>
|
||||||
|
<Icon icon="material-symbols:error-outline-rounded" />
|
||||||
|
{{ passwordIssue.message }}
|
||||||
|
</span>
|
||||||
|
</InputPassword>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
name="管理者アカウントを作成"
|
||||||
|
type="submit"
|
||||||
|
color="accent"
|
||||||
|
:disabled="!result.success || isProcessing"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.welcome {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-issue {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--error-color);
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-issue svg {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin: auto 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import serverInfo, { reloadServerInfo } from "@/lib/account";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import Input from "@/components/Input.vue";
|
||||||
|
import Button from "@/components/Button.vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import z from "zod/v3";
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { createModal } from "@/lib/modal";
|
||||||
|
import Loading from "@/components/Modal/Loading.vue";
|
||||||
|
import Error from "@/components/Modal/Error.vue";
|
||||||
|
import Success from "@/components/Modal/Success.vue";
|
||||||
|
import InputPassword from "@/components/InputPassword.vue";
|
||||||
|
import client from "@/lib/client";
|
||||||
|
import { getIssueFromPath } from "@/lib/validation";
|
||||||
|
import { Icon } from "@iconify/vue";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const isProcessing = ref<boolean>(false);
|
||||||
|
|
||||||
|
if (!serverInfo.value.success) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverInfo.value.isFirstAdminExists) {
|
||||||
|
router.replace("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverInfo.value.isInitialized) {
|
||||||
|
router.replace("/setup/initialization");
|
||||||
|
}
|
||||||
|
|
||||||
|
const userid = ref<string>("");
|
||||||
|
const email = ref<string>("");
|
||||||
|
const password = ref<string>("");
|
||||||
|
const useridIssue = computed(() => getIssueFromPath("userid", result.value));
|
||||||
|
const emailIssue = computed(() => getIssueFromPath("email", result.value));
|
||||||
|
const passwordIssue = computed(() => getIssueFromPath("password", result.value));
|
||||||
|
|
||||||
|
const EmailRegex = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:([0-9]{1,3}\.){3}[0-9]{1,3})\])$/i;
|
||||||
|
const schema = z.object({
|
||||||
|
userid: z.string({ message: "文字列で入力してください。" })
|
||||||
|
.trim().min(3, "3文字以上で入力してください。")
|
||||||
|
.max(20, "20文字以内で入力してください。"),
|
||||||
|
email: z.string({ message: "文字列で入力してください。" })
|
||||||
|
.trim().min(6, "6文字以上で入力してください。")
|
||||||
|
.max(254, "254文字以内で入力してください。")
|
||||||
|
.regex(EmailRegex, "形式が異なります。"),
|
||||||
|
password: z.string({ message: "文字列で入力してください。" })
|
||||||
|
.trim().min(8, "8文字以上で入力してください。"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = computed(() => schema.safeParse({
|
||||||
|
userid: userid.value,
|
||||||
|
email: email.value,
|
||||||
|
password: password.value,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const submit = async (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
isProcessing.value = true;
|
||||||
|
|
||||||
|
const closeLoadingModal = createModal({
|
||||||
|
component: Loading,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.value.success) {
|
||||||
|
const messages = result.value.error.issues.map(issue => issue.message);
|
||||||
|
|
||||||
|
closeLoadingModal();
|
||||||
|
|
||||||
|
return createModal({
|
||||||
|
component: Error,
|
||||||
|
onClose: () => isProcessing.value = false,
|
||||||
|
props: {
|
||||||
|
error: `不正な入力です。<br>${messages.join("<br>")}`,
|
||||||
|
canClose: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await client.request("setup/create-admin", result.value.data);
|
||||||
|
|
||||||
|
if (!response.success) {
|
||||||
|
closeLoadingModal();
|
||||||
|
|
||||||
|
return createModal({
|
||||||
|
component: Error,
|
||||||
|
onClose: () => isProcessing.value = false,
|
||||||
|
props: {
|
||||||
|
error: response.error.message,
|
||||||
|
canClose: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeLoadingModal();
|
||||||
|
|
||||||
|
return createModal({
|
||||||
|
component: Success,
|
||||||
|
onClose: async () => {
|
||||||
|
isProcessing.value = false;
|
||||||
|
await reloadServerInfo();
|
||||||
|
router.push("/");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
<template>
|
||||||
|
<div class="welcome">
|
||||||
|
<span class="title">LynqChatへようこそ</span>
|
||||||
|
|
||||||
|
<p><!--
|
||||||
|
-->ここでは、LynqChatの初期設定を行います。<!--
|
||||||
|
-->このページにアクセスできているということは、起動に必要な処理の過程に問題はありません。<!--
|
||||||
|
-->LynqChatで技術的な問題がありましたら、<!--
|
||||||
|
--><a href="https://gitea.last2014.com/last2014/lynq-chat/issues">Issue</a><!--
|
||||||
|
-->にて報告してください。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form novalidate @submit="submit">
|
||||||
|
<Input
|
||||||
|
label="サーバー名"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="name"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="input-issue"
|
||||||
|
v-if="nameIssue"
|
||||||
|
>
|
||||||
|
<Icon icon="material-symbols:error-outline-rounded" />
|
||||||
|
{{ nameIssue.message }}
|
||||||
|
</span>
|
||||||
|
</Input>
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
label="サーバー説明"
|
||||||
|
autocomplete="on"
|
||||||
|
v-model="description"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="input-issue"
|
||||||
|
v-if="descriptionIssue"
|
||||||
|
>
|
||||||
|
<Icon icon="material-symbols:error-outline-rounded" />
|
||||||
|
{{ descriptionIssue.message }}
|
||||||
|
</span>
|
||||||
|
</Textarea>
|
||||||
|
|
||||||
|
<Toggle
|
||||||
|
label="サインアップに招待コードを必須とする"
|
||||||
|
description="オンにすることで、サインアップに招待コードの入力が必須となります。招待コードは、初期設定後にいつでも作成・削除ができます。"
|
||||||
|
:isRow="true"
|
||||||
|
:size="1"
|
||||||
|
v-model="requiredInvitationCode"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
name="スタート"
|
||||||
|
type="submit"
|
||||||
|
color="accent"
|
||||||
|
:disabled="!result.success || isProcessing"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.welcome {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-issue {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--error-color);
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-issue svg {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin: auto 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import serverInfo, { reloadServerInfo } from "@/lib/account";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import Input from "@/components/Input.vue";
|
||||||
|
import Toggle from "@/components/Toggle.vue";
|
||||||
|
import Button from "@/components/Button.vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import z from "zod/v3";
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { createModal } from "@/lib/modal";
|
||||||
|
import Loading from "@/components/Modal/Loading.vue";
|
||||||
|
import Error from "@/components/Modal/Error.vue";
|
||||||
|
import Success from "@/components/Modal/Success.vue";
|
||||||
|
import client from "@/lib/client";
|
||||||
|
import { getIssueFromPath } from "@/lib/validation";
|
||||||
|
import { Icon } from "@iconify/vue";
|
||||||
|
import Textarea from "@/components/Textarea.vue";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const isProcessing = ref<boolean>(false);
|
||||||
|
|
||||||
|
if (!serverInfo.value.success) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverInfo.value.isInitialized) {
|
||||||
|
if (serverInfo.value.isFirstAdminExists) {
|
||||||
|
router.replace("/");
|
||||||
|
} else {
|
||||||
|
router.replace("/setup/create-admin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = ref<string>("");
|
||||||
|
const description = ref<string>("");
|
||||||
|
const requiredInvitationCode = ref<boolean>(false);
|
||||||
|
const nameIssue = computed(() => getIssueFromPath("name", result.value));
|
||||||
|
const descriptionIssue = computed(() => getIssueFromPath("description", result.value));
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
name: z.string({ message: "文字列で入力してください。" })
|
||||||
|
.trim().min(1, "この項目は必須です。")
|
||||||
|
.max(20, "20文字以内で入力してください。"),
|
||||||
|
description: z.string({ message: "文字列で入力してください。" })
|
||||||
|
.trim().min(1, "この項目は必須です。"),
|
||||||
|
requiredInvitationCode: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = computed(() => schema.safeParse({
|
||||||
|
name: name.value,
|
||||||
|
description: description.value,
|
||||||
|
requiredInvitationCode: requiredInvitationCode.value,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const submit = async (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
isProcessing.value = true;
|
||||||
|
|
||||||
|
const closeLoadingModal = createModal({
|
||||||
|
component: Loading,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.value.success) {
|
||||||
|
const messages = result.value.error.issues.map(issue => issue.message);
|
||||||
|
|
||||||
|
closeLoadingModal();
|
||||||
|
|
||||||
|
return createModal({
|
||||||
|
component: Error,
|
||||||
|
onClose: () => isProcessing.value = false,
|
||||||
|
props: {
|
||||||
|
error: `不正な入力です。<br>${messages.join("<br>")}`,
|
||||||
|
canClose: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await client.request("setup/initialization", result.value.data);
|
||||||
|
|
||||||
|
if (!response.success) {
|
||||||
|
closeLoadingModal();
|
||||||
|
|
||||||
|
return createModal({
|
||||||
|
component: Error,
|
||||||
|
onClose: () => isProcessing.value = false,
|
||||||
|
props: {
|
||||||
|
error: response.error.message,
|
||||||
|
canClose: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeLoadingModal();
|
||||||
|
|
||||||
|
return createModal({
|
||||||
|
component: Success,
|
||||||
|
onClose: async () => {
|
||||||
|
isProcessing.value = false;
|
||||||
|
await reloadServerInfo();
|
||||||
|
router.push("/setup/create-admin");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -18,6 +18,10 @@ export default defineConfig(({ mode }) => {
|
|||||||
target: `http://localhost:${apiPort}`,
|
target: `http://localhost:${apiPort}`,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
|
"/manifest.json": {
|
||||||
|
target: `http://localhost:${apiPort}`,
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export default interface ServerInfo {
|
|||||||
"server-info": {
|
"server-info": {
|
||||||
body: never;
|
body: never;
|
||||||
response: (Success & {
|
response: (Success & {
|
||||||
|
name: string | null;
|
||||||
|
description: string | null;
|
||||||
isInitialized: boolean;
|
isInitialized: boolean;
|
||||||
isFirstAdminExists: boolean;
|
isFirstAdminExists: boolean;
|
||||||
userCount: number;
|
userCount: number;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Success from "../../modules/response/success";
|
|||||||
import UnknownError from "../../modules/error/unknown";
|
import UnknownError from "../../modules/error/unknown";
|
||||||
|
|
||||||
export default interface SetupInitialization {
|
export default interface SetupInitialization {
|
||||||
"setup/initilization": {
|
"setup/initialization": {
|
||||||
body: {
|
body: {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
|||||||
Generated
+347
@@ -43,6 +43,9 @@ importers:
|
|||||||
fs:
|
fs:
|
||||||
specifier: 0.0.1-security
|
specifier: 0.0.1-security
|
||||||
version: 0.0.1-security
|
version: 0.0.1-security
|
||||||
|
lynqchat-js:
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../lynqchat-js
|
||||||
os: {specifier: ^0.1.2, version: 0.1.2}
|
os: {specifier: ^0.1.2, version: 0.1.2}
|
||||||
tsc-alias:
|
tsc-alias:
|
||||||
specifier: ^1.8.16
|
specifier: ^1.8.16
|
||||||
@@ -75,6 +78,12 @@ importers:
|
|||||||
|
|
||||||
packages/frontend:
|
packages/frontend:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@iconify/vue':
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.0(vue@3.5.30(typescript@5.9.3))
|
||||||
|
'@unhead/vue':
|
||||||
|
specifier: 3.0.0-beta.9
|
||||||
|
version: 3.0.0-beta.9(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.0.4(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))
|
version: 6.0.4(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))
|
||||||
@@ -102,6 +111,9 @@ importers:
|
|||||||
vue-tsc:
|
vue-tsc:
|
||||||
specifier: ^3.1.4
|
specifier: ^3.1.4
|
||||||
version: 3.2.5(typescript@5.9.3)
|
version: 3.2.5(typescript@5.9.3)
|
||||||
|
zod:
|
||||||
|
specifier: ^4.3.6
|
||||||
|
version: 4.3.6
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^24.10.1
|
specifier: ^24.10.1
|
||||||
@@ -337,6 +349,14 @@ packages:
|
|||||||
'@fastify/static@9.0.0':
|
'@fastify/static@9.0.0':
|
||||||
resolution: {integrity: sha512-r64H8Woe/vfilg5RTy7lwWlE8ZZcTrc3kebYFMEUBrMqlydhQyoiExQXdYAy2REVpST/G35+stAM8WYp1WGmMA==}
|
resolution: {integrity: sha512-r64H8Woe/vfilg5RTy7lwWlE8ZZcTrc3kebYFMEUBrMqlydhQyoiExQXdYAy2REVpST/G35+stAM8WYp1WGmMA==}
|
||||||
|
|
||||||
|
'@iconify/types@2.0.0':
|
||||||
|
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||||
|
|
||||||
|
'@iconify/vue@5.0.0':
|
||||||
|
resolution: {integrity: sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: '>=3'
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.13':
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||||
|
|
||||||
@@ -410,10 +430,140 @@ packages:
|
|||||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
'@oxc-parser/binding-android-arm-eabi@0.106.0':
|
||||||
|
resolution: {integrity: sha512-uoo8Bbc0/UrsQHlpdelqz8+jQ5hQqJs6MKjeiGqSU0E5Dkben2PuxXjg2jmabT+TzclysNEyE7eKHGTA7uVVqQ==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-android-arm64@0.106.0':
|
||||||
|
resolution: {integrity: sha512-7+hnrpce0uX96Hu8seWMJXqDnBTtSikibn1xa1yCa/musU1XZOLznhdWKA1usaPnwLBXP+7+h6nrdvKZ4HoT5Q==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-darwin-arm64@0.106.0':
|
||||||
|
resolution: {integrity: sha512-J7d6j8PwicRXTL4I00eWhqupuq0Pei9EafTzoB7ccluNo5fXNspkIH1NtGpgxPsLyUkZy5Nb5J3Y80TpdX6yQA==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-darwin-x64@0.106.0':
|
||||||
|
resolution: {integrity: sha512-5LhQlSACZPeyxbcE8WNMW1s88ExWGRnk0LQbQ3Co3gYkmgw12x2q6RnPT0N9BC6490VnWsynFafwCMPSrMnjfg==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-freebsd-x64@0.106.0':
|
||||||
|
resolution: {integrity: sha512-IInBOOMzB54rV/s8K5Feu6krWNHMR/V52prXy+9B0GhjOSQ2Q7EAd8y1gXWgjKB0NMDychCLgdaInanUn45eyQ==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm-gnueabihf@0.106.0':
|
||||||
|
resolution: {integrity: sha512-p0IQvugmAsA2288b30FP5ncbcp6juBQrsZNZD6SDiWRY3X3g5OH5puVtihE5KMNkeHmmd3S8MEHFCv0G1tYGPA==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm-musleabihf@0.106.0':
|
||||||
|
resolution: {integrity: sha512-VgJPJVygSyFEfFtv6hscx9AbnewsxDUCxWmgrB/GHktoMlDQSDBh9aG1lENiiJnB2FLR8WG15446X3Mw2I4Zog==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm64-gnu@0.106.0':
|
||||||
|
resolution: {integrity: sha512-Gqs6q/pwlpgzx5qE2RtlTnY7hJuS1a5PYBT3unpSAMUE0LrbV7kQ8thmQo1ngI1tnCImWpuuXjZ2YbI0iKquXw==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm64-musl@0.106.0':
|
||||||
|
resolution: {integrity: sha512-Bvtp8SK4MyahReapEPodracfBV9ed7+5WCHyjhSWoljrapJIU4OOLSsRyZ9zV2KhkjuD66DZq/qQv6pC73zzWQ==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-ppc64-gnu@0.106.0':
|
||||||
|
resolution: {integrity: sha512-DIXyavnpbBo+F/4G04LZ4xuuGXDY4m9qHB/HWtVj9z+Frb/r+SPAuptqAZFtJ9avcwbAOe3LO+K8BWHmK6+lnw==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-riscv64-gnu@0.106.0':
|
||||||
|
resolution: {integrity: sha512-VdqTcLTET72nPcJkSz3xrpcxab7q2/z04d6y+Th1mUTyXs2b/9VC3BcDmaFAfmhz8GX/5FVuzUTQzda1mTsh/g==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-riscv64-musl@0.106.0':
|
||||||
|
resolution: {integrity: sha512-FgHBGg9DHQ0dePOWQ9rNN+DHueJa1XWHc9u0VJCVY+XXAx3iT2ASj21xZ1wA+Rh92CyuuZ7RpQ6Y+O57fieNlg==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-s390x-gnu@0.106.0':
|
||||||
|
resolution: {integrity: sha512-fEIx2bUggt+s1eTaRVzhy5VgdrO1B8tUKxOPpGwwdF9VSP0KnLPaAv/gA4trJPxuIjjJRRVoK42v9R4O1jkbLg==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-x64-gnu@0.106.0':
|
||||||
|
resolution: {integrity: sha512-DbDQkdK8ZuS/jnRx8UbESQ5ypCJpD7VpERB/RWZfSdA2+B4TbonDwNWbTU+q2VJTbh5Xq1X65eQyz4/MIfiFSQ==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-x64-musl@0.106.0':
|
||||||
|
resolution: {integrity: sha512-D0PbaLv1MyNFDmjY4UqLQFlC+0GPCvrzI/8VlAvG7ztAZx0KdFYT3pPGsHjKshUJW9+e42JK29abLd0bZ4I95w==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-openharmony-arm64@0.106.0':
|
||||||
|
resolution: {integrity: sha512-uXSzts/ghlqmWm1cQTctyxdAnvha5dzVW5JkEB30J4M47yj2FcCtzUGdZO/sgXxggD/QM7EANlB66cOyk/NsoA==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-wasm32-wasi@0.106.0':
|
||||||
|
resolution: {integrity: sha512-oU8wkw9U1vhkICQIJLX8uy1lCPJqXf7aAidaqT2wJOce4a9XmGr2YNseEKbmVV/1TQaSHpHZNsDXglYicb4qKQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [wasm32]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-win32-arm64-msvc@0.106.0':
|
||||||
|
resolution: {integrity: sha512-zYRSn6MNlL8qcUIPRQWDu1JdgVqZa5iR4Drld8FBue3fHQGL0XrNQEd8qoWmuNo7FI0WiBRRuVgtkPaNoSsYmg==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-win32-ia32-msvc@0.106.0':
|
||||||
|
resolution: {integrity: sha512-FRHVO84i5WgQDk0XI4oRt2qDhRUXyot2EGBSogp34LoE5hsondyuZ244+Fod9czgscmgSb6Aon8PaEhHQ0lJYg==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@oxc-parser/binding-win32-x64-msvc@0.106.0':
|
||||||
|
resolution: {integrity: sha512-ydMjY15RdfRZZa7RrP+jjeudbDFDqKo5CGDTxvYBJ4jpROvVo0ThqN85vvNfVJ55gEUSjodCqvmA30qNTBZd/A==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@oxc-project/runtime@0.115.0':
|
'@oxc-project/runtime@0.115.0':
|
||||||
resolution: {integrity: sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==}
|
resolution: {integrity: sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
|
||||||
|
'@oxc-project/types@0.106.0':
|
||||||
|
resolution: {integrity: sha512-QdsH3rZq480VnOHSHgPYOhjL8O8LBdcnSjM408BpPCCUc0JYYZPG9Gafl9i3OcGk/7137o+gweb4cCv3WAUykg==}
|
||||||
|
|
||||||
'@oxc-project/types@0.115.0':
|
'@oxc-project/types@0.115.0':
|
||||||
resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==}
|
resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==}
|
||||||
|
|
||||||
@@ -553,6 +703,9 @@ packages:
|
|||||||
'@types/argparse@1.0.38':
|
'@types/argparse@1.0.38':
|
||||||
resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
|
resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
|
||||||
|
|
||||||
|
'@types/estree@1.0.8':
|
||||||
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
'@types/node@24.1.0':
|
'@types/node@24.1.0':
|
||||||
resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==}
|
resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==}
|
||||||
|
|
||||||
@@ -562,6 +715,15 @@ packages:
|
|||||||
'@types/web-push@3.6.4':
|
'@types/web-push@3.6.4':
|
||||||
resolution: {integrity: sha512-GnJmSr40H3RAnj0s34FNTcJi1hmWFV5KXugE0mYWnYhgTAHLJ/dJKAwDmvPJYMke0RplY2XE9LnM4hqSqKIjhQ==}
|
resolution: {integrity: sha512-GnJmSr40H3RAnj0s34FNTcJi1hmWFV5KXugE0mYWnYhgTAHLJ/dJKAwDmvPJYMke0RplY2XE9LnM4hqSqKIjhQ==}
|
||||||
|
|
||||||
|
'@unhead/vue@3.0.0-beta.9':
|
||||||
|
resolution: {integrity: sha512-X66jeffzB+IH3cXBPLhbBAFCsTuTVYD0+0N5aelNw5MbE9CpNnLJCIcwUyqh/UdEwaBMehRNPlGY+fiRrapRqQ==}
|
||||||
|
peerDependencies:
|
||||||
|
vite: '>=6'
|
||||||
|
vue: '>=3.5.18'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
vite:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.4':
|
'@vitejs/plugin-vue@6.0.4':
|
||||||
resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==}
|
resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@@ -925,6 +1087,9 @@ packages:
|
|||||||
estree-walker@2.0.2:
|
estree-walker@2.0.2:
|
||||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
|
estree-walker@3.0.3:
|
||||||
|
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
|
||||||
|
|
||||||
exsolve@1.0.8:
|
exsolve@1.0.8:
|
||||||
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
||||||
|
|
||||||
@@ -1066,6 +1231,9 @@ packages:
|
|||||||
hookable@5.5.3:
|
hookable@5.5.3:
|
||||||
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
|
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
|
||||||
|
|
||||||
|
hookable@6.1.0:
|
||||||
|
resolution: {integrity: sha512-ZoKZSJgu8voGK2geJS+6YtYjvIzu9AOM/KZXsBxr83uhLL++e9pEv/dlgwgy3dvHg06kTz6JOh1hk3C8Ceiymw==}
|
||||||
|
|
||||||
http-errors@2.0.1:
|
http-errors@2.0.1:
|
||||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@@ -1302,6 +1470,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
magic-regexp@0.10.0:
|
||||||
|
resolution: {integrity: sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==}
|
||||||
|
|
||||||
magic-string-ast@1.0.3:
|
magic-string-ast@1.0.3:
|
||||||
resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==}
|
resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==}
|
||||||
engines: {node: '>=20.19.0'}
|
engines: {node: '>=20.19.0'}
|
||||||
@@ -1395,6 +1566,15 @@ packages:
|
|||||||
os@0.1.2:
|
os@0.1.2:
|
||||||
resolution: {integrity: sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==}
|
resolution: {integrity: sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==}
|
||||||
|
|
||||||
|
oxc-parser@0.106.0:
|
||||||
|
resolution: {integrity: sha512-KSqA8PNgqi+wadUoGJXWyTr0mLuMzEABXQK5hKlj+cEWID+Rhw8xiqLappTDaCUpOqnKCpyO9N5RlzlFxR+TBw==}
|
||||||
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
|
|
||||||
|
oxc-walker@0.7.0:
|
||||||
|
resolution: {integrity: sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A==}
|
||||||
|
peerDependencies:
|
||||||
|
oxc-parser: '>=0.98.0'
|
||||||
|
|
||||||
path-browserify@1.0.1:
|
path-browserify@1.0.1:
|
||||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||||
|
|
||||||
@@ -1582,6 +1762,10 @@ packages:
|
|||||||
reflect-metadata@0.2.2:
|
reflect-metadata@0.2.2:
|
||||||
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
|
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
|
||||||
|
|
||||||
|
regexp-tree@0.1.27:
|
||||||
|
resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
require-directory@2.1.1:
|
require-directory@2.1.1:
|
||||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -1775,6 +1959,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
|
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
|
type-level-regexp@0.1.17:
|
||||||
|
resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==}
|
||||||
|
|
||||||
typescript@5.9.3:
|
typescript@5.9.3:
|
||||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
@@ -1793,6 +1980,14 @@ packages:
|
|||||||
undici-types@7.8.0:
|
undici-types@7.8.0:
|
||||||
resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
|
resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==}
|
||||||
|
|
||||||
|
unhead@3.0.0-beta.9:
|
||||||
|
resolution: {integrity: sha512-1GVW+FnpPk3/kdrkqELkhu7XgD6brEezJAESLfy05Y581T1CdpMklcBkKMm7Q5vY1nivrLEVos6C7j9lKEM9oQ==}
|
||||||
|
peerDependencies:
|
||||||
|
vite: '>=6'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
vite:
|
||||||
|
optional: true
|
||||||
|
|
||||||
universalify@2.0.1:
|
universalify@2.0.1:
|
||||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
@@ -1801,6 +1996,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==}
|
resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==}
|
||||||
engines: {node: '>=20.19.0'}
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
|
unplugin@2.3.11:
|
||||||
|
resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==}
|
||||||
|
engines: {node: '>=18.12.0'}
|
||||||
|
|
||||||
unplugin@3.0.0:
|
unplugin@3.0.0:
|
||||||
resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==}
|
resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@@ -2109,6 +2308,13 @@ snapshots:
|
|||||||
fastq: 1.20.1
|
fastq: 1.20.1
|
||||||
glob: 13.0.6
|
glob: 13.0.6
|
||||||
|
|
||||||
|
'@iconify/types@2.0.0': {}
|
||||||
|
|
||||||
|
'@iconify/vue@5.0.0(vue@3.5.30(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
'@iconify/types': 2.0.0
|
||||||
|
vue: 3.5.30(typescript@5.9.3)
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.13':
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
@@ -2218,8 +2424,72 @@ snapshots:
|
|||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.20.1
|
fastq: 1.20.1
|
||||||
|
|
||||||
|
'@oxc-parser/binding-android-arm-eabi@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-android-arm64@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-darwin-arm64@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-darwin-x64@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-freebsd-x64@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm-gnueabihf@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm-musleabihf@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm64-gnu@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-arm64-musl@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-ppc64-gnu@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-riscv64-gnu@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-riscv64-musl@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-s390x-gnu@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-x64-gnu@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-linux-x64-musl@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-openharmony-arm64@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-wasm32-wasi@0.106.0':
|
||||||
|
dependencies:
|
||||||
|
'@napi-rs/wasm-runtime': 1.1.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-win32-arm64-msvc@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-win32-ia32-msvc@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@oxc-parser/binding-win32-x64-msvc@0.106.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@oxc-project/runtime@0.115.0': {}
|
'@oxc-project/runtime@0.115.0': {}
|
||||||
|
|
||||||
|
'@oxc-project/types@0.106.0': {}
|
||||||
|
|
||||||
'@oxc-project/types@0.115.0': {}
|
'@oxc-project/types@0.115.0': {}
|
||||||
|
|
||||||
'@phc/format@1.0.0': {}
|
'@phc/format@1.0.0': {}
|
||||||
@@ -2319,6 +2589,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/argparse@1.0.38': {}
|
'@types/argparse@1.0.38': {}
|
||||||
|
|
||||||
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
'@types/node@24.1.0':
|
'@types/node@24.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.8.0
|
undici-types: 7.8.0
|
||||||
@@ -2331,6 +2603,17 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.12.0
|
'@types/node': 24.12.0
|
||||||
|
|
||||||
|
'@unhead/vue@3.0.0-beta.9(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
hookable: 6.1.0
|
||||||
|
magic-string: 0.30.21
|
||||||
|
oxc-parser: 0.106.0
|
||||||
|
oxc-walker: 0.7.0(oxc-parser@0.106.0)
|
||||||
|
unhead: 3.0.0-beta.9(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2))
|
||||||
|
vue: 3.5.30(typescript@5.9.3)
|
||||||
|
optionalDependencies:
|
||||||
|
vite: 8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2)
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.4(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))':
|
'@vitejs/plugin-vue@6.0.4(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.30(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rolldown/pluginutils': 1.0.0-rc.2
|
'@rolldown/pluginutils': 1.0.0-rc.2
|
||||||
@@ -2729,6 +3012,10 @@ snapshots:
|
|||||||
|
|
||||||
estree-walker@2.0.2: {}
|
estree-walker@2.0.2: {}
|
||||||
|
|
||||||
|
estree-walker@3.0.3:
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
|
||||||
exsolve@1.0.8: {}
|
exsolve@1.0.8: {}
|
||||||
|
|
||||||
fast-decode-uri-component@1.0.1: {}
|
fast-decode-uri-component@1.0.1: {}
|
||||||
@@ -2895,6 +3182,8 @@ snapshots:
|
|||||||
|
|
||||||
hookable@5.5.3: {}
|
hookable@5.5.3: {}
|
||||||
|
|
||||||
|
hookable@6.1.0: {}
|
||||||
|
|
||||||
http-errors@2.0.1:
|
http-errors@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
@@ -3096,6 +3385,16 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
|
|
||||||
|
magic-regexp@0.10.0:
|
||||||
|
dependencies:
|
||||||
|
estree-walker: 3.0.3
|
||||||
|
magic-string: 0.30.21
|
||||||
|
mlly: 1.8.1
|
||||||
|
regexp-tree: 0.1.27
|
||||||
|
type-level-regexp: 0.1.17
|
||||||
|
ufo: 1.6.3
|
||||||
|
unplugin: 2.3.11
|
||||||
|
|
||||||
magic-string-ast@1.0.3:
|
magic-string-ast@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
@@ -3167,6 +3466,36 @@ snapshots:
|
|||||||
|
|
||||||
os@0.1.2: {}
|
os@0.1.2: {}
|
||||||
|
|
||||||
|
oxc-parser@0.106.0:
|
||||||
|
dependencies:
|
||||||
|
'@oxc-project/types': 0.106.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@oxc-parser/binding-android-arm-eabi': 0.106.0
|
||||||
|
'@oxc-parser/binding-android-arm64': 0.106.0
|
||||||
|
'@oxc-parser/binding-darwin-arm64': 0.106.0
|
||||||
|
'@oxc-parser/binding-darwin-x64': 0.106.0
|
||||||
|
'@oxc-parser/binding-freebsd-x64': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-arm-gnueabihf': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-arm-musleabihf': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-arm64-gnu': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-arm64-musl': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-ppc64-gnu': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-riscv64-gnu': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-riscv64-musl': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-s390x-gnu': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-x64-gnu': 0.106.0
|
||||||
|
'@oxc-parser/binding-linux-x64-musl': 0.106.0
|
||||||
|
'@oxc-parser/binding-openharmony-arm64': 0.106.0
|
||||||
|
'@oxc-parser/binding-wasm32-wasi': 0.106.0
|
||||||
|
'@oxc-parser/binding-win32-arm64-msvc': 0.106.0
|
||||||
|
'@oxc-parser/binding-win32-ia32-msvc': 0.106.0
|
||||||
|
'@oxc-parser/binding-win32-x64-msvc': 0.106.0
|
||||||
|
|
||||||
|
oxc-walker@0.7.0(oxc-parser@0.106.0):
|
||||||
|
dependencies:
|
||||||
|
magic-regexp: 0.10.0
|
||||||
|
oxc-parser: 0.106.0
|
||||||
|
|
||||||
path-browserify@1.0.1: {}
|
path-browserify@1.0.1: {}
|
||||||
|
|
||||||
path-is-absolute@1.0.1: {}
|
path-is-absolute@1.0.1: {}
|
||||||
@@ -3338,6 +3667,8 @@ snapshots:
|
|||||||
|
|
||||||
reflect-metadata@0.2.2: {}
|
reflect-metadata@0.2.2: {}
|
||||||
|
|
||||||
|
regexp-tree@0.1.27: {}
|
||||||
|
|
||||||
require-directory@2.1.1: {}
|
require-directory@2.1.1: {}
|
||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
@@ -3521,6 +3852,8 @@ snapshots:
|
|||||||
|
|
||||||
type-fest@4.41.0: {}
|
type-fest@4.41.0: {}
|
||||||
|
|
||||||
|
type-level-regexp@0.1.17: {}
|
||||||
|
|
||||||
typescript@5.9.3: {}
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
ufo@1.6.3: {}
|
ufo@1.6.3: {}
|
||||||
@@ -3539,6 +3872,13 @@ snapshots:
|
|||||||
|
|
||||||
undici-types@7.8.0: {}
|
undici-types@7.8.0: {}
|
||||||
|
|
||||||
|
unhead@3.0.0-beta.9(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2)):
|
||||||
|
dependencies:
|
||||||
|
hookable: 6.1.0
|
||||||
|
magic-string: 0.30.21
|
||||||
|
optionalDependencies:
|
||||||
|
vite: 8.0.0(@types/node@24.12.0)(esbuild@0.27.4)(tsx@4.21.0)(yaml@2.8.2)
|
||||||
|
|
||||||
universalify@2.0.1: {}
|
universalify@2.0.1: {}
|
||||||
|
|
||||||
unplugin-utils@0.3.1:
|
unplugin-utils@0.3.1:
|
||||||
@@ -3546,6 +3886,13 @@ snapshots:
|
|||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
unplugin@2.3.11:
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/remapping': 2.3.5
|
||||||
|
acorn: 8.16.0
|
||||||
|
picomatch: 4.0.3
|
||||||
|
webpack-virtual-modules: 0.6.2
|
||||||
|
|
||||||
unplugin@3.0.0:
|
unplugin@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/remapping': 2.3.5
|
'@jridgewell/remapping': 2.3.5
|
||||||
|
|||||||
Reference in New Issue
Block a user