From 1c4a700d92f7c5e13f958fa5cfa4dc98b94f8edd Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Thu, 26 Sep 2024 00:23:03 +0800
Subject: [PATCH 01/71] =?UTF-8?q?refactor:=20=E5=B0=86=20yirimirai=20?=
=?UTF-8?q?=E7=9A=84=E7=BB=84=E4=BB=B6=E9=9B=86=E6=88=90=E8=BF=9B=20platfo?=
=?UTF-8?q?rm=20=E5=8C=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pkg/command/entities.py | 5 +-
pkg/core/entities.py | 13 +-
pkg/pipeline/cntfilter/cntfilter.py | 15 +-
pkg/pipeline/controller.py | 9 +-
pkg/pipeline/entities.py | 6 +-
pkg/pipeline/longtext/longtext.py | 7 +-
pkg/pipeline/longtext/strategies/forward.py | 20 +-
pkg/pipeline/longtext/strategies/image.py | 9 +-
pkg/pipeline/longtext/strategy.py | 9 +-
pkg/pipeline/pool.py | 8 +-
pkg/pipeline/preproc/preproc.py | 7 +-
pkg/pipeline/process/handlers/chat.py | 6 +-
pkg/pipeline/process/handlers/command.py | 9 +-
pkg/pipeline/respback/respback.py | 2 +-
pkg/pipeline/resprule/entities.py | 6 +-
pkg/pipeline/resprule/resprule.py | 2 +-
pkg/pipeline/resprule/rule.py | 6 +-
pkg/pipeline/resprule/rules/atbot.py | 13 +-
pkg/pipeline/resprule/rules/prefix.py | 7 +-
pkg/pipeline/resprule/rules/random.py | 5 +-
pkg/pipeline/resprule/rules/regexp.py | 5 +-
pkg/pipeline/wrapper/wrapper.py | 13 +-
pkg/platform/adapter.py | 26 +-
pkg/platform/manager.py | 28 +-
pkg/platform/sources/aiocqhttp.py | 71 +-
pkg/platform/sources/nakuru.py | 78 +-
pkg/platform/sources/qqbotpy.py | 91 +--
pkg/platform/sources/yirimirai.py | 212 ++---
pkg/platform/types/__init__.py | 0
pkg/platform/types/base.py | 105 +++
pkg/platform/types/entities.py | 143 ++++
pkg/platform/types/events.py | 124 +++
pkg/platform/types/message.py | 826 ++++++++++++++++++++
pkg/plugin/context.py | 7 +-
pkg/plugin/events.py | 7 +-
pkg/provider/entities.py | 22 +-
36 files changed, 1580 insertions(+), 342 deletions(-)
create mode 100644 pkg/platform/types/__init__.py
create mode 100644 pkg/platform/types/base.py
create mode 100644 pkg/platform/types/entities.py
create mode 100644 pkg/platform/types/events.py
create mode 100644 pkg/platform/types/message.py
diff --git a/pkg/command/entities.py b/pkg/command/entities.py
index 86975510..3ea660f1 100644
--- a/pkg/command/entities.py
+++ b/pkg/command/entities.py
@@ -3,10 +3,11 @@
import typing
import pydantic
-import mirai
+# import mirai
from ..core import app, entities as core_entities
from . import errors, operator
+from ..platform.types import message as platform_message
class CommandReturn(pydantic.BaseModel):
@@ -17,7 +18,7 @@ class CommandReturn(pydantic.BaseModel):
"""文本
"""
- image: typing.Optional[mirai.Image] = None
+ image: typing.Optional[platform_message.Image] = None
"""弃用"""
image_url: typing.Optional[str] = None
diff --git a/pkg/core/entities.py b/pkg/core/entities.py
index 6305a0ec..744c6d03 100644
--- a/pkg/core/entities.py
+++ b/pkg/core/entities.py
@@ -6,13 +6,16 @@
import asyncio
import pydantic
-import mirai
+# import mirai
from ..provider import entities as llm_entities
from ..provider.modelmgr import entities
from ..provider.sysprompt import entities as sysprompt_entities
from ..provider.tools import entities as tools_entities
from ..platform import adapter as msadapter
+from ..platform.types import message as platform_message
+from ..platform.types import events as platform_events
+from ..platform.types import entities as platform_entities
class LauncherTypes(enum.Enum):
@@ -40,10 +43,10 @@ class Query(pydantic.BaseModel):
sender_id: int
"""发送者ID,platform处理阶段设置"""
- message_event: mirai.MessageEvent
+ message_event: platform_events.MessageEvent
"""事件,platform收到的原始事件"""
- message_chain: mirai.MessageChain
+ message_chain: platform_message.MessageChain
"""消息链,platform收到的原始消息链"""
adapter: msadapter.MessageSourceAdapter
@@ -67,10 +70,10 @@ class Query(pydantic.BaseModel):
use_funcs: typing.Optional[list[tools_entities.LLMFunction]] = None
"""使用的函数,由前置处理器阶段设置"""
- resp_messages: typing.Optional[list[llm_entities.Message]] | typing.Optional[list[mirai.MessageChain]] = []
+ resp_messages: typing.Optional[list[llm_entities.Message]] | typing.Optional[list[platform_message.MessageChain]] = []
"""由Process阶段生成的回复消息对象列表"""
- resp_message_chain: typing.Optional[list[mirai.MessageChain]] = None
+ resp_message_chain: typing.Optional[list[platform_message.MessageChain]] = None
"""回复消息链,从resp_messages包装而得"""
# ======= 内部保留 =======
diff --git a/pkg/pipeline/cntfilter/cntfilter.py b/pkg/pipeline/cntfilter/cntfilter.py
index 29e66cc4..f0c5428e 100644
--- a/pkg/pipeline/cntfilter/cntfilter.py
+++ b/pkg/pipeline/cntfilter/cntfilter.py
@@ -1,8 +1,8 @@
from __future__ import annotations
-import mirai
-import mirai.models
-import mirai.models.message
+# import mirai
+# import mirai.models
+# import mirai.models.message
from ...core import app
@@ -12,6 +12,9 @@
from . import filter as filter_model, entities as filter_entities
from .filters import cntignore, banwords, baiduexamine
from ...provider import entities as llm_entities
+from ...platform.types import message as platform_message
+from ...platform.types import events as platform_events
+from ...platform.types import entities as platform_entities
@stage.stage_class('PostContentFilterStage')
@@ -89,8 +92,8 @@ async def _pre_process(
elif result.level == filter_entities.ResultLevel.PASS: # 传到下一个
message = result.replacement
- query.message_chain = mirai.MessageChain(
- mirai.Plain(message)
+ query.message_chain = platform_message.MessageChain(
+ platform_message.Plain(message)
)
return entities.StageProcessResult(
@@ -148,7 +151,7 @@ async def process(
contain_non_text = False
- text_components = [mirai.Plain, mirai.models.message.Source]
+ text_components = [platform_message.Plain, platform_message.Source]
for me in query.message_chain:
if type(me) not in text_components:
diff --git a/pkg/pipeline/controller.py b/pkg/pipeline/controller.py
index 677db31d..27b96dee 100644
--- a/pkg/pipeline/controller.py
+++ b/pkg/pipeline/controller.py
@@ -4,11 +4,12 @@
import typing
import traceback
-import mirai
+# import mirai
from ..core import app, entities
from . import entities as pipeline_entities
from ..plugin import events
+from ..platform.types import message as platform_message
class Controller:
@@ -73,11 +74,11 @@ async def _check_output(self, query: entities.Query, result: pipeline_entities.S
# 处理str类型
if isinstance(result.user_notice, str):
- result.user_notice = mirai.MessageChain(
- mirai.Plain(result.user_notice)
+ result.user_notice = platform_message.MessageChain(
+ platform_message.Plain(result.user_notice)
)
elif isinstance(result.user_notice, list):
- result.user_notice = mirai.MessageChain(
+ result.user_notice = platform_message.MessageChain(
*result.user_notice
)
diff --git a/pkg/pipeline/entities.py b/pkg/pipeline/entities.py
index e8cfc427..347f5db7 100644
--- a/pkg/pipeline/entities.py
+++ b/pkg/pipeline/entities.py
@@ -4,8 +4,8 @@
import typing
import pydantic
-import mirai
-import mirai.models.message as mirai_message
+# import mirai
+from ..platform.types import message as platform_message
from ..core import entities
@@ -25,7 +25,7 @@ class StageProcessResult(pydantic.BaseModel):
new_query: entities.Query
- user_notice: typing.Optional[typing.Union[str, list[mirai_message.MessageComponent], mirai.MessageChain, None]] = []
+ user_notice: typing.Optional[typing.Union[str, list[platform_message.MessageComponent], platform_message.MessageChain, None]] = []
"""只要设置了就会发送给用户"""
# TODO delete
diff --git a/pkg/pipeline/longtext/longtext.py b/pkg/pipeline/longtext/longtext.py
index 0ab34abc..d3715b7e 100644
--- a/pkg/pipeline/longtext/longtext.py
+++ b/pkg/pipeline/longtext/longtext.py
@@ -3,7 +3,7 @@
import traceback
from PIL import Image, ImageDraw, ImageFont
-from mirai.models.message import MessageComponent, Plain, MessageChain
+# from mirai.models.message import MessageComponent, Plain, MessageChain
from ...core import app
from . import strategy
@@ -11,6 +11,7 @@
from .. import stage, entities, stagemgr
from ...core import entities as core_entities
from ...config import manager as cfg_mgr
+from ...platform.types import message as platform_message
@stage.stage_class("LongTextProcessStage")
@@ -63,14 +64,14 @@ async def process(self, query: core_entities.Query, stage_inst_name: str) -> ent
contains_non_plain = False
for msg in query.resp_message_chain[-1]:
- if not isinstance(msg, Plain):
+ if not isinstance(msg, platform_message.Plain):
contains_non_plain = True
break
if contains_non_plain:
self.ap.logger.debug("消息中包含非 Plain 组件,跳过长消息处理。")
elif len(str(query.resp_message_chain[-1])) > self.ap.platform_cfg.data['long-text-process']['threshold']:
- query.resp_message_chain[-1] = MessageChain(await self.strategy_impl.process(str(query.resp_message_chain[-1]), query))
+ query.resp_message_chain[-1] = platform_message.MessageChain(await self.strategy_impl.process(str(query.resp_message_chain[-1]), query))
return entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
diff --git a/pkg/pipeline/longtext/strategies/forward.py b/pkg/pipeline/longtext/strategies/forward.py
index 4a790313..206bf08c 100644
--- a/pkg/pipeline/longtext/strategies/forward.py
+++ b/pkg/pipeline/longtext/strategies/forward.py
@@ -2,15 +2,17 @@
from __future__ import annotations
import typing
-from mirai.models import MessageChain
-from mirai.models.message import MessageComponent, ForwardMessageNode
-from mirai.models.base import MiraiBaseModel
+# from mirai.models import MessageChain
+# from mirai.models.message import MessageComponent, ForwardMessageNode
+# from mirai.models.base import MiraiBaseModel
+import pydantic
from .. import strategy as strategy_model
from ....core import entities as core_entities
+from ....platform.types import message as platform_message
-class ForwardMessageDiaplay(MiraiBaseModel):
+class ForwardMessageDiaplay(pydantic.BaseModel):
title: str = "群聊的聊天记录"
brief: str = "[聊天记录]"
source: str = "聊天记录"
@@ -18,13 +20,13 @@ class ForwardMessageDiaplay(MiraiBaseModel):
summary: str = "查看x条转发消息"
-class Forward(MessageComponent):
+class Forward(platform_message.MessageComponent):
"""合并转发。"""
type: str = "Forward"
"""消息组件类型。"""
display: ForwardMessageDiaplay
"""显示信息"""
- node_list: typing.List[ForwardMessageNode]
+ node_list: typing.List[platform_message.ForwardMessageNode]
"""转发消息节点列表。"""
def __init__(self, *args, **kwargs):
if len(args) == 1:
@@ -39,7 +41,7 @@ def __str__(self):
@strategy_model.strategy_class("forward")
class ForwardComponentStrategy(strategy_model.LongTextStrategy):
- async def process(self, message: str, query: core_entities.Query) -> list[MessageComponent]:
+ async def process(self, message: str, query: core_entities.Query) -> list[platform_message.MessageComponent]:
display = ForwardMessageDiaplay(
title="群聊的聊天记录",
brief="[聊天记录]",
@@ -49,10 +51,10 @@ async def process(self, message: str, query: core_entities.Query) -> list[Messag
)
node_list = [
- ForwardMessageNode(
+ platform_message.ForwardMessageNode(
sender_id=query.adapter.bot_account_id,
sender_name='QQ用户',
- message_chain=MessageChain([message])
+ message_chain=platform_message.MessageChain([message])
)
]
diff --git a/pkg/pipeline/longtext/strategies/image.py b/pkg/pipeline/longtext/strategies/image.py
index f96f03c5..3b1805c3 100644
--- a/pkg/pipeline/longtext/strategies/image.py
+++ b/pkg/pipeline/longtext/strategies/image.py
@@ -8,8 +8,9 @@
from PIL import Image, ImageDraw, ImageFont
-from mirai.models import MessageChain, Image as ImageComponent
-from mirai.models.message import MessageComponent
+# from mirai.models import MessageChain, Image as ImageComponent
+# from mirai.models.message import MessageComponent
+from ....platform.types import message as platform_message
from .. import strategy as strategy_model
from ....core import entities as core_entities
@@ -23,7 +24,7 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
async def initialize(self):
self.text_render_font = ImageFont.truetype(self.ap.platform_cfg.data['long-text-process']['font-path'], 32, encoding="utf-8")
- async def process(self, message: str, query: core_entities.Query) -> list[MessageComponent]:
+ async def process(self, message: str, query: core_entities.Query) -> list[platform_message.MessageComponent]:
img_path = self.text_to_image(
text_str=message,
save_as='temp/{}.png'.format(int(time.time()))
@@ -46,7 +47,7 @@ async def process(self, message: str, query: core_entities.Query) -> list[Messag
os.remove(compressed_path)
return [
- ImageComponent(
+ platform_message.Image(
base64=b64.decode('utf-8'),
)
]
diff --git a/pkg/pipeline/longtext/strategy.py b/pkg/pipeline/longtext/strategy.py
index 5d7e24fb..5bc46a39 100644
--- a/pkg/pipeline/longtext/strategy.py
+++ b/pkg/pipeline/longtext/strategy.py
@@ -2,11 +2,12 @@
import abc
import typing
-import mirai
-from mirai.models.message import MessageComponent
+# import mirai
+# from mirai.models.message import MessageComponent
from ...core import app
from ...core import entities as core_entities
+from ...platform.types import message as platform_message
preregistered_strategies: list[typing.Type[LongTextStrategy]] = []
@@ -51,7 +52,7 @@ async def initialize(self):
pass
@abc.abstractmethod
- async def process(self, message: str, query: core_entities.Query) -> list[MessageComponent]:
+ async def process(self, message: str, query: core_entities.Query) -> list[platform_message.MessageComponent]:
"""处理长文本
在 platform.json 中配置 long-text-process 字段,只要 文本长度超过了 threshold 就会调用此方法
@@ -61,6 +62,6 @@ async def process(self, message: str, query: core_entities.Query) -> list[Messag
query (core_entities.Query): 此次请求的上下文对象
Returns:
- list[mirai.models.messages.MessageComponent]: 转换后的 YiriMirai 消息组件列表
+ list[platform_message.MessageComponent]: 转换后的 平台 消息组件列表
"""
return []
diff --git a/pkg/pipeline/pool.py b/pkg/pipeline/pool.py
index ba7f9991..b7f79510 100644
--- a/pkg/pipeline/pool.py
+++ b/pkg/pipeline/pool.py
@@ -2,10 +2,12 @@
import asyncio
-import mirai
+# import mirai
from ..core import entities
from ..platform import adapter as msadapter
+from ..platform.types import message as platform_message
+from ..platform.types import events as platform_events
class QueryPool:
@@ -30,8 +32,8 @@ async def add_query(
launcher_type: entities.LauncherTypes,
launcher_id: int,
sender_id: int,
- message_event: mirai.MessageEvent,
- message_chain: mirai.MessageChain,
+ message_event: platform_events.MessageEvent,
+ message_chain: platform_message.MessageChain,
adapter: msadapter.MessageSourceAdapter
) -> entities.Query:
async with self.condition:
diff --git a/pkg/pipeline/preproc/preproc.py b/pkg/pipeline/preproc/preproc.py
index ebe4d311..976c8f7c 100644
--- a/pkg/pipeline/preproc/preproc.py
+++ b/pkg/pipeline/preproc/preproc.py
@@ -1,11 +1,12 @@
from __future__ import annotations
-import mirai
+# import mirai
from .. import stage, entities, stagemgr
from ...core import entities as core_entities
from ...provider import entities as llm_entities
from ...plugin import events
+from ...platform.types import message as platform_message
@stage.stage_class("PreProcessor")
@@ -55,11 +56,11 @@ async def process(
content_list = []
for me in query.message_chain:
- if isinstance(me, mirai.Plain):
+ if isinstance(me, platform_message.Plain):
content_list.append(
llm_entities.ContentElement.from_text(me.text)
)
- elif isinstance(me, mirai.Image):
+ elif isinstance(me, platform_message.Image):
if self.ap.provider_cfg.data['enable-vision'] and query.use_model.vision_supported:
if me.url is not None:
content_list.append(
diff --git a/pkg/pipeline/process/handlers/chat.py b/pkg/pipeline/process/handlers/chat.py
index cb8899bd..d87e2853 100644
--- a/pkg/pipeline/process/handlers/chat.py
+++ b/pkg/pipeline/process/handlers/chat.py
@@ -5,7 +5,7 @@
import traceback
import json
-import mirai
+# import mirai
from .. import handler
from ... import entities
@@ -13,6 +13,8 @@
from ....provider import entities as llm_entities, runnermgr
from ....plugin import events
+from ....platform.types import message as platform_message
+
class ChatMessageHandler(handler.MessageHandler):
@@ -40,7 +42,7 @@ async def handle(
if event_ctx.is_prevented_default():
if event_ctx.event.reply is not None:
- mc = mirai.MessageChain(event_ctx.event.reply)
+ mc = platform_message.MessageChain(event_ctx.event.reply)
query.resp_messages.append(mc)
diff --git a/pkg/pipeline/process/handlers/command.py b/pkg/pipeline/process/handlers/command.py
index 8c8fb8ba..5f6ed6ee 100644
--- a/pkg/pipeline/process/handlers/command.py
+++ b/pkg/pipeline/process/handlers/command.py
@@ -1,13 +1,14 @@
from __future__ import annotations
import typing
-import mirai
+# import mirai
from .. import handler
from ... import entities
from ....core import entities as core_entities
from ....provider import entities as llm_entities
from ....plugin import events
+from ....platform.types import message as platform_message
class CommandHandler(handler.MessageHandler):
@@ -46,7 +47,7 @@ async def handle(
if event_ctx.is_prevented_default():
if event_ctx.event.reply is not None:
- mc = mirai.MessageChain(event_ctx.event.reply)
+ mc = platform_message.MessageChain(event_ctx.event.reply)
query.resp_messages.append(mc)
@@ -63,8 +64,8 @@ async def handle(
else:
if event_ctx.event.alter is not None:
- query.message_chain = mirai.MessageChain([
- mirai.Plain(event_ctx.event.alter)
+ query.message_chain = platform_message.MessageChain([
+ platform_message.Plain(event_ctx.event.alter)
])
session = await self.ap.sess_mgr.get_session(query)
diff --git a/pkg/pipeline/respback/respback.py b/pkg/pipeline/respback/respback.py
index d3af14e5..1b0cd3ac 100644
--- a/pkg/pipeline/respback/respback.py
+++ b/pkg/pipeline/respback/respback.py
@@ -3,7 +3,7 @@
import random
import asyncio
-import mirai
+# import mirai
from ...core import app
diff --git a/pkg/pipeline/resprule/entities.py b/pkg/pipeline/resprule/entities.py
index ffee3081..42c2092e 100644
--- a/pkg/pipeline/resprule/entities.py
+++ b/pkg/pipeline/resprule/entities.py
@@ -1,9 +1,11 @@
import pydantic
-import mirai
+# import mirai
+
+from ...platform.types import message as platform_message
class RuleJudgeResult(pydantic.BaseModel):
matching: bool = False
- replacement: mirai.MessageChain = None
+ replacement: platform_message.MessageChain = None
diff --git a/pkg/pipeline/resprule/resprule.py b/pkg/pipeline/resprule/resprule.py
index b7fdb372..aa07bb7c 100644
--- a/pkg/pipeline/resprule/resprule.py
+++ b/pkg/pipeline/resprule/resprule.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-import mirai
+# import mirai
from ...core import app
from . import entities as rule_entities, rule
diff --git a/pkg/pipeline/resprule/rule.py b/pkg/pipeline/resprule/rule.py
index bfab4152..b40e5ac5 100644
--- a/pkg/pipeline/resprule/rule.py
+++ b/pkg/pipeline/resprule/rule.py
@@ -2,11 +2,13 @@
import abc
import typing
-import mirai
+# import mirai
from ...core import app, entities as core_entities
from . import entities
+from ...platform.types import message as platform_message
+
preregisetered_rules: list[typing.Type[GroupRespondRule]] = []
@@ -35,7 +37,7 @@ async def initialize(self):
async def match(
self,
message_text: str,
- message_chain: mirai.MessageChain,
+ message_chain: platform_message.MessageChain,
rule_dict: dict,
query: core_entities.Query
) -> entities.RuleJudgeResult:
diff --git a/pkg/pipeline/resprule/rules/atbot.py b/pkg/pipeline/resprule/rules/atbot.py
index 4b39409c..d767f95a 100644
--- a/pkg/pipeline/resprule/rules/atbot.py
+++ b/pkg/pipeline/resprule/rules/atbot.py
@@ -1,10 +1,11 @@
from __future__ import annotations
-import mirai
+# import mirai
from .. import rule as rule_model
from .. import entities
from ....core import entities as core_entities
+from ....platform.types import message as platform_message
@rule_model.rule_class("at-bot")
@@ -13,16 +14,16 @@ class AtBotRule(rule_model.GroupRespondRule):
async def match(
self,
message_text: str,
- message_chain: mirai.MessageChain,
+ message_chain: platform_message.MessageChain,
rule_dict: dict,
query: core_entities.Query
) -> entities.RuleJudgeResult:
- if message_chain.has(mirai.At(query.adapter.bot_account_id)) and rule_dict['at']:
- message_chain.remove(mirai.At(query.adapter.bot_account_id))
+ if message_chain.has(platform_message.At(query.adapter.bot_account_id)) and rule_dict['at']:
+ message_chain.remove(platform_message.At(query.adapter.bot_account_id))
- if message_chain.has(mirai.At(query.adapter.bot_account_id)): # 回复消息时会at两次,检查并删除重复的
- message_chain.remove(mirai.At(query.adapter.bot_account_id))
+ if message_chain.has(platform_message.At(query.adapter.bot_account_id)): # 回复消息时会at两次,检查并删除重复的
+ message_chain.remove(platform_message.At(query.adapter.bot_account_id))
return entities.RuleJudgeResult(
matching=True,
diff --git a/pkg/pipeline/resprule/rules/prefix.py b/pkg/pipeline/resprule/rules/prefix.py
index 98b50321..c010c0f8 100644
--- a/pkg/pipeline/resprule/rules/prefix.py
+++ b/pkg/pipeline/resprule/rules/prefix.py
@@ -1,8 +1,9 @@
-import mirai
+# import mirai
from .. import rule as rule_model
from .. import entities
from ....core import entities as core_entities
+from ....platform.types import message as platform_message
@rule_model.rule_class("prefix")
@@ -11,7 +12,7 @@ class PrefixRule(rule_model.GroupRespondRule):
async def match(
self,
message_text: str,
- message_chain: mirai.MessageChain,
+ message_chain: platform_message.MessageChain,
rule_dict: dict,
query: core_entities.Query
) -> entities.RuleJudgeResult:
@@ -22,7 +23,7 @@ async def match(
# 查找第一个plain元素
for me in message_chain:
- if isinstance(me, mirai.Plain):
+ if isinstance(me, platform_message.Plain):
me.text = me.text[len(prefix):]
return entities.RuleJudgeResult(
diff --git a/pkg/pipeline/resprule/rules/random.py b/pkg/pipeline/resprule/rules/random.py
index 80acf6a5..bf8603a9 100644
--- a/pkg/pipeline/resprule/rules/random.py
+++ b/pkg/pipeline/resprule/rules/random.py
@@ -1,10 +1,11 @@
import random
-import mirai
+# import mirai
from .. import rule as rule_model
from .. import entities
from ....core import entities as core_entities
+from ....platform.types import message as platform_message
@rule_model.rule_class("random")
@@ -13,7 +14,7 @@ class RandomRespRule(rule_model.GroupRespondRule):
async def match(
self,
message_text: str,
- message_chain: mirai.MessageChain,
+ message_chain: platform_message.MessageChain,
rule_dict: dict,
query: core_entities.Query
) -> entities.RuleJudgeResult:
diff --git a/pkg/pipeline/resprule/rules/regexp.py b/pkg/pipeline/resprule/rules/regexp.py
index aaa46449..a6a3ecd2 100644
--- a/pkg/pipeline/resprule/rules/regexp.py
+++ b/pkg/pipeline/resprule/rules/regexp.py
@@ -1,10 +1,11 @@
import re
-import mirai
+# import mirai
from .. import rule as rule_model
from .. import entities
from ....core import entities as core_entities
+from ....platform.types import message as platform_message
@rule_model.rule_class("regexp")
@@ -13,7 +14,7 @@ class RegExpRule(rule_model.GroupRespondRule):
async def match(
self,
message_text: str,
- message_chain: mirai.MessageChain,
+ message_chain: platform_message.MessageChain,
rule_dict: dict,
query: core_entities.Query
) -> entities.RuleJudgeResult:
diff --git a/pkg/pipeline/wrapper/wrapper.py b/pkg/pipeline/wrapper/wrapper.py
index e6ce99aa..0e093826 100644
--- a/pkg/pipeline/wrapper/wrapper.py
+++ b/pkg/pipeline/wrapper/wrapper.py
@@ -2,7 +2,7 @@
import typing
-import mirai
+# import mirai
from ...core import app, entities as core_entities
from .. import entities
@@ -10,6 +10,7 @@
from ...core import entities as core_entities
from ...config import manager as cfg_mgr
from ...plugin import events
+from ...platform.types import message as platform_message
@stage.stage_class("ResponseWrapper")
@@ -34,7 +35,7 @@ async def process(
"""
# 如果 resp_messages[-1] 已经是 MessageChain 了
- if isinstance(query.resp_messages[-1], mirai.MessageChain):
+ if isinstance(query.resp_messages[-1], platform_message.MessageChain):
query.resp_message_chain.append(query.resp_messages[-1])
yield entities.StageProcessResult(
@@ -96,7 +97,7 @@ async def process(
else:
if event_ctx.event.reply is not None:
- query.resp_message_chain.append(mirai.MessageChain(event_ctx.event.reply))
+ query.resp_message_chain.append(platform_message.MessageChain(event_ctx.event.reply))
else:
@@ -113,7 +114,7 @@ async def process(
reply_text = f'调用函数 {".".join(function_names)}...'
- query.resp_message_chain.append(mirai.MessageChain([mirai.Plain(reply_text)]))
+ query.resp_message_chain.append(platform_message.MessageChain([platform_message.Plain(reply_text)]))
if self.ap.platform_cfg.data['track-function-calls']:
@@ -139,11 +140,11 @@ async def process(
else:
if event_ctx.event.reply is not None:
- query.resp_message_chain.append(mirai.MessageChain(event_ctx.event.reply))
+ query.resp_message_chain.append(platform_message.MessageChain(event_ctx.event.reply))
else:
- query.resp_message_chain.append(mirai.MessageChain([mirai.Plain(reply_text)]))
+ query.resp_message_chain.append(platform_message.MessageChain([platform_message.Plain(reply_text)]))
yield entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
diff --git a/pkg/platform/adapter.py b/pkg/platform/adapter.py
index 4b159b79..c6d97b3a 100644
--- a/pkg/platform/adapter.py
+++ b/pkg/platform/adapter.py
@@ -4,9 +4,11 @@
import typing
import abc
-import mirai
+# import mirai
from ..core import app
+from .types import message as platform_message
+from .types import events as platform_events
preregistered_adapters: list[typing.Type[MessageSourceAdapter]] = []
@@ -55,7 +57,7 @@ async def send_message(
self,
target_type: str,
target_id: str,
- message: mirai.MessageChain
+ message: platform_message.MessageChain
):
"""主动发送消息
@@ -68,8 +70,8 @@ async def send_message(
async def reply_message(
self,
- message_source: mirai.MessageEvent,
- message: mirai.MessageChain,
+ message_source: platform_events.MessageEvent,
+ message: platform_message.MessageChain,
quote_origin: bool = False
):
"""回复消息
@@ -87,8 +89,8 @@ async def is_muted(self, group_id: int) -> bool:
def register_listener(
self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, MessageSourceAdapter], None]
+ event_type: typing.Type[platform_message.Event],
+ callback: typing.Callable[[platform_message.Event, MessageSourceAdapter], None]
):
"""注册事件监听器
@@ -100,8 +102,8 @@ def register_listener(
def unregister_listener(
self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, MessageSourceAdapter], None]
+ event_type: typing.Type[platform_message.Event],
+ callback: typing.Callable[[platform_message.Event, MessageSourceAdapter], None]
):
"""注销事件监听器
@@ -127,7 +129,7 @@ async def kill(self) -> bool:
class MessageConverter:
"""消息链转换器基类"""
@staticmethod
- def yiri2target(message_chain: mirai.MessageChain):
+ def yiri2target(message_chain: platform_message.MessageChain):
"""将YiriMirai消息链转换为目标消息链
Args:
@@ -139,7 +141,7 @@ def yiri2target(message_chain: mirai.MessageChain):
raise NotImplementedError
@staticmethod
- def target2yiri(message_chain: typing.Any) -> mirai.MessageChain:
+ def target2yiri(message_chain: typing.Any) -> platform_message.MessageChain:
"""将目标消息链转换为YiriMirai消息链
Args:
@@ -155,7 +157,7 @@ class EventConverter:
"""事件转换器基类"""
@staticmethod
- def yiri2target(event: typing.Type[mirai.Event]):
+ def yiri2target(event: typing.Type[platform_message.Event]):
"""将YiriMirai事件转换为目标事件
Args:
@@ -167,7 +169,7 @@ def yiri2target(event: typing.Type[mirai.Event]):
raise NotImplementedError
@staticmethod
- def target2yiri(event: typing.Any) -> mirai.Event:
+ def target2yiri(event: typing.Any) -> platform_message.Event:
"""将目标事件的调用参数转换为YiriMirai的事件参数对象
Args:
diff --git a/pkg/platform/manager.py b/pkg/platform/manager.py
index b9696426..4e5131d5 100644
--- a/pkg/platform/manager.py
+++ b/pkg/platform/manager.py
@@ -6,13 +6,17 @@
import asyncio
import traceback
-from mirai import At, GroupMessage, MessageEvent, StrangerMessage, \
- FriendMessage, Image, MessageChain, Plain
-import mirai
+# from mirai import At, GroupMessage, MessageEvent, StrangerMessage, \
+# FriendMessage, Image, MessageChain, Plain
+# import mirai
from ..platform import adapter as msadapter
from ..core import app, entities as core_entities
from ..plugin import events
+from .types import message as platform_message
+from .types import events as platform_events
+from .types import entities as platform_entities
+
# 控制QQ消息输入输出的类
class PlatformManager:
@@ -32,7 +36,7 @@ async def initialize(self):
from .sources import yirimirai, nakuru, aiocqhttp, qqbotpy
- async def on_friend_message(event: FriendMessage, adapter: msadapter.MessageSourceAdapter):
+ async def on_friend_message(event: platform_events.FriendMessage, adapter: msadapter.MessageSourceAdapter):
event_ctx = await self.ap.plugin_mgr.emit_event(
event=events.PersonMessageReceived(
@@ -55,7 +59,7 @@ async def on_friend_message(event: FriendMessage, adapter: msadapter.MessageSour
adapter=adapter
)
- async def on_stranger_message(event: StrangerMessage, adapter: msadapter.MessageSourceAdapter):
+ async def on_stranger_message(event: platform_events.StrangerMessage, adapter: msadapter.MessageSourceAdapter):
event_ctx = await self.ap.plugin_mgr.emit_event(
event=events.PersonMessageReceived(
@@ -78,7 +82,7 @@ async def on_stranger_message(event: StrangerMessage, adapter: msadapter.Message
adapter=adapter
)
- async def on_group_message(event: GroupMessage, adapter: msadapter.MessageSourceAdapter):
+ async def on_group_message(event: platform_events.GroupMessage, adapter: msadapter.MessageSourceAdapter):
event_ctx = await self.ap.plugin_mgr.emit_event(
event=events.GroupMessageReceived(
@@ -127,16 +131,16 @@ async def on_group_message(event: GroupMessage, adapter: msadapter.MessageSource
if adapter_name == 'yiri-mirai':
adapter_inst.register_listener(
- StrangerMessage,
+ platform_events.StrangerMessage,
on_stranger_message
)
adapter_inst.register_listener(
- FriendMessage,
+ platform_events.FriendMessage,
on_friend_message
)
adapter_inst.register_listener(
- GroupMessage,
+ platform_events.GroupMessage,
on_group_message
)
@@ -146,13 +150,13 @@ async def on_group_message(event: GroupMessage, adapter: msadapter.MessageSource
if len(self.adapters) == 0:
self.ap.logger.warning('未运行平台适配器,请根据文档配置并启用平台适配器。')
- async def send(self, event: mirai.MessageEvent, msg: mirai.MessageChain, adapter: msadapter.MessageSourceAdapter):
+ async def send(self, event: platform_events.MessageEvent, msg: platform_message.MessageChain, adapter: msadapter.MessageSourceAdapter):
- if self.ap.platform_cfg.data['at-sender'] and isinstance(event, GroupMessage):
+ if self.ap.platform_cfg.data['at-sender'] and isinstance(event, platform_events.GroupMessage):
msg.insert(
0,
- At(
+ platform_message.At(
event.sender.id
)
)
diff --git a/pkg/platform/sources/aiocqhttp.py b/pkg/platform/sources/aiocqhttp.py
index ebdd56e5..d4278768 100644
--- a/pkg/platform/sources/aiocqhttp.py
+++ b/pkg/platform/sources/aiocqhttp.py
@@ -5,31 +5,34 @@
import time
import datetime
-import mirai
-import mirai.models.message as yiri_message
+# import mirai
+# import mirai.models.message as yiri_message
import aiocqhttp
from .. import adapter
from ...pipeline.longtext.strategies import forward
from ...core import app
+from ..types import message as platform_message
+from ..types import events as platform_events
+from ..types import entities as platform_entities
class AiocqhttpMessageConverter(adapter.MessageConverter):
@staticmethod
- def yiri2target(message_chain: mirai.MessageChain) -> typing.Tuple[list, int, datetime.datetime]:
+ def yiri2target(message_chain: platform_message.MessageChain) -> typing.Tuple[list, int, datetime.datetime]:
msg_list = aiocqhttp.Message()
msg_id = 0
msg_time = None
for msg in message_chain:
- if type(msg) is mirai.Plain:
+ if type(msg) is platform_message.Plain:
msg_list.append(aiocqhttp.MessageSegment.text(msg.text))
- elif type(msg) is yiri_message.Source:
+ elif type(msg) is platform_message.Source:
msg_id = msg.id
msg_time = msg.time
- elif type(msg) is mirai.Image:
+ elif type(msg) is platform_message.Image:
arg = ''
if msg.base64:
arg = msg.base64
@@ -40,13 +43,11 @@ def yiri2target(message_chain: mirai.MessageChain) -> typing.Tuple[list, int, da
elif msg.path:
arg = msg.path
msg_list.append(aiocqhttp.MessageSegment.image(arg))
- elif type(msg) is mirai.At:
+ elif type(msg) is platform_message.At:
msg_list.append(aiocqhttp.MessageSegment.at(msg.target))
- elif type(msg) is mirai.AtAll:
+ elif type(msg) is platform_message.AtAll:
msg_list.append(aiocqhttp.MessageSegment.at("all"))
- elif type(msg) is mirai.Face:
- msg_list.append(aiocqhttp.MessageSegment.face(msg.face_id))
- elif type(msg) is mirai.Voice:
+ elif type(msg) is platform_message.Voice:
arg = ''
if msg.base64:
arg = msg.base64
@@ -74,25 +75,25 @@ def target2yiri(message: str, message_id: int = -1):
yiri_msg_list = []
yiri_msg_list.append(
- yiri_message.Source(id=message_id, time=datetime.datetime.now())
+ platform_message.Source(id=message_id, time=datetime.datetime.now())
)
for msg in message:
if msg.type == "at":
if msg.data["qq"] == "all":
- yiri_msg_list.append(yiri_message.AtAll())
+ yiri_msg_list.append(platform_message.AtAll())
else:
yiri_msg_list.append(
- yiri_message.At(
+ platform_message.At(
target=msg.data["qq"],
)
)
elif msg.type == "text":
- yiri_msg_list.append(yiri_message.Plain(text=msg.data["text"]))
+ yiri_msg_list.append(platform_message.Plain(text=msg.data["text"]))
elif msg.type == "image":
- yiri_msg_list.append(yiri_message.Image(url=msg.data["url"]))
+ yiri_msg_list.append(platform_message.Image(url=msg.data["url"]))
- chain = mirai.MessageChain(yiri_msg_list)
+ chain = platform_message.MessageChain(yiri_msg_list)
return chain
@@ -100,11 +101,11 @@ def target2yiri(message: str, message_id: int = -1):
class AiocqhttpEventConverter(adapter.EventConverter):
@staticmethod
- def yiri2target(event: mirai.Event, bot_account_id: int):
+ def yiri2target(event: platform_events.Event, bot_account_id: int):
msg, msg_id, msg_time = AiocqhttpMessageConverter.yiri2target(event.message_chain)
- if type(event) is mirai.GroupMessage:
+ if type(event) is platform_events.GroupMessage:
role = "member"
if event.sender.permission == "ADMINISTRATOR":
@@ -140,7 +141,7 @@ def yiri2target(event: mirai.Event, bot_account_id: int):
}
return aiocqhttp.Event.from_payload(payload)
- elif type(event) is mirai.FriendMessage:
+ elif type(event) is platform_events.FriendMessage:
payload = {
"post_type": "message",
@@ -177,15 +178,15 @@ def target2yiri(event: aiocqhttp.Event):
permission = "ADMINISTRATOR"
elif event.sender["role"] == "owner":
permission = "OWNER"
- converted_event = mirai.GroupMessage(
- sender=mirai.models.entities.GroupMember(
+ converted_event = platform_events.GroupMessage(
+ sender=platform_entities.GroupMember(
id=event.sender["user_id"], # message_seq 放哪?
member_name=event.sender["nickname"],
permission=permission,
- group=mirai.models.entities.Group(
+ group=platform_entities.Group(
id=event.group_id,
name=event.sender["nickname"],
- permission=mirai.models.entities.Permission.Member,
+ permission=platform_entities.Permission.Member,
),
special_title=event.sender["title"] if "title" in event.sender else "",
join_timestamp=0,
@@ -197,8 +198,8 @@ def target2yiri(event: aiocqhttp.Event):
)
return converted_event
elif event.message_type == "private":
- return mirai.FriendMessage(
- sender=mirai.models.entities.Friend(
+ return platform_events.FriendMessage(
+ sender=platform_entities.Friend(
id=event.sender["user_id"],
nickname=event.sender["nickname"],
remark="",
@@ -240,7 +241,7 @@ async def shutdown_trigger_placeholder():
self.bot = aiocqhttp.CQHttp()
async def send_message(
- self, target_type: str, target_id: str, message: mirai.MessageChain
+ self, target_type: str, target_id: str, message: platform_message.MessageChain
):
aiocq_msg = AiocqhttpMessageConverter.yiri2target(message)[0]
@@ -251,8 +252,8 @@ async def send_message(
async def reply_message(
self,
- message_source: mirai.MessageEvent,
- message: mirai.MessageChain,
+ message_source: platform_events.MessageEvent,
+ message: platform_message.MessageChain,
quote_origin: bool = False,
):
aiocq_event = AiocqhttpEventConverter.yiri2target(message_source, self.bot_account_id)
@@ -270,8 +271,8 @@ async def is_muted(self, group_id: int) -> bool:
def register_listener(
self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, adapter.MessageSourceAdapter], None],
+ event_type: typing.Type[platform_events.Event],
+ callback: typing.Callable[[platform_events.Event, adapter.MessageSourceAdapter], None],
):
async def on_message(event: aiocqhttp.Event):
self.bot_account_id = event.self_id
@@ -280,15 +281,15 @@ async def on_message(event: aiocqhttp.Event):
except:
traceback.print_exc()
- if event_type == mirai.GroupMessage:
+ if event_type == platform_events.GroupMessage:
self.bot.on_message("group")(on_message)
- elif event_type == mirai.FriendMessage:
+ elif event_type == platform_events.FriendMessage:
self.bot.on_message("private")(on_message)
def unregister_listener(
self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, adapter.MessageSourceAdapter], None],
+ event_type: typing.Type[platform_events.Event],
+ callback: typing.Callable[[platform_events.Event, adapter.MessageSourceAdapter], None],
):
return super().unregister_listener(event_type, callback)
diff --git a/pkg/platform/sources/nakuru.py b/pkg/platform/sources/nakuru.py
index 94c29812..5c05f9d4 100644
--- a/pkg/platform/sources/nakuru.py
+++ b/pkg/platform/sources/nakuru.py
@@ -6,26 +6,29 @@
import traceback
import logging
-import mirai
+# import mirai
import nakuru
import nakuru.entities.components as nkc
from .. import adapter as adapter_model
from ...pipeline.longtext.strategies import forward
+from ...platform.types import message as platform_message
+from ...platform.types import entities as platform_entities
+from ...platform.types import events as platform_events
class NakuruProjectMessageConverter(adapter_model.MessageConverter):
"""消息转换器"""
@staticmethod
- def yiri2target(message_chain: mirai.MessageChain) -> list:
+ def yiri2target(message_chain: platform_message.MessageChain) -> list:
msg_list = []
- if type(message_chain) is mirai.MessageChain:
+ if type(message_chain) is platform_message.MessageChain:
msg_list = message_chain.__root__
elif type(message_chain) is list:
msg_list = message_chain
elif type(message_chain) is str:
- msg_list = [mirai.Plain(message_chain)]
+ msg_list = [platform_message.Plain(message_chain)]
else:
raise Exception("Unknown message type: " + str(message_chain) + str(type(message_chain)))
@@ -33,22 +36,20 @@ def yiri2target(message_chain: mirai.MessageChain) -> list:
# 遍历并转换
for component in msg_list:
- if type(component) is mirai.Plain:
+ if type(component) is platform_message.Plain:
nakuru_msg_list.append(nkc.Plain(component.text, False))
- elif type(component) is mirai.Image:
+ elif type(component) is platform_message.Image:
if component.url is not None:
nakuru_msg_list.append(nkc.Image.fromURL(component.url))
elif component.base64 is not None:
nakuru_msg_list.append(nkc.Image.fromBase64(component.base64))
elif component.path is not None:
nakuru_msg_list.append(nkc.Image.fromFileSystem(component.path))
- elif type(component) is mirai.Face:
- nakuru_msg_list.append(nkc.Face(id=component.face_id))
- elif type(component) is mirai.At:
+ elif type(component) is platform_message.At:
nakuru_msg_list.append(nkc.At(qq=component.target))
- elif type(component) is mirai.AtAll:
+ elif type(component) is platform_message.AtAll:
nakuru_msg_list.append(nkc.AtAll())
- elif type(component) is mirai.Voice:
+ elif type(component) is platform_message.Voice:
if component.url is not None:
nakuru_msg_list.append(nkc.Record.fromURL(component.url))
elif component.path is not None:
@@ -80,49 +81,47 @@ def yiri2target(message_chain: mirai.MessageChain) -> list:
return nakuru_msg_list
@staticmethod
- def target2yiri(message_chain: typing.Any, message_id: int = -1) -> mirai.MessageChain:
+ def target2yiri(message_chain: typing.Any, message_id: int = -1) -> platform_message.MessageChain:
"""将Yiri的消息链转换为YiriMirai的消息链"""
assert type(message_chain) is list
yiri_msg_list = []
import datetime
# 添加Source组件以标记message_id等信息
- yiri_msg_list.append(mirai.models.message.Source(id=message_id, time=datetime.datetime.now()))
+ yiri_msg_list.append(platform_message.Source(id=message_id, time=datetime.datetime.now()))
for component in message_chain:
if type(component) is nkc.Plain:
- yiri_msg_list.append(mirai.Plain(text=component.text))
+ yiri_msg_list.append(platform_message.Plain(text=component.text))
elif type(component) is nkc.Image:
- yiri_msg_list.append(mirai.Image(url=component.url))
- elif type(component) is nkc.Face:
- yiri_msg_list.append(mirai.Face(face_id=component.id))
+ yiri_msg_list.append(platform_message.Image(url=component.url))
elif type(component) is nkc.At:
- yiri_msg_list.append(mirai.At(target=component.qq))
+ yiri_msg_list.append(platform_message.At(target=component.qq))
elif type(component) is nkc.AtAll:
- yiri_msg_list.append(mirai.AtAll())
+ yiri_msg_list.append(platform_message.AtAll())
else:
pass
# logging.debug("转换后的消息链: " + str(yiri_msg_list))
- chain = mirai.MessageChain(yiri_msg_list)
+ chain = platform_message.MessageChain(yiri_msg_list)
return chain
class NakuruProjectEventConverter(adapter_model.EventConverter):
"""事件转换器"""
@staticmethod
- def yiri2target(event: typing.Type[mirai.Event]):
- if event is mirai.GroupMessage:
+ def yiri2target(event: typing.Type[platform_events.Event]):
+ if event is platform_events.GroupMessage:
return nakuru.GroupMessage
- elif event is mirai.FriendMessage:
+ elif event is platform_events.FriendMessage:
return nakuru.FriendMessage
else:
raise Exception("未支持转换的事件类型: " + str(event))
@staticmethod
- def target2yiri(event: typing.Any) -> mirai.Event:
+ def target2yiri(event: typing.Any) -> platform_events.Event:
yiri_chain = NakuruProjectMessageConverter.target2yiri(event.message, event.message_id)
if type(event) is nakuru.FriendMessage: # 私聊消息事件
- return mirai.FriendMessage(
- sender=mirai.models.entities.Friend(
+ return platform_events.FriendMessage(
+ sender=platform_entities.Friend(
id=event.sender.user_id,
nickname=event.sender.nickname,
remark=event.sender.nickname
@@ -138,16 +137,15 @@ def target2yiri(event: typing.Any) -> mirai.Event:
elif event.sender.role == "owner":
permission = "OWNER"
- import mirai.models.entities as entities
- return mirai.GroupMessage(
- sender=mirai.models.entities.GroupMember(
+ return platform_events.GroupMessage(
+ sender=platform_entities.GroupMember(
id=event.sender.user_id,
member_name=event.sender.nickname,
permission=permission,
- group=mirai.models.entities.Group(
+ group=platform_entities.Group(
id=event.group_id,
name=event.sender.nickname,
- permission=entities.Permission.Member
+ permission=platform_entities.Permission.Member
),
special_title=event.sender.title,
join_timestamp=0,
@@ -189,7 +187,7 @@ async def send_message(
self,
target_type: str,
target_id: str,
- message: typing.Union[mirai.MessageChain, list],
+ message: typing.Union[platform_message.MessageChain, list],
converted: bool = False
):
task = None
@@ -222,8 +220,8 @@ async def send_message(
async def reply_message(
self,
- message_source: mirai.MessageEvent,
- message: mirai.MessageChain,
+ message_source: platform_events.MessageEvent,
+ message: platform_message.MessageChain,
quote_origin: bool = False
):
message = self.message_converter.yiri2target(message)
@@ -233,14 +231,14 @@ async def reply_message(
id=message_source.message_chain.message_id,
)
)
- if type(message_source) is mirai.GroupMessage:
+ if type(message_source) is platform_events.GroupMessage:
await self.send_message(
"group",
message_source.sender.group.id,
message,
converted=True
)
- elif type(message_source) is mirai.FriendMessage:
+ elif type(message_source) is platform_events.FriendMessage:
await self.send_message(
"person",
message_source.sender.id,
@@ -258,8 +256,8 @@ def is_muted(self, group_id: int) -> bool:
def register_listener(
self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, adapter_model.MessageSourceAdapter], None]
+ event_type: typing.Type[platform_events.Event],
+ callback: typing.Callable[[platform_events.Event, adapter_model.MessageSourceAdapter], None]
):
try:
@@ -286,8 +284,8 @@ async def listener_wrapper(app: nakuru.CQHTTP, source: source_cls):
def unregister_listener(
self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, adapter_model.MessageSourceAdapter], None]
+ event_type: typing.Type[platform_events.Event],
+ callback: typing.Callable[[platform_events.Event, adapter_model.MessageSourceAdapter], None]
):
nakuru_event_name = self.event_converter.yiri2target(event_type).__name__
diff --git a/pkg/platform/sources/qqbotpy.py b/pkg/platform/sources/qqbotpy.py
index a79013c3..5a882c93 100644
--- a/pkg/platform/sources/qqbotpy.py
+++ b/pkg/platform/sources/qqbotpy.py
@@ -6,7 +6,7 @@
import re
import traceback
-import mirai
+# import mirai
import botpy
import botpy.message as botpy_message
import botpy.types.message as botpy_message_type
@@ -17,17 +17,21 @@
from ...pipeline.longtext.strategies import forward
from ...core import app
from ...config import manager as cfg_mgr
+from ...platform.types import entities as platform_entities
+from ...platform.types import events as platform_events
+from ...platform.types import message as platform_message
-class OfficialGroupMessage(mirai.GroupMessage):
+
+class OfficialGroupMessage(platform_events.GroupMessage):
pass
-class OfficialFriendMessage(mirai.FriendMessage):
+class OfficialFriendMessage(platform_events.FriendMessage):
pass
event_handler_mapping = {
- mirai.GroupMessage: ["on_at_message_create", "on_group_at_message_create"],
- mirai.FriendMessage: ["on_direct_message_create", "on_c2c_message_create"],
+ platform_events.GroupMessage: ["on_at_message_create", "on_group_at_message_create"],
+ platform_events.FriendMessage: ["on_direct_message_create", "on_c2c_message_create"],
}
@@ -123,16 +127,16 @@ class OfficialMessageConverter(adapter_model.MessageConverter):
"""QQ 官方消息转换器"""
@staticmethod
- def yiri2target(message_chain: mirai.MessageChain):
+ def yiri2target(message_chain: platform_message.MessageChain):
"""将 YiriMirai 的消息链转换为 QQ 官方消息"""
msg_list = []
- if type(message_chain) is mirai.MessageChain:
+ if type(message_chain) is platform_message.MessageChain:
msg_list = message_chain.__root__
elif type(message_chain) is list:
msg_list = message_chain
elif type(message_chain) is str:
- msg_list = [mirai.Plain(text=message_chain)]
+ msg_list = [platform_message.Plain(text=message_chain)]
else:
raise Exception(
"Unknown message type: " + str(message_chain) + str(type(message_chain))
@@ -153,22 +157,22 @@ def yiri2target(message_chain: mirai.MessageChain):
# 遍历并转换
for component in msg_list:
- if type(component) is mirai.Plain:
+ if type(component) is platform_message.Plain:
offcial_messages.append({"type": "text", "content": component.text})
- elif type(component) is mirai.Image:
+ elif type(component) is platform_message.Image:
if component.url is not None:
offcial_messages.append({"type": "image", "content": component.url})
elif component.path is not None:
offcial_messages.append(
{"type": "file_image", "content": component.path}
)
- elif type(component) is mirai.At:
+ elif type(component) is platform_message.At:
offcial_messages.append({"type": "at", "content": ""})
- elif type(component) is mirai.AtAll:
+ elif type(component) is platform_message.AtAll:
print(
"上层组件要求发送 AtAll 消息,但 QQ 官方 API 不支持此消息类型,忽略此消息。"
)
- elif type(component) is mirai.Voice:
+ elif type(component) is platform_message.Voice:
print(
"上层组件要求发送 Voice 消息,但 QQ 官方 API 不支持此消息类型,忽略此消息。"
)
@@ -197,29 +201,29 @@ def extract_message_chain_from_obj(
message: typing.Union[botpy_message.Message, botpy_message.DirectMessage, botpy_message.GroupMessage, botpy_message.C2CMessage],
message_id: str = None,
bot_account_id: int = 0,
- ) -> mirai.MessageChain:
+ ) -> platform_message.MessageChain:
yiri_msg_list = []
# 存id
yiri_msg_list.append(
- mirai.models.message.Source(
+ platform_message.Source(
id=save_msg_id(message_id), time=datetime.datetime.now()
)
)
if type(message) not in [botpy_message.DirectMessage, botpy_message.C2CMessage]:
- yiri_msg_list.append(mirai.At(target=bot_account_id))
+ yiri_msg_list.append(platform_message.At(target=bot_account_id))
if hasattr(message, "mentions"):
for mention in message.mentions:
if mention.bot:
continue
- yiri_msg_list.append(mirai.At(target=mention.id))
+ yiri_msg_list.append(platform_message.At(target=mention.id))
for attachment in message.attachments:
if attachment.content_type.startswith("image"):
- yiri_msg_list.append(mirai.Image(url=attachment.url))
+ yiri_msg_list.append(platform_message.Image(url=attachment.url))
else:
logging.warning(
"不支持的附件类型:" + attachment.content_type + ",忽略此附件。"
@@ -227,9 +231,9 @@ def extract_message_chain_from_obj(
content = re.sub(r"<@!\d+>", "", str(message.content))
if content.strip() != "":
- yiri_msg_list.append(mirai.Plain(text=content))
+ yiri_msg_list.append(platform_message.Plain(text=content))
- chain = mirai.MessageChain(yiri_msg_list)
+ chain = platform_message.MessageChain(yiri_msg_list)
return chain
@@ -244,10 +248,10 @@ def __init__(self, member_openid_mapping: OpenIDMapping[str, int], group_openid_
self.member_openid_mapping = member_openid_mapping
self.group_openid_mapping = group_openid_mapping
- def yiri2target(self, event: typing.Type[mirai.Event]):
- if event == mirai.GroupMessage:
+ def yiri2target(self, event: typing.Type[platform_events.Event]):
+ if event == platform_events.GroupMessage:
return botpy_message.Message
- elif event == mirai.FriendMessage:
+ elif event == platform_events.FriendMessage:
return botpy_message.DirectMessage
else:
raise Exception(
@@ -257,8 +261,7 @@ def yiri2target(self, event: typing.Type[mirai.Event]):
def target2yiri(
self,
event: typing.Union[botpy_message.Message, botpy_message.DirectMessage, botpy_message.GroupMessage, botpy_message.C2CMessage],
- ) -> mirai.Event:
- import mirai.models.entities as mirai_entities
+ ) -> platform_events.Event:
if type(event) == botpy_message.Message: # 频道内,转群聊事件
permission = "MEMBER"
@@ -268,15 +271,15 @@ def target2yiri(
elif "4" in event.member.roles:
permission = "OWNER"
- return mirai.GroupMessage(
- sender=mirai_entities.GroupMember(
+ return platform_events.GroupMessage(
+ sender=platform_entities.GroupMember(
id=event.author.id,
member_name=event.author.username,
permission=permission,
- group=mirai_entities.Group(
+ group=platform_entities.Group(
id=event.channel_id,
name=event.author.username,
- permission=mirai_entities.Permission.Member,
+ permission=platform_entities.Permission.Member,
),
special_title="",
join_timestamp=int(
@@ -297,8 +300,8 @@ def target2yiri(
),
)
elif type(event) == botpy_message.DirectMessage: # 频道私聊,转私聊事件
- return mirai.FriendMessage(
- sender=mirai_entities.Friend(
+ return platform_events.FriendMessage(
+ sender=platform_entities.Friend(
id=event.guild_id,
nickname=event.author.username,
remark=event.author.username,
@@ -317,14 +320,14 @@ def target2yiri(
replacing_member_id = self.member_openid_mapping.save_openid(event.author.member_openid)
return OfficialGroupMessage(
- sender=mirai_entities.GroupMember(
+ sender=platform_entities.GroupMember(
id=replacing_member_id,
member_name=replacing_member_id,
permission="MEMBER",
- group=mirai_entities.Group(
+ group=platform_entities.Group(
id=self.group_openid_mapping.save_openid(event.group_openid),
name=replacing_member_id,
- permission=mirai_entities.Permission.Member,
+ permission=platform_entities.Permission.Member,
),
special_title="",
join_timestamp=int(0),
@@ -345,7 +348,7 @@ def target2yiri(
user_id_alter = self.member_openid_mapping.save_openid(event.author.user_openid) # 实测这里的user_openid与group的member_openid是一样的
return OfficialFriendMessage(
- sender=mirai_entities.Friend(
+ sender=platform_entities.Friend(
id=user_id_alter,
nickname=user_id_alter,
remark=user_id_alter,
@@ -410,7 +413,7 @@ def __init__(self, cfg: dict, ap: app.Application):
self.bot = botpy.Client(intents=intents)
async def send_message(
- self, target_type: str, target_id: str, message: mirai.MessageChain
+ self, target_type: str, target_id: str, message: platform_message.MessageChain
):
message_list = self.message_converter.yiri2target(message)
@@ -437,8 +440,8 @@ async def send_message(
async def reply_message(
self,
- message_source: mirai.MessageEvent,
- message: mirai.MessageChain,
+ message_source: platform_events.MessageEvent,
+ message: platform_message.MessageChain,
quote_origin: bool = False,
):
@@ -463,13 +466,13 @@ async def reply_message(
]
)
- if type(message_source) == mirai.GroupMessage:
+ if type(message_source) == platform_events.GroupMessage:
args["channel_id"] = str(message_source.sender.group.id)
args["msg_id"] = cached_message_ids[
str(message_source.message_chain.message_id)
]
await self.bot.api.post_message(**args)
- elif type(message_source) == mirai.FriendMessage:
+ elif type(message_source) == platform_events.FriendMessage:
args["guild_id"] = str(message_source.sender.id)
args["msg_id"] = cached_message_ids[
str(message_source.message_chain.message_id)
@@ -534,9 +537,9 @@ async def is_muted(self, group_id: int) -> bool:
def register_listener(
self,
- event_type: typing.Type[mirai.Event],
+ event_type: typing.Type[platform_events.Event],
callback: typing.Callable[
- [mirai.Event, adapter_model.MessageSourceAdapter], None
+ [platform_events.Event, adapter_model.MessageSourceAdapter], None
],
):
@@ -560,9 +563,9 @@ async def wrapper(
def unregister_listener(
self,
- event_type: typing.Type[mirai.Event],
+ event_type: typing.Type[platform_events.Event],
callback: typing.Callable[
- [mirai.Event, adapter_model.MessageSourceAdapter], None
+ [platform_events.Event, adapter_model.MessageSourceAdapter], None
],
):
delattr(self.bot, event_handler_mapping[event_type])
diff --git a/pkg/platform/sources/yirimirai.py b/pkg/platform/sources/yirimirai.py
index 7768dcf0..4082e90a 100644
--- a/pkg/platform/sources/yirimirai.py
+++ b/pkg/platform/sources/yirimirai.py
@@ -1,124 +1,124 @@
-import asyncio
-import typing
+# import asyncio
+# import typing
-import mirai
-import mirai.models.bus
-from mirai.bot import MiraiRunner
+# import mirai
+# import mirai.models.bus
+# from mirai.bot import MiraiRunner
-from .. import adapter as adapter_model
-from ...core import app
+# from .. import adapter as adapter_model
+# from ...core import app
-@adapter_model.adapter_class("yiri-mirai")
-class YiriMiraiAdapter(adapter_model.MessageSourceAdapter):
- """YiriMirai适配器"""
- bot: mirai.Mirai
+# @adapter_model.adapter_class("yiri-mirai")
+# class YiriMiraiAdapter(adapter_model.MessageSourceAdapter):
+# """YiriMirai适配器"""
+# bot: mirai.Mirai
- def __init__(self, config: dict, ap: app.Application):
- """初始化YiriMirai的对象"""
- self.ap = ap
- self.config = config
- if 'adapter' not in config or \
- config['adapter'] == 'WebSocketAdapter':
- self.bot = mirai.Mirai(
- qq=config['qq'],
- adapter=mirai.WebSocketAdapter(
- host=config['host'],
- port=config['port'],
- verify_key=config['verifyKey']
- )
- )
- elif config['adapter'] == 'HTTPAdapter':
- self.bot = mirai.Mirai(
- qq=config['qq'],
- adapter=mirai.HTTPAdapter(
- host=config['host'],
- port=config['port'],
- verify_key=config['verifyKey']
- )
- )
- else:
- raise Exception('Unknown adapter for YiriMirai: ' + config['adapter'])
+# def __init__(self, config: dict, ap: app.Application):
+# """初始化YiriMirai的对象"""
+# self.ap = ap
+# self.config = config
+# if 'adapter' not in config or \
+# config['adapter'] == 'WebSocketAdapter':
+# self.bot = mirai.Mirai(
+# qq=config['qq'],
+# adapter=mirai.WebSocketAdapter(
+# host=config['host'],
+# port=config['port'],
+# verify_key=config['verifyKey']
+# )
+# )
+# elif config['adapter'] == 'HTTPAdapter':
+# self.bot = mirai.Mirai(
+# qq=config['qq'],
+# adapter=mirai.HTTPAdapter(
+# host=config['host'],
+# port=config['port'],
+# verify_key=config['verifyKey']
+# )
+# )
+# else:
+# raise Exception('Unknown adapter for YiriMirai: ' + config['adapter'])
- async def send_message(
- self,
- target_type: str,
- target_id: str,
- message: mirai.MessageChain
- ):
- """发送消息
+# async def send_message(
+# self,
+# target_type: str,
+# target_id: str,
+# message: mirai.MessageChain
+# ):
+# """发送消息
- Args:
- target_type (str): 目标类型,`person`或`group`
- target_id (str): 目标ID
- message (mirai.MessageChain): YiriMirai库的消息链
- """
- task = None
- if target_type == 'person':
- task = self.bot.send_friend_message(int(target_id), message)
- elif target_type == 'group':
- task = self.bot.send_group_message(int(target_id), message)
- else:
- raise Exception('Unknown target type: ' + target_type)
+# Args:
+# target_type (str): 目标类型,`person`或`group`
+# target_id (str): 目标ID
+# message (mirai.MessageChain): YiriMirai库的消息链
+# """
+# task = None
+# if target_type == 'person':
+# task = self.bot.send_friend_message(int(target_id), message)
+# elif target_type == 'group':
+# task = self.bot.send_group_message(int(target_id), message)
+# else:
+# raise Exception('Unknown target type: ' + target_type)
- await task
+# await task
- async def reply_message(
- self,
- message_source: mirai.MessageEvent,
- message: mirai.MessageChain,
- quote_origin: bool = False
- ):
- """回复消息
+# async def reply_message(
+# self,
+# message_source: mirai.MessageEvent,
+# message: mirai.MessageChain,
+# quote_origin: bool = False
+# ):
+# """回复消息
- Args:
- message_source (mirai.MessageEvent): YiriMirai消息源事件
- message (mirai.MessageChain): YiriMirai库的消息链
- quote_origin (bool, optional): 是否引用原消息. Defaults to False.
- """
- await self.bot.send(message_source, message, quote_origin)
+# Args:
+# message_source (mirai.MessageEvent): YiriMirai消息源事件
+# message (mirai.MessageChain): YiriMirai库的消息链
+# quote_origin (bool, optional): 是否引用原消息. Defaults to False.
+# """
+# await self.bot.send(message_source, message, quote_origin)
- async def is_muted(self, group_id: int) -> bool:
- result = await self.bot.member_info(target=group_id, member_id=self.bot.qq).get()
- if result.mute_time_remaining > 0:
- return True
- return False
+# async def is_muted(self, group_id: int) -> bool:
+# result = await self.bot.member_info(target=group_id, member_id=self.bot.qq).get()
+# if result.mute_time_remaining > 0:
+# return True
+# return False
- def register_listener(
- self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, adapter_model.MessageSourceAdapter], None]
- ):
- """注册事件监听器
+# def register_listener(
+# self,
+# event_type: typing.Type[mirai.Event],
+# callback: typing.Callable[[mirai.Event, adapter_model.MessageSourceAdapter], None]
+# ):
+# """注册事件监听器
- Args:
- event_type (typing.Type[mirai.Event]): YiriMirai事件类型
- callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件
- """
- async def wrapper(event: mirai.Event):
- await callback(event, self)
- self.bot.on(event_type)(wrapper)
+# Args:
+# event_type (typing.Type[mirai.Event]): YiriMirai事件类型
+# callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件
+# """
+# async def wrapper(event: mirai.Event):
+# await callback(event, self)
+# self.bot.on(event_type)(wrapper)
- def unregister_listener(
- self,
- event_type: typing.Type[mirai.Event],
- callback: typing.Callable[[mirai.Event, adapter_model.MessageSourceAdapter], None]
- ):
- """注销事件监听器
+# def unregister_listener(
+# self,
+# event_type: typing.Type[mirai.Event],
+# callback: typing.Callable[[mirai.Event, adapter_model.MessageSourceAdapter], None]
+# ):
+# """注销事件监听器
- Args:
- event_type (typing.Type[mirai.Event]): YiriMirai事件类型
- callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件
- """
- assert isinstance(self.bot, mirai.Mirai)
- bus = self.bot.bus
- assert isinstance(bus, mirai.models.bus.ModelEventBus)
+# Args:
+# event_type (typing.Type[mirai.Event]): YiriMirai事件类型
+# callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件
+# """
+# assert isinstance(self.bot, mirai.Mirai)
+# bus = self.bot.bus
+# assert isinstance(bus, mirai.models.bus.ModelEventBus)
- bus.unsubscribe(event_type, callback)
+# bus.unsubscribe(event_type, callback)
- async def run_async(self):
- self.bot_account_id = self.bot.qq
- return await MiraiRunner(self.bot)._run()
+# async def run_async(self):
+# self.bot_account_id = self.bot.qq
+# return await MiraiRunner(self.bot)._run()
- async def kill(self) -> bool:
- return False
+# async def kill(self) -> bool:
+# return False
diff --git a/pkg/platform/types/__init__.py b/pkg/platform/types/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/platform/types/base.py b/pkg/platform/types/base.py
new file mode 100644
index 00000000..964e9c6f
--- /dev/null
+++ b/pkg/platform/types/base.py
@@ -0,0 +1,105 @@
+
+from typing import Dict, List, Type
+
+import pydantic.main as pdm
+from pydantic import BaseModel
+
+
+class PlatformMetaclass(pdm.ModelMetaclass):
+ """此类是 YiriMirai 中使用的 pydantic 模型的元类的基类。"""
+
+
+def to_camel(name: str) -> str:
+ """将下划线命名风格转换为小驼峰命名。"""
+ if name[:2] == '__': # 不处理双下划线开头的特殊命名。
+ return name
+ name_parts = name.split('_')
+ return ''.join(name_parts[:1] + [x.title() for x in name_parts[1:]])
+
+
+class PlatformBaseModel(BaseModel, metaclass=PlatformMetaclass):
+ """模型基类。
+
+ 启用了三项配置:
+ 1. 允许解析时传入额外的值,并将额外值保存在模型中。
+ 2. 允许通过别名访问字段。
+ 3. 自动生成小驼峰风格的别名,以符合 mirai-api-http 的命名。
+ """
+ def __init__(self, *args, **kwargs):
+ """"""
+ super().__init__(*args, **kwargs)
+
+ def __repr__(self) -> str:
+ return self.__class__.__name__ + '(' + ', '.join(
+ (f'{k}={repr(v)}' for k, v in self.__dict__.items() if v)
+ ) + ')'
+
+ class Config:
+ extra = 'allow'
+ allow_population_by_field_name = True
+ alias_generator = to_camel
+
+
+class PlatformIndexedMetaclass(PlatformMetaclass):
+ """可以通过子类名获取子类的类的元类。"""
+ __indexedbases__: List[Type['PlatformIndexedModel']] = []
+ __indexedmodel__ = None
+
+ def __new__(cls, name, bases, attrs, **kwargs):
+ new_cls = super().__new__(cls, name, bases, attrs, **kwargs)
+ # 第一类:MiraiIndexedModel
+ if name == 'PlatformIndexedModel':
+ cls.__indexedmodel__ = new_cls
+ new_cls.__indexes__ = {}
+ return new_cls
+ # 第二类:MiraiIndexedModel 的直接子类,这些是可以通过子类名获取子类的类。
+ if cls.__indexedmodel__ in bases:
+ cls.__indexedbases__.append(new_cls)
+ new_cls.__indexes__ = {}
+ return new_cls
+ # 第三类:MiraiIndexedModel 的直接子类的子类,这些添加到直接子类的索引中。
+ for base in cls.__indexedbases__:
+ if issubclass(new_cls, base):
+ base.__indexes__[name] = new_cls
+ return new_cls
+
+ def __getitem__(cls, name):
+ return cls.get_subtype(name)
+
+
+class PlatformIndexedModel(PlatformBaseModel, metaclass=PlatformIndexedMetaclass):
+ """可以通过子类名获取子类的类。"""
+ __indexes__: Dict[str, Type['PlatformIndexedModel']]
+
+ @classmethod
+ def get_subtype(cls, name: str) -> Type['PlatformIndexedModel']:
+ """根据类名称,获取相应的子类类型。
+
+ Args:
+ name: 类名称。
+
+ Returns:
+ Type['MiraiIndexedModel']: 子类类型。
+ """
+ try:
+ type_ = cls.__indexes__.get(name)
+ if not (type_ and issubclass(type_, cls)):
+ raise ValueError(f'`{name}` 不是 `{cls.__name__}` 的子类!')
+ return type_
+ except AttributeError as e:
+ raise ValueError(f'`{name}` 不是 `{cls.__name__}` 的子类!') from None
+
+ @classmethod
+ def parse_subtype(cls, obj: dict) -> 'PlatformIndexedModel':
+ """通过字典,构造对应的模型对象。
+
+ Args:
+ obj: 一个字典,包含了模型对象的属性。
+
+ Returns:
+ MiraiIndexedModel: 构造的对象。
+ """
+ if cls in PlatformIndexedModel.__subclasses__():
+ ModelType = cls.get_subtype(obj['type'])
+ return ModelType.parse_obj(obj)
+ return super().parse_obj(obj)
diff --git a/pkg/platform/types/entities.py b/pkg/platform/types/entities.py
new file mode 100644
index 00000000..8077bd15
--- /dev/null
+++ b/pkg/platform/types/entities.py
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+"""
+此模块提供实体和配置项模型。
+"""
+import abc
+from datetime import datetime
+from enum import Enum
+import typing
+
+import pydantic
+
+
+class Entity(pydantic.BaseModel):
+ """实体,表示一个用户或群。"""
+ id: int
+ """QQ 号或群号。"""
+ @abc.abstractmethod
+ def get_avatar_url(self) -> str:
+ """头像图片链接。"""
+
+ @abc.abstractmethod
+ def get_name(self) -> str:
+ """名称。"""
+
+
+class Friend(Entity):
+ """好友。"""
+ id: int
+ """QQ 号。"""
+ nickname: typing.Optional[str]
+ """昵称。"""
+ remark: typing.Optional[str]
+ """备注。"""
+ def get_avatar_url(self) -> str:
+ return f'http://q4.qlogo.cn/g?b=qq&nk={self.id}&s=140'
+
+ def get_name(self) -> str:
+ return self.nickname or self.remark or ''
+
+
+class Permission(str, Enum):
+ """群成员身份权限。"""
+ Member = "MEMBER"
+ """成员。"""
+ Administrator = "ADMINISTRATOR"
+ """管理员。"""
+ Owner = "OWNER"
+ """群主。"""
+ def __repr__(self) -> str:
+ return repr(self.value)
+
+
+class Group(Entity):
+ """群。"""
+ id: int
+ """群号。"""
+ name: str
+ """群名称。"""
+ permission: Permission
+ """Bot 在群中的权限。"""
+ def get_avatar_url(self) -> str:
+ return f'https://p.qlogo.cn/gh/{self.id}/{self.id}/'
+
+ def get_name(self) -> str:
+ return self.name
+
+
+class GroupMember(Entity):
+ """群成员。"""
+ id: int
+ """QQ 号。"""
+ member_name: str
+ """群成员名称。"""
+ permission: Permission
+ """Bot 在群中的权限。"""
+ group: Group
+ """群。"""
+ special_title: str = ''
+ """群头衔。"""
+ join_timestamp: datetime = datetime.utcfromtimestamp(0)
+ """加入群的时间。"""
+ last_speak_timestamp: datetime = datetime.utcfromtimestamp(0)
+ """最后一次发言的时间。"""
+ mute_time_remaining: int = 0
+ """禁言剩余时间。"""
+ def get_avatar_url(self) -> str:
+ return f'http://q4.qlogo.cn/g?b=qq&nk={self.id}&s=140'
+
+ def get_name(self) -> str:
+ return self.member_name
+
+
+class Client(Entity):
+ """来自其他客户端的用户。"""
+ id: int
+ """识别 id。"""
+ platform: str
+ """来源平台。"""
+ def get_avatar_url(self) -> str:
+ raise NotImplementedError
+
+ def get_name(self) -> str:
+ return self.platform
+
+
+class Subject(pydantic.BaseModel):
+ """另一种实体类型表示。"""
+ id: int
+ """QQ 号或群号。"""
+ kind: typing.Literal['Friend', 'Group', 'Stranger']
+ """类型。"""
+
+
+class Config(pydantic.BaseModel):
+ """配置项类型。"""
+ def modify(self, **kwargs) -> 'Config':
+ """修改部分设置。"""
+ for k, v in kwargs.items():
+ if k in self.__fields__:
+ setattr(self, k, v)
+ else:
+ raise ValueError(f'未知配置项: {k}')
+ return self
+
+
+class GroupConfigModel(Config):
+ """群配置。"""
+ name: str
+ """群名称。"""
+ confess_talk: bool
+ """是否允许坦白说。"""
+ allow_member_invite: bool
+ """是否允许成员邀请好友入群。"""
+ auto_approve: bool
+ """是否开启自动审批入群。"""
+ anonymous_chat: bool
+ """是否开启匿名聊天。"""
+ announcement: str = ''
+ """群公告。"""
+
+
+class MemberInfoModel(Config, GroupMember):
+ """群成员信息。"""
diff --git a/pkg/platform/types/events.py b/pkg/platform/types/events.py
new file mode 100644
index 00000000..1b008cf4
--- /dev/null
+++ b/pkg/platform/types/events.py
@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+"""
+此模块提供事件模型。
+"""
+from datetime import datetime
+from enum import Enum
+import typing
+
+import pydantic
+
+from . import entities as platform_entities
+from . import message as platform_message
+
+
+class Event(pydantic.BaseModel):
+ """事件基类。
+
+ Args:
+ type: 事件名。
+ """
+ type: str
+ """事件名。"""
+ def __repr__(self):
+ return self.__class__.__name__ + '(' + ', '.join(
+ (
+ f'{k}={repr(v)}'
+ for k, v in self.__dict__.items() if k != 'type' and v
+ )
+ ) + ')'
+
+ @classmethod
+ def parse_subtype(cls, obj: dict) -> 'Event':
+ try:
+ return typing.cast(Event, super().parse_subtype(obj))
+ except ValueError:
+ return Event(type=obj['type'])
+
+ @classmethod
+ def get_subtype(cls, name: str) -> typing.Type['Event']:
+ try:
+ return typing.cast(typing.Type[Event], super().get_subtype(name))
+ except ValueError:
+ return Event
+
+
+###############################
+# Bot Event
+class BotEvent(Event):
+ """Bot 自身事件。
+
+ Args:
+ type: 事件名。
+ qq: Bot 的 QQ 号。
+ """
+ type: str
+ """事件名。"""
+ qq: int
+ """Bot 的 QQ 号。"""
+
+
+###############################
+# Message Event
+class MessageEvent(Event):
+ """消息事件。
+
+ Args:
+ type: 事件名。
+ message_chain: 消息内容。
+ """
+ type: str
+ """事件名。"""
+ message_chain: platform_message.MessageChain
+ """消息内容。"""
+
+
+class FriendMessage(MessageEvent):
+ """好友消息。
+
+ Args:
+ type: 事件名。
+ sender: 发送消息的好友。
+ message_chain: 消息内容。
+ """
+ type: str = 'FriendMessage'
+ """事件名。"""
+ sender: platform_entities.Friend
+ """发送消息的好友。"""
+ message_chain: platform_message.MessageChain
+ """消息内容。"""
+
+
+class GroupMessage(MessageEvent):
+ """群消息。
+
+ Args:
+ type: 事件名。
+ sender: 发送消息的群成员。
+ message_chain: 消息内容。
+ """
+ type: str = 'GroupMessage'
+ """事件名。"""
+ sender: platform_entities.GroupMember
+ """发送消息的群成员。"""
+ message_chain: platform_message.MessageChain
+ """消息内容。"""
+ @property
+ def group(self) -> platform_entities.Group:
+ return self.sender.group
+
+
+class StrangerMessage(MessageEvent):
+ """陌生人消息。
+
+ Args:
+ type: 事件名。
+ sender: 发送消息的人。
+ message_chain: 消息内容。
+ """
+ type: str = 'StrangerMessage'
+ """事件名。"""
+ sender: platform_entities.Friend
+ """发送消息的人。"""
+ message_chain: platform_message.MessageChain
+ """消息内容。"""
diff --git a/pkg/platform/types/message.py b/pkg/platform/types/message.py
new file mode 100644
index 00000000..00e420b1
--- /dev/null
+++ b/pkg/platform/types/message.py
@@ -0,0 +1,826 @@
+import itertools
+import logging
+from datetime import datetime
+from enum import Enum
+from pathlib import Path
+import typing
+
+import pydantic
+import pydantic.main
+
+from . import entities as platform_entities
+from .base import PlatformBaseModel, PlatformIndexedMetaclass, PlatformIndexedModel
+
+
+logger = logging.getLogger(__name__)
+
+
+class MessageComponentMetaclass(PlatformIndexedMetaclass):
+ """消息组件元类。"""
+ __message_component__ = None
+
+ def __new__(cls, name, bases, attrs, **kwargs):
+ new_cls = super().__new__(cls, name, bases, attrs, **kwargs)
+ if name == 'MessageComponent':
+ cls.__message_component__ = new_cls
+
+ if not cls.__message_component__:
+ return new_cls
+
+ for base in bases:
+ if issubclass(base, cls.__message_component__):
+ # 获取字段名
+ if hasattr(new_cls, '__fields__'):
+ # 忽略 type 字段
+ new_cls.__parameter_names__ = list(new_cls.__fields__)[1:]
+ else:
+ new_cls.__parameter_names__ = []
+ break
+
+ return new_cls
+
+
+class MessageComponent(PlatformIndexedModel, metaclass=MessageComponentMetaclass):
+ """消息组件。"""
+ type: str
+ """消息组件类型。"""
+ def __str__(self):
+ return ''
+
+ def __repr__(self):
+ return self.__class__.__name__ + '(' + ', '.join(
+ (
+ f'{k}={repr(v)}'
+ for k, v in self.__dict__.items() if k != 'type' and v
+ )
+ ) + ')'
+
+ def __init__(self, *args, **kwargs):
+ # 解析参数列表,将位置参数转化为具名参数
+ parameter_names = self.__parameter_names__
+ if len(args) > len(parameter_names):
+ raise TypeError(
+ f'`{self.type}`需要{len(parameter_names)}个参数,但传入了{len(args)}个。'
+ )
+ for name, value in zip(parameter_names, args):
+ if name in kwargs:
+ raise TypeError(f'在 `{self.type}` 中,具名参数 `{name}` 与位置参数重复。')
+ kwargs[name] = value
+
+ super().__init__(**kwargs)
+
+
+TMessageComponent = typing.TypeVar('TMessageComponent', bound=MessageComponent)
+
+
+class MessageChain(PlatformBaseModel):
+ """消息链。
+
+ 一个构造消息链的例子:
+ ```py
+ message_chain = MessageChain([
+ AtAll(),
+ Plain("Hello World!"),
+ ])
+ ```
+
+ `Plain` 可以省略。
+ ```py
+ message_chain = MessageChain([
+ AtAll(),
+ "Hello World!",
+ ])
+ ```
+
+ 在调用 API 时,参数中需要 MessageChain 的,也可以使用 `List[MessageComponent]` 代替。
+ 例如,以下两种写法是等价的:
+ ```py
+ await bot.send_friend_message(12345678, [
+ Plain("Hello World!")
+ ])
+ ```
+ ```py
+ await bot.send_friend_message(12345678, MessageChain([
+ Plain("Hello World!")
+ ]))
+ ```
+
+ 可以使用 `in` 运算检查消息链中:
+ 1. 是否有某个消息组件。
+ 2. 是否有某个类型的消息组件。
+
+ ```py
+ if AtAll in message_chain:
+ print('AtAll')
+
+ if At(bot.qq) in message_chain:
+ print('At Me')
+ ```
+
+ 消息链对索引操作进行了增强。以消息组件类型为索引,获取消息链中的全部该类型的消息组件。
+ ```py
+ plain_list = message_chain[Plain]
+ '[Plain("Hello World!")]'
+ ```
+
+ 可以用加号连接两个消息链。
+ ```py
+ MessageChain(['Hello World!']) + MessageChain(['Goodbye World!'])
+ # 返回 MessageChain([Plain("Hello World!"), Plain("Goodbye World!")])
+ ```
+
+ """
+ __root__: typing.List[MessageComponent]
+
+ @staticmethod
+ def _parse_message_chain(msg_chain: typing.Iterable):
+ result = []
+ for msg in msg_chain:
+ if isinstance(msg, dict):
+ result.append(MessageComponent.parse_subtype(msg))
+ elif isinstance(msg, MessageComponent):
+ result.append(msg)
+ elif isinstance(msg, str):
+ result.append(Plain(msg))
+ else:
+ raise TypeError(
+ f"消息链中元素需为 dict 或 str 或 MessageComponent,当前类型:{type(msg)}"
+ )
+ return result
+
+ @pydantic.validator('__root__', always=True, pre=True)
+ def _parse_component(cls, msg_chain):
+ if isinstance(msg_chain, (str, MessageComponent)):
+ msg_chain = [msg_chain]
+ if not msg_chain:
+ msg_chain = []
+ return cls._parse_message_chain(msg_chain)
+
+ @classmethod
+ def parse_obj(cls, msg_chain: typing.Iterable):
+ """通过列表形式的消息链,构造对应的 `MessageChain` 对象。
+
+ Args:
+ msg_chain: 列表形式的消息链。
+ """
+ result = cls._parse_message_chain(msg_chain)
+ return cls(__root__=result)
+
+ def __init__(self, __root__: typing.Iterable[MessageComponent] = None):
+ super().__init__(__root__=__root__)
+
+ def __str__(self):
+ return "".join(str(component) for component in self.__root__)
+
+ def __repr__(self):
+ return f'{self.__class__.__name__}({self.__root__!r})'
+
+ def __iter__(self):
+ yield from self.__root__
+
+ def get_first(self,
+ t: typing.Type[TMessageComponent]) -> typing.Optional[TMessageComponent]:
+ """获取消息链中第一个符合类型的消息组件。"""
+ for component in self:
+ if isinstance(component, t):
+ return component
+ return None
+
+ @typing.overload
+ def __getitem__(self, index: int) -> MessageComponent:
+ ...
+
+ @typing.overload
+ def __getitem__(self, index: slice) -> typing.List[MessageComponent]:
+ ...
+
+ @typing.overload
+ def __getitem__(self,
+ index: typing.Type[TMessageComponent]) -> typing.List[TMessageComponent]:
+ ...
+
+ @typing.overload
+ def __getitem__(
+ self, index: typing.Tuple[typing.Type[TMessageComponent], int]
+ ) -> typing.List[TMessageComponent]:
+ ...
+
+ def __getitem__(
+ self, index: typing.Union[int, slice, typing.Type[TMessageComponent],
+ typing.Tuple[typing.Type[TMessageComponent], int]]
+ ) -> typing.Union[MessageComponent, typing.List[MessageComponent],
+ typing.List[TMessageComponent]]:
+ return self.get(index)
+
+ def __setitem__(
+ self, key: typing.Union[int, slice],
+ value: typing.Union[MessageComponent, str, typing.Iterable[typing.Union[MessageComponent,
+ str]]]
+ ):
+ if isinstance(value, str):
+ value = Plain(value)
+ if isinstance(value, typing.Iterable):
+ value = (Plain(c) if isinstance(c, str) else c for c in value)
+ self.__root__[key] = value # type: ignore
+
+ def __delitem__(self, key: typing.Union[int, slice]):
+ del self.__root__[key]
+
+ def __reversed__(self) -> typing.Iterable[MessageComponent]:
+ return reversed(self.__root__)
+
+ def has(
+ self, sub: typing.Union[MessageComponent, typing.Type[MessageComponent],
+ 'MessageChain', str]
+ ) -> bool:
+ """判断消息链中:
+ 1. 是否有某个消息组件。
+ 2. 是否有某个类型的消息组件。
+
+ Args:
+ sub (`Union[MessageComponent, Type[MessageComponent], 'MessageChain', str]`):
+ 若为 `MessageComponent`,则判断该组件是否在消息链中。
+ 若为 `Type[MessageComponent]`,则判断该组件类型是否在消息链中。
+
+ Returns:
+ bool: 是否找到。
+ """
+ if isinstance(sub, type): # 检测消息链中是否有某种类型的对象
+ for i in self:
+ if type(i) is sub:
+ return True
+ return False
+ if isinstance(sub, MessageComponent): # 检查消息链中是否有某个组件
+ for i in self:
+ if i == sub:
+ return True
+ return False
+ raise TypeError(f"类型不匹配,当前类型:{type(sub)}")
+
+ def __contains__(self, sub) -> bool:
+ return self.has(sub)
+
+ def __ge__(self, other):
+ return other in self
+
+ def __len__(self) -> int:
+ return len(self.__root__)
+
+ def __add__(
+ self, other: typing.Union['MessageChain', MessageComponent, str]
+ ) -> 'MessageChain':
+ if isinstance(other, MessageChain):
+ return self.__class__(self.__root__ + other.__root__)
+ if isinstance(other, str):
+ return self.__class__(self.__root__ + [Plain(other)])
+ if isinstance(other, MessageComponent):
+ return self.__class__(self.__root__ + [other])
+ return NotImplemented
+
+ def __radd__(self, other: typing.Union[MessageComponent, str]) -> 'MessageChain':
+ if isinstance(other, MessageComponent):
+ return self.__class__([other] + self.__root__)
+ if isinstance(other, str):
+ return self.__class__(
+ [typing.cast(MessageComponent, Plain(other))] + self.__root__
+ )
+ return NotImplemented
+
+ def __mul__(self, other: int):
+ if isinstance(other, int):
+ return self.__class__(self.__root__ * other)
+ return NotImplemented
+
+ def __rmul__(self, other: int):
+ return self.__mul__(other)
+
+ def __iadd__(self, other: typing.Iterable[typing.Union[MessageComponent, str]]):
+ self.extend(other)
+
+ def __imul__(self, other: int):
+ if isinstance(other, int):
+ self.__root__ *= other
+ return NotImplemented
+
+ def index(
+ self,
+ x: typing.Union[MessageComponent, typing.Type[MessageComponent]],
+ i: int = 0,
+ j: int = -1
+ ) -> int:
+ """返回 x 在消息链中首次出现项的索引号(索引号在 i 或其后且在 j 之前)。
+
+ Args:
+ x (`Union[MessageComponent, Type[MessageComponent]]`):
+ 要查找的消息元素或消息元素类型。
+ i: 从哪个位置开始查找。
+ j: 查找到哪个位置结束。
+
+ Returns:
+ int: 如果找到,则返回索引号。
+
+ Raises:
+ ValueError: 没有找到。
+ TypeError: 类型不匹配。
+ """
+ if isinstance(x, type):
+ l = len(self)
+ if i < 0:
+ i += l
+ if i < 0:
+ i = 0
+ if j < 0:
+ j += l
+ if j > l:
+ j = l
+ for index in range(i, j):
+ if type(self[index]) is x:
+ return index
+ raise ValueError("消息链中不存在该类型的组件。")
+ if isinstance(x, MessageComponent):
+ return self.__root__.index(x, i, j)
+ raise TypeError(f"类型不匹配,当前类型:{type(x)}")
+
+ def count(self, x: typing.Union[MessageComponent, typing.Type[MessageComponent]]) -> int:
+ """返回消息链中 x 出现的次数。
+
+ Args:
+ x (`Union[MessageComponent, Type[MessageComponent]]`):
+ 要查找的消息元素或消息元素类型。
+
+ Returns:
+ int: 次数。
+ """
+ if isinstance(x, type):
+ return sum(1 for i in self if type(i) is x)
+ if isinstance(x, MessageComponent):
+ return self.__root__.count(x)
+ raise TypeError(f"类型不匹配,当前类型:{type(x)}")
+
+ def extend(self, x: typing.Iterable[typing.Union[MessageComponent, str]]):
+ """将另一个消息链中的元素添加到消息链末尾。
+
+ Args:
+ x: 另一个消息链,也可为消息元素或字符串元素的序列。
+ """
+ self.__root__.extend(Plain(c) if isinstance(c, str) else c for c in x)
+
+ def append(self, x: typing.Union[MessageComponent, str]):
+ """将一个消息元素或字符串元素添加到消息链末尾。
+
+ Args:
+ x: 消息元素或字符串元素。
+ """
+ self.__root__.append(Plain(x) if isinstance(x, str) else x)
+
+ def insert(self, i: int, x: typing.Union[MessageComponent, str]):
+ """将一个消息元素或字符串添加到消息链中指定位置。
+
+ Args:
+ i: 插入位置。
+ x: 消息元素或字符串元素。
+ """
+ self.__root__.insert(i, Plain(x) if isinstance(x, str) else x)
+
+ def pop(self, i: int = -1) -> MessageComponent:
+ """从消息链中移除并返回指定位置的元素。
+
+ Args:
+ i: 移除位置。默认为末尾。
+
+ Returns:
+ MessageComponent: 移除的元素。
+ """
+ return self.__root__.pop(i)
+
+ def remove(self, x: typing.Union[MessageComponent, typing.Type[MessageComponent]]):
+ """从消息链中移除指定元素或指定类型的一个元素。
+
+ Args:
+ x: 指定的元素或元素类型。
+ """
+ if isinstance(x, type):
+ self.pop(self.index(x))
+ if isinstance(x, MessageComponent):
+ self.__root__.remove(x)
+
+ def exclude(
+ self,
+ x: typing.Union[MessageComponent, typing.Type[MessageComponent]],
+ count: int = -1
+ ) -> 'MessageChain':
+ """返回移除指定元素或指定类型的元素后剩余的消息链。
+
+ Args:
+ x: 指定的元素或元素类型。
+ count: 至多移除的数量。默认为全部移除。
+
+ Returns:
+ MessageChain: 剩余的消息链。
+ """
+ def _exclude():
+ nonlocal count
+ x_is_type = isinstance(x, type)
+ for c in self:
+ if count > 0 and ((x_is_type and type(c) is x) or c == x):
+ count -= 1
+ continue
+ yield c
+
+ return self.__class__(_exclude())
+
+ def reverse(self):
+ """将消息链原地翻转。"""
+ self.__root__.reverse()
+
+ @classmethod
+ def join(cls, *args: typing.Iterable[typing.Union[str, MessageComponent]]):
+ return cls(
+ Plain(c) if isinstance(c, str) else c
+ for c in itertools.chain(*args)
+ )
+
+ @property
+ def source(self) -> typing.Optional['Source']:
+ """获取消息链中的 `Source` 对象。"""
+ return self.get_first(Source)
+
+ @property
+ def message_id(self) -> int:
+ """获取消息链的 message_id,若无法获取,返回 -1。"""
+ source = self.source
+ return source.id if source else -1
+
+
+TMessage = typing.Union[MessageChain, typing.Iterable[typing.Union[MessageComponent, str]],
+ MessageComponent, str]
+"""可以转化为 MessageChain 的类型。"""
+
+
+class Source(MessageComponent):
+ """源。包含消息的基本信息。"""
+ type: str = "Source"
+ """消息组件类型。"""
+ id: int
+ """消息的识别号,用于引用回复(Source 类型永远为 MessageChain 的第一个元素)。"""
+ time: datetime
+ """消息时间。"""
+
+
+class Plain(MessageComponent):
+ """纯文本。"""
+ type: str = "Plain"
+ """消息组件类型。"""
+ text: str
+ """文字消息。"""
+ def __str__(self):
+ return self.text
+
+ def __repr__(self):
+ return f'Plain({self.text!r})'
+
+
+class Quote(MessageComponent):
+ """引用。"""
+ type: str = "Quote"
+ """消息组件类型。"""
+ id: typing.Optional[int] = None
+ """被引用回复的原消息的 message_id。"""
+ group_id: typing.Optional[int] = None
+ """被引用回复的原消息所接收的群号,当为好友消息时为0。"""
+ sender_id: typing.Optional[int] = None
+ """被引用回复的原消息的发送者的QQ号。"""
+ target_id: typing.Optional[int] = None
+ """被引用回复的原消息的接收者者的QQ号(或群号)。"""
+ origin: MessageChain
+ """被引用回复的原消息的消息链对象。"""
+
+ @pydantic.validator("origin", always=True, pre=True)
+ def origin_formater(cls, v):
+ return MessageChain.parse_obj(v)
+
+
+class At(MessageComponent):
+ """At某人。"""
+ type: str = "At"
+ """消息组件类型。"""
+ target: int
+ """群员 QQ 号。"""
+ display: typing.Optional[str] = None
+ """At时显示的文字,发送消息时无效,自动使用群名片。"""
+ def __eq__(self, other):
+ return isinstance(other, At) and self.target == other.target
+
+ def __str__(self):
+ return f"@{self.display or self.target}"
+
+ def as_mirai_code(self) -> str:
+ return f"[mirai:at:{self.target}]"
+
+
+class AtAll(MessageComponent):
+ """At全体。"""
+ type: str = "AtAll"
+ """消息组件类型。"""
+ def __str__(self):
+ return "@全体成员"
+
+ def as_mirai_code(self) -> str:
+ return f"[mirai:atall]"
+
+
+class Image(MessageComponent):
+ """图片。"""
+ type: str = "Image"
+ """消息组件类型。"""
+ image_id: typing.Optional[str] = None
+ """图片的 image_id,群图片与好友图片格式不同。不为空时将忽略 url 属性。"""
+ url: typing.Optional[pydantic.HttpUrl] = None
+ """图片的 URL,发送时可作网络图片的链接;接收时为腾讯图片服务器的链接,可用于图片下载。"""
+ path: typing.Union[str, Path, None] = None
+ """图片的路径,发送本地图片。"""
+ base64: typing.Optional[str] = None
+ """图片的 Base64 编码。"""
+ def __eq__(self, other):
+ return isinstance(
+ other, Image
+ ) and self.type == other.type and self.uuid == other.uuid
+
+ def __str__(self):
+ return '[图片]'
+
+ def as_mirai_code(self) -> str:
+ return f"[mirai:image:{self.image_id}]"
+
+ @pydantic.validator('path')
+ def validate_path(cls, path: typing.Union[str, Path, None]):
+ """修复 path 参数的行为,使之相对于 YiriMirai 的启动路径。"""
+ if path:
+ try:
+ return str(Path(path).resolve(strict=True))
+ except FileNotFoundError:
+ raise ValueError(f"无效路径:{path}")
+ else:
+ return path
+
+ @property
+ def uuid(self):
+ image_id = self.image_id
+ if image_id[0] == '{': # 群图片
+ image_id = image_id[1:37]
+ elif image_id[0] == '/': # 好友图片
+ image_id = image_id[1:]
+ return image_id
+
+ async def download(
+ self,
+ filename: typing.Union[str, Path, None] = None,
+ directory: typing.Union[str, Path, None] = None,
+ determine_type: bool = True
+ ):
+ """下载图片到本地。
+
+ Args:
+ filename: 下载到本地的文件路径。与 `directory` 二选一。
+ directory: 下载到本地的文件夹路径。与 `filename` 二选一。
+ determine_type: 是否自动根据图片类型确定拓展名,默认为 True。
+ """
+ if not self.url:
+ logger.warning(f'图片 `{self.uuid}` 无 url 参数,下载失败。')
+ return
+
+ import httpx
+ async with httpx.AsyncClient() as client:
+ response = await client.get(self.url)
+ response.raise_for_status()
+ content = response.content
+
+ if filename:
+ path = Path(filename)
+ if determine_type:
+ import imghdr
+ path = path.with_suffix(
+ '.' + str(imghdr.what(None, content))
+ )
+ path.parent.mkdir(parents=True, exist_ok=True)
+ elif directory:
+ import imghdr
+ path = Path(directory)
+ path.mkdir(parents=True, exist_ok=True)
+ path = path / f'{self.uuid}.{imghdr.what(None, content)}'
+ else:
+ raise ValueError("请指定文件路径或文件夹路径!")
+
+ import aiofiles
+ async with aiofiles.open(path, 'wb') as f:
+ await f.write(content)
+
+ return path
+
+ @classmethod
+ async def from_local(
+ cls,
+ filename: typing.Union[str, Path, None] = None,
+ content: typing.Optional[bytes] = None,
+ ) -> "Image":
+ """从本地文件路径加载图片,以 base64 的形式传递。
+
+ Args:
+ filename: 从本地文件路径加载图片,与 `content` 二选一。
+ content: 从本地文件内容加载图片,与 `filename` 二选一。
+
+ Returns:
+ Image: 图片对象。
+ """
+ if content:
+ pass
+ elif filename:
+ path = Path(filename)
+ import aiofiles
+ async with aiofiles.open(path, 'rb') as f:
+ content = await f.read()
+ else:
+ raise ValueError("请指定图片路径或图片内容!")
+ import base64
+ img = cls(base64=base64.b64encode(content).decode())
+ return img
+
+ @classmethod
+ def from_unsafe_path(cls, path: typing.Union[str, Path]) -> "Image":
+ """从不安全的路径加载图片。
+
+ Args:
+ path: 从不安全的路径加载图片。
+
+ Returns:
+ Image: 图片对象。
+ """
+ return cls.construct(path=str(path))
+
+
+class Unknown(MessageComponent):
+ """未知。"""
+ type: str = "Unknown"
+ """消息组件类型。"""
+ text: str
+ """文本。"""
+
+
+class Voice(MessageComponent):
+ """语音。"""
+ type: str = "Voice"
+ """消息组件类型。"""
+ voice_id: typing.Optional[str] = None
+ """语音的 voice_id,不为空时将忽略 url 属性。"""
+ url: typing.Optional[str] = None
+ """语音的 URL,发送时可作网络语音的链接;接收时为腾讯语音服务器的链接,可用于语音下载。"""
+ path: typing.Optional[str] = None
+ """语音的路径,发送本地语音。"""
+ base64: typing.Optional[str] = None
+ """语音的 Base64 编码。"""
+ length: typing.Optional[int] = None
+ """语音的长度,单位为秒。"""
+ @pydantic.validator('path')
+ def validate_path(cls, path: typing.Optional[str]):
+ """修复 path 参数的行为,使之相对于 YiriMirai 的启动路径。"""
+ if path:
+ try:
+ return str(Path(path).resolve(strict=True))
+ except FileNotFoundError:
+ raise ValueError(f"无效路径:{path}")
+ else:
+ return path
+
+ def __str__(self):
+ return '[语音]'
+
+ async def download(
+ self,
+ filename: typing.Union[str, Path, None] = None,
+ directory: typing.Union[str, Path, None] = None
+ ):
+ """下载语音到本地。
+
+ 语音采用 silk v3 格式,silk 格式的编码解码请使用 [graiax-silkcoder](https://pypi.org/project/graiax-silkcoder/)。
+
+ Args:
+ filename: 下载到本地的文件路径。与 `directory` 二选一。
+ directory: 下载到本地的文件夹路径。与 `filename` 二选一。
+ """
+ if not self.url:
+ logger.warning(f'语音 `{self.voice_id}` 无 url 参数,下载失败。')
+ return
+
+ import httpx
+ async with httpx.AsyncClient() as client:
+ response = await client.get(self.url)
+ response.raise_for_status()
+ content = response.content
+
+ if filename:
+ path = Path(filename)
+ path.parent.mkdir(parents=True, exist_ok=True)
+ elif directory:
+ path = Path(directory)
+ path.mkdir(parents=True, exist_ok=True)
+ path = path / f'{self.voice_id}.silk'
+ else:
+ raise ValueError("请指定文件路径或文件夹路径!")
+
+ import aiofiles
+ async with aiofiles.open(path, 'wb') as f:
+ await f.write(content)
+
+ @classmethod
+ async def from_local(
+ cls,
+ filename: typing.Union[str, Path, None] = None,
+ content: typing.Optional[bytes] = None,
+ ) -> "Voice":
+ """从本地文件路径加载语音,以 base64 的形式传递。
+
+ Args:
+ filename: 从本地文件路径加载语音,与 `content` 二选一。
+ content: 从本地文件内容加载语音,与 `filename` 二选一。
+ """
+ if content:
+ pass
+ if filename:
+ path = Path(filename)
+ import aiofiles
+ async with aiofiles.open(path, 'rb') as f:
+ content = await f.read()
+ else:
+ raise ValueError("请指定语音路径或语音内容!")
+ import base64
+ img = cls(base64=base64.b64encode(content).decode())
+ return img
+
+
+class ForwardMessageNode(pydantic.BaseModel):
+ """合并转发中的一条消息。"""
+ sender_id: typing.Optional[int] = None
+ """发送人QQ号。"""
+ sender_name: typing.Optional[str] = None
+ """显示名称。"""
+ message_chain: typing.Optional[MessageChain] = None
+ """消息内容。"""
+ message_id: typing.Optional[int] = None
+ """消息的 message_id,可以只使用此属性,从缓存中读取消息内容。"""
+ time: typing.Optional[datetime] = None
+ """发送时间。"""
+ @pydantic.validator('message_chain', check_fields=False)
+ def _validate_message_chain(cls, value: typing.Union[MessageChain, list]):
+ if isinstance(value, list):
+ return MessageChain.parse_obj(value)
+ return value
+
+ @classmethod
+ def create(
+ cls, sender: typing.Union[platform_entities.Friend, platform_entities.GroupMember], message: MessageChain
+ ) -> 'ForwardMessageNode':
+ """从消息链生成转发消息。
+
+ Args:
+ sender: 发送人。
+ message: 消息内容。
+
+ Returns:
+ ForwardMessageNode: 生成的一条消息。
+ """
+ return ForwardMessageNode(
+ sender_id=sender.id,
+ sender_name=sender.get_name(),
+ message_chain=message
+ )
+
+
+class Forward(MessageComponent):
+ """合并转发。"""
+ type: str = "Forward"
+ """消息组件类型。"""
+ node_list: typing.List[ForwardMessageNode]
+ """转发消息节点列表。"""
+ def __init__(self, *args, **kwargs):
+ if len(args) == 1:
+ self.node_list = args[0]
+ super().__init__(**kwargs)
+ super().__init__(*args, **kwargs)
+
+ def __str__(self):
+ return '[聊天记录]'
+
+
+class File(MessageComponent):
+ """文件。"""
+ type: str = "File"
+ """消息组件类型。"""
+ id: str
+ """文件识别 ID。"""
+ name: str
+ """文件名称。"""
+ size: int
+ """文件大小。"""
+ def __str__(self):
+ return f'[文件]{self.name}'
+
diff --git a/pkg/plugin/context.py b/pkg/plugin/context.py
index 42cb6be2..9e4d8caf 100644
--- a/pkg/plugin/context.py
+++ b/pkg/plugin/context.py
@@ -3,11 +3,12 @@
import typing
import abc
import pydantic
-import mirai
+# import mirai
from . import events
from ..provider.tools import entities as tools_entities
from ..core import app
+from ..platform.types import message as platform_message
def register(
@@ -174,7 +175,7 @@ def add_return(self, key: str, ret):
self.__return_value__[key] = []
self.__return_value__[key].append(ret)
- async def reply(self, message_chain: mirai.MessageChain):
+ async def reply(self, message_chain: platform_message.MessageChain):
"""回复此次消息请求
Args:
@@ -190,7 +191,7 @@ async def send_message(
self,
target_type: str,
target_id: str,
- message: mirai.MessageChain
+ message: platform_message.MessageChain
):
"""主动发送消息
diff --git a/pkg/plugin/events.py b/pkg/plugin/events.py
index b5919762..3fc2ea73 100644
--- a/pkg/plugin/events.py
+++ b/pkg/plugin/events.py
@@ -3,10 +3,11 @@
import typing
import pydantic
-import mirai
+# import mirai
from ..core import entities as core_entities
from ..provider import entities as llm_entities
+from ..platform.types import message as platform_message
class BaseEventModel(pydantic.BaseModel):
@@ -31,7 +32,7 @@ class PersonMessageReceived(BaseEventModel):
sender_id: int
"""发送者ID(QQ号)"""
- message_chain: mirai.MessageChain
+ message_chain: platform_message.MessageChain
class GroupMessageReceived(BaseEventModel):
@@ -43,7 +44,7 @@ class GroupMessageReceived(BaseEventModel):
sender_id: int
- message_chain: mirai.MessageChain
+ message_chain: platform_message.MessageChain
class PersonNormalMessageReceived(BaseEventModel):
diff --git a/pkg/provider/entities.py b/pkg/provider/entities.py
index 50000722..950cbb17 100644
--- a/pkg/provider/entities.py
+++ b/pkg/provider/entities.py
@@ -4,7 +4,9 @@
import enum
import pydantic
-import mirai
+# import mirai
+
+from ..platform.types import message as platform_message
class FunctionCall(pydantic.BaseModel):
@@ -79,7 +81,7 @@ def readable_str(self) -> str:
else:
return '未知消息'
- def get_content_mirai_message_chain(self, prefix_text: str="") -> mirai.MessageChain | None:
+ def get_content_mirai_message_chain(self, prefix_text: str="") -> platform_message.MessageChain | None:
"""将内容转换为 Mirai MessageChain 对象
Args:
@@ -89,15 +91,15 @@ def get_content_mirai_message_chain(self, prefix_text: str="") -> mirai.MessageC
if self.content is None:
return None
elif isinstance(self.content, str):
- return mirai.MessageChain([mirai.Plain(prefix_text+self.content)])
+ return platform_message.MessageChain([platform_message.Plain(prefix_text+self.content)])
elif isinstance(self.content, list):
mc = []
for ce in self.content:
if ce.type == 'text':
- mc.append(mirai.Plain(ce.text))
+ mc.append(platform_message.Plain(ce.text))
elif ce.type == 'image_url':
if ce.image_url.url.startswith("http"):
- mc.append(mirai.Image(url=ce.image_url.url))
+ mc.append(platform_message.Image(url=ce.image_url.url))
else: # base64
b64_str = ce.image_url.url
@@ -105,15 +107,15 @@ def get_content_mirai_message_chain(self, prefix_text: str="") -> mirai.MessageC
if b64_str.startswith("data:"):
b64_str = b64_str.split(",")[1]
- mc.append(mirai.Image(base64=b64_str))
+ mc.append(platform_message.Image(base64=b64_str))
# 找第一个文字组件
if prefix_text:
for i, c in enumerate(mc):
- if isinstance(c, mirai.Plain):
- mc[i] = mirai.Plain(prefix_text+c.text)
+ if isinstance(c, platform_message.Plain):
+ mc[i] = platform_message.Plain(prefix_text+c.text)
break
else:
- mc.insert(0, mirai.Plain(prefix_text))
+ mc.insert(0, platform_message.Plain(prefix_text))
- return mirai.MessageChain(mc)
+ return platform_message.MessageChain(mc)
From fdba470e9a7d82dad9f30922267e0b440aea7185 Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Thu, 26 Sep 2024 00:28:57 +0800
Subject: [PATCH 02/71] =?UTF-8?q?perf:=20=E5=B0=86=20platform=20=E7=9A=84?=
=?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E5=AF=BC=E5=85=A5=E5=8C=85=20=5F=5Finit?=
=?UTF-8?q?=5F=5F=20=E4=B8=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pkg/platform/types/__init__.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pkg/platform/types/__init__.py b/pkg/platform/types/__init__.py
index e69de29b..998b0fb8 100644
--- a/pkg/platform/types/__init__.py
+++ b/pkg/platform/types/__init__.py
@@ -0,0 +1,3 @@
+from .entities import *
+from .events import *
+from .message import *
From e8da26cb8a8f0583e6143db26d4ec20eff3f6975 Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Thu, 26 Sep 2024 11:23:37 +0800
Subject: [PATCH 03/71] fix: missing break
---
pkg/plugin/manager.py | 2 ++
pkg/plugin/setting.py | 1 +
2 files changed, 3 insertions(+)
diff --git a/pkg/plugin/manager.py b/pkg/plugin/manager.py
index 4e0784aa..b1241eaf 100644
--- a/pkg/plugin/manager.py
+++ b/pkg/plugin/manager.py
@@ -48,6 +48,8 @@ async def load_plugins(self):
# 按优先级倒序
self.plugins.sort(key=lambda x: x.priority, reverse=True)
+ self.ap.logger.debug(f'优先级排序后的插件列表 {self.plugins}')
+
async def initialize_plugins(self):
for plugin in self.plugins:
try:
diff --git a/pkg/plugin/setting.py b/pkg/plugin/setting.py
index 7e715af1..bd50603f 100644
--- a/pkg/plugin/setting.py
+++ b/pkg/plugin/setting.py
@@ -45,6 +45,7 @@ async def sync_setting(
for plugin_container in plugin_containers:
if plugin_container.plugin_name == value['name']:
plugin_container.set_from_setting_dict(value)
+ break
self.settings.data = {
'plugins': [
From 3469515e044f9546bb0b2b58c1b2f5127add3772 Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Thu, 26 Sep 2024 13:01:45 +0800
Subject: [PATCH 04/71] =?UTF-8?q?feat:=20=E5=88=A0=E9=99=A4=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81=E4=B8=AD=E5=AF=B9=20mirai=20=E7=9A=84=E5=BC=95?=
=?UTF-8?q?=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/ISSUE_TEMPLATE/bug-report.yml | 2 +-
.github/dependabot.yml | 1 -
.github/pull_request_template.md | 3 ++
pkg/command/entities.py | 1 -
pkg/core/bootutils/deps.py | 1 -
pkg/core/entities.py | 1 -
pkg/pipeline/cntfilter/cntfilter.py | 4 ---
pkg/pipeline/controller.py | 1 -
pkg/pipeline/entities.py | 5 ---
pkg/pipeline/longtext/longtext.py | 1 -
pkg/pipeline/longtext/strategies/forward.py | 3 --
pkg/pipeline/longtext/strategies/image.py | 2 --
pkg/pipeline/longtext/strategy.py | 2 --
pkg/pipeline/pool.py | 1 -
pkg/pipeline/preproc/preproc.py | 1 -
pkg/pipeline/process/handlers/chat.py | 1 -
pkg/pipeline/process/handlers/command.py | 1 -
pkg/pipeline/respback/respback.py | 1 -
pkg/pipeline/resprule/entities.py | 1 -
pkg/pipeline/resprule/resprule.py | 1 -
pkg/pipeline/resprule/rule.py | 2 --
pkg/pipeline/resprule/rules/atbot.py | 1 -
pkg/pipeline/resprule/rules/prefix.py | 1 -
pkg/pipeline/resprule/rules/random.py | 1 -
pkg/pipeline/resprule/rules/regexp.py | 1 -
pkg/pipeline/wrapper/wrapper.py | 14 +++-----
pkg/platform/adapter.py | 39 ++++++++++-----------
pkg/platform/manager.py | 2 --
pkg/platform/sources/aiocqhttp.py | 2 --
pkg/platform/sources/nakuru.py | 1 -
pkg/platform/sources/qqbotpy.py | 1 -
pkg/platform/sources/yirimirai.py | 3 --
pkg/platform/types/base.py | 14 ++++----
pkg/platform/types/message.py | 13 ++-----
pkg/plugin/context.py | 5 ++-
pkg/plugin/events.py | 1 -
pkg/provider/entities.py | 9 +++--
requirements.txt | 1 -
38 files changed, 42 insertions(+), 103 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml
index 12f9b83e..a5947b06 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/bug-report.yml
@@ -8,10 +8,10 @@ body:
label: 消息平台适配器
description: "连接QQ使用的框架"
options:
- - yiri-mirai(Mirai)
- Nakuru(go-cqhttp)
- aiocqhttp(使用 OneBot 协议接入的)
- qq-botpy(QQ官方API)
+ - yiri-mirai(Mirai)
validations:
required: false
- type: input
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index d1973eb3..53c58493 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -10,5 +10,4 @@ updates:
schedule:
interval: "weekly"
allow:
- - dependency-name: "yiri-mirai-rc"
- dependency-name: "openai"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 6b636c25..a4b3a1a4 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -6,8 +6,11 @@
### PR 作者完成
+*请在方括号间写`x`以打勾
+
- [ ] 阅读仓库[贡献指引](https://github.com/RockChinQ/QChatGPT/blob/master/CONTRIBUTING.md)了吗?
- [ ] 与项目所有者沟通过了吗?
+- [ ] 我确定已自行测试所作的更改,确保功能符合预期。
### 项目所有者完成
diff --git a/pkg/command/entities.py b/pkg/command/entities.py
index 3ea660f1..463dfe38 100644
--- a/pkg/command/entities.py
+++ b/pkg/command/entities.py
@@ -3,7 +3,6 @@
import typing
import pydantic
-# import mirai
from ..core import app, entities as core_entities
from . import errors, operator
diff --git a/pkg/core/bootutils/deps.py b/pkg/core/bootutils/deps.py
index e7df3e82..c392f800 100644
--- a/pkg/core/bootutils/deps.py
+++ b/pkg/core/bootutils/deps.py
@@ -5,7 +5,6 @@
"openai": "openai",
"anthropic": "anthropic",
"colorlog": "colorlog",
- "mirai": "yiri-mirai-rc",
"aiocqhttp": "aiocqhttp",
"botpy": "qq-botpy",
"PIL": "pillow",
diff --git a/pkg/core/entities.py b/pkg/core/entities.py
index 744c6d03..dbaa5ffd 100644
--- a/pkg/core/entities.py
+++ b/pkg/core/entities.py
@@ -6,7 +6,6 @@
import asyncio
import pydantic
-# import mirai
from ..provider import entities as llm_entities
from ..provider.modelmgr import entities
diff --git a/pkg/pipeline/cntfilter/cntfilter.py b/pkg/pipeline/cntfilter/cntfilter.py
index f0c5428e..f7376b61 100644
--- a/pkg/pipeline/cntfilter/cntfilter.py
+++ b/pkg/pipeline/cntfilter/cntfilter.py
@@ -1,9 +1,5 @@
from __future__ import annotations
-# import mirai
-# import mirai.models
-# import mirai.models.message
-
from ...core import app
from .. import stage, entities, stagemgr
diff --git a/pkg/pipeline/controller.py b/pkg/pipeline/controller.py
index 27b96dee..0f07e068 100644
--- a/pkg/pipeline/controller.py
+++ b/pkg/pipeline/controller.py
@@ -4,7 +4,6 @@
import typing
import traceback
-# import mirai
from ..core import app, entities
from . import entities as pipeline_entities
diff --git a/pkg/pipeline/entities.py b/pkg/pipeline/entities.py
index 347f5db7..cbeb3d0e 100644
--- a/pkg/pipeline/entities.py
+++ b/pkg/pipeline/entities.py
@@ -4,7 +4,6 @@
import typing
import pydantic
-# import mirai
from ..platform.types import message as platform_message
from ..core import entities
@@ -28,10 +27,6 @@ class StageProcessResult(pydantic.BaseModel):
user_notice: typing.Optional[typing.Union[str, list[platform_message.MessageComponent], platform_message.MessageChain, None]] = []
"""只要设置了就会发送给用户"""
- # TODO delete
- # admin_notice: typing.Optional[typing.Union[str, list[mirai_message.MessageComponent], mirai.MessageChain, None]] = []
- """只要设置了就会发送给管理员"""
-
console_notice: typing.Optional[str] = ''
"""只要设置了就会输出到控制台"""
diff --git a/pkg/pipeline/longtext/longtext.py b/pkg/pipeline/longtext/longtext.py
index d3715b7e..ecb745d0 100644
--- a/pkg/pipeline/longtext/longtext.py
+++ b/pkg/pipeline/longtext/longtext.py
@@ -3,7 +3,6 @@
import traceback
from PIL import Image, ImageDraw, ImageFont
-# from mirai.models.message import MessageComponent, Plain, MessageChain
from ...core import app
from . import strategy
diff --git a/pkg/pipeline/longtext/strategies/forward.py b/pkg/pipeline/longtext/strategies/forward.py
index 206bf08c..c39c9208 100644
--- a/pkg/pipeline/longtext/strategies/forward.py
+++ b/pkg/pipeline/longtext/strategies/forward.py
@@ -2,9 +2,6 @@
from __future__ import annotations
import typing
-# from mirai.models import MessageChain
-# from mirai.models.message import MessageComponent, ForwardMessageNode
-# from mirai.models.base import MiraiBaseModel
import pydantic
from .. import strategy as strategy_model
diff --git a/pkg/pipeline/longtext/strategies/image.py b/pkg/pipeline/longtext/strategies/image.py
index 3b1805c3..9e32e598 100644
--- a/pkg/pipeline/longtext/strategies/image.py
+++ b/pkg/pipeline/longtext/strategies/image.py
@@ -8,8 +8,6 @@
from PIL import Image, ImageDraw, ImageFont
-# from mirai.models import MessageChain, Image as ImageComponent
-# from mirai.models.message import MessageComponent
from ....platform.types import message as platform_message
from .. import strategy as strategy_model
diff --git a/pkg/pipeline/longtext/strategy.py b/pkg/pipeline/longtext/strategy.py
index 5bc46a39..6f66bbff 100644
--- a/pkg/pipeline/longtext/strategy.py
+++ b/pkg/pipeline/longtext/strategy.py
@@ -2,8 +2,6 @@
import abc
import typing
-# import mirai
-# from mirai.models.message import MessageComponent
from ...core import app
from ...core import entities as core_entities
diff --git a/pkg/pipeline/pool.py b/pkg/pipeline/pool.py
index b7f79510..45f16e66 100644
--- a/pkg/pipeline/pool.py
+++ b/pkg/pipeline/pool.py
@@ -2,7 +2,6 @@
import asyncio
-# import mirai
from ..core import entities
from ..platform import adapter as msadapter
diff --git a/pkg/pipeline/preproc/preproc.py b/pkg/pipeline/preproc/preproc.py
index 976c8f7c..3a71a841 100644
--- a/pkg/pipeline/preproc/preproc.py
+++ b/pkg/pipeline/preproc/preproc.py
@@ -1,6 +1,5 @@
from __future__ import annotations
-# import mirai
from .. import stage, entities, stagemgr
from ...core import entities as core_entities
diff --git a/pkg/pipeline/process/handlers/chat.py b/pkg/pipeline/process/handlers/chat.py
index d87e2853..6e192b78 100644
--- a/pkg/pipeline/process/handlers/chat.py
+++ b/pkg/pipeline/process/handlers/chat.py
@@ -5,7 +5,6 @@
import traceback
import json
-# import mirai
from .. import handler
from ... import entities
diff --git a/pkg/pipeline/process/handlers/command.py b/pkg/pipeline/process/handlers/command.py
index 5f6ed6ee..cec64a45 100644
--- a/pkg/pipeline/process/handlers/command.py
+++ b/pkg/pipeline/process/handlers/command.py
@@ -1,7 +1,6 @@
from __future__ import annotations
import typing
-# import mirai
from .. import handler
from ... import entities
diff --git a/pkg/pipeline/respback/respback.py b/pkg/pipeline/respback/respback.py
index 1b0cd3ac..d3dd83fe 100644
--- a/pkg/pipeline/respback/respback.py
+++ b/pkg/pipeline/respback/respback.py
@@ -3,7 +3,6 @@
import random
import asyncio
-# import mirai
from ...core import app
diff --git a/pkg/pipeline/resprule/entities.py b/pkg/pipeline/resprule/entities.py
index 42c2092e..22927154 100644
--- a/pkg/pipeline/resprule/entities.py
+++ b/pkg/pipeline/resprule/entities.py
@@ -1,5 +1,4 @@
import pydantic
-# import mirai
from ...platform.types import message as platform_message
diff --git a/pkg/pipeline/resprule/resprule.py b/pkg/pipeline/resprule/resprule.py
index aa07bb7c..77858f0d 100644
--- a/pkg/pipeline/resprule/resprule.py
+++ b/pkg/pipeline/resprule/resprule.py
@@ -1,6 +1,5 @@
from __future__ import annotations
-# import mirai
from ...core import app
from . import entities as rule_entities, rule
diff --git a/pkg/pipeline/resprule/rule.py b/pkg/pipeline/resprule/rule.py
index b40e5ac5..ad69d8a0 100644
--- a/pkg/pipeline/resprule/rule.py
+++ b/pkg/pipeline/resprule/rule.py
@@ -2,8 +2,6 @@
import abc
import typing
-# import mirai
-
from ...core import app, entities as core_entities
from . import entities
diff --git a/pkg/pipeline/resprule/rules/atbot.py b/pkg/pipeline/resprule/rules/atbot.py
index d767f95a..a0b7a7c8 100644
--- a/pkg/pipeline/resprule/rules/atbot.py
+++ b/pkg/pipeline/resprule/rules/atbot.py
@@ -1,6 +1,5 @@
from __future__ import annotations
-# import mirai
from .. import rule as rule_model
from .. import entities
diff --git a/pkg/pipeline/resprule/rules/prefix.py b/pkg/pipeline/resprule/rules/prefix.py
index c010c0f8..fb7bbcfc 100644
--- a/pkg/pipeline/resprule/rules/prefix.py
+++ b/pkg/pipeline/resprule/rules/prefix.py
@@ -1,4 +1,3 @@
-# import mirai
from .. import rule as rule_model
from .. import entities
diff --git a/pkg/pipeline/resprule/rules/random.py b/pkg/pipeline/resprule/rules/random.py
index bf8603a9..0178f2c4 100644
--- a/pkg/pipeline/resprule/rules/random.py
+++ b/pkg/pipeline/resprule/rules/random.py
@@ -1,6 +1,5 @@
import random
-# import mirai
from .. import rule as rule_model
from .. import entities
diff --git a/pkg/pipeline/resprule/rules/regexp.py b/pkg/pipeline/resprule/rules/regexp.py
index a6a3ecd2..f5f5b3f6 100644
--- a/pkg/pipeline/resprule/rules/regexp.py
+++ b/pkg/pipeline/resprule/rules/regexp.py
@@ -1,6 +1,5 @@
import re
-# import mirai
from .. import rule as rule_model
from .. import entities
diff --git a/pkg/pipeline/wrapper/wrapper.py b/pkg/pipeline/wrapper/wrapper.py
index 0e093826..1ffb3147 100644
--- a/pkg/pipeline/wrapper/wrapper.py
+++ b/pkg/pipeline/wrapper/wrapper.py
@@ -2,7 +2,6 @@
import typing
-# import mirai
from ...core import app, entities as core_entities
from .. import entities
@@ -46,19 +45,14 @@ async def process(
else:
if query.resp_messages[-1].role == 'command':
- # query.resp_message_chain.append(mirai.MessageChain("[bot] "+query.resp_messages[-1].content))
- query.resp_message_chain.append(query.resp_messages[-1].get_content_mirai_message_chain(prefix_text='[bot] '))
+ query.resp_message_chain.append(query.resp_messages[-1].get_content_platform_message_chain(prefix_text='[bot] '))
yield entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
new_query=query
)
elif query.resp_messages[-1].role == 'plugin':
- # if not isinstance(query.resp_messages[-1].content, mirai.MessageChain):
- # query.resp_message_chain.append(mirai.MessageChain(query.resp_messages[-1].content))
- # else:
- # query.resp_message_chain.append(query.resp_messages[-1].content)
- query.resp_message_chain.append(query.resp_messages[-1].get_content_mirai_message_chain())
+ query.resp_message_chain.append(query.resp_messages[-1].get_content_platform_message_chain())
yield entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
@@ -73,7 +67,7 @@ async def process(
reply_text = ''
if result.content: # 有内容
- reply_text = str(result.get_content_mirai_message_chain())
+ reply_text = str(result.get_content_platform_message_chain())
# ============= 触发插件事件 ===============
event_ctx = await self.ap.plugin_mgr.emit_event(
@@ -101,7 +95,7 @@ async def process(
else:
- query.resp_message_chain.append(result.get_content_mirai_message_chain())
+ query.resp_message_chain.append(result.get_content_platform_message_chain())
yield entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
diff --git a/pkg/platform/adapter.py b/pkg/platform/adapter.py
index c6d97b3a..7cf64a12 100644
--- a/pkg/platform/adapter.py
+++ b/pkg/platform/adapter.py
@@ -4,7 +4,6 @@
import typing
import abc
-# import mirai
from ..core import app
from .types import message as platform_message
@@ -64,7 +63,7 @@ async def send_message(
Args:
target_type (str): 目标类型,`person`或`group`
target_id (str): 目标ID
- message (mirai.MessageChain): YiriMirai库的消息链
+ message (platform.types.MessageChain): 消息链
"""
raise NotImplementedError
@@ -77,8 +76,8 @@ async def reply_message(
"""回复消息
Args:
- message_source (mirai.MessageEvent): YiriMirai消息源事件
- message (mirai.MessageChain): YiriMirai库的消息链
+ message_source (platform.types.MessageEvent): 消息源事件
+ message (platform.types.MessageChain): 消息链
quote_origin (bool, optional): 是否引用原消息. Defaults to False.
"""
raise NotImplementedError
@@ -95,8 +94,8 @@ def register_listener(
"""注册事件监听器
Args:
- event_type (typing.Type[mirai.Event]): YiriMirai事件类型
- callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件
+ event_type (typing.Type[platform.types.Event]): 事件类型
+ callback (typing.Callable[[platform.types.Event], None]): 回调函数,接收一个参数,为事件
"""
raise NotImplementedError
@@ -108,8 +107,8 @@ def unregister_listener(
"""注销事件监听器
Args:
- event_type (typing.Type[mirai.Event]): YiriMirai事件类型
- callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件
+ event_type (typing.Type[platform.types.Event]): 事件类型
+ callback (typing.Callable[[platform.types.Event], None]): 回调函数,接收一个参数,为事件
"""
raise NotImplementedError
@@ -130,25 +129,25 @@ class MessageConverter:
"""消息链转换器基类"""
@staticmethod
def yiri2target(message_chain: platform_message.MessageChain):
- """将YiriMirai消息链转换为目标消息链
+ """将源平台消息链转换为目标平台消息链
Args:
- message_chain (mirai.MessageChain): YiriMirai消息链
+ message_chain (platform.types.MessageChain): 源平台消息链
Returns:
- typing.Any: 目标消息链
+ typing.Any: 目标平台消息链
"""
raise NotImplementedError
@staticmethod
def target2yiri(message_chain: typing.Any) -> platform_message.MessageChain:
- """将目标消息链转换为YiriMirai消息链
+ """将目标平台消息链转换为源平台消息链
Args:
- message_chain (typing.Any): 目标消息链
+ message_chain (typing.Any): 目标平台消息链
Returns:
- mirai.MessageChain: YiriMirai消息链
+ platform.types.MessageChain: 源平台消息链
"""
raise NotImplementedError
@@ -158,24 +157,24 @@ class EventConverter:
@staticmethod
def yiri2target(event: typing.Type[platform_message.Event]):
- """将YiriMirai事件转换为目标事件
+ """将源平台事件转换为目标平台事件
Args:
- event (typing.Type[mirai.Event]): YiriMirai事件
+ event (typing.Type[platform.types.Event]): 源平台事件
Returns:
- typing.Any: 目标事件
+ typing.Any: 目标平台事件
"""
raise NotImplementedError
@staticmethod
def target2yiri(event: typing.Any) -> platform_message.Event:
- """将目标事件的调用参数转换为YiriMirai的事件参数对象
+ """将目标平台事件的调用参数转换为源平台的事件参数对象
Args:
- event (typing.Any): 目标事件
+ event (typing.Any): 目标平台事件
Returns:
- typing.Type[mirai.Event]: YiriMirai事件
+ typing.Type[platform.types.Event]: 源平台事件
"""
raise NotImplementedError
diff --git a/pkg/platform/manager.py b/pkg/platform/manager.py
index 4e5131d5..d46e5b80 100644
--- a/pkg/platform/manager.py
+++ b/pkg/platform/manager.py
@@ -6,9 +6,7 @@
import asyncio
import traceback
-# from mirai import At, GroupMessage, MessageEvent, StrangerMessage, \
# FriendMessage, Image, MessageChain, Plain
-# import mirai
from ..platform import adapter as msadapter
from ..core import app, entities as core_entities
diff --git a/pkg/platform/sources/aiocqhttp.py b/pkg/platform/sources/aiocqhttp.py
index adf9c4e1..25d197e3 100644
--- a/pkg/platform/sources/aiocqhttp.py
+++ b/pkg/platform/sources/aiocqhttp.py
@@ -5,8 +5,6 @@
import time
import datetime
-# import mirai
-# import mirai.models.message as yiri_message
import aiocqhttp
from .. import adapter
diff --git a/pkg/platform/sources/nakuru.py b/pkg/platform/sources/nakuru.py
index 5c05f9d4..2fbe8be4 100644
--- a/pkg/platform/sources/nakuru.py
+++ b/pkg/platform/sources/nakuru.py
@@ -6,7 +6,6 @@
import traceback
import logging
-# import mirai
import nakuru
import nakuru.entities.components as nkc
diff --git a/pkg/platform/sources/qqbotpy.py b/pkg/platform/sources/qqbotpy.py
index 5a882c93..cbc86f44 100644
--- a/pkg/platform/sources/qqbotpy.py
+++ b/pkg/platform/sources/qqbotpy.py
@@ -6,7 +6,6 @@
import re
import traceback
-# import mirai
import botpy
import botpy.message as botpy_message
import botpy.types.message as botpy_message_type
diff --git a/pkg/platform/sources/yirimirai.py b/pkg/platform/sources/yirimirai.py
index 4082e90a..aa0823fd 100644
--- a/pkg/platform/sources/yirimirai.py
+++ b/pkg/platform/sources/yirimirai.py
@@ -1,9 +1,6 @@
# import asyncio
# import typing
-# import mirai
-# import mirai.models.bus
-# from mirai.bot import MiraiRunner
# from .. import adapter as adapter_model
# from ...core import app
diff --git a/pkg/platform/types/base.py b/pkg/platform/types/base.py
index 964e9c6f..d3c0be49 100644
--- a/pkg/platform/types/base.py
+++ b/pkg/platform/types/base.py
@@ -6,7 +6,7 @@
class PlatformMetaclass(pdm.ModelMetaclass):
- """此类是 YiriMirai 中使用的 pydantic 模型的元类的基类。"""
+ """此类是平台中使用的 pydantic 模型的元类的基类。"""
def to_camel(name: str) -> str:
@@ -23,7 +23,7 @@ class PlatformBaseModel(BaseModel, metaclass=PlatformMetaclass):
启用了三项配置:
1. 允许解析时传入额外的值,并将额外值保存在模型中。
2. 允许通过别名访问字段。
- 3. 自动生成小驼峰风格的别名,以符合 mirai-api-http 的命名。
+ 3. 自动生成小驼峰风格的别名。
"""
def __init__(self, *args, **kwargs):
""""""
@@ -47,17 +47,17 @@ class PlatformIndexedMetaclass(PlatformMetaclass):
def __new__(cls, name, bases, attrs, **kwargs):
new_cls = super().__new__(cls, name, bases, attrs, **kwargs)
- # 第一类:MiraiIndexedModel
+ # 第一类:PlatformIndexedModel
if name == 'PlatformIndexedModel':
cls.__indexedmodel__ = new_cls
new_cls.__indexes__ = {}
return new_cls
- # 第二类:MiraiIndexedModel 的直接子类,这些是可以通过子类名获取子类的类。
+ # 第二类:PlatformIndexedModel 的直接子类,这些是可以通过子类名获取子类的类。
if cls.__indexedmodel__ in bases:
cls.__indexedbases__.append(new_cls)
new_cls.__indexes__ = {}
return new_cls
- # 第三类:MiraiIndexedModel 的直接子类的子类,这些添加到直接子类的索引中。
+ # 第三类:PlatformIndexedModel 的直接子类的子类,这些添加到直接子类的索引中。
for base in cls.__indexedbases__:
if issubclass(new_cls, base):
base.__indexes__[name] = new_cls
@@ -79,7 +79,7 @@ def get_subtype(cls, name: str) -> Type['PlatformIndexedModel']:
name: 类名称。
Returns:
- Type['MiraiIndexedModel']: 子类类型。
+ Type['PlatformIndexedModel']: 子类类型。
"""
try:
type_ = cls.__indexes__.get(name)
@@ -97,7 +97,7 @@ def parse_subtype(cls, obj: dict) -> 'PlatformIndexedModel':
obj: 一个字典,包含了模型对象的属性。
Returns:
- MiraiIndexedModel: 构造的对象。
+ PlatformIndexedModel: 构造的对象。
"""
if cls in PlatformIndexedModel.__subclasses__():
ModelType = cls.get_subtype(obj['type'])
diff --git a/pkg/platform/types/message.py b/pkg/platform/types/message.py
index 00e420b1..e790f881 100644
--- a/pkg/platform/types/message.py
+++ b/pkg/platform/types/message.py
@@ -514,9 +514,6 @@ def __eq__(self, other):
def __str__(self):
return f"@{self.display or self.target}"
- def as_mirai_code(self) -> str:
- return f"[mirai:at:{self.target}]"
-
class AtAll(MessageComponent):
"""At全体。"""
@@ -525,9 +522,6 @@ class AtAll(MessageComponent):
def __str__(self):
return "@全体成员"
- def as_mirai_code(self) -> str:
- return f"[mirai:atall]"
-
class Image(MessageComponent):
"""图片。"""
@@ -549,12 +543,9 @@ def __eq__(self, other):
def __str__(self):
return '[图片]'
- def as_mirai_code(self) -> str:
- return f"[mirai:image:{self.image_id}]"
-
@pydantic.validator('path')
def validate_path(cls, path: typing.Union[str, Path, None]):
- """修复 path 参数的行为,使之相对于 YiriMirai 的启动路径。"""
+ """修复 path 参数的行为,使之相对于 QChatGPT 的启动路径。"""
if path:
try:
return str(Path(path).resolve(strict=True))
@@ -682,7 +673,7 @@ class Voice(MessageComponent):
"""语音的长度,单位为秒。"""
@pydantic.validator('path')
def validate_path(cls, path: typing.Optional[str]):
- """修复 path 参数的行为,使之相对于 YiriMirai 的启动路径。"""
+ """修复 path 参数的行为,使之相对于 QChatGPT 的启动路径。"""
if path:
try:
return str(Path(path).resolve(strict=True))
diff --git a/pkg/plugin/context.py b/pkg/plugin/context.py
index 9e4d8caf..f6cc1769 100644
--- a/pkg/plugin/context.py
+++ b/pkg/plugin/context.py
@@ -3,7 +3,6 @@
import typing
import abc
import pydantic
-# import mirai
from . import events
from ..provider.tools import entities as tools_entities
@@ -179,7 +178,7 @@ async def reply(self, message_chain: platform_message.MessageChain):
"""回复此次消息请求
Args:
- message_chain (mirai.MessageChain): YiriMirai库的消息链,若用户使用的不是 YiriMirai 适配器,程序也能自动转换为目标消息链
+ message_chain (platform.types.MessageChain): 源平台的消息链,若用户使用的不是源平台适配器,程序也能自动转换为目标平台消息链
"""
await self.host.ap.platform_mgr.send(
event=self.event.query.message_event,
@@ -198,7 +197,7 @@ async def send_message(
Args:
target_type (str): 目标类型,`person`或`group`
target_id (str): 目标ID
- message (mirai.MessageChain): YiriMirai库的消息链,若用户使用的不是 YiriMirai 适配器,程序也能自动转换为目标消息链
+ message (platform.types.MessageChain): 源平台的消息链,若用户使用的不是源平台适配器,程序也能自动转换为目标平台消息链
"""
await self.event.query.adapter.send_message(
target_type=target_type,
diff --git a/pkg/plugin/events.py b/pkg/plugin/events.py
index 3fc2ea73..013dd113 100644
--- a/pkg/plugin/events.py
+++ b/pkg/plugin/events.py
@@ -3,7 +3,6 @@
import typing
import pydantic
-# import mirai
from ..core import entities as core_entities
from ..provider import entities as llm_entities
diff --git a/pkg/provider/entities.py b/pkg/provider/entities.py
index 950cbb17..803613a3 100644
--- a/pkg/provider/entities.py
+++ b/pkg/provider/entities.py
@@ -4,7 +4,6 @@
import enum
import pydantic
-# import mirai
from ..platform.types import message as platform_message
@@ -75,14 +74,14 @@ class Message(pydantic.BaseModel):
def readable_str(self) -> str:
if self.content is not None:
- return str(self.role) + ": " + str(self.get_content_mirai_message_chain())
+ return str(self.role) + ": " + str(self.get_content_platform_message_chain())
elif self.tool_calls is not None:
return f'调用工具: {self.tool_calls[0].id}'
else:
return '未知消息'
- def get_content_mirai_message_chain(self, prefix_text: str="") -> platform_message.MessageChain | None:
- """将内容转换为 Mirai MessageChain 对象
+ def get_content_platform_message_chain(self, prefix_text: str="") -> platform_message.MessageChain | None:
+ """将内容转换为平台消息 MessageChain 对象
Args:
prefix_text (str): 首个文字组件的前缀文本
@@ -108,7 +107,7 @@ def get_content_mirai_message_chain(self, prefix_text: str="") -> platform_messa
b64_str = b64_str.split(",")[1]
mc.append(platform_message.Image(base64=b64_str))
-
+
# 找第一个文字组件
if prefix_text:
for i, c in enumerate(mc):
diff --git a/requirements.txt b/requirements.txt
index 1b554d29..7bf257ed 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,6 @@ requests
openai>1.0.0
anthropic
colorlog~=6.6.0
-yiri-mirai-rc
aiocqhttp
qq-botpy
nakuru-project-idk
From c53ffaca6c0f4791db90272846eb2a572b0ce95e Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Thu, 26 Sep 2024 14:38:18 +0800
Subject: [PATCH 05/71] =?UTF-8?q?fix:=20=E5=A4=84=E7=90=86=E6=8F=92?=
=?UTF-8?q?=E4=BB=B6=20import=20mirai=20=E6=97=B6=E7=9A=84=E5=85=BC?=
=?UTF-8?q?=E5=AE=B9=E6=80=A7=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pkg/core/entities.py | 2 +-
pkg/platform/manager.py | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/pkg/core/entities.py b/pkg/core/entities.py
index dbaa5ffd..67b05666 100644
--- a/pkg/core/entities.py
+++ b/pkg/core/entities.py
@@ -110,7 +110,7 @@ class Session(pydantic.BaseModel):
using_conversation: typing.Optional[Conversation] = None
- conversations: typing.Optional[list[Conversation]] = []
+ conversations: typing.Optional[list[Conversation]] = pydantic.Field(default_factory=list)
create_time: typing.Optional[datetime.datetime] = pydantic.Field(default_factory=datetime.datetime.now)
diff --git a/pkg/platform/manager.py b/pkg/platform/manager.py
index d46e5b80..aed8deff 100644
--- a/pkg/platform/manager.py
+++ b/pkg/platform/manager.py
@@ -2,6 +2,7 @@
import json
import os
+import sys
import logging
import asyncio
import traceback
@@ -15,6 +16,10 @@
from .types import events as platform_events
from .types import entities as platform_entities
+# 处理 3.4 移除了 YiriMirai 之后,插件的兼容性问题
+from . import types as mirai
+sys.modules['mirai'] = mirai
+
# 控制QQ消息输入输出的类
class PlatformManager:
From 21f153e5c32a9d21c442cbf80dbad56333c492ca Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Fri, 11 Oct 2024 22:23:08 +0800
Subject: [PATCH 06/71] =?UTF-8?q?chore:=20webui=20=E5=89=8D=E7=AB=AF?=
=?UTF-8?q?=E6=A8=A1=E6=9D=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
web/.browserslistrc | 4 +
web/.editorconfig | 5 +
web/.eslintrc.js | 10 +
web/.gitignore | 22 +
web/README.md | 1 +
web/index.html | 16 +
web/jsconfig.json | 20 +
web/package-lock.json | 4867 ++++++++++++++++++++++++++++++++++
web/package.json | 34 +
web/public/favicon.ico | Bin 0 -> 15406 bytes
web/src/App.vue | 11 +
web/src/assets/logo.png | Bin 0 -> 11955 bytes
web/src/assets/logo.svg | 6 +
web/src/main.js | 20 +
web/src/pages/index.vue | 6 +
web/src/plugins/index.js | 15 +
web/src/plugins/vuetify.js | 19 +
web/src/router/index.js | 36 +
web/src/styles/settings.scss | 10 +
web/vite.config.mjs | 54 +
20 files changed, 5156 insertions(+)
create mode 100644 web/.browserslistrc
create mode 100644 web/.editorconfig
create mode 100644 web/.eslintrc.js
create mode 100644 web/.gitignore
create mode 100644 web/README.md
create mode 100644 web/index.html
create mode 100644 web/jsconfig.json
create mode 100644 web/package-lock.json
create mode 100644 web/package.json
create mode 100644 web/public/favicon.ico
create mode 100644 web/src/App.vue
create mode 100644 web/src/assets/logo.png
create mode 100644 web/src/assets/logo.svg
create mode 100644 web/src/main.js
create mode 100644 web/src/pages/index.vue
create mode 100644 web/src/plugins/index.js
create mode 100644 web/src/plugins/vuetify.js
create mode 100644 web/src/router/index.js
create mode 100644 web/src/styles/settings.scss
create mode 100644 web/vite.config.mjs
diff --git a/web/.browserslistrc b/web/.browserslistrc
new file mode 100644
index 00000000..dc3bc09a
--- /dev/null
+++ b/web/.browserslistrc
@@ -0,0 +1,4 @@
+> 1%
+last 2 versions
+not dead
+not ie 11
diff --git a/web/.editorconfig b/web/.editorconfig
new file mode 100644
index 00000000..7053c49a
--- /dev/null
+++ b/web/.editorconfig
@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/web/.eslintrc.js b/web/.eslintrc.js
new file mode 100644
index 00000000..6e7e1b14
--- /dev/null
+++ b/web/.eslintrc.js
@@ -0,0 +1,10 @@
+module.exports = {
+ root: true,
+ env: {
+ node: true,
+ },
+ extends: [
+ 'plugin:vue/vue3-essential',
+ 'eslint:recommended',
+ ],
+}
diff --git a/web/.gitignore b/web/.gitignore
new file mode 100644
index 00000000..11f5d714
--- /dev/null
+++ b/web/.gitignore
@@ -0,0 +1,22 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/web/README.md b/web/README.md
new file mode 100644
index 00000000..280a55a2
--- /dev/null
+++ b/web/README.md
@@ -0,0 +1 @@
+# WebUI
diff --git a/web/index.html b/web/index.html
new file mode 100644
index 00000000..150c3979
--- /dev/null
+++ b/web/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ LangBot 面板
+
+
+
+
+
+
+
+
diff --git a/web/jsconfig.json b/web/jsconfig.json
new file mode 100644
index 00000000..dad0634c
--- /dev/null
+++ b/web/jsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "target": "es5",
+ "module": "esnext",
+ "baseUrl": "./",
+ "moduleResolution": "bundler",
+ "paths": {
+ "@/*": [
+ "src/*"
+ ]
+ },
+ "lib": [
+ "esnext",
+ "dom",
+ "dom.iterable",
+ "scripthost"
+ ]
+ }
+}
diff --git a/web/package-lock.json b/web/package-lock.json
new file mode 100644
index 00000000..bca39b56
--- /dev/null
+++ b/web/package-lock.json
@@ -0,0 +1,4867 @@
+{
+ "name": "web",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "web",
+ "version": "0.0.0",
+ "dependencies": {
+ "@mdi/font": "7.4.47",
+ "core-js": "^3.37.1",
+ "roboto-fontface": "*",
+ "vue": "^3.4.31",
+ "vuetify": "^3.6.11"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.0.5",
+ "eslint": "^8.57.0",
+ "eslint-config-standard": "^17.1.0",
+ "eslint-plugin-import": "^2.29.1",
+ "eslint-plugin-n": "^16.6.2",
+ "eslint-plugin-node": "^11.1.0",
+ "eslint-plugin-promise": "^6.4.0",
+ "eslint-plugin-vue": "^9.27.0",
+ "sass": "1.77.6",
+ "unplugin-fonts": "^1.1.1",
+ "unplugin-vue-components": "^0.27.2",
+ "unplugin-vue-router": "^0.10.0",
+ "vite": "^5.3.3",
+ "vite-plugin-vuetify": "^2.0.3",
+ "vue-router": "^4.4.0"
+ }
+ },
+ "node_modules/@antfu/utils": {
+ "version": "0.7.10",
+ "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
+ "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
+ "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz",
+ "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.25.6"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz",
+ "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.24.8",
+ "@babel/helper-validator-identifier": "^7.24.7",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.11.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz",
+ "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.3",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@mdi/font": {
+ "version": "7.4.47",
+ "resolved": "https://registry.npmjs.org/@mdi/font/-/font-7.4.47.tgz",
+ "integrity": "sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz",
+ "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz",
+ "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz",
+ "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz",
+ "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz",
+ "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz",
+ "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz",
+ "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz",
+ "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz",
+ "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz",
+ "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz",
+ "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz",
+ "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz",
+ "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz",
+ "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz",
+ "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz",
+ "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz",
+ "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rtsao/scc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.4.tgz",
+ "integrity": "sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@vue-macros/common": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-1.14.0.tgz",
+ "integrity": "sha512-xwQhDoEXRNXobNQmdqOD20yUGdVLVLZe4zhDlT9q/E+z+mvT3wukaAoJG80XRnv/BcgOOCVpxqpkQZ3sNTgjWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.25.6",
+ "@rollup/pluginutils": "^5.1.0",
+ "@vue/compiler-sfc": "^3.5.4",
+ "ast-kit": "^1.1.0",
+ "local-pkg": "^0.5.0",
+ "magic-string-ast": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=16.14.0"
+ },
+ "peerDependencies": {
+ "vue": "^2.7.0 || ^3.2.25"
+ },
+ "peerDependenciesMeta": {
+ "vue": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.10.tgz",
+ "integrity": "sha512-iXWlk+Cg/ag7gLvY0SfVucU8Kh2CjysYZjhhP70w9qI4MvSox4frrP+vDGvtQuzIcgD8+sxM6lZvCtdxGunTAA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/shared": "3.5.10",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.10.tgz",
+ "integrity": "sha512-DyxHC6qPcktwYGKOIy3XqnHRrrXyWR2u91AjP+nLkADko380srsC2DC3s7Y1Rk6YfOlxOlvEQKa9XXmLI+W4ZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.10",
+ "@vue/shared": "3.5.10"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.10.tgz",
+ "integrity": "sha512-to8E1BgpakV7224ZCm8gz1ZRSyjNCAWEplwFMWKlzCdP9DkMKhRRwt0WkCjY7jkzi/Vz3xgbpeig5Pnbly4Tow==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/compiler-core": "3.5.10",
+ "@vue/compiler-dom": "3.5.10",
+ "@vue/compiler-ssr": "3.5.10",
+ "@vue/shared": "3.5.10",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.11",
+ "postcss": "^8.4.47",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.10.tgz",
+ "integrity": "sha512-hxP4Y3KImqdtyUKXDRSxKSRkSm1H9fCvhojEYrnaoWhE4w/y8vwWhnosJoPPe2AXm5sU7CSbYYAgkt2ZPhDz+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.10",
+ "@vue/shared": "3.5.10"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "6.6.4",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.10.tgz",
+ "integrity": "sha512-kW08v06F6xPSHhid9DJ9YjOGmwNDOsJJQk0ax21wKaUYzzuJGEuoKNU2Ujux8FLMrP7CFJJKsHhXN9l2WOVi2g==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/shared": "3.5.10"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.10.tgz",
+ "integrity": "sha512-9Q86I5Qq3swSkFfzrZ+iqEy7Vla325M7S7xc1NwKnRm/qoi1Dauz0rT6mTMmscqx4qz0EDJ1wjB+A36k7rl8mA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.10",
+ "@vue/shared": "3.5.10"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.10.tgz",
+ "integrity": "sha512-t3x7ht5qF8ZRi1H4fZqFzyY2j+GTMTDxRheT+i8M9Ph0oepUxoadmbwlFwMoW7RYCpNQLpP2Yx3feKs+fyBdpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.10",
+ "@vue/runtime-core": "3.5.10",
+ "@vue/shared": "3.5.10",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.10.tgz",
+ "integrity": "sha512-IVE97tt2kGKwHNq9yVO0xdh1IvYfZCShvDSy46JIh5OQxP1/EXSpoDqetVmyIzL7CYOWnnmMkVqd7YK2QSWkdw==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.10",
+ "@vue/shared": "3.5.10"
+ },
+ "peerDependencies": {
+ "vue": "3.5.10"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.10.tgz",
+ "integrity": "sha512-VkkBhU97Ki+XJ0xvl4C9YJsIZ2uIlQ7HqPpZOS3m9VCvmROPaChZU6DexdMJqvz9tbgG+4EtFVrSuailUq5KGQ==",
+ "license": "MIT"
+ },
+ "node_modules/@vuetify/loader-shared": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@vuetify/loader-shared/-/loader-shared-2.0.3.tgz",
+ "integrity": "sha512-Ss3GC7eJYkp2SF6xVzsT7FAruEmdihmn4OCk2+UocREerlXKWgOKKzTN5PN3ZVN5q05jHHrsNhTuWbhN61Bpdg==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "upath": "^2.0.1"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.0",
+ "vuetify": "^3.0.0"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.12.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+ "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "devOptional": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
+ "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+ "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.4",
+ "is-string": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.findlastindex": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
+ "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
+ "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
+ "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
+ "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.22.3",
+ "es-errors": "^1.2.1",
+ "get-intrinsic": "^1.2.3",
+ "is-array-buffer": "^3.0.4",
+ "is-shared-array-buffer": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ast-kit": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-1.2.1.tgz",
+ "integrity": "sha512-h31wotR7rkFLrlmGPn0kGqOZ/n5EQFvp7dBs400chpHDhHc8BK3gpvyHDluRujuGgeoTAv3dSIMz9BI3JxAWyQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.6",
+ "pathe": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=16.14.0"
+ }
+ },
+ "node_modules/ast-walker-scope": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.6.2.tgz",
+ "integrity": "sha512-1UWOyC50xI3QZkRuDj6PqDtpm1oHWtYs+NQGwqL/2R11eN3Q81PHAHPM0SWW3BNQm53UDwS//Jv8L4CCVLM1bQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "ast-kit": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=16.14.0"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/builtin-modules": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/builtins": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz",
+ "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.0.0"
+ }
+ },
+ "node_modules/builtins/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "devOptional": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/confbox": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz",
+ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/core-js": {
+ "version": "3.38.1",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz",
+ "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "license": "MIT"
+ },
+ "node_modules/data-view-buffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
+ "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
+ "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
+ "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.23.3",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+ "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "arraybuffer.prototype.slice": "^1.0.3",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "data-view-buffer": "^1.0.1",
+ "data-view-byte-length": "^1.0.1",
+ "data-view-byte-offset": "^1.0.0",
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-set-tostringtag": "^2.0.3",
+ "es-to-primitive": "^1.2.1",
+ "function.prototype.name": "^1.1.6",
+ "get-intrinsic": "^1.2.4",
+ "get-symbol-description": "^1.0.2",
+ "globalthis": "^1.0.3",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.0.3",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.0.7",
+ "is-array-buffer": "^3.0.4",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.1",
+ "is-negative-zero": "^2.0.3",
+ "is-regex": "^1.1.4",
+ "is-shared-array-buffer": "^1.0.3",
+ "is-string": "^1.0.7",
+ "is-typed-array": "^1.1.13",
+ "is-weakref": "^1.0.2",
+ "object-inspect": "^1.13.1",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.5",
+ "regexp.prototype.flags": "^1.5.2",
+ "safe-array-concat": "^1.1.2",
+ "safe-regex-test": "^1.0.3",
+ "string.prototype.trim": "^1.2.9",
+ "string.prototype.trimend": "^1.0.8",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.2",
+ "typed-array-byte-length": "^1.0.1",
+ "typed-array-byte-offset": "^1.0.2",
+ "typed-array-length": "^1.0.6",
+ "unbox-primitive": "^1.0.2",
+ "which-typed-array": "^1.1.15"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+ "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
+ "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
+ "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.0"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "devOptional": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-compat-utils": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz",
+ "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "eslint": ">=6.0.0"
+ }
+ },
+ "node_modules/eslint-compat-utils/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint-config-standard": {
+ "version": "17.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
+ "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^8.0.1",
+ "eslint-plugin-import": "^2.25.2",
+ "eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
+ "eslint-plugin-promise": "^6.0.0"
+ }
+ },
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+ "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7",
+ "is-core-module": "^2.13.0",
+ "resolve": "^1.22.4"
+ }
+ },
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-module-utils": {
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
+ "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.2.7"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-es": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz",
+ "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-utils": "^2.0.0",
+ "regexpp": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=4.19.1"
+ }
+ },
+ "node_modules/eslint-plugin-es-x": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz",
+ "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/ota-meshi",
+ "https://opencollective.com/eslint"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.1.2",
+ "@eslint-community/regexpp": "^4.11.0",
+ "eslint-compat-utils": "^0.5.1"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=8"
+ }
+ },
+ "node_modules/eslint-plugin-import": {
+ "version": "2.30.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz",
+ "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rtsao/scc": "^1.1.0",
+ "array-includes": "^3.1.8",
+ "array.prototype.findlastindex": "^1.2.5",
+ "array.prototype.flat": "^1.3.2",
+ "array.prototype.flatmap": "^1.3.2",
+ "debug": "^3.2.7",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.9",
+ "eslint-module-utils": "^2.9.0",
+ "hasown": "^2.0.2",
+ "is-core-module": "^2.15.1",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.8",
+ "object.groupby": "^1.0.3",
+ "object.values": "^1.2.0",
+ "semver": "^6.3.1",
+ "tsconfig-paths": "^3.15.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eslint-plugin-n": {
+ "version": "16.6.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz",
+ "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "builtins": "^5.0.1",
+ "eslint-plugin-es-x": "^7.5.0",
+ "get-tsconfig": "^4.7.0",
+ "globals": "^13.24.0",
+ "ignore": "^5.2.4",
+ "is-builtin-module": "^3.2.1",
+ "is-core-module": "^2.12.1",
+ "minimatch": "^3.1.2",
+ "resolve": "^1.22.2",
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-n/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint-plugin-node": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz",
+ "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-plugin-es": "^3.0.0",
+ "eslint-utils": "^2.0.0",
+ "ignore": "^5.1.1",
+ "minimatch": "^3.0.4",
+ "resolve": "^1.10.1",
+ "semver": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=5.16.0"
+ }
+ },
+ "node_modules/eslint-plugin-promise": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz",
+ "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-vue": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.28.0.tgz",
+ "integrity": "sha512-ShrihdjIhOTxs+MfWun6oJWuk+g/LAhN+CiuOl/jjkG3l0F2AuK5NMTaWqyvBgkFtpYmyks6P4603mLmhNJW8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "globals": "^13.24.0",
+ "natural-compare": "^1.4.0",
+ "nth-check": "^2.1.1",
+ "postcss-selector-parser": "^6.0.15",
+ "semver": "^7.6.3",
+ "vue-eslint-parser": "^9.4.3",
+ "xml-name-validator": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-vue/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.1.3"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/function.prototype.name": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
+ "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "functions-have-names": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-symbol-description": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
+ "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz",
+ "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/has-bigints": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+ "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/immutable": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
+ "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/internal-slot": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
+ "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.0",
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
+ "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+ "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-bigints": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+ "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-builtin-module": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+ "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "builtin-modules": "^3.3.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
+ "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-data-view": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
+ "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+ "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+ "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+ "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+ "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+ "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
+ "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+ "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/local-pkg": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
+ "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mlly": "^1.4.2",
+ "pkg-types": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.11",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
+ "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
+ "node_modules/magic-string-ast": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-0.6.2.tgz",
+ "integrity": "sha512-oN3Bcd7ZVt+0VGEs7402qR/tjgjbM7kPlH/z7ufJnzTLVBzXJITRHOJiwMmmYMgZfdoWQsfQcY+iKlxiBppnMA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "magic-string": "^0.30.10"
+ },
+ "engines": {
+ "node": ">=16.14.0"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mlly": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz",
+ "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.3",
+ "pathe": "^1.1.2",
+ "pkg-types": "^1.1.1",
+ "ufo": "^1.5.3"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
+ "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "has-symbols": "^1.0.3",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.groupby": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
+ "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pkg-types": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz",
+ "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.1.7",
+ "mlly": "^1.7.1",
+ "pathe": "^1.1.2"
+ }
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
+ "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
+ "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "set-function-name": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/roboto-fontface": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz",
+ "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/rollup": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz",
+ "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.22.5",
+ "@rollup/rollup-android-arm64": "4.22.5",
+ "@rollup/rollup-darwin-arm64": "4.22.5",
+ "@rollup/rollup-darwin-x64": "4.22.5",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.22.5",
+ "@rollup/rollup-linux-arm-musleabihf": "4.22.5",
+ "@rollup/rollup-linux-arm64-gnu": "4.22.5",
+ "@rollup/rollup-linux-arm64-musl": "4.22.5",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5",
+ "@rollup/rollup-linux-riscv64-gnu": "4.22.5",
+ "@rollup/rollup-linux-s390x-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-musl": "4.22.5",
+ "@rollup/rollup-win32-arm64-msvc": "4.22.5",
+ "@rollup/rollup-win32-ia32-msvc": "4.22.5",
+ "@rollup/rollup-win32-x64-msvc": "4.22.5",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-array-concat": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
+ "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "get-intrinsic": "^1.2.4",
+ "has-symbols": "^1.0.3",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
+ "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.1.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/sass": {
+ "version": "1.77.6",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz",
+ "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/scule": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
+ "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
+ "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
+ "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
+ "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
+ "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
+ "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
+ "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
+ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+ "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.0.3",
+ "which-boxed-primitive": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/unplugin": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.14.1.tgz",
+ "integrity": "sha512-lBlHbfSFPToDYp9pjXlUEFVxYLaue9f9T1HC+4OHlmj+HnMDdz9oZY+erXfoCe/5V/7gKUSY2jpXPb9S7f0f/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.12.1",
+ "webpack-virtual-modules": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "webpack-sources": "^3"
+ },
+ "peerDependenciesMeta": {
+ "webpack-sources": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-fonts": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unplugin-fonts/-/unplugin-fonts-1.1.1.tgz",
+ "integrity": "sha512-/Aw/rL9D2aslGGM0vi+2R2aG508RSwawLnnBuo+JDSqYc4cHJO1R1phllhN6GysEhBp/6a4B6+vSFPVapWyAAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-glob": "^3.2.12",
+ "unplugin": "^1.3.1"
+ },
+ "peerDependencies": {
+ "@nuxt/kit": "^3.0.0",
+ "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@nuxt/kit": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-vue-components": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.4.tgz",
+ "integrity": "sha512-1XVl5iXG7P1UrOMnaj2ogYa5YTq8aoh5jwDPQhemwO/OrXW+lPQKDXd1hMz15qxQPxgb/XXlbgo3HQ2rLEbmXQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@antfu/utils": "^0.7.10",
+ "@rollup/pluginutils": "^5.1.0",
+ "chokidar": "^3.6.0",
+ "debug": "^4.3.6",
+ "fast-glob": "^3.3.2",
+ "local-pkg": "^0.5.0",
+ "magic-string": "^0.30.11",
+ "minimatch": "^9.0.5",
+ "mlly": "^1.7.1",
+ "unplugin": "^1.12.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@babel/parser": "^7.15.8",
+ "@nuxt/kit": "^3.2.2",
+ "vue": "2 || 3"
+ },
+ "peerDependenciesMeta": {
+ "@babel/parser": {
+ "optional": true
+ },
+ "@nuxt/kit": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-vue-components/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/unplugin-vue-components/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/unplugin-vue-router": {
+ "version": "0.10.8",
+ "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.10.8.tgz",
+ "integrity": "sha512-xi+eLweYAqolIoTRSmumbi6Yx0z5M0PLvl+NFNVWHJgmE2ByJG1SZbrn+TqyuDtIyln20KKgq8tqmL7aLoiFjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.25.4",
+ "@rollup/pluginutils": "^5.1.0",
+ "@vue-macros/common": "^1.12.2",
+ "ast-walker-scope": "^0.6.2",
+ "chokidar": "^3.6.0",
+ "fast-glob": "^3.3.2",
+ "json5": "^2.2.3",
+ "local-pkg": "^0.5.0",
+ "magic-string": "^0.30.11",
+ "mlly": "^1.7.1",
+ "pathe": "^1.1.2",
+ "scule": "^1.3.0",
+ "unplugin": "^1.12.2",
+ "yaml": "^2.5.0"
+ },
+ "peerDependencies": {
+ "vue-router": "^4.4.0"
+ },
+ "peerDependenciesMeta": {
+ "vue-router": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-vue-router/node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/upath": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz",
+ "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4",
+ "yarn": "*"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vite": {
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+ "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-vuetify": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/vite-plugin-vuetify/-/vite-plugin-vuetify-2.0.4.tgz",
+ "integrity": "sha512-A4cliYUoP/u4AWSRVRvAPKgpgR987Pss7LpFa7s1GvOe8WjgDq92Rt3eVXrvgxGCWvZsPKziVqfHHdCMqeDhfw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vuetify/loader-shared": "^2.0.3",
+ "debug": "^4.3.3",
+ "upath": "^2.0.1"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": ">=5",
+ "vue": "^3.0.0",
+ "vuetify": "^3.0.0"
+ }
+ },
+ "node_modules/vue": {
+ "version": "3.5.10",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.10.tgz",
+ "integrity": "sha512-Vy2kmJwHPlouC/tSnIgXVg03SG+9wSqT1xu1Vehc+ChsXsRd7jLkKgMltVEFOzUdBr3uFwBCG+41LJtfAcBRng==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.10",
+ "@vue/compiler-sfc": "3.5.10",
+ "@vue/runtime-dom": "3.5.10",
+ "@vue/server-renderer": "3.5.10",
+ "@vue/shared": "3.5.10"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-eslint-parser": {
+ "version": "9.4.3",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
+ "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.4",
+ "eslint-scope": "^7.1.1",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.3.1",
+ "esquery": "^1.4.0",
+ "lodash": "^4.17.21",
+ "semver": "^7.3.6"
+ },
+ "engines": {
+ "node": "^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=6.0.0"
+ }
+ },
+ "node_modules/vue-eslint-parser/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/vue-router": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.5.tgz",
+ "integrity": "sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
+ "node_modules/vuetify": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.2.tgz",
+ "integrity": "sha512-q0WTcRG977+a9Dqhb8TOaPm+Xmvj0oVhnBJhAdHWFSov3HhHTTxlH2nXP/GBTXZuuMHDbBeIWFuUR2/1Fx0PPw==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20 || >=14.13"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/johnleider"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.7",
+ "vite-plugin-vuetify": ">=1.0.0",
+ "vue": "^3.3.0",
+ "webpack-plugin-vuetify": ">=2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ },
+ "vite-plugin-vuetify": {
+ "optional": true
+ },
+ "webpack-plugin-vuetify": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/webpack-virtual-modules": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+ "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-bigint": "^1.0.1",
+ "is-boolean-object": "^1.1.0",
+ "is-number-object": "^1.0.4",
+ "is-string": "^1.0.5",
+ "is-symbol": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
+ "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/xml-name-validator": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
+ "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yaml": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz",
+ "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/web/package.json b/web/package.json
new file mode 100644
index 00000000..3225f51b
--- /dev/null
+++ b/web/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "web",
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "lint": "eslint . --fix --ignore-path .gitignore"
+ },
+ "dependencies": {
+ "@mdi/font": "7.4.47",
+ "core-js": "^3.37.1",
+ "roboto-fontface": "*",
+ "vue": "^3.4.31",
+ "vuetify": "^3.6.11"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.0.5",
+ "eslint": "^8.57.0",
+ "eslint-config-standard": "^17.1.0",
+ "eslint-plugin-import": "^2.29.1",
+ "eslint-plugin-n": "^16.6.2",
+ "eslint-plugin-node": "^11.1.0",
+ "eslint-plugin-promise": "^6.4.0",
+ "eslint-plugin-vue": "^9.27.0",
+ "sass": "1.77.6",
+ "unplugin-fonts": "^1.1.1",
+ "unplugin-vue-components": "^0.27.2",
+ "unplugin-vue-router": "^0.10.0",
+ "vite": "^5.3.3",
+ "vite-plugin-vuetify": "^2.0.3",
+ "vue-router": "^4.4.0"
+ }
+}
diff --git a/web/public/favicon.ico b/web/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..8fb9f91b3aab4eec0c76ffc5342528033c61e247
GIT binary patch
literal 15406
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
+
+
+
+
+
+
+
+
diff --git a/web/src/assets/logo.png b/web/src/assets/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..a5f23ae7bff64954cf3537377a9f99306baf083d
GIT binary patch
literal 11955
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
+
+
+
+
+
diff --git a/web/src/main.js b/web/src/main.js
new file mode 100644
index 00000000..d31eee22
--- /dev/null
+++ b/web/src/main.js
@@ -0,0 +1,20 @@
+/**
+ * main.js
+ *
+ * Bootstraps Vuetify and other plugins then mounts the App`
+ */
+
+// Plugins
+import { registerPlugins } from '@/plugins'
+
+// Components
+import App from './App.vue'
+
+// Composables
+import { createApp } from 'vue'
+
+const app = createApp(App)
+
+registerPlugins(app)
+
+app.mount('#app')
diff --git a/web/src/pages/index.vue b/web/src/pages/index.vue
new file mode 100644
index 00000000..6488c51b
--- /dev/null
+++ b/web/src/pages/index.vue
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/web/src/plugins/index.js b/web/src/plugins/index.js
new file mode 100644
index 00000000..9eb2eb24
--- /dev/null
+++ b/web/src/plugins/index.js
@@ -0,0 +1,15 @@
+/**
+ * plugins/index.js
+ *
+ * Automatically included in `./src/main.js`
+ */
+
+// Plugins
+import vuetify from './vuetify'
+import router from '@/router'
+
+export function registerPlugins (app) {
+ app
+ .use(vuetify)
+ .use(router)
+}
diff --git a/web/src/plugins/vuetify.js b/web/src/plugins/vuetify.js
new file mode 100644
index 00000000..1db02919
--- /dev/null
+++ b/web/src/plugins/vuetify.js
@@ -0,0 +1,19 @@
+/**
+ * plugins/vuetify.js
+ *
+ * Framework documentation: https://vuetifyjs.com`
+ */
+
+// Styles
+import '@mdi/font/css/materialdesignicons.css'
+import 'vuetify/styles'
+
+// Composables
+import { createVuetify } from 'vuetify'
+
+// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
+export default createVuetify({
+ theme: {
+ defaultTheme: 'light',
+ },
+})
diff --git a/web/src/router/index.js b/web/src/router/index.js
new file mode 100644
index 00000000..cffec2d7
--- /dev/null
+++ b/web/src/router/index.js
@@ -0,0 +1,36 @@
+
+/**
+ * router/index.ts
+ *
+ * Automatic routes for `./src/pages/*.vue`
+ */
+
+// Composables
+import { createRouter, createWebHistory } from 'vue-router/auto'
+import { routes } from 'vue-router/auto-routes'
+
+const router = createRouter({
+ history: createWebHistory(import.meta.env.BASE_URL),
+ routes,
+})
+
+// Workaround for https://github.com/vitejs/vite/issues/11804
+router.onError((err, to) => {
+ if (err?.message?.includes?.('Failed to fetch dynamically imported module')) {
+ if (!localStorage.getItem('vuetify:dynamic-reload')) {
+ console.log('Reloading page to fix dynamic import error')
+ localStorage.setItem('vuetify:dynamic-reload', 'true')
+ location.assign(to.fullPath)
+ } else {
+ console.error('Dynamic import error, reloading page did not fix it', err)
+ }
+ } else {
+ console.error(err)
+ }
+})
+
+router.isReady().then(() => {
+ localStorage.removeItem('vuetify:dynamic-reload')
+})
+
+export default router
diff --git a/web/src/styles/settings.scss b/web/src/styles/settings.scss
new file mode 100644
index 00000000..3e36a279
--- /dev/null
+++ b/web/src/styles/settings.scss
@@ -0,0 +1,10 @@
+/**
+ * src/styles/settings.scss
+ *
+ * Configures SASS variables and Vuetify overwrites
+ */
+
+// https://vuetifyjs.com/features/sass-variables/`
+// @use 'vuetify/settings' with (
+// $color-pack: false
+// );
diff --git a/web/vite.config.mjs b/web/vite.config.mjs
new file mode 100644
index 00000000..1e6733cd
--- /dev/null
+++ b/web/vite.config.mjs
@@ -0,0 +1,54 @@
+// Plugins
+import Components from 'unplugin-vue-components/vite'
+import Vue from '@vitejs/plugin-vue'
+import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
+import ViteFonts from 'unplugin-fonts/vite'
+import VueRouter from 'unplugin-vue-router/vite'
+
+// Utilities
+import { defineConfig } from 'vite'
+import { fileURLToPath, URL } from 'node:url'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ VueRouter(),
+ Vue({
+ template: { transformAssetUrls }
+ }),
+ // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme
+ Vuetify({
+ autoImport: true,
+ styles: {
+ configFile: 'src/styles/settings.scss',
+ },
+ }),
+ Components(),
+ ViteFonts({
+ google: {
+ families: [{
+ name: 'Roboto',
+ styles: 'wght@100;300;400;500;700;900',
+ }],
+ },
+ }),
+ ],
+ define: { 'process.env': {} },
+ resolve: {
+ alias: {
+ '@': fileURLToPath(new URL('./src', import.meta.url))
+ },
+ extensions: [
+ '.js',
+ '.json',
+ '.jsx',
+ '.mjs',
+ '.ts',
+ '.tsx',
+ '.vue',
+ ],
+ },
+ server: {
+ port: 3000,
+ },
+})
From 7c3557e94355fc1dfd02f35d2d332e82764e3455 Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Fri, 11 Oct 2024 22:27:53 +0800
Subject: [PATCH 07/71] =?UTF-8?q?feat:=20=E6=8C=81=E4=B9=85=E5=8C=96?=
=?UTF-8?q?=E5=92=8C=20web=20=E6=8E=A5=E5=8F=A3=E5=9F=BA=E7=A1=80=E6=9E=B6?=
=?UTF-8?q?=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 7 +-
main.py | 13 +--
pkg/api/__init__.py | 0
pkg/api/http/__init__.py | 0
pkg/api/http/controller/__init__.py | 0
pkg/api/http/controller/group.py | 91 +++++++++++++++++++++
pkg/api/http/controller/groups/__init__.py | 0
pkg/api/http/controller/groups/log.py | 21 +++++
pkg/api/http/controller/main.py | 48 +++++++++++
pkg/api/http/service/__init__.py | 0
pkg/core/app.py | 30 +++++--
pkg/core/boot.py | 9 +-
pkg/core/bootutils/deps.py | 3 +
pkg/core/bootutils/log.py | 5 +-
pkg/core/migrations/m013_http_api_config.py | 30 +++++++
pkg/core/stages/build_app.py | 14 ++++
pkg/core/stages/migrate.py | 2 +-
pkg/core/stages/setup_logger.py | 36 +++++++-
pkg/persistence/__init__.py | 0
pkg/persistence/database.py | 40 +++++++++
pkg/persistence/databases/__init__.py | 0
pkg/persistence/databases/sqlite.py | 13 +++
pkg/persistence/mgr.py | 55 +++++++++++++
pkg/utils/logcache.py | 49 +++++++++++
requirements.txt | 5 +-
templates/system.json | 13 ++-
26 files changed, 462 insertions(+), 22 deletions(-)
create mode 100644 pkg/api/__init__.py
create mode 100644 pkg/api/http/__init__.py
create mode 100644 pkg/api/http/controller/__init__.py
create mode 100644 pkg/api/http/controller/group.py
create mode 100644 pkg/api/http/controller/groups/__init__.py
create mode 100644 pkg/api/http/controller/groups/log.py
create mode 100644 pkg/api/http/controller/main.py
create mode 100644 pkg/api/http/service/__init__.py
create mode 100644 pkg/core/migrations/m013_http_api_config.py
create mode 100644 pkg/persistence/__init__.py
create mode 100644 pkg/persistence/database.py
create mode 100644 pkg/persistence/databases/__init__.py
create mode 100644 pkg/persistence/databases/sqlite.py
create mode 100644 pkg/persistence/mgr.py
create mode 100644 pkg/utils/logcache.py
diff --git a/.gitignore b/.gitignore
index 56282ca8..65ef5e47 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,8 @@ __pycache__/
database.db
qchatgpt.log
/banlist.py
-plugins/
-!plugins/__init__.py
+/plugins/
+!/plugins/__init__.py
/revcfg.py
prompts/
logs/
@@ -34,4 +34,5 @@ bard.json
res/instance_id.json
.DS_Store
/data
-botpy.log*
\ No newline at end of file
+botpy.log*
+/poc
\ No newline at end of file
diff --git a/main.py b/main.py
index 0ad87bd2..273c8579 100644
--- a/main.py
+++ b/main.py
@@ -13,7 +13,10 @@
"""
-async def main_entry():
+import asyncio
+
+
+async def main_entry(loop: asyncio.AbstractEventLoop):
print(asciiart)
import sys
@@ -46,7 +49,7 @@ async def main_entry():
sys.exit(0)
from pkg.core import boot
- await boot.main()
+ await boot.main(loop)
if __name__ == '__main__':
@@ -65,8 +68,8 @@ async def main_entry():
if invalid_pwd:
print("请在QChatGPT项目根目录下以命令形式运行此程序。")
input("按任意键退出...")
- exit(0)
+ exit(1)
- import asyncio
+ loop = asyncio.new_event_loop()
- asyncio.run(main_entry())
+ loop.run_until_complete(main_entry(loop))
diff --git a/pkg/api/__init__.py b/pkg/api/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/api/http/__init__.py b/pkg/api/http/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/api/http/controller/__init__.py b/pkg/api/http/controller/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/api/http/controller/group.py b/pkg/api/http/controller/group.py
new file mode 100644
index 00000000..b9533567
--- /dev/null
+++ b/pkg/api/http/controller/group.py
@@ -0,0 +1,91 @@
+from __future__ import annotations
+
+import abc
+import typing
+import quart
+from quart.typing import RouteCallable
+
+from ....core import app
+
+
+preregistered_groups: list[type[RouterGroup]] = []
+"""RouterGroup 的预注册列表"""
+
+def group_class(name: str, path: str) -> None:
+ """注册一个 RouterGroup"""
+
+ def decorator(cls: typing.Type[RouterGroup]) -> typing.Type[RouterGroup]:
+ cls.name = name
+ cls.path = path
+ preregistered_groups.append(cls)
+ return cls
+
+ return decorator
+
+
+class RouterGroup(abc.ABC):
+
+ name: str
+
+ path: str
+
+ ap: app.Application
+
+ quart_app: quart.Quart
+
+ def __init__(self, ap: app.Application, quart_app: quart.Quart) -> None:
+ self.ap = ap
+ self.quart_app = quart_app
+
+ @abc.abstractmethod
+ async def initialize(self) -> None:
+ pass
+
+ def route(self, rule: str, **options: typing.Any) -> typing.Callable[[RouteCallable], RouteCallable]: # decorator
+ """注册一个路由"""
+ def decorator(f: RouteCallable) -> RouteCallable:
+ nonlocal rule
+ rule = self.path + rule
+
+ async def handler_error(*args, **kwargs):
+ try:
+ return await f(*args, **kwargs)
+ except Exception as e: # 自动 500
+ return self.http_status(500, -2, str(e))
+
+ new_f = handler_error
+ new_f.__name__ = f.__name__
+ new_f.__doc__ = f.__doc__
+
+ self.quart_app.route(rule, **options)(new_f)
+ return f
+
+ return decorator
+
+ def _cors(self, response: quart.Response) -> quart.Response:
+ # Quart-Cors 似乎很久没维护了,所以自己写
+ response.headers['Access-Control-Allow-Origin'] = '*'
+ response.headers['Access-Control-Allow-Headers'] = '*'
+ response.headers['Access-Control-Allow-Methods'] = '*'
+ response.headers['Access-Control-Allow-Credentials'] = 'true'
+ return response
+
+ def success(self, data: typing.Any = None) -> quart.Response:
+ """返回一个 200 响应"""
+ return self._cors(quart.jsonify({
+ 'code': 0,
+ 'msg': 'ok',
+ 'data': data,
+ }))
+
+ def fail(self, code: int, msg: str) -> quart.Response:
+ """返回一个异常响应"""
+
+ return self._cors(quart.jsonify({
+ 'code': code,
+ 'msg': msg,
+ }))
+
+ def http_status(self, status: int, code: int, msg: str) -> quart.Response:
+ """返回一个指定状态码的响应"""
+ return self.fail(code, msg), status
diff --git a/pkg/api/http/controller/groups/__init__.py b/pkg/api/http/controller/groups/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/api/http/controller/groups/log.py b/pkg/api/http/controller/groups/log.py
new file mode 100644
index 00000000..fe6de631
--- /dev/null
+++ b/pkg/api/http/controller/groups/log.py
@@ -0,0 +1,21 @@
+from __future__ import annotations
+
+import traceback
+
+import quart
+
+from .....core import app
+from .. import group
+
+
+@group.group_class('log', '/api/v1/log')
+class LogRouterGroup(group.RouterGroup):
+
+ async def initialize(self) -> None:
+ @self.route('', methods=['GET'])
+ async def _() -> str:
+ return self.success(
+ data={
+ "logs": self.ap.log_cache.get_all_logs()
+ }
+ )
diff --git a/pkg/api/http/controller/main.py b/pkg/api/http/controller/main.py
new file mode 100644
index 00000000..83e86696
--- /dev/null
+++ b/pkg/api/http/controller/main.py
@@ -0,0 +1,48 @@
+from __future__ import annotations
+
+import asyncio
+
+import quart
+
+from ....core import app
+from .groups import log
+from . import group
+
+
+class HTTPController:
+
+ ap: app.Application
+
+ quart_app: quart.Quart
+
+ def __init__(self, ap: app.Application) -> None:
+ self.ap = ap
+ self.quart_app = quart.Quart(__name__)
+
+ async def initialize(self) -> None:
+ await self.register_routes()
+
+ async def run(self) -> None:
+ if self.ap.system_cfg.data['http-api']['enable']:
+ async def shutdown_trigger_placeholder():
+ while True:
+ await asyncio.sleep(1)
+
+ asyncio.create_task(self.quart_app.run_task(
+ host=self.ap.system_cfg.data['http-api']['host'],
+ port=self.ap.system_cfg.data['http-api']['port'],
+ shutdown_trigger=shutdown_trigger_placeholder
+ ))
+
+ async def register_routes(self) -> None:
+
+ @self.quart_app.route('/healthz')
+ async def healthz():
+ return {
+ "code": 0,
+ "msg": "ok"
+ }
+
+ for g in group.preregistered_groups:
+ ginst = g(self.ap, self.quart_app)
+ await ginst.initialize()
diff --git a/pkg/api/http/service/__init__.py b/pkg/api/http/service/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/core/app.py b/pkg/core/app.py
index e6e25ea0..2f0e0340 100644
--- a/pkg/core/app.py
+++ b/pkg/core/app.py
@@ -17,11 +17,18 @@
from ..pipeline import pool
from ..pipeline import controller, stagemgr
from ..utils import version as version_mgr, proxy as proxy_mgr, announce as announce_mgr
+from ..persistence import mgr as persistencemgr
+from ..api.http.controller import main as http_controller
+from ..utils import logcache
class Application:
"""运行时应用对象和上下文"""
+ event_loop: asyncio.AbstractEventLoop = None
+
+ asyncio_tasks: list[asyncio.Task] = []
+
platform_mgr: im_mgr.PlatformManager = None
cmd_mgr: cmdmgr.CommandManager = None
@@ -78,6 +85,12 @@ class Application:
logger: logging.Logger = None
+ persistence_mgr: persistencemgr.PersistenceManager = None
+
+ http_ctrl: http_controller.HTTPController = None
+
+ log_cache: logcache.LogCache = None
+
def __init__(self):
pass
@@ -91,13 +104,21 @@ async def run(self):
try:
+ # 后续可能会允许动态重启其他任务
+ # 故为了防止程序在非 Ctrl-C 情况下退出,这里创建一个不会结束的协程
+ async def never_ending():
+ while True:
+ await asyncio.sleep(1)
+
tasks = [
- asyncio.create_task(self.platform_mgr.run()),
- asyncio.create_task(self.ctrl.run())
+ asyncio.create_task(self.platform_mgr.run()), # 消息平台
+ asyncio.create_task(self.ctrl.run()), # 消息处理循环
+ asyncio.create_task(self.http_ctrl.run()), # http 接口服务
+ asyncio.create_task(never_ending())
]
+ self.asyncio_tasks.extend(tasks)
- # 挂信号处理
-
+ # 挂系统信号处理
import signal
def signal_handler(sig, frame):
@@ -109,7 +130,6 @@ def signal_handler(sig, frame):
signal.signal(signal.SIGINT, signal_handler)
await asyncio.gather(*tasks, return_exceptions=True)
-
except asyncio.CancelledError:
pass
except Exception as e:
diff --git a/pkg/core/boot.py b/pkg/core/boot.py
index 5663c2ef..1e5f1052 100644
--- a/pkg/core/boot.py
+++ b/pkg/core/boot.py
@@ -1,6 +1,7 @@
from __future__ import print_function
import traceback
+import asyncio
from . import app
from ..audit import identifier
@@ -19,13 +20,15 @@
]
-async def make_app() -> app.Application:
+async def make_app(loop: asyncio.AbstractEventLoop) -> app.Application:
# 生成标识符
identifier.init()
ap = app.Application()
+ ap.event_loop = loop
+
# 执行启动阶段
for stage_name in stage_order:
stage_cls = stage.preregistered_stages[stage_name]
@@ -38,9 +41,9 @@ async def make_app() -> app.Application:
return ap
-async def main():
+async def main(loop: asyncio.AbstractEventLoop):
try:
- app_inst = await make_app()
+ app_inst = await make_app(loop)
await app_inst.run()
except Exception as e:
traceback.print_exc()
diff --git a/pkg/core/bootutils/deps.py b/pkg/core/bootutils/deps.py
index c392f800..8c0127e5 100644
--- a/pkg/core/bootutils/deps.py
+++ b/pkg/core/bootutils/deps.py
@@ -15,6 +15,9 @@
"psutil": "psutil",
"async_lru": "async-lru",
"ollama": "ollama",
+ "quart": "quart",
+ "sqlalchemy": "sqlalchemy[asyncio]",
+ "aiosqlite": "aiosqlite",
}
diff --git a/pkg/core/bootutils/log.py b/pkg/core/bootutils/log.py
index d7b6da0a..ad8252df 100644
--- a/pkg/core/bootutils/log.py
+++ b/pkg/core/bootutils/log.py
@@ -15,7 +15,7 @@
}
-async def init_logging() -> logging.Logger:
+async def init_logging(extra_handlers: list[logging.Handler] = None) -> logging.Logger:
# 删除所有现有的logger
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
@@ -41,7 +41,8 @@ async def init_logging() -> logging.Logger:
stream_handler = logging.StreamHandler(sys.stdout)
- log_handlers: logging.Handler = [stream_handler, logging.FileHandler(log_file_name)]
+ log_handlers: list[logging.Handler] = [stream_handler, logging.FileHandler(log_file_name)]
+ log_handlers += extra_handlers if extra_handlers is not None else []
for handler in log_handlers:
handler.setLevel(level)
diff --git a/pkg/core/migrations/m013_http_api_config.py b/pkg/core/migrations/m013_http_api_config.py
new file mode 100644
index 00000000..8d7c453d
--- /dev/null
+++ b/pkg/core/migrations/m013_http_api_config.py
@@ -0,0 +1,30 @@
+from __future__ import annotations
+
+from .. import migration
+
+
+@migration.migration_class("http-api-config", 13)
+class HttpApiConfigMigration(migration.Migration):
+ """迁移"""
+
+ async def need_migrate(self) -> bool:
+ """判断当前环境是否需要运行此迁移"""
+ return 'http-api' not in self.ap.system_cfg.data or "persistence" not in self.ap.system_cfg.data
+
+ async def run(self):
+ """执行迁移"""
+
+ self.ap.system_cfg.data['http-api'] = {
+ "enable": True,
+ "host": "0.0.0.0",
+ "port": 5300
+ }
+
+ self.ap.system_cfg.data['persistence'] = {
+ "sqlite": {
+ "path": "data/persistence.db"
+ },
+ "use": "sqlite"
+ }
+
+ await self.ap.system_cfg.dump_config()
diff --git a/pkg/core/stages/build_app.py b/pkg/core/stages/build_app.py
index c0e731ce..8c63f7dc 100644
--- a/pkg/core/stages/build_app.py
+++ b/pkg/core/stages/build_app.py
@@ -15,6 +15,10 @@
from ...provider.tools import toolmgr as llm_tool_mgr
from ...provider import runnermgr
from ...platform import manager as im_mgr
+from ...persistence import mgr as persistencemgr
+from ...api.http.controller import main as http_controller
+from ...utils import logcache
+
@stage.stage_class("BuildAppStage")
class BuildAppStage(stage.BootingStage):
@@ -58,6 +62,13 @@ async def run(self, ap: app.Application):
ap.query_pool = pool.QueryPool()
+ log_cache = logcache.LogCache()
+ ap.log_cache = log_cache
+
+ persistence_mgr_inst = persistencemgr.PersistenceManager(ap)
+ await persistence_mgr_inst.initialize()
+ ap.persistence_mgr = persistence_mgr_inst
+
plugin_mgr_inst = plugin_mgr.PluginManager(ap)
await plugin_mgr_inst.initialize()
ap.plugin_mgr = plugin_mgr_inst
@@ -95,6 +106,9 @@ async def run(self, ap: app.Application):
await stage_mgr.initialize()
ap.stage_mgr = stage_mgr
+ http_ctrl = http_controller.HTTPController(ap)
+ await http_ctrl.initialize()
+ ap.http_ctrl = http_ctrl
ctrl = controller.Controller(ap)
ap.ctrl = ctrl
diff --git a/pkg/core/stages/migrate.py b/pkg/core/stages/migrate.py
index 92735c90..a4e57e78 100644
--- a/pkg/core/stages/migrate.py
+++ b/pkg/core/stages/migrate.py
@@ -6,7 +6,7 @@
from .. import migration
from ..migrations import m001_sensitive_word_migration, m002_openai_config_migration, m003_anthropic_requester_cfg_completion, m004_moonshot_cfg_completion
from ..migrations import m005_deepseek_cfg_completion, m006_vision_config, m007_qcg_center_url, m008_ad_fixwin_config_migrate, m009_msg_truncator_cfg
-from ..migrations import m010_ollama_requester_config, m011_command_prefix_config, m012_runner_config
+from ..migrations import m010_ollama_requester_config, m011_command_prefix_config, m012_runner_config, m013_http_api_config
@stage.stage_class("MigrationStage")
diff --git a/pkg/core/stages/setup_logger.py b/pkg/core/stages/setup_logger.py
index 02446b85..8f385d1f 100644
--- a/pkg/core/stages/setup_logger.py
+++ b/pkg/core/stages/setup_logger.py
@@ -1,9 +1,38 @@
from __future__ import annotations
+import logging
+import asyncio
+from datetime import datetime
+
from .. import stage, app
from ..bootutils import log
+class PersistenceHandler(logging.Handler, object):
+ """
+ 保存日志到数据库
+ """
+ ap: app.Application
+
+ def __init__(self, name, ap: app.Application):
+ logging.Handler.__init__(self)
+ self.ap = ap
+
+ def emit(self, record):
+ """
+ emit函数为自定义handler类时必重写的函数,这里可以根据需要对日志消息做一些处理,比如发送日志到服务器
+
+ 发出记录(Emit a record)
+ """
+ try:
+ msg = self.format(record)
+ if self.ap.log_cache is not None:
+ self.ap.log_cache.add_log(msg)
+
+ except Exception:
+ self.handleError(record)
+
+
@stage.stage_class("SetupLoggerStage")
class SetupLoggerStage(stage.BootingStage):
"""设置日志器阶段
@@ -12,4 +41,9 @@ class SetupLoggerStage(stage.BootingStage):
async def run(self, ap: app.Application):
"""启动
"""
- ap.logger = await log.init_logging()
+ persistence_handler = PersistenceHandler('LoggerHandler', ap)
+
+ extra_handlers = []
+ extra_handlers = [persistence_handler]
+
+ ap.logger = await log.init_logging(extra_handlers)
diff --git a/pkg/persistence/__init__.py b/pkg/persistence/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/persistence/database.py b/pkg/persistence/database.py
new file mode 100644
index 00000000..0dd82817
--- /dev/null
+++ b/pkg/persistence/database.py
@@ -0,0 +1,40 @@
+from __future__ import annotations
+
+import abc
+
+import sqlalchemy.ext.asyncio as sqlalchemy_asyncio
+
+from ..core import app
+
+
+preregistered_managers: list[type[BaseDatabaseManager]] = []
+
+def manager_class(name: str) -> None:
+ """注册一个数据库管理类"""
+
+ def decorator(cls: type[BaseDatabaseManager]) -> type[BaseDatabaseManager]:
+ cls.name = name
+ preregistered_managers.append(cls)
+ return cls
+
+ return decorator
+
+
+class BaseDatabaseManager(abc.ABC):
+ """基础数据库管理类"""
+
+ name: str
+
+ ap: app.Application
+
+ engine: sqlalchemy_asyncio.AsyncEngine
+
+ def __init__(self, ap: app.Application) -> None:
+ self.ap = ap
+
+ @abc.abstractmethod
+ async def initialize(self) -> None:
+ pass
+
+ def get_engine(self) -> sqlalchemy_asyncio.AsyncEngine:
+ return self.engine
diff --git a/pkg/persistence/databases/__init__.py b/pkg/persistence/databases/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/persistence/databases/sqlite.py b/pkg/persistence/databases/sqlite.py
new file mode 100644
index 00000000..14f89092
--- /dev/null
+++ b/pkg/persistence/databases/sqlite.py
@@ -0,0 +1,13 @@
+from __future__ import annotations
+
+import sqlalchemy.ext.asyncio as sqlalchemy_asyncio
+
+from .. import database
+
+
+@database.manager_class("sqlite")
+class SQLiteDatabaseManager(database.BaseDatabaseManager):
+ """SQLite 数据库管理类"""
+
+ async def initialize(self) -> None:
+ self.engine = sqlalchemy_asyncio.create_async_engine(f"sqlite+aiosqlite:///{self.ap.system_cfg.data['persistence']['sqlite']['path']}")
diff --git a/pkg/persistence/mgr.py b/pkg/persistence/mgr.py
new file mode 100644
index 00000000..d0c1fa26
--- /dev/null
+++ b/pkg/persistence/mgr.py
@@ -0,0 +1,55 @@
+from __future__ import annotations
+
+import asyncio
+import datetime
+
+import sqlalchemy.ext.asyncio as sqlalchemy_asyncio
+import sqlalchemy
+
+from . import database
+from ..core import app
+from .databases import sqlite
+
+
+class PersistenceManager:
+ """持久化模块管理器"""
+
+ ap: app.Application
+
+ db: database.BaseDatabaseManager
+ """数据库管理器"""
+
+ meta: sqlalchemy.MetaData
+
+ def __init__(self, ap: app.Application):
+ self.ap = ap
+ self.meta = sqlalchemy.MetaData()
+
+ async def initialize(self):
+
+ for manager in database.preregistered_managers:
+ self.db = manager(self.ap)
+ await self.db.initialize()
+
+ await self.create_tables()
+
+ async def create_tables(self):
+ # TODO: 对扩展友好
+
+ # 日志
+ async with self.get_db_engine().connect() as conn:
+ await conn.run_sync(self.meta.create_all)
+
+ await conn.commit()
+
+ async def execute_async(
+ self,
+ *args,
+ **kwargs
+ ):
+ async with self.get_db_engine().connect() as conn:
+ await conn.execute(*args, **kwargs)
+ await conn.commit()
+
+ def get_db_engine(self) -> sqlalchemy_asyncio.AsyncEngine:
+ return self.db.get_engine()
diff --git a/pkg/utils/logcache.py b/pkg/utils/logcache.py
new file mode 100644
index 00000000..0fe419f1
--- /dev/null
+++ b/pkg/utils/logcache.py
@@ -0,0 +1,49 @@
+from __future__ import annotations
+
+import pydantic
+
+
+LOG_PAGE_SIZE = 20
+MAX_CACHED_PAGES = 10
+
+
+class LogPage(pydantic.BaseModel):
+ """日志页"""
+
+ cached_count: int = 0
+
+ logs: str = ""
+
+ def add_log(self, log: str) -> bool:
+ """添加日志
+
+ Returns:
+ bool: 是否已满
+ """
+ self.logs += log
+ self.cached_count += 1
+ return self.cached_count >= LOG_PAGE_SIZE
+
+
+class LogCache:
+ """由于 logger 是同步的,但实例中的数据库操作是异步的;
+ 同时,持久化的日志信息已经写入文件了,故做一个缓存来为前端提供日志查询服务"""
+
+ log_pages: list[LogPage] = []
+ """从前到后,越新的日志页越靠后"""
+
+ def __init__(self):
+ self.log_pages = []
+ self.log_pages.append(LogPage())
+
+ def add_log(self, log: str):
+ """添加日志"""
+ if self.log_pages[-1].add_log(log):
+ self.log_pages.append(LogPage())
+
+ if len(self.log_pages) > MAX_CACHED_PAGES:
+ self.log_pages.pop(0)
+
+ def get_all_logs(self) -> str:
+ """获取所有日志"""
+ return "".join([page.logs for page in self.log_pages])
diff --git a/requirements.txt b/requirements.txt
index 7bf257ed..f001e6af 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,4 +14,7 @@ websockets
urllib3
psutil
async-lru
-ollama
\ No newline at end of file
+ollama
+quart
+sqlalchemy[asyncio]
+aiosqlite
\ No newline at end of file
diff --git a/templates/system.json b/templates/system.json
index 0f6669fe..94a8ad16 100644
--- a/templates/system.json
+++ b/templates/system.json
@@ -11,5 +11,16 @@
},
"pipeline-concurrency": 20,
"qcg-center-url": "https://api.qchatgpt.rockchin.top/api/v2",
- "help-message": "QChatGPT - 😎高稳定性、🧩支持插件、🌏实时联网的 ChatGPT QQ 机器人🤖\n链接:https://q.rkcn.top"
+ "help-message": "QChatGPT - 😎高稳定性、🧩支持插件、🌏实时联网的 ChatGPT QQ 机器人🤖\n链接:https://q.rkcn.top",
+ "http-api": {
+ "enable": true,
+ "host": "0.0.0.0",
+ "port": 5300
+ },
+ "persistence": {
+ "sqlite": {
+ "path": "data/persistence.db"
+ },
+ "use": "sqlite"
+ }
}
\ No newline at end of file
From 9703fc0366ac6ef99378b5ce6ed336cefccb3f08 Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Sun, 13 Oct 2024 22:33:51 +0800
Subject: [PATCH 08/71] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=97=A5?=
=?UTF-8?q?=E5=BF=97=E5=A2=9E=E9=87=8F=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pkg/api/http/controller/groups/log.py | 21 ---------------
pkg/api/http/controller/groups/logs.py | 32 ++++++++++++++++++++++
pkg/api/http/controller/main.py | 2 +-
pkg/utils/logcache.py | 37 ++++++++++++++++++--------
4 files changed, 59 insertions(+), 33 deletions(-)
delete mode 100644 pkg/api/http/controller/groups/log.py
create mode 100644 pkg/api/http/controller/groups/logs.py
diff --git a/pkg/api/http/controller/groups/log.py b/pkg/api/http/controller/groups/log.py
deleted file mode 100644
index fe6de631..00000000
--- a/pkg/api/http/controller/groups/log.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from __future__ import annotations
-
-import traceback
-
-import quart
-
-from .....core import app
-from .. import group
-
-
-@group.group_class('log', '/api/v1/log')
-class LogRouterGroup(group.RouterGroup):
-
- async def initialize(self) -> None:
- @self.route('', methods=['GET'])
- async def _() -> str:
- return self.success(
- data={
- "logs": self.ap.log_cache.get_all_logs()
- }
- )
diff --git a/pkg/api/http/controller/groups/logs.py b/pkg/api/http/controller/groups/logs.py
new file mode 100644
index 00000000..36aa0d75
--- /dev/null
+++ b/pkg/api/http/controller/groups/logs.py
@@ -0,0 +1,32 @@
+from __future__ import annotations
+
+import traceback
+
+import quart
+
+from .....core import app
+from .. import group
+
+
+@group.group_class('logs', '/api/v1/logs')
+class LogsRouterGroup(group.RouterGroup):
+
+ async def initialize(self) -> None:
+ @self.route('', methods=['GET'])
+ async def _() -> str:
+
+ start_page_number = int(quart.request.args.get('start_page_number', 0))
+ start_offset = int(quart.request.args.get('start_offset', 0))
+
+ logs_str, end_page_number, end_offset = self.ap.log_cache.get_log_by_pointer(
+ start_page_number=start_page_number,
+ start_offset=start_offset
+ )
+
+ return self.success(
+ data={
+ "logs": logs_str,
+ "end_page_number": end_page_number,
+ "end_offset": end_offset
+ }
+ )
diff --git a/pkg/api/http/controller/main.py b/pkg/api/http/controller/main.py
index 83e86696..6c7c72f2 100644
--- a/pkg/api/http/controller/main.py
+++ b/pkg/api/http/controller/main.py
@@ -5,7 +5,7 @@
import quart
from ....core import app
-from .groups import log
+from .groups import logs
from . import group
diff --git a/pkg/utils/logcache.py b/pkg/utils/logcache.py
index 0fe419f1..2b8151c2 100644
--- a/pkg/utils/logcache.py
+++ b/pkg/utils/logcache.py
@@ -7,12 +7,16 @@
MAX_CACHED_PAGES = 10
-class LogPage(pydantic.BaseModel):
+class LogPage():
"""日志页"""
+ number: int
+ """页码"""
- cached_count: int = 0
+ logs: list[str]
- logs: str = ""
+ def __init__(self, number: int):
+ self.number = number
+ self.logs = []
def add_log(self, log: str) -> bool:
"""添加日志
@@ -20,9 +24,8 @@ def add_log(self, log: str) -> bool:
Returns:
bool: 是否已满
"""
- self.logs += log
- self.cached_count += 1
- return self.cached_count >= LOG_PAGE_SIZE
+ self.logs.append(log)
+ return len(self.logs) >= LOG_PAGE_SIZE
class LogCache:
@@ -34,16 +37,28 @@ class LogCache:
def __init__(self):
self.log_pages = []
- self.log_pages.append(LogPage())
+ self.log_pages.append(LogPage(number=0))
def add_log(self, log: str):
"""添加日志"""
if self.log_pages[-1].add_log(log):
- self.log_pages.append(LogPage())
+ self.log_pages.append(LogPage(number=self.log_pages[-1].number + 1))
if len(self.log_pages) > MAX_CACHED_PAGES:
self.log_pages.pop(0)
- def get_all_logs(self) -> str:
- """获取所有日志"""
- return "".join([page.logs for page in self.log_pages])
+ def get_log_by_pointer(
+ self,
+ start_page_number: int,
+ start_offset: int,
+ ) -> tuple[str, int, int]:
+ """获取指定页码和偏移量的日志"""
+ final_logs_str = ""
+
+ for page in self.log_pages:
+ if page.number == start_page_number:
+ final_logs_str += "\n".join(page.logs[start_offset:])
+ elif page.number > start_page_number:
+ final_logs_str += "\n".join(page.logs)
+
+ return final_logs_str, page.number, len(page.logs)
From 0dd74c825b333532ba9415ed2ec2b7c44ecdd36e Mon Sep 17 00:00:00 2001
From: RockChinQ <1010553892@qq.com>
Date: Sun, 13 Oct 2024 22:34:35 +0800
Subject: [PATCH 09/71] =?UTF-8?q?feat:=20=E5=89=8D=E7=AB=AF=E5=9F=BA?=
=?UTF-8?q?=E7=A1=80=E6=A1=86=E6=9E=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
web/package-lock.json | 116 +++++++++++++++++++++++++-
web/package.json | 4 +-
web/public/favicon.ico | Bin 15406 -> 9662 bytes
web/src/App.vue | 23 ++++-
web/src/assets/langbot-logo-block.png | Bin 0 -> 14953 bytes
web/src/assets/logo.png | Bin 11955 -> 0 bytes
web/src/assets/logo.svg | 6 --
web/src/pages/DashBoard.vue | 11 +++
web/src/pages/{index.vue => Logs.vue} | 5 +-
web/src/pages/Plugins.vue | 9 ++
web/src/pages/Settings.vue | 9 ++
web/src/plugins/index.js | 3 +
web/src/router/index.js | 12 ++-
web/src/store/index.js | 9 ++
web/vite.config.mjs | 2 +-
15 files changed, 193 insertions(+), 16 deletions(-)
create mode 100644 web/src/assets/langbot-logo-block.png
delete mode 100644 web/src/assets/logo.png
delete mode 100644 web/src/assets/logo.svg
create mode 100644 web/src/pages/DashBoard.vue
rename web/src/pages/{index.vue => Logs.vue} (53%)
create mode 100644 web/src/pages/Plugins.vue
create mode 100644 web/src/pages/Settings.vue
create mode 100644 web/src/store/index.js
diff --git a/web/package-lock.json b/web/package-lock.json
index bca39b56..d60c5734 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -9,10 +9,12 @@
"version": "0.0.0",
"dependencies": {
"@mdi/font": "7.4.47",
+ "axios": "^1.7.7",
"core-js": "^3.37.1",
"roboto-fontface": "*",
"vue": "^3.4.31",
- "vuetify": "^3.6.11"
+ "vuetify": "^3.6.11",
+ "vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.5",
@@ -958,7 +960,6 @@
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
- "dev": true,
"license": "MIT"
},
"node_modules/@vue/reactivity": {
@@ -1260,6 +1261,12 @@
"node": ">=16.14.0"
}
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -1276,6 +1283,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/axios": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
+ "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1468,6 +1486,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1642,6 +1672,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -2489,6 +2528,26 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.9",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+ "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -2499,6 +2558,20 @@
"is-callable": "^1.1.3"
}
},
+ "node_modules/form-data": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
+ "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -3345,6 +3418,27 @@
"node": ">=8.6"
}
},
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -3740,6 +3834,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "license": "MIT"
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -4750,6 +4850,18 @@
}
}
},
+ "node_modules/vuex": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
+ "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.0.0-beta.11"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.2"
+ }
+ },
"node_modules/webpack-virtual-modules": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
diff --git a/web/package.json b/web/package.json
index 3225f51b..b24ede85 100644
--- a/web/package.json
+++ b/web/package.json
@@ -9,10 +9,12 @@
},
"dependencies": {
"@mdi/font": "7.4.47",
+ "axios": "^1.7.7",
"core-js": "^3.37.1",
"roboto-fontface": "*",
"vue": "^3.4.31",
- "vuetify": "^3.6.11"
+ "vuetify": "^3.6.11",
+ "vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.5",
diff --git a/web/public/favicon.ico b/web/public/favicon.ico
index 8fb9f91b3aab4eec0c76ffc5342528033c61e247..00a756f5cedd93bf5228625c6ddeb185eb09e441 100644
GIT binary patch
literal 9662
zcmeHNdvH|M8NUexq$trkrKnZ03e-*oERISmZ6_fF2tE*HM5!o4he5CdtzczJhk;r|
z1VY{z0t66HK&HGBAPR|j$fJ!s5=e4)H`&du*}Suxglu*A#}Pwe`|O^c3x@mbgM-VSJ`3ohh7TJoUE4I7
zZ{7HNZT~2elU}5n;v8~zbdb~Gpti;;YA8A-bkU{FQSht2@wXPf?7a>A#t+`e+g_(8
za|Ll>9XiAr&K-7Yt7RG?G*2ki31KAMz&2I}igtdzZ>HH46E)U=|1H-;X5A!
z!k_p8)yNk_-yC-|@zK6Ibi>)6=A?!>8W&CFr;~&qm`gk#gdJ|_*MI!rdcq8`r%TLkU)|a!ipr8+BJ=fpF%HjZ?bca7eff=_$3y(IROv*&
zwU>^e&s*%zZNRY##6rWt_eh)aa;LuM=X5*Xq>BCTf*-H?wt?=tqw5gYY~(;(G937;
zj}QFEKbdrgJ|NqTR&qKWA_t3ggxjycj`&n_Ig{FNG?T-2gPO|nsC@g}Tku7bA!7rz
z)EdZ+cFl$>h&4;R@o_xZxqz(oW?`%Ezlu|Gyn8HVKj_!`2R6~4P9TSqsJ+!f6?-|p
zVScK8;#{A(iR{SBo~1f}*G>G~9`VLnQ|Z}+8cT9WlQ_epFU*5aU!%tFHKJYB*<_MA
zpQ~e`4#fWYtR&=J66*%`zbAef+%e?tA*kn7>aU!<$uq{kZz;95SiRb`n6;$!_=PTqR#CIH$&Jn4-cH7o8*jD)E;;pes;y9R2sh+4NKN4p
z#4?Xq06lg4mr+}bMd9l45Bq>Wld0lVJowW=cIJ=Bj~@JiPvwLd(q+a1UlBD_mXI+!
zP0VNSI0PL&e-H8HTku0m=E4(VP3sxsu?Hbj{%1nBwno@0ef~`wxHuFDe>4Z)ryH%!
z)PePiDdQs_n=n6lY&qo>vDV;N?v35`K7;*$IK>>76Q%y^1qZ}Db~@Ur`kPeP2zy8`E_mSVj5{1hu_mawn&lO59Y`(~#C$_0VwT7U
zU2`x{{EV|~+gz&F6be5(Y^_wCw}Z6FFLugPZ{9Fp6uZ}6IfdBh#6G8kEM^^-U}WNyh%o
zAC7m1TfNrj_*FePkBWK7^H&wuJnk_k_Yim8V|e6W*Zafko1-L1IP^QO>KM#5+yD6A
zCgz3>2zm79!-qm`?{YZWSBj|M&7|kKq0J@L@v+N+rN=Or9#?{zkP;FxO>x
zcZP40Yk*&TPsO^Iv9tUE(iqIx`5WGq4UzhlGsjFMDuN1s
zU#)s>6<`m-cXffE55TO-eKNX*;_~N5-BXNjMxJHHQzKOTT>k{J4q^-v
zJ)C7*qDsJvwR2sSj{!cYH|Gkp|32U+Vd=T
R2s@W^jbA>raUCv6{{yx2ON;;j
literal 15406
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
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/src/assets/langbot-logo-block.png b/web/src/assets/langbot-logo-block.png
new file mode 100644
index 0000000000000000000000000000000000000000..b2caca7b6b950b6fb2b79d71d1bbe20576c2c906
GIT binary patch
literal 14953
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
WM;=@(*}%7>bk-Jj=8dMlDgOfo2LuHG
literal 0
HcmV?d00001
diff --git a/web/src/assets/logo.png b/web/src/assets/logo.png
deleted file mode 100644
index a5f23ae7bff64954cf3537377a9f99306baf083d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 11955
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
-
-
-
-
-
diff --git a/web/src/pages/DashBoard.vue b/web/src/pages/DashBoard.vue
new file mode 100644
index 00000000..744848ec
--- /dev/null
+++ b/web/src/pages/DashBoard.vue
@@ -0,0 +1,11 @@
+
+ Dashboard
+
+
+
+
+
diff --git a/web/src/pages/index.vue b/web/src/pages/Logs.vue
similarity index 53%
rename from web/src/pages/index.vue
rename to web/src/pages/Logs.vue
index 6488c51b..2a63fbbd 100644
--- a/web/src/pages/index.vue
+++ b/web/src/pages/Logs.vue
@@ -1,6 +1,9 @@
+ Logs
+
+
\ No newline at end of file
diff --git a/web/src/pages/Plugins.vue b/web/src/pages/Plugins.vue
new file mode 100644
index 00000000..e8aa62b4
--- /dev/null
+++ b/web/src/pages/Plugins.vue
@@ -0,0 +1,9 @@
+
+ Plugins
+
+
+
+
+
\ No newline at end of file
diff --git a/web/src/pages/Settings.vue b/web/src/pages/Settings.vue
new file mode 100644
index 00000000..5c044f7c
--- /dev/null
+++ b/web/src/pages/Settings.vue
@@ -0,0 +1,9 @@
+
+ Settings
+
+
+
+
+
\ No newline at end of file
diff --git a/web/src/plugins/index.js b/web/src/plugins/index.js
index 9eb2eb24..c9305e28 100644
--- a/web/src/plugins/index.js
+++ b/web/src/plugins/index.js
@@ -7,9 +7,12 @@
// Plugins
import vuetify from './vuetify'
import router from '@/router'
+import store from '@/store'
+
export function registerPlugins (app) {
app
.use(vuetify)
.use(router)
+ .use(store)
}
diff --git a/web/src/router/index.js b/web/src/router/index.js
index cffec2d7..0c556d28 100644
--- a/web/src/router/index.js
+++ b/web/src/router/index.js
@@ -7,7 +7,17 @@
// Composables
import { createRouter, createWebHistory } from 'vue-router/auto'
-import { routes } from 'vue-router/auto-routes'
+import DashBoard from '../pages/DashBoard.vue'
+import Settings from '../pages/Settings.vue'
+import Logs from '../pages/Logs.vue'
+import Plugins from '../pages/Plugins.vue'
+
+const routes = [
+ { path: '/', component: DashBoard },
+ { path: '/settings', component: Settings },
+ { path: '/logs', component: Logs },
+ { path: '/plugins', component: Plugins },
+]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
diff --git a/web/src/store/index.js b/web/src/store/index.js
new file mode 100644
index 00000000..b62f226b
--- /dev/null
+++ b/web/src/store/index.js
@@ -0,0 +1,9 @@
+import { createStore } from 'vuex'
+import router from '@/router'
+import axios from 'axios'
+
+export default createStore({
+ state: {},
+ mutations: {},
+ actions: {},
+})
diff --git a/web/vite.config.mjs b/web/vite.config.mjs
index 1e6733cd..9870a71e 100644
--- a/web/vite.config.mjs
+++ b/web/vite.config.mjs
@@ -49,6 +49,6 @@ export default defineConfig({
],
},
server: {
- port: 3000,
+ port: 3002,
},
})
From 231dca956d6e8d1a70c6acde421b5690b5e580ec Mon Sep 17 00:00:00 2001
From: Junyan Qin <1010553892@qq.com>
Date: Mon, 14 Oct 2024 18:52:28 +0800
Subject: [PATCH 10/71] =?UTF-8?q?feat:=20=E6=97=A5=E5=BF=97=E9=A1=B5?=
=?UTF-8?q?=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
web/src/App.vue | 50 +++++++++++++++--
web/src/components/PageTitle.vue | 51 +++++++++++++++++
web/src/pages/DashBoard.vue | 4 +-
web/src/pages/Logs.vue | 95 +++++++++++++++++++++++++++++++-
web/src/pages/Plugins.vue | 8 ++-
web/src/pages/Settings.vue | 8 ++-
web/src/plugins/index.js | 4 +-
web/src/store/index.js | 6 +-
8 files changed, 213 insertions(+), 13 deletions(-)
create mode 100644 web/src/components/PageTitle.vue
diff --git a/web/src/App.vue b/web/src/App.vue
index f5c38a01..7ba342ba 100644
--- a/web/src/App.vue
+++ b/web/src/App.vue
@@ -2,17 +2,32 @@
-
+