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/reflection": "^6.6.7",
|
||||
"@types/web-push": "^3.6.4",
|
||||
"lynqchat-js": "workspace:*",
|
||||
"argon2": "^0.44.0",
|
||||
"cross-env": "^10.1.0",
|
||||
"fastify": "^5.7.4",
|
||||
|
||||
@@ -11,6 +11,7 @@ import Authorization from "@/lib/auth";
|
||||
import { RequestContext } from "@mikro-orm/core";
|
||||
import { DatabaseError, ErrorBase } from "@/errors";
|
||||
import { ConfigEntity } from "@/modules/entities/Config";
|
||||
import type ApiMap from "lynqchat-js/1.0.0-alpha.0/map";
|
||||
|
||||
process.title = "LynqChat";
|
||||
|
||||
@@ -83,7 +84,8 @@ try {
|
||||
fastify.addHook("onRequest", async (req, res) => {
|
||||
if (
|
||||
req.url.startsWith("/api") &&
|
||||
!req.url.startsWith("/api/setup")
|
||||
!req.url.startsWith("/api/setup") &&
|
||||
!req.url.startsWith("/api/server-info")
|
||||
) {
|
||||
try {
|
||||
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, {
|
||||
prefix: "/api",
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ export class UserEntity {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
})
|
||||
isOwner: boolean = false;
|
||||
isAdmin: boolean = false;
|
||||
|
||||
@Property({
|
||||
type: "boolean",
|
||||
|
||||
@@ -9,7 +9,7 @@ export class UserRepository extends EntityRepository<UserEntity> {
|
||||
userid: z.string().trim().min(3).max(20),
|
||||
username: z.string().trim().min(3).max(30),
|
||||
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),
|
||||
isAdmin: z.boolean(),
|
||||
});
|
||||
|
||||
@@ -14,8 +14,13 @@ export default async function ServerInfo(fastify: FastifyInstance) {
|
||||
const configCount = await config.count();
|
||||
const userCount = await user.count();
|
||||
|
||||
const serverName = await config.findOne({ name: "name" });
|
||||
const serverDescription = await config.findOne({ name: "description" });
|
||||
|
||||
return res.send({
|
||||
success: true,
|
||||
name: serverName?.value ?? null,
|
||||
description: serverDescription?.value ?? null,
|
||||
isInitialized: configCount > 0,
|
||||
isFirstAdminExists: userCount > 0,
|
||||
userCount,
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<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>
|
||||
<body>
|
||||
<style>
|
||||
|
||||
@@ -3,20 +3,23 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev": "vite dev --host",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"dexie": "^4.3.0",
|
||||
"vue": "^3.5.24",
|
||||
"vue-router": "^5.0.2",
|
||||
"lynqchat-js": "workspace:*",
|
||||
"@iconify/vue": "^5.0.0",
|
||||
"@unhead/vue": "3.0.0-beta.9",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"dexie": "^4.3.0",
|
||||
"lynqchat-js": "workspace:*",
|
||||
"typescript": "~5.9.3",
|
||||
"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": {
|
||||
"@types/node": "^24.10.1"
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
:size="6"
|
||||
/>
|
||||
|
||||
<div class="modals-container" />
|
||||
|
||||
<main class="layout">
|
||||
<div class="left-menu">
|
||||
<div>
|
||||
@@ -12,11 +14,23 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-main">
|
||||
<div class="content-header">
|
||||
{{
|
||||
$route.meta.title
|
||||
?? (serverInfo.success
|
||||
? serverInfo.name
|
||||
: null)
|
||||
?? "LynqChat"
|
||||
}}
|
||||
</div>
|
||||
|
||||
<div class="route-main">
|
||||
<RouterView
|
||||
:key="$route.fullPath"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -26,7 +40,7 @@ main.layout {
|
||||
gap: 1rem;
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
padding: 1rem;
|
||||
padding: 1.5rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -36,6 +50,8 @@ main.layout {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.left-menu div {
|
||||
@@ -44,26 +60,65 @@ main.layout {
|
||||
font-weight: bold;
|
||||
font-size: 1.4rem;
|
||||
border-radius: 2rem;
|
||||
padding: 1rem;
|
||||
transition: all 100ms ease-in;
|
||||
padding: 1rem 1.5rem;
|
||||
transition: background-color 250ms ease-out;
|
||||
}
|
||||
|
||||
.left-menu div:hover {
|
||||
background-color: var(--border-color);
|
||||
}
|
||||
|
||||
.route-main {
|
||||
.content-main {
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 0.75rem;
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
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 {
|
||||
position: fixed;
|
||||
inset: 0.5rem 0.5rem 0 auto;
|
||||
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>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -74,11 +129,15 @@ import serverInfo from "@/lib/account";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
if (!serverInfo.success) {
|
||||
if (!serverInfo.value.success) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (!serverInfo.isFirstAdminExists) {
|
||||
router.replace("/setup");
|
||||
if (!serverInfo.value.isInitialized) {
|
||||
router.replace("/setup/initialization");
|
||||
}
|
||||
|
||||
if (!serverInfo.value.isFirstAdminExists) {
|
||||
router.replace("/setup/create-admin");
|
||||
}
|
||||
</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>
|
||||
.progress {
|
||||
flex-shrink: 0;
|
||||
border: v-bind(borderSize) solid #425C97;
|
||||
border-radius: 100%;
|
||||
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 {
|
||||
--bg-color: #ffffff;
|
||||
--bg-sub-color: #f1f1f1;
|
||||
--text-color: #000000;
|
||||
--text-sub-color: #595959;
|
||||
--border-color: #e0e0e0;
|
||||
--error-color: #ff0000;
|
||||
--success-color: #00ff00;
|
||||
--accent-color: #3ad0a1;
|
||||
--accent-in-text-color: #000000;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg-color: #1b1b1b;
|
||||
--bg-sub-color: #252525;
|
||||
--text-color: #ffffff;
|
||||
--text-sub-color: #a4a4a4;
|
||||
--border-color: #2c2c2c;
|
||||
}
|
||||
}
|
||||
@@ -15,12 +25,45 @@
|
||||
* {
|
||||
margin: 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 {
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
font-size: 14px;
|
||||
font-family: "BIZ UDPGothic", sans-serif;
|
||||
line-height: 1.5rem;
|
||||
tab-size: 2;
|
||||
background-color: var(--bg-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 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;
|
||||
@@ -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 { createRouter, createWebHistory } from "vue-router";
|
||||
import routerStatus from "@/lib/router";
|
||||
import { createHead } from "@unhead/vue/client";
|
||||
import serverInfo from "@/lib/account";
|
||||
|
||||
import "@/global.css";
|
||||
import Layout from "@/Layout.vue";
|
||||
|
||||
const app = createApp(Layout);
|
||||
|
||||
app.use(createHead());
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
meta: {
|
||||
title: "ホーム",
|
||||
},
|
||||
component: () => import("@/routes/index.vue"),
|
||||
},
|
||||
{
|
||||
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(() => {
|
||||
routerStatus.isLoad = true;
|
||||
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;
|
||||
});
|
||||
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}`,
|
||||
changeOrigin: true,
|
||||
},
|
||||
"/manifest.json": {
|
||||
target: `http://localhost:${apiPort}`,
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
|
||||
@@ -8,6 +8,8 @@ export default interface ServerInfo {
|
||||
"server-info": {
|
||||
body: never;
|
||||
response: (Success & {
|
||||
name: string | null;
|
||||
description: string | null;
|
||||
isInitialized: boolean;
|
||||
isFirstAdminExists: boolean;
|
||||
userCount: number;
|
||||
|
||||
@@ -5,7 +5,7 @@ import Success from "../../modules/response/success";
|
||||
import UnknownError from "../../modules/error/unknown";
|
||||
|
||||
export default interface SetupInitialization {
|
||||
"setup/initilization": {
|
||||
"setup/initialization": {
|
||||
body: {
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
Generated
+347
@@ -43,6 +43,9 @@ importers:
|
||||
fs:
|
||||
specifier: 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}
|
||||
tsc-alias:
|
||||
specifier: ^1.8.16
|
||||
@@ -75,6 +78,12 @@ importers:
|
||||
|
||||
packages/frontend:
|
||||
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':
|
||||
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))
|
||||
@@ -102,6 +111,9 @@ importers:
|
||||
vue-tsc:
|
||||
specifier: ^3.1.4
|
||||
version: 3.2.5(typescript@5.9.3)
|
||||
zod:
|
||||
specifier: ^4.3.6
|
||||
version: 4.3.6
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^24.10.1
|
||||
@@ -337,6 +349,14 @@ packages:
|
||||
'@fastify/static@9.0.0':
|
||||
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':
|
||||
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||
|
||||
@@ -410,10 +430,140 @@ packages:
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
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':
|
||||
resolution: {integrity: sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==}
|
||||
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':
|
||||
resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==}
|
||||
|
||||
@@ -553,6 +703,9 @@ packages:
|
||||
'@types/argparse@1.0.38':
|
||||
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':
|
||||
resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==}
|
||||
|
||||
@@ -562,6 +715,15 @@ packages:
|
||||
'@types/web-push@3.6.4':
|
||||
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':
|
||||
resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -925,6 +1087,9 @@ packages:
|
||||
estree-walker@2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
|
||||
estree-walker@3.0.3:
|
||||
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
|
||||
|
||||
exsolve@1.0.8:
|
||||
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
||||
|
||||
@@ -1066,6 +1231,9 @@ packages:
|
||||
hookable@5.5.3:
|
||||
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
|
||||
|
||||
hookable@6.1.0:
|
||||
resolution: {integrity: sha512-ZoKZSJgu8voGK2geJS+6YtYjvIzu9AOM/KZXsBxr83uhLL++e9pEv/dlgwgy3dvHg06kTz6JOh1hk3C8Ceiymw==}
|
||||
|
||||
http-errors@2.0.1:
|
||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -1302,6 +1470,9 @@ packages:
|
||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
magic-regexp@0.10.0:
|
||||
resolution: {integrity: sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==}
|
||||
|
||||
magic-string-ast@1.0.3:
|
||||
resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
@@ -1395,6 +1566,15 @@ packages:
|
||||
os@0.1.2:
|
||||
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:
|
||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||
|
||||
@@ -1582,6 +1762,10 @@ packages:
|
||||
reflect-metadata@0.2.2:
|
||||
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:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1775,6 +1959,9 @@ packages:
|
||||
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
type-level-regexp@0.1.17:
|
||||
resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==}
|
||||
|
||||
typescript@5.9.3:
|
||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||
engines: {node: '>=14.17'}
|
||||
@@ -1793,6 +1980,14 @@ packages:
|
||||
undici-types@7.8.0:
|
||||
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:
|
||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@@ -1801,6 +1996,10 @@ packages:
|
||||
resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==}
|
||||
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:
|
||||
resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -2109,6 +2308,13 @@ snapshots:
|
||||
fastq: 1.20.1
|
||||
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':
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
@@ -2218,8 +2424,72 @@ snapshots:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
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/types@0.106.0': {}
|
||||
|
||||
'@oxc-project/types@0.115.0': {}
|
||||
|
||||
'@phc/format@1.0.0': {}
|
||||
@@ -2319,6 +2589,8 @@ snapshots:
|
||||
|
||||
'@types/argparse@1.0.38': {}
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/node@24.1.0':
|
||||
dependencies:
|
||||
undici-types: 7.8.0
|
||||
@@ -2331,6 +2603,17 @@ snapshots:
|
||||
dependencies:
|
||||
'@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))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-rc.2
|
||||
@@ -2729,6 +3012,10 @@ snapshots:
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
|
||||
estree-walker@3.0.3:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
|
||||
exsolve@1.0.8: {}
|
||||
|
||||
fast-decode-uri-component@1.0.1: {}
|
||||
@@ -2895,6 +3182,8 @@ snapshots:
|
||||
|
||||
hookable@5.5.3: {}
|
||||
|
||||
hookable@6.1.0: {}
|
||||
|
||||
http-errors@2.0.1:
|
||||
dependencies:
|
||||
depd: 2.0.0
|
||||
@@ -3096,6 +3385,16 @@ snapshots:
|
||||
dependencies:
|
||||
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:
|
||||
dependencies:
|
||||
magic-string: 0.30.21
|
||||
@@ -3167,6 +3466,36 @@ snapshots:
|
||||
|
||||
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-is-absolute@1.0.1: {}
|
||||
@@ -3338,6 +3667,8 @@ snapshots:
|
||||
|
||||
reflect-metadata@0.2.2: {}
|
||||
|
||||
regexp-tree@0.1.27: {}
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
@@ -3521,6 +3852,8 @@ snapshots:
|
||||
|
||||
type-fest@4.41.0: {}
|
||||
|
||||
type-level-regexp@0.1.17: {}
|
||||
|
||||
typescript@5.9.3: {}
|
||||
|
||||
ufo@1.6.3: {}
|
||||
@@ -3539,6 +3872,13 @@ snapshots:
|
||||
|
||||
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: {}
|
||||
|
||||
unplugin-utils@0.3.1:
|
||||
@@ -3546,6 +3886,13 @@ snapshots:
|
||||
pathe: 2.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:
|
||||
dependencies:
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
|
||||
Reference in New Issue
Block a user