diff --git a/.changelog/v4.0.0-dev1.md b/.changelog/v4.0.0-dev1.md
new file mode 100644
index 00000000..639b35a9
--- /dev/null
+++ b/.changelog/v4.0.0-dev1.md
@@ -0,0 +1,11 @@
+> 对应核心版本: [**v4.0.0-dev2**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.0.0-dev2)
+
+
+> [!warning]
+> **目前版本处于 `dev` 阶段,代表此版本是一个开发预览版,可能不稳定、可能随时发生更改、且不保证可用性。**
+
+
+我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+感谢您的贡献与支持!
+
+也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
diff --git a/.changelog/v4.0.0-dev2.md b/.changelog/v4.0.0-dev2.md
new file mode 100644
index 00000000..4dc01f77
--- /dev/null
+++ b/.changelog/v4.0.0-dev2.md
@@ -0,0 +1,11 @@
+> 对应核心版本: [**v4.0.0-dev4**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.0.0-dev4)
+
+
+> [!warning]
+> **目前版本处于 `dev` 阶段,代表此版本是一个开发预览版,可能不稳定、可能随时发生更改、且不保证可用性。**
+
+
+我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+感谢您的贡献与支持!
+
+也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
diff --git a/.changelog/v4.0.0-dev3.md b/.changelog/v4.0.0-dev3.md
new file mode 100644
index 00000000..da50602d
--- /dev/null
+++ b/.changelog/v4.0.0-dev3.md
@@ -0,0 +1,11 @@
+> 对应核心版本: [**v4.0.0-dev6**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.0.0-dev6)
+
+
+> [!warning]
+> **目前版本处于 `dev` 阶段,代表此版本是一个开发预览版,可能不稳定、可能随时发生更改、且不保证可用性。**
+
+
+我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+感谢您的贡献与支持!
+
+也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
diff --git a/.changelog/v4.0.0-dev4.md b/.changelog/v4.0.0-dev4.md
new file mode 100644
index 00000000..585a55c7
--- /dev/null
+++ b/.changelog/v4.0.0-dev4.md
@@ -0,0 +1,11 @@
+> 对应核心版本: [**v4.0.0-dev11**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.0.0-dev11)
+
+
+> [!warning]
+> **目前版本处于 `dev` 阶段,代表此版本是一个开发预览版,可能不稳定、可能随时发生更改、且不保证可用性。**
+
+
+我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+感谢您的贡献与支持!
+
+也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
diff --git a/.changelog/v4.0.0-dev5.md b/.changelog/v4.0.0-dev5.md
new file mode 100644
index 00000000..7b688fcd
--- /dev/null
+++ b/.changelog/v4.0.0-dev5.md
@@ -0,0 +1,11 @@
+> 对应核心版本: [**v4.0.0-dev13**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.0.0-dev13)
+
+
+> [!warning]
+> **目前版本处于 `dev` 阶段,代表此版本是一个开发预览版,可能不稳定、可能随时发生更改、且不保证可用性。**
+
+
+我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+感谢您的贡献与支持!
+
+也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
diff --git a/.changelog/v4.0.0-dev6.md b/.changelog/v4.0.0-dev6.md
new file mode 100644
index 00000000..74435d6d
--- /dev/null
+++ b/.changelog/v4.0.0-dev6.md
@@ -0,0 +1,11 @@
+> 对应核心版本: [**v4.0.0-dev14**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.0.0-dev14)
+
+
+> [!warning]
+> **目前版本处于 `dev` 阶段,代表此版本是一个开发预览版,可能不稳定、可能随时发生更改、且不保证可用性。**
+
+
+我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+感谢您的贡献与支持!
+
+也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 6664a981..160b7ab2 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -3,7 +3,7 @@ blank_issues_enabled: true
contact_links:
- name: 问题反馈
url: https://github.com/simple-robot/simpler-robot/issues/new/choose
- about: 统一的问题反馈处
+ about: simbot统一的问题反馈处
- name: 社区
url: https://github.com/orgs/simple-robot/discussions
diff --git a/.github/workflows/deploy-v4-website.yml b/.github/workflows/deploy-v4-website.yml
new file mode 100644
index 00000000..1c58f047
--- /dev/null
+++ b/.github/workflows/deploy-v4-website.yml
@@ -0,0 +1,109 @@
+name: Deploy Website
+on:
+ push:
+ branches:
+# - main
+# - dev/ver/**
+# - dev/main
+ - v4-dev/main
+ - v4-dev/v4-upgrade
+
+ paths:
+ - 'Writerside/**'
+ # Specify to run a workflow manually from the Actions tab on GitHub
+ workflow_dispatch:
+
+# Gives the workflow permissions to clone the repo and create a page deployment
+permissions:
+ id-token: write
+ pages: write
+
+env:
+ # Name of module and id separated by a slash
+ INSTANCE: Writerside/d
+ # Replace HI with the ID of the instance in capital letters
+ ARTIFACT: webHelpD2-all.zip
+ # Writerside docker image version
+ DOCKER_VERSION: 232.10275
+ # Add the variable below to upload Algolia indexes
+ # Replace HI with the ID of the instance in capital letters
+# ALGOLIA_ARTIFACT: algolia-indexes-HI.zip
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Build Writerside docs using Docker
+ uses: JetBrains/writerside-github-action@v4
+ with:
+ instance: ${{ env.INSTANCE }}
+ artifact: ${{ env.ARTIFACT }}
+ docker-version: ${{ env.DOCKER_VERSION }}
+
+ - name: Upload documentation
+ uses: actions/upload-artifact@v3
+ with:
+ name: docs
+ path: |
+ artifacts/${{ env.ARTIFACT }}
+ artifacts/report.json
+ retention-days: 7
+
+ # Add the step below to upload Algolia indexes
+ # - name: Upload algolia-indexes
+ # uses: actions/upload-artifact@v3
+ # with:
+ # name: algolia-indexes
+ # path: artifacts/${{ env.ALGOLIA_ARTIFACT }}
+ # retention-days: 7
+
+ # Add the job below and artifacts/report.json on Upload documentation step above if you want to fail the build when documentation contains errors
+ test:
+ # Requires build job results
+ needs: build
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Download artifacts
+ uses: actions/download-artifact@v1
+ with:
+ name: docs
+ path: artifacts
+
+ - name: Test documentation
+ uses: JetBrains/writerside-checker-action@v1
+ with:
+ instance: ${{ env.INSTANCE }}
+
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ # Requires the build job results
+ needs: test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download artifact
+ uses: actions/download-artifact@v3
+ with:
+ name: docs
+
+ - name: Unzip artifact
+ run: unzip -O UTF-8 -qq ${{ env.ARTIFACT }} -d dir
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v2
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v1
+ with:
+ path: dir
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v1
+
diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml.bk
similarity index 100%
rename from .github/workflows/deploy-website.yml
rename to .github/workflows/deploy-website.yml.bk
diff --git a/.github/workflows/kdoc.yml.bk b/.github/workflows/kdoc.yml.bk
index bb6c23fd..ede31418 100644
--- a/.github/workflows/kdoc.yml.bk
+++ b/.github/workflows/kdoc.yml.bk
@@ -44,7 +44,7 @@ jobs:
with:
personal_token: ${{ secrets.PUSH_TOKEN }}
external_repository: simple-robot-library/simbot3-api-docs
- publish_branch: kdoc-deploy/component-tencent-guild
+ publish_branch: kdoc-deploy/component-tencent-guild-v3
publish_dir: ./build/dokka/html
# deploy to sub dir
- destination_dir: components/tencent-guild
+ destination_dir: components/tencent-guild-v3
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index e9d40e79..bde9bcb8 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -156,7 +156,7 @@ jobs:
with:
personal_token: ${{ secrets.PUSH_TOKEN }}
external_repository: simple-robot-library/simbot3-api-docs
- publish_branch: kdoc-deploy/component-qq-guild
+ publish_branch: kdoc-deploy/component-qq-guild-v3
publish_dir: ./build/dokka/html
# deploy to sub dir
- destination_dir: components/qq-guild
+ destination_dir: components/qq-guild-v3
diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml
index 5e279b8d..39a6c086 100644
--- a/.github/workflows/publish-snapshot.yml
+++ b/.github/workflows/publish-snapshot.yml
@@ -99,7 +99,7 @@ jobs:
with:
personal_token: ${{ secrets.PUSH_TOKEN }}
external_repository: simple-robot-library/simbot3-api-docs
- publish_branch: kdoc-deploy/snapshots/component-qq-guild
+ publish_branch: kdoc-deploy/snapshots/component-qq-guild-v3
publish_dir: ./build/dokka/html
# deploy to sub dir
- destination_dir: snapshots/components/qq-guild
+ destination_dir: snapshots/components/qq-guild-v3
diff --git a/.github/workflows/publish-v4-release.yml b/.github/workflows/publish-v4-release.yml
new file mode 100644
index 00000000..22dae6eb
--- /dev/null
+++ b/.github/workflows/publish-v4-release.yml
@@ -0,0 +1,162 @@
+name: Publish V4 Release
+on:
+ push:
+ tags:
+ - v4.**.**
+
+env:
+ IS_CI: true
+ GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
+ GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
+ GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
+ OSSRH_USER: ${{ secrets.SONATYPE_USERNAME }}
+ OSSRH_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
+ SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
+ SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
+ GRADLE_OPTS: "-Xmx8g -Xms2g -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8"
+
+
+jobs:
+ run-test-and-publish-v4:
+ name: Run test and publish V4
+ strategy:
+ matrix:
+ os: [ macos-latest, windows-latest, ubuntu-latest ]
+ runs-on: ${{ matrix.os }}
+ steps:
+ # 检出仓库代码
+ - name: Check Out Repo
+ uses: actions/checkout@v3
+
+ # setup Java
+ - name: Setup Java
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: 21
+ cache: 'gradle'
+
+ # setup Gradle
+ - name: Gradle Run Test
+ uses: gradle/gradle-build-action@v2
+ with:
+ gradle-version: 8.5
+ arguments: assemble test -Porg.gradle.daemon=false
+
+ # setup Gradle
+ - name: Publish Release
+ uses: gradle/gradle-build-action@v2
+ with:
+ gradle-version: 8.5
+ arguments: |
+ publishToSonatype
+ closeAndReleaseStagingRepository
+ --info
+ --warning-mode all
+ -x test
+ --build-cache
+ -Porg.gradle.jvmargs="-Xmx8g -Xms2g -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8"
+ -Porg.gradle.daemon=false
+
+ env:
+ SIMBOT_IS_SNAPSHOT: false
+ SIMBOT_RELEASES_ONLY: true
+
+ create-release:
+ name: Create release
+ runs-on: ubuntu-latest
+ needs: run-test-and-publish-v4
+ permissions:
+ contents: write
+ steps:
+ # 检出仓库代码
+ - name: Check Out Repo
+ uses: actions/checkout@v3
+
+ # Create gitHub release
+ - name: Create Github Release
+ uses: softprops/action-gh-release@v0.1.14
+ with:
+ token: ${{ secrets.PUSH_TOKEN }}
+ body_path: .changelog/${{ github.ref_name }}.md
+ generate_release_notes: true
+ prerelease: ${{ contains(github.ref_name, 'preview') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') || contains(github.ref_name, 'dev') }}
+
+ publish-snapshot:
+ name: Publish snapshot
+ strategy:
+ matrix:
+ os: [ macos-latest, windows-latest, ubuntu-latest ]
+ runs-on: ${{ matrix.os }}
+ needs: run-test-and-publish-v4
+ steps:
+ # 检出仓库代码
+ - name: Check out repo
+ uses: actions/checkout@v3
+
+ # setup Java
+ - name: Setup java
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: 21
+
+ # setup Gradle
+ - name: Gradle publish snapshot
+ uses: gradle/gradle-build-action@v2
+ with:
+ gradle-version: 8.5
+ arguments: |
+ publishToSonatype
+ closeAndReleaseStagingRepository
+ --info
+ --warning-mode all
+ -x test
+ --build-cache
+ -Porg.gradle.jvmargs="-Xmx8g -Xms2g -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8"
+ -Porg.gradle.daemon=false
+ env:
+ SIMBOT_IS_SNAPSHOT: true
+ SIMBOT_SNAPSHOT_ONLY: true
+
+ deploy-doc:
+ name: Deploy-doc
+ runs-on: ubuntu-latest
+ needs: run-test-and-publish-v4
+ steps:
+ # 检出仓库代码
+ - name: Check out repo
+ uses: actions/checkout@v3
+ with:
+ persist-credentials: false
+ fetch-depth: 0
+ # setup Java
+ - name: Setup java
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: 21
+
+ # setup Gradle
+ - name: Gradle generate documentation
+ uses: gradle/gradle-build-action@v2
+ with:
+ gradle-version: 8.5
+ arguments: |
+ dokkaHtmlMultiModule
+ --info
+ --warning-mode all
+ -x test
+ --build-cache
+ -Porg.gradle.jvmargs="-Xmx8g -Xms2g -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8"
+ -Porg.gradle.daemon=false
+
+ - name: Push to doc repository
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ personal_token: ${{ secrets.PUSH_TOKEN }}
+ external_repository: simple-robot-library/simbot3-api-docs
+ publish_branch: kdoc-deploy/component-qq-guild
+ publish_dir: ./build/dokka/html
+ # deploy to sub dir
+ destination_dir: components/qq-guild
diff --git a/.github/workflows/publish-v4-snapshot.yml b/.github/workflows/publish-v4-snapshot.yml
new file mode 100644
index 00000000..97b26e61
--- /dev/null
+++ b/.github/workflows/publish-v4-snapshot.yml
@@ -0,0 +1,111 @@
+name: Publish V4 Snapshot
+on:
+ push:
+ branches:
+ - v4-dev/*
+ - v4-dev/v4-upgrade
+ - v4-dev/main
+
+ paths:
+ - 'buildSrc'
+ - '**src/**/kotlin/**.kt'
+ - '**src/**/java/**.java'
+ - '**/src/**/kotlin/**.kt'
+ - '**/src/**/java/**.java'
+ - '**/build.gradle.kts'
+ - 'build.gradle.kts'
+ - 'settings.gradle.kts'
+ - 'gradle.properties'
+
+ # 手动触发工作流
+ workflow_dispatch:
+
+env:
+ IS_CI: true
+ GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
+ GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
+ GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
+ OSSRH_USER: ${{ secrets.SONATYPE_USERNAME }}
+ OSSRH_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
+ SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
+ SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
+ SIMBOT_IS_SNAPSHOT: true
+ SIMBOT_SNAPSHOT_ONLY: true
+ GRADLE_OPTS: "-Dfile.encoding=UTF-8"
+
+
+jobs:
+ publish-snapshot:
+ name: Publish snapshot
+ strategy:
+ matrix:
+ os: [ macos-latest, windows-latest, ubuntu-latest ]
+ runs-on: ${{ matrix.os }}
+ steps:
+ # 检出仓库代码
+ - name: Check out repo
+ uses: actions/checkout@v3
+
+ # setup Java
+ - name: Setup java
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: 21
+
+ # setup Gradle
+ - name: Gradle test and publish snapshot
+ uses: gradle/gradle-build-action@v2
+ with:
+ gradle-version: 8.5
+ arguments: |
+ test
+ publishToSonatype
+ closeAndReleaseStagingRepository
+ --info
+ --warning-mode all
+ -Porg.gradle.jvmargs="-Xmx8g -Xms2g -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8"
+ -Porg.gradle.daemon=false
+
+ deploy-doc:
+ name: Deploy-doc
+ runs-on: ubuntu-latest
+ needs: publish-snapshot
+ steps:
+ # 检出仓库代码
+ - name: Check out repo
+ uses: actions/checkout@v3
+ with:
+ persist-credentials: false
+ fetch-depth: 0
+ # setup Java
+ - name: Setup java
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: 21
+
+ # setup Gradle
+ - name: Gradle generate documentation
+ uses: gradle/gradle-build-action@v2
+ with:
+ gradle-version: 8.5
+ arguments: |
+ -Porg.gradle.jvmargs="-Xmx4g -Xms4g -XX:MaxMetaspaceSize=2g -Dfile.encoding=UTF-8"
+ -Porg.gradle.daemon=false
+ -DisSnapshot=false
+ --info
+ --warning-mode all
+ -x test
+ --build-cache
+ dokkaHtmlMultiModule
+
+ - name: Push to doc repository
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ personal_token: ${{ secrets.PUSH_TOKEN }}
+ external_repository: simple-robot-library/simbot3-api-docs
+ publish_branch: kdoc-deploy/snapshots/component-qq-guild
+ publish_dir: ./build/dokka/html
+ # deploy to sub dir
+ destination_dir: snapshots/components/qq-guild
diff --git a/.github/workflows/test-branch.yml b/.github/workflows/test-branch.yml
index 585cb689..0e798f52 100644
--- a/.github/workflows/test-branch.yml
+++ b/.github/workflows/test-branch.yml
@@ -27,13 +27,12 @@ jobs:
os: [ macos-latest, windows-latest, ubuntu-latest ]
runs-on: ${{ matrix.os }}
steps:
-
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
- java-version: 11
- cache: 'gradle'
+ java-version: 21
+# cache: 'gradle'
- name: Run All Tests
uses: gradle/gradle-build-action@v2
diff --git a/.run/runConfigurations/allTests.run.xml b/.run/runConfigurations/allTests.run.xml
new file mode 100644
index 00000000..7a7b84bd
--- /dev/null
+++ b/.run/runConfigurations/allTests.run.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/.run/runConfigurations/publishToMavenLocal.run.xml b/.run/runConfigurations/publishToMavenLocal.run.xml
new file mode 100644
index 00000000..205cbed1
--- /dev/null
+++ b/.run/runConfigurations/publishToMavenLocal.run.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index bf90534f..e1c834c2 100644
--- a/README.md
+++ b/README.md
@@ -21,37 +21,42 @@
-这是 [**Simple Robot v3**](https://github.com/simple-robot/simpler-robot)
-下的子项目,是针对 [**QQ频道机器人**](https://bot.q.qq.com/wiki/develop/api/) 各方面的实现,
+这是
+[**Simple Robot v4**](https://github.com/simple-robot/simpler-robot/tree/v4-dev)
+下的子项目,是针对
+[**QQ频道机器人**](https://bot.q.qq.com/wiki/develop/api/)
+各方面的 simbot 组件库实现,
包括对 `API` 内容的实现、事件相关的实现以及BOT对于事件的监听与交互等。
-- 基于 [`Kotlin`](https://kotlinlang.org/) 提供[多平台](https://kotlinlang.org/docs/multiplatform.html)/JVM平台(core模块) 特性
+- 基于 [`Kotlin`](https://kotlinlang.org/) 提供 [KMP 多平台](https://kotlinlang.org/docs/multiplatform.html) 特性
- 基于 [`Kotlin coroutines`](https://github.com/Kotlin/kotlinx.coroutines) 与 [`Ktor`](https://ktor.io/) 提供高效易用的API;
-- 基于 [`Kotlin serialization`](https://github.com/Kotlin/kotlinx.serialization) 进行数据序列化/反序列化操作。
+
+- 基于 [`Kotlin`](https://kotlinlang.org/) 提供 [KMP 多平台](https://kotlinlang.org/docs/multiplatform.html) 特性,提供 Java 友好的API。
+- 基于 [`Kotlin coroutines`](https://github.com/Kotlin/kotlinx.coroutines) 与 [`Ktor`](https://ktor.io/) 提供轻量高效的API。
> [!Note]
-> 下文中 `Simple Robot v3` 简称为 `simbot3`
+> 下文中 `Simple Robot v4` 简称为 `simbot4`
## 文档
-- 了解simbot3: [**simbot3官网**](https://simbot.forte.love)
-- **QQ频道组件**手册:https://simple-robot.github.io/simbot-component-qq-guild/ (尚在 _🔧建设中_,暂未配置域名)
+- 了解simbot: [**Simple Robot 应用手册**](https://simbot.forte.love)
+- **QQ频道组件**手册: (即当前仓库的 GitHub Pages)
- **API文档**: [**文档引导站点**](https://docs.simbot.forte.love) 中QQ频道的 [**KDoc站点**](https://docs.simbot.forte.love/components/qq-guild)
---
-我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+我们欢迎并期望着您的
+[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)
+或
+[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
感谢您的贡献与支持!
## 模块引导
### API模块
-> JVM | JS | native
-
基于 `Ktor` 针对 [QQ频道API](https://bot.q.qq.com/wiki/develop/api/)
的基本完整的[KMP](https://kotlinlang.org/docs/multiplatform.html)多平台封装实现,
-支持 JVM、JS 和 native 平台,
是一个简单高效轻量级的API实现模块。
此模块基本不会提供什么多余的实现,其目标为在提供封装的情况下尽可能地保留原始API的使用手感,不做过多的封装。
@@ -60,12 +65,8 @@
### 标准库模块
-> JVM | JS | native
-
基于 [API模块](simbot-component-qq-guild-api) 针对bot的"登录"鉴权实现简单高效轻量级的事件订阅功能。
-通过[KMP](https://kotlinlang.org/docs/multiplatform.html)多平台支持 JVM、JS 和 native 平台,
-
此模块在API模块的基础上提供了针对事件相关的功能实现,包括事件订阅的能力。
同样的,其目标为在提供封装的情况下尽可能地保留原始API的使用手感,不做过多的封装。
@@ -73,12 +74,13 @@
### 核心组件模块
-> JVM Only
-
-基于 [标准库模块](simbot-component-qq-guild-stdlib) 对 [simbot3核心库](https://github.com/simple-robot/simpler-robot) 的组件实现,
-是一个相对高度封装的模块,并提供simbot3大部分能力,包括事件监听、多组件协同、Spring Boot Starter 等。
+基于
+[标准库模块](simbot-component-qq-guild-stdlib)
+对 [simbot4核心库](https://github.com/simple-robot/simpler-robot)
+的组件实现,
+是一个相对高度封装的模块,并提供simbot4大部分能力,包括事件监听、多组件协同、Spring Boot Starter 等。
-👉 [前往模块](simbot-component-qq-guild-core) 了解更多。
+👉 [前往模块](simbot-component-qq-guild-core-1) 了解更多。
## 法欧莉
diff --git a/Writerside/.idea/.gitignore b/Writerside/.idea/.gitignore
new file mode 100644
index 00000000..df2b2e45
--- /dev/null
+++ b/Writerside/.idea/.gitignore
@@ -0,0 +1,6 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+
+vcs.xml
+modules.xml
\ No newline at end of file
diff --git a/Writerside/.idea/markdown.xml b/Writerside/.idea/markdown.xml
new file mode 100644
index 00000000..f6d2542c
--- /dev/null
+++ b/Writerside/.idea/markdown.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Writerside/c.list b/Writerside/c.list
new file mode 100644
index 00000000..5babfee2
--- /dev/null
+++ b/Writerside/c.list
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/Writerside/cfg/buildprofiles.xml b/Writerside/cfg/buildprofiles.xml
new file mode 100644
index 00000000..fd8d9c87
--- /dev/null
+++ b/Writerside/cfg/buildprofiles.xml
@@ -0,0 +1,36 @@
+
+
+
+
+ ruby
+ logo-icon.svg
+ logo-icon.svg
+ https://github.com/simple-robot/simbot-component-qq-guild/
+ GitHub
+ https://github.com/simple-robot/simbot-component-qq-guild/
+ true
+
+ true
+ zh-CN
+ false
+
+
+
+
+ false
+
+
+
+
+
diff --git a/Writerside/cfg/glossary.xml b/Writerside/cfg/glossary.xml
new file mode 100644
index 00000000..cb5ce8f3
--- /dev/null
+++ b/Writerside/cfg/glossary.xml
@@ -0,0 +1,5 @@
+
+
+
+ 组件:针对一组一个或多个「组件标识」和「插件」的统称。
+
diff --git a/Writerside/d.tree b/Writerside/d.tree
new file mode 100644
index 00000000..163705b0
--- /dev/null
+++ b/Writerside/d.tree
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Writerside/images/logo-icon.svg b/Writerside/images/logo-icon.svg
new file mode 100644
index 00000000..03a946a3
--- /dev/null
+++ b/Writerside/images/logo-icon.svg
@@ -0,0 +1,1205 @@
+
+
+
diff --git a/Writerside/topics/Home.md b/Writerside/topics/Home.md
new file mode 100644
index 00000000..a28c575f
--- /dev/null
+++ b/Writerside/topics/Home.md
@@ -0,0 +1,57 @@
+# 欢迎!
+
+这里是
+[**Simple Robot v4**](https://github.com/simple-robot/simpler-robot/tree/v4-dev)
+的
+[QQ频道组件](https://github.com/simple-robot/simbot-component-qq-guild/)
+应用手册!
+
+## 概述
+
+**QQ频道组件** 是针对
+[**QQ频道机器人**](https://bot.q.qq.com/wiki/develop/api/)
+各方面的 Simple Robot 组件库实现,
+包括对 `API`、事件的封装、bot 订阅与处理事件的实现以及作为 Simple Robot 的组件库的实现。
+
+- 基于 [`Kotlin`](https://kotlinlang.org/) 提供 [KMP 多平台](https://kotlinlang.org/docs/multiplatform.html) 特性,提供 Java 友好的API。
+- 基于 [`Kotlin coroutines`](https://github.com/Kotlin/kotlinx.coroutines) 与 [`Ktor`](https://ktor.io/) 提供轻量高效的API。
+
+### 了解 Simple Robot
+
+- [Simple Robot 应用手册](https://simbot.forte.love)
+- [Simple Robot 组织库](https://github.com/simple-robot)
+
+### API文档
+
+- [API文档引导站](https://docs.simbot.forte.love)
+
+## 反馈与协助!
+
+我们欢迎并期望着您的
+[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)
+或
+[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+感谢您的贡献与支持!
+
+## 法欧莉
+
+如果你想看一看通过 **QQ频道组件** 实现的应用案例,
+可以前往QQ频道添加亲爱的 [法欧莉斯卡雷特](https://qun.qq.com/qunpro/robot/share?robot_appid=101986850) 来体验~
+
+
+## License
+
+`simbot-component-qq-guild` 使用 `LGPLv3` 许可证开源。
+
+```
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
+Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along with this program.
+If not, see .
+```
diff --git a/Writerside/topics/api.md b/Writerside/topics/api.md
new file mode 100644
index 00000000..10e49c17
--- /dev/null
+++ b/Writerside/topics/api.md
@@ -0,0 +1,9 @@
+# 概述
+
+提供一些针对QQ频道提供的一些特殊消息、具体功能概念实现的描述。
+
+比如,
+
+即为一种特殊类型的消息,而
+
+便是一种功能概念实现。
diff --git a/Writerside/topics/ark/api_ark.md b/Writerside/topics/ark/api_ark.md
new file mode 100644
index 00000000..bee184f6
--- /dev/null
+++ b/Writerside/topics/ark/api_ark.md
@@ -0,0 +1,4 @@
+# Ark消息
+
+QQ频道中有一些针对 `Ark消息` 的API。
+
diff --git a/Writerside/topics/bot-config.md b/Writerside/topics/bot-config.md
new file mode 100644
index 00000000..e67d653d
--- /dev/null
+++ b/Writerside/topics/bot-config.md
@@ -0,0 +1,280 @@
+# Bot配置文件
+
+
+在使用 Spring Boot 时自动注册 bot 所需的配置文件。
+
+
+
+
+如果你在使用 Spring Boot,
+将配置文件放在在你的资源目录中:
+resources/simbot-bots/,
+并以 `.bot.json` 作为扩展名,例如 `mybot.bot.json`。
+
+这个扫描目录是可配置的。
+这是属于 simbot4 Spring Boot starter 的配置,可参考
+[simbot手册: 使用 Spring Boot 3](https://simbot.forte.love/start-use-spring-boot-3.html)。
+
+
+
+## 示例
+
+```json
+{
+ "component": "simbot.qqguild",
+ "ticket": {
+ "appId": "你的botId",
+ "secret": "你的bot secret, 如果用不到也可以给空字符串",
+ "token": "你的bot token"
+ }
+}
+```
+{collapsible="true" default-state="expanded" collapsed-title="简单示例"}
+
+```json
+{
+ "component": "simbot.qqguild",
+ "ticket": {
+ "appId": "你的botId",
+ "secret": "你的bot secret, 如果用不到也可以给空字符串",
+ "token": "你的bot token"
+ },
+ "config": {
+ "serverUrl": null,
+ "shard": {
+ "type": "full"
+ },
+ "intents": {
+ "type": "raw",
+ "intents": 1073741827
+ },
+ "clientProperties": null,
+ "timeout": null,
+ "cache": {
+ "enable": true,
+ "transmit": null,
+ "dynamic": null,
+ "dispatcher": null
+ }
+ }
+}
+```
+{collapsible="true" default-state="collapsed" collapsed-title="完整示例"}
+
+## 属性描述
+
+
+
+
+固定值:`simbot.qqguild`
+
+
+
+
+bot用于登录的票据信息,必填。
+
+
+
+
+`String`
+
+bot开发配置中的 `appID`
+
+
+
+
+`String`
+
+bot开发配置中的 `AppSecret`, 如果用不到可以给空字符串
+
+
+
+
+`String`
+
+bot开发配置中的 `Token`。
+
+
+
+
+
+
+
+可选项,提供一些额外的可配置属性。
+
+
+
+
+`String`
+
+目标服务器地址。默认为 `null`。
+
+当值为特殊值:`"SANDBOX"` 时会选择使用 `QQGuild.SANDBOX_URL_STRING`,
+也就是沙箱服务器地址。
+
+
+
+
+`ShardConfig`
+
+分片信息配置,默认为 `Full`。
+
+根据 `type` 值的不同,可使用不同的属性。
+
+
+
+
+无额外属性,代表一个全量单片。
+
+```json
+{
+ "type": "full"
+}
+```
+
+
+
+
+```json
+{
+ "type": "simple",
+ "value": 0,
+ "total": 1
+}
+```
+
+
+对应的分片信息属性。
+对应的分片信息属性。
+
+
+
+
+
+
+
+
+
+`IntentsConfig?`
+
+要订阅的事件的 intents 信息。默认 `1073741827`,
+也就是订阅:
+- 频道相关事件
+- 频道成员相关事件
+- 公域消息相关事件
+
+根据 `type` 的不同可选的属性不同。
+
+
+
+
+直接使用 `intents` 原始的标记位最终数值。
+
+```json
+{
+ "type": "raw",
+ "intents": 1073741824
+}
+```
+
+
+
+
+通过名称寻找所有可用的 `EventIntents` 并合并为最终的 `intents`。
+名称基于继承了 `EventIntents` 的 object 的简单类名,例如 `Guilds`。
+
+```json
+{
+ "type": "nameBased",
+ "names": ["Guilds", "PublicGuildMessages"]
+}
+```
+
+
+
+
+
+
+
+`Map?`
+
+用作 `Signal.Identify.Data.properties` 中的参数。
+
+```json
+{
+ "config": {
+ "clientProperties": {
+ "k1": "v1",
+ "foo": "bar"
+ }
+ }
+}
+```
+
+
+
+
+`TimeoutConfig?`
+
+与部分超时相关的配置信息。
+当任意属性不为 `null` 时会为 bot 中用于请求API的 `HttpClient`
+配置 [HttpTimeout][HttpTimeout] 插件。
+
+默认为 `null`。
+
+
+
+
+`Long?`
+
+API请求中的超时请求配置。参考 [HttpTimeout][HttpTimeout] 中的相关说明。
+
+默认为 `null`。
+
+
+
+
+`Long?`
+
+API请求中的超时请求配置。参考 [HttpTimeout][HttpTimeout] 中的相关说明。
+
+默认为 `null`。
+
+
+
+
+`Long?`
+
+API请求中的超时请求配置。参考 [HttpTimeout][HttpTimeout] 中的相关说明。
+
+默认为 `null`。
+
+
+
+
+
+
+
+`CacheConfig?`
+
+缓存相关配置。
+
+```json
+"config": {
+ "cache": {
+ "transmit": {
+ "enable": true
+ }
+ }
+}
+```
+
+有关 `transmit` 的详细描述,
+请参考 `TransmitCacheConfig` 的文档注释或 API Doc。
+
+
+
+
+
+
+[HttpTimeout]: https://ktor.io/docs/timeout.html
diff --git a/Writerside/topics/embed/api_embed.md b/Writerside/topics/embed/api_embed.md
new file mode 100644
index 00000000..66a519dd
--- /dev/null
+++ b/Writerside/topics/embed/api_embed.md
@@ -0,0 +1,4 @@
+# Embed消息
+
+QQ频道中有一些针对 `Embed消息` 的API。
+
diff --git a/Writerside/topics/event.md b/Writerside/topics/event.md
new file mode 100644
index 00000000..2706dbd5
--- /dev/null
+++ b/Writerside/topics/event.md
@@ -0,0 +1,104 @@
+# 事件类型
+
+QQ频道组件中的**事件类型**包含两个层面:
+
+1. **API 模块** 中,对 QQ频道 API 中官方定义的事件结构的基本封装与实现。
+2. **核心模块** 中,基于 API 模块中的事件封装,对 simbot4 标准库中的 `Event` 事件类型的实现。
+
+
+## API 模块事件封装
+
+API 模块所有的事件封装类型都在包 `love.forte.simbot.qguild.event` 中,
+并且基本上命名与官网API中的事件类型名称有一定关联。
+
+所有事件封装类型均继承密封类 `love.forte.simbot.qguild.event.Signal.Dispatch`。
+
+
+子频道创建事件 CHANNEL_CREATE
+子频道修改事件 CHANNEL_UPDATE
+子频道删除事件 CHANNEL_DELETE
+主题创建事件 FORUM_THREAD_CREATE
+主题更新事件 FORUM_THREAD_UPDATE
+主题删除事件 FORUM_THREAD_DELETE
+帖子创建事件 FORUM_POST_CREATE
+帖子删除事件 FORUM_POST_DELETE
+回复创建事件 FORUM_REPLY_CREATE
+回复删除事件 FORUM_REPLY_DELETE
+帖子审核事件 FORUM_PUBLISH_AUDIT_RESULT
+"开放"创建主题事件 OPEN_FORUM_THREAD_CREATE
+"开放"更新主题事件 OPEN_FORUM_THREAD_UPDATE
+"开放"删除主题事件 OPEN_FORUM_THREAD_DELETE
+"开放"帖子创建(评论)事件 OPEN_FORUM_POST_CREATE
+"开放"帖子删除(评论)事件 OPEN_FORUM_POST_DELETE
+"开放"回复创建事件 OPEN_FORUM_REPLY_CREATE
+"开放"回复删除事件 OPEN_FORUM_REPLY_DELETE
+Bot加入频道事件 GUILD_CREATE
+频道信息变更事件 GUILD_UPDATE
+Bot因各种原因退出频道事件 GUILD_DELETE
+新用户加入频道事件 GUILD_MEMBER_ADD
+用户的频道属性发生变化事件 GUILD_MEMBER_UPDATE
+用户离开频道事件 GUILD_MEMBER_REMOVE
+收到公域at消息事件 AT_MESSAGE_CREATE
+
+PUBLIC_MESSAGE_DELETE
+此事件官网文档似乎没有详细说明,请慎重使用
+
+私信消息事件 DIRECT_MESSAGE_CREATE
+(私域)发送消息事件 MESSAGE_CREATE
+
+MESSAGE_DELETE
+此事件官网文档似乎没有详细说明,请慎重使用
+
+消息审核通过事件 MESSAGE_AUDIT_PASS
+消息审核不通过事件 MESSAGE_AUDIT_REJECT
+
+
+API 模块事件封装可以使用在 **标准库模块 (stdlib)** 中,使用 `Bot` 类型对他们进行监听与处理。
+
+
+## Simbot 标准库 Event 实现
+
+使用核心库,可以在 simbot4 的 `Application` 或 Spring Boot 中使用这些事件类型实现。
+
+核心模块所有的 simbot Event 实现类型定义都在包 `love.forte.simbot.component.qguild.event` 中。
+
+所有实现类型均继承 `love.forte.simbot.qguild.component.event.QGEvent`。
+
+> QQ频道的 simbot 事件实现会根据含义,选择性的实现一些特定的类型。
+> 举个例子,`QGAtMessageCreateEvent` 可以代表“子频道消息事件”,
+> 因此它实现了 `ChatChannelMessageEvent`。
+
+
+仔细观察可以发现,大部分 simbot Event 实现类型都可以与 API 模块的事件封装类型相对应。
+
+
+
+子频道创建事件
+子频道修改事件
+子频道删除事件
+主题创建事件
+主题更新事件
+主题删除事件
+帖子创建事件
+帖子删除事件
+回复创建事件
+回复删除事件
+帖子审核事件
+新用户加入频道事件
+用户的频道属性发生变化事件
+用户离开频道事件
+新用户加入频道事件
+用户的频道属性发生变化事件
+用户离开频道事件
+收到公域at消息事件
+"开放"创建主题事件
+"开放"更新主题事件
+"开放"删除主题事件
+"开放"帖子创建(评论)事件
+"开放"帖子删除(评论)事件
+"开放"回复创建事件
+"开放"回复删除事件
+
+特殊的事件类型,用于包装兼容那些尚未被封装支持的 API 模块的事件封装类型。
+
+
diff --git a/Writerside/topics/forum/api_forum.md b/Writerside/topics/forum/api_forum.md
new file mode 100644
index 00000000..2c5a8f2e
--- /dev/null
+++ b/Writerside/topics/forum/api_forum.md
@@ -0,0 +1,624 @@
+---
+switcher-label: Java API 风格
+---
+
+# 论坛 Forum
+
+QQ频道中有一些针对 `论坛子频道` 的API。([参考文档](https://bot.q.qq.com/wiki/develop/api/openapi/forum/model.html#thread))
+
+
+## API
+
+首先是 `API` 模块中对相关API的封装类型,它们在 `love.forte.simbot.qguild.api.forum` 中:
+
+- `DeleteThreadApi`
+- `GetThreadApi`
+- `GetThreadListApi`
+- `PublishThreadApi`
+
+使用它们的方式都差不多,我们选其中一个 `GetThreadListApi` 作为示例:
+
+
+
+
+```kotlin
+// QQ频道API请求用的 token
+val token = "Bot xxx"
+
+// Ktor 的 HttpClient
+// 在不同平台下请注意选择可用的引擎,比如在JS平台下使用 `JS` 引擎,windows系统平台下使用 `WinHttp` 等。
+val client = HttpClient()
+
+// 请求的服务器地址
+// 此处为沙箱地址,也可选择正式地址或其他第三方代理地址
+val server = QQGuild.SANDBOX_URL
+
+val api = GetThreadListApi.create("channel ID")
+val result = api.requestData(client, server, token)
+
+result.threads.forEach { thread ->
+ // 遍历结果...
+}
+```
+
+
+
+
+
+```java
+// QQ频道API请求用的 token
+String token = "Bot xxx";
+
+// Ktor 的 HttpClient
+// 此处选择使用 HttpClientJvmKt.HttpClient 自动加载环境中存在的 HttpClient 引擎
+// 请保证classpath中存在一个可用的 HttpClient JVM 引擎
+HttpClient client = HttpClientJvmKt.HttpClient(config -> Unit.INSTANCE);
+
+// 请求的服务器地址
+// 此处为沙箱地址,也可选择正式地址或其他第三方代理地址
+Url server = QQGuild.SANDBOX_URL;
+
+GetThreadListApi api = GetThreadListApi.create("channel ID");
+CompletableFuture extends ThreadListResult> result = ApiRequests.requestDataAsync(api, client, token, server);
+
+result.thenApply(ThreadListResult::getThreads)
+ .thenAccept(threads -> {
+ for (Thread thread : threads) {
+ // 遍历结果
+ }
+ });
+```
+{switcher-key="%ja%"}
+
+```java
+// QQ频道API请求用的 token
+String token = "Bot xxx";
+
+// Ktor 的 HttpClient
+// 此处选择使用 HttpClientJvmKt.HttpClient 自动加载环境中存在的 HttpClient 引擎
+// 请保证classpath中存在一个可用的 HttpClient JVM 引擎
+HttpClient client = HttpClientJvmKt.HttpClient(config -> Unit.INSTANCE);
+
+// 请求的服务器地址
+// 此处为沙箱地址,也可选择正式地址或其他第三方代理地址
+Url server = QQGuild.SANDBOX_URL;
+
+GetThreadListApi api = GetThreadListApi.create("channel ID");
+ThreadListResult result =.requestDataBlocking(api, client, token, server);
+
+for (Thread thread : result.getThreads()) {
+// 遍历结果
+}
+```
+{switcher-key="%jb%"}
+
+
+
+
+## 组件能力
+
+在组件模块 `core` 中,也同样针对论坛子频道的相关内容提供了API。
+在组件模块中提供了一些新的类型:
+
+- `QGForumChannel` : 表示论坛子频道的 `Channel` 实现
+- `QGForums` : 表示一个 `QGGuild` 针对帖子的相关操作
+- `QGThread` : 表示一个主题帖
+- `QGThreadCreator` : 一个用于构造并发布帖子的构造器
+
+
+> 这些操作大多从 `QGGuild` 作为入口提供。
+
+
+
+
+
+```kotlin
+val guild: QGGuild = ....
+
+// 在所有的子频道中筛选出 论坛子频道
+guild.channels.asFlow()
+ // highlight-next-line
+ .filterIsInstance()
+ .collect { channel: QGForumChannel ->
+ // ...
+ channel.threads.collect {
+ // 获取所有的主题帖
+ }
+ val thread: QGThread? = channel.thread("123".ID) // 获取指定ID的主题帖
+
+ // 构造并发布一个主题贴
+ channel.createThread {
+ title = ...
+ content = ...
+ format = ...
+ }
+
+ // 假设其不为null
+ // 删除某个主题帖
+ thread!!.delete()
+}
+```
+
+除了在 `channels` 中通过类型筛选以外,也可以通过 `QGGuild.forums` 来进行操作:
+
+```kotlin
+val guild: QGGuild = ....
+
+// 在所有的子频道中筛选出 论坛子频道
+// highlight-next-line
+guild.forums.forumChannels
+ .collect { channel: QGForumChannel ->
+ // ...
+ channel.threads.collect {
+ // 获取所有的主题帖
+ }
+ val thread: QGThread? = channel.thread("123".ID) // 获取指定ID的主题帖
+ // 构造并发布一个主题贴
+ channel.createThread {
+ title = ...
+ content = ...
+ format = ...
+ }
+ // 假设其不为null
+ // 删除某个主题帖
+ thread!!.delete()
+}
+// 根据ID获取指定的 论坛子频道 实例
+val forumChannel: QGForumChannel? = guild.forums.forumChannel("666".ID)
+
+```
+
+
+
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getChannels().collectAsync(channel -> {
+ // 遍历所有的论坛子频道
+ // highlight-next-line
+ if (channel instanceof QGForumChannel forumChannel) {
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collectAsync(thread -> {
+ // ...
+ }); // thenXxx?
+ // 获取指定ID的主题帖
+ CompletableFuture extends QGThread> threadAsync = forumChannel.getThreadAsync(Identifies.ID("123"));
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishAsync();
+
+ threadAsync.thenAccept(thread -> { // or use thenCompose
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteAsync();
+ });
+ }
+});
+```
+{switcher-key="%ja%"}
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getChannels().collect(channel -> {
+ // 遍历所有的论坛子频道
+ // highlight-next-line
+ if (channel instanceof QGForumChannel forumChannel) {
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collect(thread -> {
+ // ...
+ });
+ // 获取指定ID的主题帖
+ QGThread thread = forumChannel.getThread(Identifies.ID("123")); // nullable
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishBlocking();
+
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteBlocking();
+ }
+});
+```
+{switcher-key="%jb%"}
+
+除了在 `channels` 中通过类型筛选以外,也可以通过 `QGGuild.forums` 来进行操作:
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getForums()
+ // highlight-next-line
+ .getForumChannels()
+ .collectAsync(forumChannel -> {
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collectAsync(thread -> {
+ // ...
+ }); // thenXxx?
+ // 获取指定ID的主题帖
+ CompletableFuture extends QGThread> threadAsync = forumChannel.getThreadAsync(Identifies.ID("123"));
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishAsync();
+ threadAsync.thenAccept(thread -> { // or use thenCompose
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteAsync();
+ });
+ });
+```
+{switcher-key="%ja%"}
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getForums()
+ // highlight-next-line
+ .getForumChannels()
+ .collect(forumChannel -> {
+ // 遍历所有的论坛子频道
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collect(thread -> {
+ // ...
+ });
+ // 获取指定ID的主题帖
+ QGThread thread = forumChannel.getThread(Identifies.ID("123")); // nullable
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishBlocking();
+
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteBlocking();
+ });
+```
+{switcher-key="%jb%"}
+
+
+
+
+
+## API事件 {id="api_dispatch"}
+
+API模块实现了与论坛相关的事件类型,它们的类型(与继承关系)如下:
+
+- `OpenForumDispatch` : **开放论坛事件**
+ - `OpenForumThreadDispatch` : 开放论坛事件 - **主题贴事件**
+ - `OpenForumThreadCreate` : 主题贴事件: **主题贴创建**
+ - `OpenForumThreadUpdate` : 主题贴事件: **主题贴更新**
+ - `OpenForumThreadDelete` : 主题贴事件: **主题贴删除**
+ - `OpenForumPostDispatch` : 开放论坛事件 - **评论事件**
+ - `OpenForumPostCreate` : 评论事件 - **评论创建**
+ - `OpenForumPostDelete` : 评论事件 - **评论删除**
+ - `OpenForumReplyDispatch` : 开放论坛事件 - **回复事件**
+ - `OpenForumReplyCreate` : 回复事件 - **回复创建**
+ - `OpenForumReplyDelete` : 回复事件 - **回复删除**
+
+:::note 开放论坛事件
+
+对应的 `instents` 为 `EventIntents.OpenForumsEvent.intents`
+
+更多可参考 [官方文档](https://bot.q.qq.com/wiki/develop/api/gateway/open_forum.html#oepn-forum-event-intents-open-forum-event)
+
+:::
+
+- `ForumDispatch` : **论坛事件**
+ - `ForumThreadDispatch` : 论坛事件 - **主题贴事件**
+ - `ForumThreadCreate` : 主题贴事件: **主题贴创建**
+ - `ForumThreadUpdate` : 主题贴事件: **主题贴更新**
+ - `ForumThreadDelete` : 主题贴事件: **主题贴删除**
+ - `ForumPostDispatch` : 论坛事件 - **评论事件**
+ - `ForumPostCreate` : 评论事件 - **评论创建**
+ - `ForumPostDelete` : 评论事件 - **评论删除**
+ - `ForumReplyDispatch` : 论坛事件 - **回复事件**
+ - `ForumReplyCreate` : 回复事件 - **回复创建**
+ - `ForumReplyDelete` : 回复事件 - **回复删除**
+ - `ForumPublishAuditResult` : 论坛事件 - **帖子审核事件**
+
+
+:::note 论坛事件
+
+对应的 `instents` 为 `EventIntents.ForumsEvent.intents`
+
+更多可参考 [官方文档](https://bot.q.qq.com/wiki/develop/api/gateway/forum.html)
+
+:::
+
+:::info 仅私域
+
+非开放的论坛事件是仅支持**私域BOT**的。
+
+:::
+
+### 标准库应用
+
+在使用 `stdlib` 标准库时可以对它们进行监听,以 `OpenForumThreadCreate` 为例:
+
+
+
+
+```kotlin
+// 配置并创建bot
+val bot = BotFactory.create("app id", "sec", "token") {
+ useSandboxServerUrl()
+ // 为了示例,增加对 OpenForumsEvent 事件的支持
+ intents += EventIntents.OpenForumsEvent.intents
+}
+
+bot.process { raw ->
+ println("OpenForumThreadCreate: $this")
+ println("OpenForumThreadCreate.raw: $raw")
+}
+
+bot.start()
+bot.join()
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("appid", "sec", "token", (config) -> {
+ config.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ config.setIntentsValue(
+ config.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ });
+
+bot.registerProcessor(EventProcessors.async(OpenForumThreadCreate.class, (event, raw) -> {
+ System.out.println("OpenForumThreadCreate: " + event);
+ System.out.println("OpenForumThreadCreate.raw: " + raw);
+ return CompletableFuture.completedFuture(null); // Void?
+ }));
+
+bot.startAsync().thenCompose((v) -> bot.joinAsync()).join();
+```
+{switcher-key="%ja%"}
+
+```java
+Bot bot = BotFactory.create("appid", "sec", "token", (config) -> {
+ config.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ config.setIntentsValue(
+ config.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ return Unit.INSTANCE;
+ });
+
+bot.registerBlockingProcessor(EventProcessors.block(OpenForumThreadCreate.class, (event, raw) -> {
+ System.out.println("OpenForumThreadCreate: " + event);
+ System.out.println("OpenForumThreadCreate.raw: " + raw);
+ }));
+
+bot.startBlocking();
+bot.joinBlocking();
+```
+{switcher-key="%jb%"}
+
+
+
+
+### 组件模块应用
+
+#### core 组件模块
+
+core 组件模块基于 simbot api 针对上述事件提供了进一步的封装实现:
+
+- `QGOpenForumEvent` : **开放论坛事件**
+ - `QGOpenForumThreadEvent` : 开放论坛事件 - **主题贴事件**
+ - `QGOpenForumThreadCreateEvent` : 主题贴事件: **主题贴创建**
+ - `QGOpenForumThreadUpdateEvent` : 主题贴事件: **主题贴更新**
+ - `QGOpenForumThreadDeleteEvent` : 主题贴事件: **主题贴删除**
+ - `QGOpenForumPostEvent` : 开放论坛事件 - **评论事件**
+ - `QGOpenForumPostCreateEvent` : 评论事件 - **评论创建**
+ - `QGOpenForumPostDeleteEvent` : 评论事件 - **评论删除**
+ - `QGOpenForumReplyEvent` : 开放论坛事件 - **回复事件**
+ - `QGOpenForumReplyCreateEvent` : 回复事件 - **回复创建**
+ - `QGOpenForumReplyDeleteEvent` : 回复事件 - **回复删除**
+
+
+- `QGForumEvent` : **论坛事件**
+ - `QGForumThreadEvent` : 论坛事件 - **主题贴事件**
+ - `QGForumThreadCreateEvent` : 主题贴事件: **主题贴创建**
+ - `QGForumThreadUpdateEvent` : 主题贴事件: **主题贴更新**
+ - `QGForumThreadDeleteEvent` : 主题贴事件: **主题贴删除**
+ - `QGForumPostEvent` : 论坛事件 - **评论事件**
+ - `QGForumPostCreateEvent` : 评论事件 - **评论创建**
+ - `QGForumPostDeleteEvent` : 评论事件 - **评论删除**
+ - `QGForumReplyEvent` : 论坛事件 - **回复事件**
+ - `QGForumReplyCreateEvent` : 回复事件 - **回复创建**
+ - `QGForumReplyDeleteEvent` : 回复事件 - **回复删除**
+ - `QGForumPublishAuditResultEvent` : 论坛事件 - **帖子审核事件**
+
+它们基本上与 API 模块中的基础实现类型一一对应。
+
+在使用 simbot 核心库时:
+
+
+
+
+```kotlin
+val app = launchSimpleApplication {
+ useQQGuild()
+}
+
+app.eventDispatcher.apply {
+ // 所有开放论坛事件
+ listen {
+ println("Open forum event: $it")
+
+ EventResult.empty()
+ }
+
+ // 所有论坛事件
+ listen {
+ println("Forum event: $it")
+
+ EventResult.empty()
+ }
+}
+
+app.qqGuildBots {
+ val bot = register("appid", "sec", "token") {
+ botConfig {
+ useSandboxServerUrl()
+ // 追加事件订阅
+ intents += EventIntents.OpenForumsEvent.intents + EventIntents.ForumsEvent.intents
+ }
+ }
+
+ bot.start()
+}
+
+app.join()
+```
+
+
+
+
+
+```java
+var future = Applications.launchApplicationAsync(Simple.INSTANCE, configurer -> {
+ configurer.install(QQGuildBotManager.Factory);
+ configurer.install(QQGuildComponent.Factory);
+}).asFuture().thenCompose(application -> {
+ // 所有开放论坛事件
+ application.getEventDispatcher().register(EventListeners.async(QGOpenForumEvent.class, (context, event) -> {
+ System.out.println("QG open forum event: " + event);
+ return CompletableFuture.completedFuture(EventResult.empty());
+ }));
+ // 所有论坛事件
+ application.getEventDispatcher().register(EventListeners.async(QGForumEvent.class, (context, event) -> {
+ System.out.println("QG forum event: " + event);
+ return CompletableFuture.completedFuture(EventResult.empty());
+ }));
+ // 寻找并注册 bot
+ for (var botManager : application.getBotManagers()) {
+ if (botManager instanceof QQGuildBotManager qqGuildBotManager) {
+ var bot = qqGuildBotManager.register("appid", "sec", "token", (qgBotConfig) -> {
+ qgBotConfig.botConfig(botConfig -> {
+ botConfig.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ botConfig.setIntentsValue(
+ botConfig.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ });
+ });
+ bot.startAsync();
+ break;
+ }
+ }
+
+ return application.asFuture();
+});
+
+future.join();
+```
+{switcher-key="%ja%"}
+
+```java
+final var application = Applications.launchApplicationBlocking(Simple.INSTANCE, configurer -> {
+ configurer.install(QQGuildBotManager.Factory);
+ configurer.install(QQGuildComponent.Factory);
+});
+
+// 所有开放论坛事件
+application.getEventDispatcher().register(EventListeners.block(QGOpenForumEvent.class, (context, event) -> {
+ System.out.println("QG open forum event: " + event);
+ return EventResult.empty();
+ }));
+
+// 所有论坛事件
+application.getEventDispatcher().register(EventListeners.block(QGForumEvent.class, (context, event) -> {
+ System.out.println("QG forum event: " + event);
+ return EventResult.empty();
+ }));
+
+// 寻找并注册 bot
+for (var botManager : application.getBotManagers()) {
+ if (botManager instanceof QQGuildBotManager qqGuildBotManager) {
+ var bot = qqGuildBotManager.register("appid", "sec", "token", (qgBotConfig) -> {
+ qgBotConfig.botConfig(botConfig -> {
+ botConfig.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ botConfig.setIntentsValue(
+ botConfig.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ });
+ });
+ bot.startBlocking();
+ break;
+ }
+}
+
+application.joinBlocking();
+```
+{switcher-key="%jb%"}
+
+
+
+
+#### SpringBoot
+
+或在 SpringBoot 中:
+
+> _省略掉有关SpringBoot项目本身的配置说明_
+
+
+
+
+```kotlin
+@Listener
+suspend fun onForumEvent(event: QGForumEvent) {
+ println("Event: $event")
+}
+```
+
+
+
+
+```java
+@Listener
+public CompletableFuture onForumEvent(QGForumEvent event) {
+ System.out.println("Event: " + event);
+ return CompletableFuture.completedFuture(null);
+}
+```
+{switcher-key="%ja%"}
+
+```java
+@Listener
+public void onForumEvent(QGForumEvent event) {
+ System.out.println("Event: " + event);
+}
+```
+{switcher-key="%jb%"}
+
+
+
diff --git a/Writerside/topics/messages.md b/Writerside/topics/messages.md
new file mode 100644
index 00000000..30aa93d6
--- /dev/null
+++ b/Writerside/topics/messages.md
@@ -0,0 +1,35 @@
+# 消息类型
+
+
+
+- 对那些 **核心库** 中、实现了 simbot4 标准库的 `Message.Element` 消息元素类型的说明,
+- 对一些与 **核心库** 中“消息”相关的内容的补充说明。
+
+
+
+## 消息元素实现
+
+所有的 `Message.Element` 特殊实现类型均定义在包 `love.forte.simbot.component.qguild.message` 中。
+
+它们都继承了 `love.forte.simbot.component.qguild.message.QGMessageElement` 。
+
+
+对 API 模块中 Ark 消息的包装体,可用来发送 Ark
消息。
+
+对 API 模块中 Embed 消息的包装体,可用来发送 Embed
消息。
+TODO Message type
+TODO Message type
+
+
+发送消息时,QQ频道的消息引用。与官方发送消息API中的 `reference` 对应。
+
+
+
+
+仅用于发送。
+
+发送消息时,指定一个需要回复的目标消息ID。
+
+
+
+
diff --git a/Writerside/topics/old/3.2.0.0/api/old-api-forum.md b/Writerside/topics/old/3.2.0.0/api/old-api-forum.md
new file mode 100644
index 00000000..0933a060
--- /dev/null
+++ b/Writerside/topics/old/3.2.0.0/api/old-api-forum.md
@@ -0,0 +1,617 @@
+# 论坛
+
+QQ频道中有一些针对 `论坛子频道` 的API。( [参考文档](https://bot.q.qq.com/wiki/develop/api/openapi/forum/model.html#thread) )
+
+
+## API {id="api_1"}
+
+首先是 `API` 模块中对相关API的封装类型,它们在 `love.forte.simbot.qguild.api.forum` 中:
+
+- `DeleteThreadApi`
+- `GetThreadApi`
+- `GetThreadListApi`
+- `PublishThreadApi`
+
+使用它们的方式都差不多,我们选其中一个 `GetThreadListApi` 作为示例:
+
+
+
+
+```kotlin
+// QQ频道API请求用的 token
+val token = "Bot xxx"
+
+// Ktor 的 HttpClient
+// 在不同平台下请注意选择可用的引擎,比如在JS平台下使用 `JS` 引擎,windows系统平台下使用 `WinHttp` 等。
+val client = HttpClient()
+
+// 请求的服务器地址
+// 此处为沙箱地址,也可选择正式地址或其他第三方代理地址
+val server = QQGuild.SANDBOX_URL
+
+val api = GetThreadListApi.create("channel ID")
+val result = api.request(client, server, token)
+
+result.threads.forEach { thread ->
+ // 遍历结果...
+}
+```
+
+
+
+
+```java
+// QQ频道API请求用的 token
+String token = "Bot xxx";
+
+// Ktor 的 HttpClient
+// 此处选择使用 HttpClientJvmKt.HttpClient 自动加载环境中存在的 HttpClient 引擎
+// 请保证classpath中存在一个可用的 HttpClient JVM 引擎
+HttpClient client = HttpClientJvmKt.HttpClient(config -> Unit.INSTANCE);
+
+// 请求的服务器地址
+// 此处为沙箱地址,也可选择正式地址或其他第三方代理地址
+Url server = QQGuild.SANDBOX_URL;
+
+GetThreadListApi api = GetThreadListApi.create("channel ID");
+ThreadListResult result = api.doRequestBlocking(client, server, token);
+
+for (Thread thread : result.getThreads()) {
+// 遍历结果
+}
+```
+
+
+
+
+```java
+// QQ频道API请求用的 token
+String token = "Bot xxx";
+
+// Ktor 的 HttpClient
+// 此处选择使用 HttpClientJvmKt.HttpClient 自动加载环境中存在的 HttpClient 引擎
+// 请保证classpath中存在一个可用的 HttpClient JVM 引擎
+HttpClient client = HttpClientJvmKt.HttpClient(config -> Unit.INSTANCE);
+
+// 请求的服务器地址
+// 此处为沙箱地址,也可选择正式地址或其他第三方代理地址
+Url server = QQGuild.SANDBOX_URL;
+
+GetThreadListApi api = GetThreadListApi.create("channel ID");
+CompletableFuture extends ThreadListResult> result = api.doRequestAsync(client, server, token);
+
+result.thenApply(ThreadListResult::getThreads)
+ .thenAccept(threads -> {
+ for (Thread thread : threads) {
+ // 遍历结果
+ }
+ });
+```
+
+
+
+
+## 组件能力
+
+在组件模块 `core` 中,也同样针对论坛子频道的相关内容提供了API。
+在组件模块中提供了一些新的类型:
+
+- `QGForumChannel` : 表示论坛子频道的 `Channel` 实现
+- `QGForums` : 表示一个 `QGGuild` 针对帖子的相关操作
+- `QGThread` : 表示一个主题帖
+- `QGThreadCreator` : 一个用于构造并发布帖子的构造器
+
+
+> 这些操作大多从 `QGGuild` 作为入口提供。
+
+
+
+
+
+```kotlin
+val guild: QGGuild = ....
+
+// 在所有的子频道中筛选出 论坛子频道
+guild.channels.asFlow()
+ // highlight-next-line
+ .filterIsInstance()
+ .collect { channel: QGForumChannel ->
+ // ...
+ channel.threads.collect {
+ // 获取所有的主题帖
+ }
+ val thread: QGThread? = channel.thread("123".ID) // 获取指定ID的主题帖
+
+ // 构造并发布一个主题贴
+ channel.createThread {
+ title = ...
+ content = ...
+ format = ...
+ }
+
+ // 假设其不为null
+ // 删除某个主题帖
+ thread!!.delete()
+}
+```
+
+除了在 `channels` 中通过类型筛选以外,也可以通过 `QGGuild.forums` 来进行操作:
+
+```kotlin
+val guild: QGGuild = ....
+
+// 在所有的子频道中筛选出 论坛子频道
+// highlight-next-line
+guild.forums.forumChannels
+ .collect { channel: QGForumChannel ->
+ // ...
+ channel.threads.collect {
+ // 获取所有的主题帖
+ }
+ val thread: QGThread? = channel.thread("123".ID) // 获取指定ID的主题帖
+ // 构造并发布一个主题贴
+ channel.createThread {
+ title = ...
+ content = ...
+ format = ...
+ }
+ // 假设其不为null
+ // 删除某个主题帖
+ thread!!.delete()
+}
+// 根据ID获取指定的 论坛子频道 实例
+val forumChannel: QGForumChannel? = guild.forums.forumChannel("666".ID)
+
+```
+
+
+
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getChannels().collect(channel -> {
+ // 遍历所有的论坛子频道
+ // highlight-next-line
+ if (channel instanceof QGForumChannel forumChannel) {
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collect(thread -> {
+ // ...
+ });
+ // 获取指定ID的主题帖
+ QGThread thread = forumChannel.getThread(Identifies.ID("123")); // nullable
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishBlocking();
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteBlocking();
+ }
+});
+```
+
+除了在 `channels` 中通过类型筛选以外,也可以通过 `QGGuild.forums` 来进行操作:
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getForums()
+ // highlight-next-line
+ .getForumChannels()
+ .collect(forumChannel -> {
+ // 遍历所有的论坛子频道
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collect(thread -> {
+ // ...
+ });
+ // 获取指定ID的主题帖
+ QGThread thread = forumChannel.getThread(Identifies.ID("123")); // nullable
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishBlocking();
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteBlocking();
+ });
+```
+
+
+
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getChannels().collectAsync(channel -> {
+ // 遍历所有的论坛子频道
+ // highlight-next-line
+ if (channel instanceof QGForumChannel forumChannel) {
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collectAsync(thread -> {
+ // ...
+ }); // thenXxx?
+ // 获取指定ID的主题帖
+ CompletableFuture extends QGThread> threadAsync = forumChannel.getThreadAsync(Identifies.ID("123"));
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishAsync();
+ threadAsync.thenAccept(thread -> { // or use thenCompose
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteAsync();
+ });
+ }
+});
+```
+
+除了在 `channels` 中通过类型筛选以外,也可以通过 `QGGuild.forums` 来进行操作:
+
+```java
+QGGuild guild = ...;
+
+// 直接遍历
+// 你也可以选择转为列表后再操作
+guild.getForums()
+ // highlight-next-line
+ .getForumChannels()
+ .collectAsync(forumChannel -> {
+ // 获取所有的主题帖并遍历
+ forumChannel.getThreads().collectAsync(thread -> {
+ // ...
+ }); // thenXxx?
+ // 获取指定ID的主题帖
+ CompletableFuture extends QGThread> threadAsync = forumChannel.getThreadAsync(Identifies.ID("123"));
+ // 构造并发布一个主题贴
+ forumChannel.threadCreator()
+ .title(...)
+ .content(...)
+ .format(...)
+ .publishAsync();
+ threadAsync.thenAccept(thread -> { // or use thenCompose
+ // 假设其不为null
+ assert thread != null;
+ // 删除某个主题帖
+ thread.deleteAsync();
+ });
+ });
+```
+
+
+
+
+
+## API事件
+
+API模块实现了与论坛相关的事件类型,它们的类型(与继承关系)如下:
+
+- `OpenForumDispatch` : **开放论坛事件**
+ - `OpenForumThreadDispatch` : 开放论坛事件 - **主题贴事件**
+ - `OpenForumThreadCreate` : 主题贴事件: **主题贴创建**
+ - `OpenForumThreadUpdate` : 主题贴事件: **主题贴更新**
+ - `OpenForumThreadDelete` : 主题贴事件: **主题贴删除**
+ - `OpenForumPostDispatch` : 开放论坛事件 - **评论事件**
+ - `OpenForumPostCreate` : 评论事件 - **评论创建**
+ - `OpenForumPostDelete` : 评论事件 - **评论删除**
+ - `OpenForumReplyDispatch` : 开放论坛事件 - **回复事件**
+ - `OpenForumReplyCreate` : 回复事件 - **回复创建**
+ - `OpenForumReplyDelete` : 回复事件 - **回复删除**
+
+
+
+
+对应的 `instents` 为 `EventIntents.OpenForumsEvent.intents`
+
+更多可参考 [官方文档](https://bot.q.qq.com/wiki/develop/api/gateway/open_forum.html#oepn-forum-event-intents-open-forum-event)
+
+
+
+
+- `ForumDispatch` : **论坛事件**
+ - `ForumThreadDispatch` : 论坛事件 - **主题贴事件**
+ - `ForumThreadCreate` : 主题贴事件: **主题贴创建**
+ - `ForumThreadUpdate` : 主题贴事件: **主题贴更新**
+ - `ForumThreadDelete` : 主题贴事件: **主题贴删除**
+ - `ForumPostDispatch` : 论坛事件 - **评论事件**
+ - `ForumPostCreate` : 评论事件 - **评论创建**
+ - `ForumPostDelete` : 评论事件 - **评论删除**
+ - `ForumReplyDispatch` : 论坛事件 - **回复事件**
+ - `ForumReplyCreate` : 回复事件 - **回复创建**
+ - `ForumReplyDelete` : 回复事件 - **回复删除**
+ - `ForumPublishAuditResult` : 论坛事件 - **帖子审核事件**
+
+
+
+对应的 `instents` 为 `EventIntents.ForumsEvent.intents`
+
+更多可参考 [官方文档](https://bot.q.qq.com/wiki/develop/api/gateway/forum.html)
+
+
+
+
+> 非开放的论坛事件是仅支持**私域BOT**的。
+
+### 标准库应用
+
+在使用 `stdlib` 标准库时可以对它们进行监听,以 `OpenForumThreadCreate` 为例:
+
+
+
+
+```kotlin
+// 配置并创建bot
+val bot = BotFactory.create("app id", "sec", "token") {
+ useSandboxServerUrl()
+ // 为了示例,增加对 OpenForumsEvent 事件的支持
+ intents += EventIntents.OpenForumsEvent.intents
+}
+
+bot.registerProcessor { raw ->
+ println("OpenForumThreadCreate: $this")
+ println("OpenForumThreadCreate.raw: $raw")
+}
+
+bot.start()
+bot.join()
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("appid", "sec", "token", (config) -> {
+ config.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ config.setIntentsValue(
+ config.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ return Unit.INSTANCE;
+ });
+
+bot.registerBlockingProcessor(OpenForumThreadCreate.class, (event, raw) -> {
+ System.out.println("OpenForumThreadCreate: " + event);
+ System.out.println("OpenForumThreadCreate.raw: " + raw);
+});
+
+bot.startBlocking();
+bot.joinBlocking();
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("appid", "sec", "token", (config) -> {
+ config.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ config.setIntentsValue(
+ config.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ return Unit.INSTANCE;
+ });
+
+bot.registerAsyncProcessor(OpenForumThreadCreate.class, (event, raw) -> {
+ System.out.println("OpenForumThreadCreate: " + event);
+ System.out.println("OpenForumThreadCreate.raw: " + raw);
+ return CompletableFuture.completedFuture(null); // Void?
+});
+
+bot.startAsync().thenCompose((v) -> bot.joinAsync()).join();
+```
+
+
+
+
+### 组件模块应用
+
+#### core 组件模块
+
+core 组件模块基于 simbot api 针对上述事件提供了进一步的封装实现:
+
+- `QGOpenForumEvent` : **开放论坛事件**
+ - `QGOpenForumThreadEvent` : 开放论坛事件 - **主题贴事件**
+ - `QGOpenForumThreadCreateEvent` : 主题贴事件: **主题贴创建**
+ - `QGOpenForumThreadUpdateEvent` : 主题贴事件: **主题贴更新**
+ - `QGOpenForumThreadDeleteEvent` : 主题贴事件: **主题贴删除**
+ - `QGOpenForumPostEvent` : 开放论坛事件 - **评论事件**
+ - `QGOpenForumPostCreateEvent` : 评论事件 - **评论创建**
+ - `QGOpenForumPostDeleteEvent` : 评论事件 - **评论删除**
+ - `QGOpenForumReplyEvent` : 开放论坛事件 - **回复事件**
+ - `QGOpenForumReplyCreateEvent` : 回复事件 - **回复创建**
+ - `QGOpenForumReplyDeleteEvent` : 回复事件 - **回复删除**
+
+
+- `QGForumEvent` : **论坛事件**
+ - `QGForumThreadEvent` : 论坛事件 - **主题贴事件**
+ - `QGForumThreadCreateEvent` : 主题贴事件: **主题贴创建**
+ - `QGForumThreadUpdateEvent` : 主题贴事件: **主题贴更新**
+ - `QGForumThreadDeleteEvent` : 主题贴事件: **主题贴删除**
+ - `QGForumPostEvent` : 论坛事件 - **评论事件**
+ - `QGForumPostCreateEvent` : 评论事件 - **评论创建**
+ - `QGForumPostDeleteEvent` : 评论事件 - **评论删除**
+ - `QGForumReplyEvent` : 论坛事件 - **回复事件**
+ - `QGForumReplyCreateEvent` : 回复事件 - **回复创建**
+ - `QGForumReplyDeleteEvent` : 回复事件 - **回复删除**
+ - `QGForumPublishAuditResultEvent` : 论坛事件 - **帖子审核事件**
+
+它们基本上与 API 模块中的基础实现类型一一对应。
+
+在使用 simbot 核心库时:
+
+
+
+
+```kotlin
+val app = createSimpleApplication {
+ useQQGuild()
+}
+
+app.eventListenerManager.listeners {
+ // 所有开放论坛事件
+ QGOpenForumEvent {
+ println("Open forum event: $it")
+ }
+
+ // 所有论坛事件
+ QGForumEvent {
+ println("Forum event: $it")
+ }
+}
+
+app.qqGuildBots {
+ val bot = register("appid", "sec", "token") {
+ botConfig {
+ useSandboxServerUrl()
+ // 追加事件订阅
+ intents += EventIntents.OpenForumsEvent.intents + EventIntents.ForumsEvent.intents
+ }
+ }
+
+ bot.start()
+}
+
+app.join()
+```
+
+
+
+
+```java
+SimpleApplication application = Applications.buildSimbotApplication(Simple.INSTANCE)
+ .build((builder, c) -> {
+ // 安装QQ频道组件相关的内容
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+ }).createBlocking();
+
+// 所有开放论坛事件
+application.getEventListenerManager().register(SimpleListeners.listener(QGOpenForumEvent.Key, (context, event) -> {
+ System.out.println("QG open forum event: " + event);
+}));
+
+// 所有论坛事件
+application.getEventListenerManager().register(SimpleListeners.listener(QGForumEvent.Key, (context, event) -> {
+ System.out.println("QG forum event: " + event);
+}));
+
+// 寻找并注册QQGuildBot
+for (BotManager> botManager : application.getBotManagers()) {
+ if (botManager instanceof QQGuildBotManager qqGuildBotManager) {
+ QGBog bot = qqGuildBotManager.register("appid", "sec", "token", (config) -> {
+ config.botConfig(botConfig -> {
+ botConfig.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ botConfig.setIntentsValue(
+ botConfig.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ return Unit.INSTANCE;
+ });
+ return Unit.INSTANCE;
+ });
+
+ bot.startBlocking();
+ break;
+ }
+}
+
+application.joinBlocking();
+```
+
+
+
+
+```java
+Applications.buildSimbotApplication(Simple.INSTANCE)
+ .build((builder, c) -> {
+ // 安装QQ频道组件相关的内容
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+ }).createAsync().thenAccept(application -> {
+ // 所有开放论坛事件
+ application.getEventListenerManager().register(SimpleListeners.listener(QGOpenForumEvent.Key, (context, event) -> {
+ System.out.println("QG open forum event: " + event);
+ }));
+ // 所有论坛事件
+ application.getEventListenerManager().register(SimpleListeners.listener(QGForumEvent.Key, (context, event) -> {
+ System.out.println("QG forum event: " + event);
+ }));
+ // 寻找并注册QQGuildBot
+ for (BotManager> botManager : application.getBotManagers()) {
+ if (botManager instanceof QQGuildBotManager qqGuildBotManager) {
+ QGBot bot = qqGuildBotManager.register("appid", "sec", "token", (config) -> {
+ config.botConfig(botConfig -> {
+ botConfig.useSandboxServerUrl();
+ // 追加对 OpenForumsEvent 事件的订阅:OpenForumsEvent 与默认订阅合并
+ botConfig.setIntentsValue(
+ botConfig.getIntentsValue() | EventIntents.OpenForumsEvent.getIntents()
+ );
+ return Unit.INSTANCE;
+ });
+ return Unit.INSTANCE;
+ });
+ bot.startAsync();
+ break;
+ }
+ }
+ })
+ .join();
+```
+
+
+
+
+#### SpringBoot
+
+或在 SpringBoot 中:
+
+> _省略掉有关SpringBoot项目本身的配置说明_
+
+
+
+
+```kotlin
+@Listener
+suspend fun onForumEvent(event: QGForumEvent) {
+ println("Event: $event")
+}
+```
+
+
+
+
+```java
+@Listener
+public void onForumEvent(QGForumEvent event) {
+ System.out.println("Event: " + event);
+}
+```
+
+
+
+
+```java
+@Listener
+public CompletableFuture onForumEvent(QGForumEvent event) {
+ System.out.println("Event: " + event);
+ return CompletableFuture.completedFuture(null);
+}
+```
+
+
+
diff --git a/Writerside/topics/old/3.2.0.0/old-bot-config.md b/Writerside/topics/old/3.2.0.0/old-bot-config.md
new file mode 100644
index 00000000..b58764f1
--- /dev/null
+++ b/Writerside/topics/old/3.2.0.0/old-bot-config.md
@@ -0,0 +1,223 @@
+# BOT配置文件
+
+```json
+{
+ "component": "simbot.qqguild",
+ "ticket": {
+ "type": "plain",
+ "appId": "APPID",
+ "token": "TOKEN",
+ "secret": "SECRET"
+ },
+ "config": {
+ "serverUrl": null,
+ "shard": {
+ "type": "full"
+ },
+ "intents": {
+ "type": "raw",
+ "intents": 1073741827
+ },
+ "timeout": {
+ "apiHttpRequestTimeoutMillis": null,
+ "apiHttpConnectTimeoutMillis": null,
+ "apiHttpSocketTimeoutMillis": null
+ },
+ "cache": {
+ "enable": true,
+ "transmit": {
+ "enable": true
+ }
+ },
+ "clientProperties": null
+ }
+}
+```
+
+
+> 文件配置类的各属性定义可参考API文档:
+> [`QGBotFileConfiguration`](https://docs.simbot.forte.love/components/qq-guild/simbot-component-qq-guild-core-common/love.forte.simbot.component.qguild.config/-q-g-bot-file-configuration/index.html)
+
+## 配置项
+
+### component
+
+固定值 `simbot.qqguild`,**必填**,代表此配置文件为QQ频道组件的。
+
+### ticket
+
+bot的票据信息,**必填**。
+
+- `type`: 配置属性的类型,详见后文
+- `appId`: BotAppID
+- `token`: 机器人令牌
+- `secret`: 机器人密钥 (目前可能不会用到,可以用 `""` 代替)
+-
+#### plain
+
+当 `type=plain` 时,与 `Ticket` 属性基本一致的配置类型, 也是默认的方案。
+
+```json
+{
+ "ticket": {
+ "type": "plain",
+ "appId": "appId-value",
+ "secret": "secret-value",
+ "token": "token-value"
+ }
+}
+```
+
+:::note 省略type
+
+当 simbot-core 版本为 `3.2.0+` 时,`type` 作为默认值 `plain` 时可以省略:
+
+```json
+{
+ "ticket": {
+ "appId": "appId-value",
+ "secret": "secret-value",
+ "token": "token-value"
+ }
+}
+```
+
+:::
+
+#### env
+
+当 `type=env` 时,使用环境变量的方式进行配置。
+
+```json
+{
+ "ticket": {
+ "type": "env",
+ "appId": "APP_ID",
+ "secret": "SECRET",
+ "token": "TOKEN",
+ "plain": false
+ }
+}
+```
+
+解析时会首先尝试获取 JVM 参数,即运行时的 `-Dxxx=xxx` (也就是 `System.getProperty`),
+当不存在时会尝试通过环境变量获取(即 `System.getenv`)。
+
+**原始输入**
+
+当 `plain` 为 `true` 时(默认为 `false`),如果某属性通过上述流程无法获取到值,则会尝试直接使用原始输入值。
+
+例如:
+
+```json
+{
+ "ticket": {
+ "type": "env",
+ "appId": "aaa",
+ "secret": "MY_SECRET",
+ "token": "MY_TOKEN",
+ "plain": true
+ }
+}
+```
+
+示例中的 `appId` 并没有找到名为 `aaa` 的 JVM 参数或环境变量,因此它会直接使用 `aaa` 作为 `appId`。
+而如果 `plain` 为 `false`,则会直接抛出 `IllegalStateException` 异常。
+
+当一个属性以 `PLAIN:` (区分大小写) 为前缀,则会直接使用原始输入值,不会尝试从环境变量中获取。
+
+例如:
+
+```json
+{
+ "ticket": {
+ "type": "env",
+ "appId": "PLAIN:aaa",
+ "secret": "MY_SECRET",
+ "token": "MY_TOKEN",
+ "plain": false
+ }
+}
+```
+
+示例中 `appId` 会直接使用 `aaa` 作为 `appId`,而不会尝试从 JVM 参数或环境变量中获取。
+
+### config
+
+其他配置,可选,默认为 `null`。
+
+#### config.serverUrl
+
+内部进行API请求时的服务器地址,参考[官方文档](https://bot.q.qq.com/wiki/develop/api/)
+
+默认为 `null`,为 `null` 时为正式环境,可使用一个固定值 `SANDBOX` 代表使用沙箱环境
+
+```json
+{
+ "config": {
+ "serverUrl": "SANDBOX"
+ }
+}
+```
+
+或者使用一个具体的其他服务器地址
+
+```json
+{
+ "config": {
+ "serverUrl": "https://example.com"
+ }
+}
+```
+
+#### config.shard
+
+[分片信息](https://bot.q.qq.com/wiki/develop/api/gateway/shard.html),默认为 `type=full`,即使用 `[0, 1]` 的分片。
+
+可以使用 `type=simple` 自定义分片:
+
+```json
+{
+ "config": {
+ "shard": {
+ "type": "simple",
+ "value": 0,
+ "total": 2
+ }
+ }
+}
+```
+
+#### config.intents
+
+[订阅的事件](https://bot.q.qq.com/wiki/develop/api/gateway/intents.html),默认情况下订阅:
+
+- `Guilds`
+- `GuildMembers`
+- `PublicGuildMessages`
+
+可通过 `type=raw` 来直接指定一个原始的订阅标记结果值:
+
+```json
+{
+ "config": {
+ "intents": {
+ "type": "raw",
+ "intents": 1073741827
+ }
+ }
+}
+```
+
+或者使用 `type=nameBased` 通过指定名称(名称选择参考 `EventIntents` 类的所有 `object` 类型的字类类名):
+
+```json
+{
+ "config": {
+ "intents": {
+ "type": "nameBased",
+ "names": ["Guilds", "GuildMembers", "PublicGuildMessages"]
+ }
+ }
+}
+```
diff --git a/Writerside/topics/old/3.2.0.0/quickstart/old-api.md b/Writerside/topics/old/3.2.0.0/quickstart/old-api.md
new file mode 100644
index 00000000..e5de4e03
--- /dev/null
+++ b/Writerside/topics/old/3.2.0.0/quickstart/old-api.md
@@ -0,0 +1,188 @@
+# 使用API
+
+**API模块**是独立的、多平台的,你可以单独使用它作为 [QQ频道API](https://bot.q.qq.com/wiki/develop/api/) 的封装库。
+
+
+## 安装
+
+
+
+
+```Kotlin
+// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。
+implementation("love.forte.simbot.component:simbot-component-qq-gulid-api:3.2.0.0") // 或参考下文所述的 Releases
+```
+
+
+
+
+```Groovy
+// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。
+implementation 'love.forte.simbot.component:simbot-component-qq-gulid-api:3.2.0.0' // 版本参考下文所述的 Releases
+```
+
+
+
+
+```xml
+
+ love.forte.simbot.component
+
+ simbot-component-qq-guild-api-jvm
+
+ 3.2.0.0
+
+```
+
+
+
+
+
+:::info 版本参考
+
+版本可前往 [**Releases**](https://github.com/simple-robot/simbot-component-qq-guild/releases) 查阅。
+
+:::
+
+## 使用
+
+:::tip 太多了
+
+我们不会在此处一一列举所有的API做演示,这不太现实。
+所有的API都在包路径 `love.forte.simbot.qguild.api` 下,你可以通过 [API文档](https://docs.simbot.forte.love/) 或查阅源码的方式来寻找你所需要的API。
+
+API包装类的命名也存在一定的规律,比如一个 `获取某列表` 的API通常会被命名为 `GetXxxListApi`。
+
+下文会选择一小部分API来做示例。
+
+:::
+
+### 获取用户频道服务器列表
+
+以 [获取用户(BOT)频道服务器列表](https://bot.q.qq.com/wiki/develop/api/openapi/user/guilds.html) 为例。
+
+
+
+
+```kotlin
+// 准备参数
+// 用于请求的token
+val token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB"
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。参考:https://ktor.io/docs/http-client-engines.html
+val client = HttpClient()
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+val server = QQGuild.SANDBOX_URL
+
+// 使用 GetBotGuildListApi 获取频道列表
+// 创建了一个参数 limit=100 的 GetBotGuildListApi,并使用上述准备好的参数进行请求。
+val list: List = GetBotGuildListApi.create(limit = 100).request(client, server, token)
+
+list.forEach { ... }
+```
+
+也可以通过额外的扩展函数来获得一个**全量数据**的数据流。
+
+```kotlin
+// 准备参数
+// 用于请求的token
+val token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB"
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。参考:https://ktor.io/docs/http-client-engines.html
+val client = HttpClient()
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+val server = QQGuild.SANDBOX_URL
+
+// 使用 GetBotGuildListApi 获取频道列表
+// 创建了一个每页数据的数据量都为 100 的全量数据流,每一页都使用上述准备好的参数进行请求。
+val guildFlow: Flow = GetBotGuildListApi.createFlow(batch = 100) { request(client, QQGuild.SANDBOX_URL, token) }
+guildFlow.collect { guild ->
+ // ...
+}
+```
+
+
+
+
+```java
+// 准备参数
+// 用于请求的token
+String token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB";
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。参考:https://ktor.io/docs/http-client-engines.html
+HttpClient client = HttpClientJvmKt.HttpClient(($1) -> Unit.INSTANCE);
+// 或者通过jvm平台库提供的工具类来构建一个默认的 client。(需要环境中存在一种引擎)
+HttpClient newClient = ApiRequestUtil.newHttpClient();
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+Url server = QQGuild.SANDBOX_URL;
+
+// 使用 GetBotGuildListApi 获取频道列表,
+// 创建了一个 limit = 100 的 GetBotGuildListApi
+GetBotGuildListApi api = GetBotGuildListApi.create(100);
+
+// 发起请求并得到结果
+List extends SimpleGuild> guildList = api.doRequestBlocking(client, server, token);
+
+for(
+SimpleGuild guild :guildList){
+ // ...
+ }
+```
+
+
+
+
+```java
+// 准备参数
+// 用于请求的token
+String token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB";
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。参考:https://ktor.io/docs/http-client-engines.html
+HttpClient client = HttpClientJvmKt.HttpClient(($1) -> Unit.INSTANCE);
+// 或者通过jvm平台库提供的工具类来构建一个默认的 client。(需要环境中存在一种引擎)
+HttpClient newClient = ApiRequestUtil.newHttpClient();
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+Url server = QQGuild.SANDBOX_URL;
+
+// 使用 GetBotGuildListApi 获取频道列表,
+// 创建了一个 limit = 100 的 GetBotGuildListApi
+GetBotGuildListApi api = GetBotGuildListApi.create(100);
+
+// 发起请求并得到 Future 结果
+api.doRequestAsync(client, server, token).thenAccept(guildList -> {
+ for (SimpleGuild guild : guildList) {
+ // ...
+ }
+});
+```
+
+
+
+
+```java
+// 准备参数
+// 用于请求的token
+String token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB";
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。参考:https://ktor.io/docs/http-client-engines.html
+HttpClient client = HttpClientJvmKt.HttpClient(($1) -> Unit.INSTANCE);
+// 或者通过jvm平台库提供的工具类来构建一个默认的 client。(需要环境中存在一种引擎)
+HttpClient newClient = ApiRequestUtil.newHttpClient();
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+Url server = QQGuild.SANDBOX_URL;
+
+// 使用 GetBotGuildListApi 获取频道列表,
+// 创建了一个 limit = 100 的 GetBotGuildListApi
+GetBotGuildListApi api = GetBotGuildListApi.create(100);
+
+// 发起请求并得到响应式结果
+Flux extends SimpleGuild> guildFlux = Mono.fromCompletionStage(api.doRequestAsync(client, server, token))
+ .flatMapIterable(Function.identity());
+
+return guildFlux;
+```
+
+
+
+
+
diff --git a/Writerside/topics/old/3.2.0.0/quickstart/old-core.md b/Writerside/topics/old/3.2.0.0/quickstart/old-core.md
new file mode 100644
index 00000000..8c5b2b9e
--- /dev/null
+++ b/Writerside/topics/old/3.2.0.0/quickstart/old-core.md
@@ -0,0 +1,495 @@
+# 使用simbot核心库
+
+通过**core模块**配合**simbot核心库**来使用强大而简单的事件调度能力。
+
+
+
+core模块亦可以称之为simbot3的**组件库**,因为它事实上实现了simbot所提供的各种API和对simbot事件类型的封装。
+
+
+
+## 前提准备
+
+首先你应当准备至少一个可用的 [QQ频道机器人](https://q.qq.com/bot) 。
+
+
+
+simbot核心库中的API大多是以**DSL风格**为主的。尽管其依旧是对 Java "友好", 但以 Java 的代码风格而言依旧会 _略显臃肿_。
+
+如果你不介意,我们更建议 Java 开发者直接使用 [SpringBoot](old-spring-boot.md),因为这更符合大多数 Java 开发者的习惯。
+
+你也可以观察后续的代码示例,来体会DSL风格的API在 Kotlin 和 Java 之间的差异。
+
+
+
+## 安装
+
+
+
+
+```kotlin
+// simbot core starter
+implementation("love.forte.simbot:simbot-core:3.3.0") // 版本请参考下文的参考链接
+// QQ频道组件
+implementation("love.forte.simbot.component:simbot-component-qq-guild-core:3.2.0.0") // 或参考下文的参考链接
+```
+
+
+
+
+```gradle
+// simbot core starter
+implementation 'love.forte.simbot:simbot-core:3.3.0' // 版本请参考下文的参考链接
+// QQ频道组件
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-core:3.2.0.0' // 或参考下文的参考链接
+```
+
+
+
+
+```xml
+
+
+ love.forte.simbot
+ simbot-core
+ \${SIMBOT_VERSION}
+
+
+
+love.forte.simbot.component
+simbot-component-qq-guild-core
+3.2.0.0
+
+
+```
+
+
+
+
+
+
+
+
+
+simbot核心库(`simbot-core`)的版本可前往 [**simbot Releases**](https://github.com/simple-robot/simpler-robot/releases)
+查阅。
+
+QQ频道组件版本可前往 [**Releases**](https://github.com/simple-robot/simbot-component-qq-guild/releases) 查阅。
+
+
+
+
+## 构建Application
+
+首先构建一个 simbot 的 `Application`,这里以 `SimpleApplication` (也就是最基础的实现) 为例:
+
+
+
+
+```kotlin title='com.example.App'
+val application = createSimpleApplication {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ install(QQGuildComponent)
+ install(QQGuildBotManager)
+}
+
+application.join() // 挂起直到被关闭
+```
+
+或使用扩展函数来简化上述代码:
+
+```kotlin title='com.example.App'
+val application = createSimpleApplication {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ useQQGuild()
+}
+
+application.join() // 挂起直到被关闭
+```
+
+
+
+
+```java title='com.example.App'
+final ApplicationLauncher launcher = Applications.simbotApplication(Simple.INSTANCE, c -> { /* Application配置 */ }, (builder, configuration) -> {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+});
+
+// 启动 application
+SimpleApplication application = launcher.launchBlocking();
+application.
+
+joinBlocking(); // 阻塞直到被关闭
+```
+
+
+
+
+```java title='com.example.App'
+final ApplicationLauncher launcher = Applications.simbotApplication(Simple.INSTANCE, c -> { /* Application配置 */ }, (builder, configuration) -> {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+});
+
+// 启动 application, 结束后转化为 Future 并阻塞直到完成(application被关闭)
+launcher.
+
+launchAsync().
+
+thenCompose(SimpleApplication::asFuture).
+
+join();
+```
+
+
+
+
+
+## 监听函数
+
+完成对Application的构建之后,我们便可以开始注册监听函数用以处理事件了。
+
+下面我们实现如此功能: 当收到一个**(公域)子频道消息**,且内容为 "你好",则**引用回复**一句 "你也好"。
+流程大致为:
+
+```text
+用户:
+@BOT 你好
+
+BOT:
+> 用户: @BOT 你好
+你也好
+```
+
+> 在公域中的BOT要想收到消息必须被 `@` 。
+
+
+
+
+```kotlin title='com.example.App'
+val application = createSimpleApplication {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ install(QQGuildComponent)
+ install(QQGuildBotManager)
+}
+
+// 获取 eventListenerManager 并注册监听函数
+application.eventListenerManager.listeners {
+ // highlight-start
+ ChannelMessageEvent { event ->
+ // 当下述条件满足,则此处才被执行,并引用回复一句 '你也好'
+ event.reply("你也好")
+ } onMatch { event ->
+ // 匹配判断: 当消息中存在任何 AT 消息,且at的目标是bot,且消息文本为 '你好' 时
+ val bot = event.bot
+ event.messageContent.messages.any { it is At && bot.isMe(it.target) }
+ && event.messageContent.plainText.trim() == "你好"
+ }
+ // highlight-end
+}
+
+application.join() // 挂起直到被关闭
+```
+
+
+
+
+```java title='com.example.App'
+final ApplicationLauncher launcher = Applications.simbotApplication(Simple.INSTANCE, c -> { /* Application配置 */ }, (builder, configuration) -> {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+});
+
+// 启动 application
+SimpleApplication application = launcher.launchBlocking();
+
+// 获取 EventListenerManager 并用于注册监听函数
+EventListenerManager eventListenerManager = application.getEventListenerManager();
+
+// 注册一个 EventListener 实例,此实例通过 SimpleListeners.listener(...) 构建而得。
+// highlight-start
+eventListenerManager.
+
+register(SimpleListeners.listener(ChannelMessageEvent.Key, (context, event) ->{
+// 匹配判断: 当消息中存在任何 AT 消息,且at的目标是bot,且消息文本为 '你好' 时
+Bot bot = event.getBot();
+boolean atBot = false;
+MessageContent messageContent = event.getMessageContent();
+ for(
+Message.Element> message :messageContent.
+
+getMessages()){
+ if(message instanceof
+At at &&bot.
+
+isMe(at.getTarget())){
+atBot =true;
+ break;
+ }
+ }
+
+ return atBot &&"你好".
+
+equals(messageContent.getPlainText().
+
+trim());
+ },(context,event)->{
+ // 当上面的匹配通过,则此处才被执行,并引用回复一句 '你也好'
+ event.
+
+replyBlocking("你也好");
+}));
+// highlight-end
+
+ application.
+
+joinBlocking(); // 阻塞直到被关闭
+```
+
+
+
+
+```java title='com.example.App'
+final ApplicationLauncher launcher = Applications.simbotApplication(Simple.INSTANCE, c -> { /* Application配置 */ }, (builder, configuration) -> {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+});
+
+// 启动 application 结束后转化为 Future 并阻塞直到完成(application被关闭)
+launcher.
+
+launchAsync().
+
+thenCompose(application ->{
+SimpleEventListenerManager eventListenerManager = application.getEventListenerManager();
+// highlight-start
+ eventListenerManager.
+
+register(SimpleListeners.listener(ChannelMessageEvent.Key, (context, event) ->{
+// 匹配判断: 当消息中存在任何 AT 消息,且at的目标是bot,且消息文本为 '你好' 时
+Bot bot = event.getBot();
+boolean atBot = false;
+MessageContent messageContent = event.getMessageContent();
+ for(
+Message.Element> message :messageContent.
+
+getMessages()){
+ if(message instanceof
+At at &&bot.
+
+isMe(at.getTarget())){
+atBot =true;
+ break;
+ }
+ }
+
+ return atBot &&"你好".
+
+equals(messageContent.getPlainText().
+
+trim());
+ },(context,event)->{
+// 当上面的匹配通过,则此处才被执行,并引用回复一句 '你也好'
+CompletableFuture extends MessageReceipt> replyAsync = event.replyAsync("你也好");
+ return EventResult.
+
+of(replyAsync); // 通过 EventResult.of(future) 将你的异步结果返回,事件处理器会挂起并处理此异步结果
+ }));
+ // highlight-end
+
+ return application.
+
+asFuture();
+}).
+
+join();
+```
+
+
+
+
+
+> 其实上述示例中,在BOT为公域的情况下也可以不去判断 `At` 消息类型,直接判断 `plainText` 是否为 `"你好"` 即可。
+
+## 注册bot
+
+当监听函数注册完了之后,我们就需要注册bot了。当bot被注册并启动后,它们收到的事件就会流入到Application中的事件处理器中被统一处理。
+
+
+
+
+```kotlin title='com.example.App'
+val application = createSimpleApplication {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ install(QQGuildComponent)
+ install(QQGuildBotManager)
+}
+
+application.eventListenerManager.listeners {
+ // 注册事件...
+}
+
+// 寻找到一个 QQGuildBotManager 并注册bot
+// highlight-start
+val qqGuildBotManager = application.botManagers.first { it is QQGuildBotManager } as QQGuildBotManager
+val bot: QGBot = qqGuildBotManager.register("APP ID", "secret", "token") { // this: QGBotComponentConfiguration
+ // **组件BOT**的额外配置信息
+ this.cacheConfig = CacheConfig(enable = true, TransmitCacheConfig(enable = true)) // 启用 '传递性缓存', 此缓存配置默认启用
+ // 其他额外配置...
+
+ botConfig {
+ // **此处为对应 stdlib bot 的配置信息
+ }
+}
+bot.start() // 启用bot
+// highlight-end
+
+application.join() // 挂起直到被关闭
+```
+
+或者通过扩展函数来简化上述代码:
+
+```kotlin
+val application = createSimpleApplication {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ install(QQGuildComponent)
+ install(QQGuildBotManager)
+}
+
+application.eventListenerManager.listeners {
+ // 注册监听函数...
+}
+
+// 寻找到一个 QQGuildBotManager 并注册bot
+// highlight-start
+application.qgGuildBots {
+ val bot: QGBot = register("APP ID", "secret", "token") { // this: QGBotComponentConfiguration
+ // **组件BOT**的额外配置信息
+ this.cacheConfig = CacheConfig(enable = true, TransmitCacheConfig(enable = true)) // 启用 '传递性缓存', 此缓存配置默认启用
+ // 其他额外配置...
+
+ botConfig {
+ // **此处为对应 stdlib bot 的配置信息
+ }
+ }
+ bot.start() // 启用bot
+}
+// highlight-end
+
+application.join() // 挂起直到被关闭
+```
+
+
+
+
+```java title='com.example.App'
+final ApplicationLauncher launcher = Applications.simbotApplication(Simple.INSTANCE, c -> { /* Application配置 */ }, (builder, configuration) -> {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+});
+
+// 启动 application
+SimpleApplication application = launcher.launchBlocking();
+// 注册监听函数...
+
+// highlight-start
+for(
+BotManager> botManager :application.
+
+getBotManagers()){
+ // 找到第一个 QQGuildBotManager 并对其进行操作
+ if(botManager instanceof
+QQGuildBotManager qqGuildBotManager){
+QGBot bot = qqGuildBotManager.register("APP ID", "secret", "token", configuration -> {
+ // **组件BOT**的额外配置信息
+ configuration.setCacheConfig(...);
+ configuration.botConfig(botConfig -> {
+ // **此处为对应 stdlib bot 的配置信息
+ return Unit.INSTANCE; // 结束配置
+ });
+
+ return Unit.INSTANCE; // 结束配置
+});
+
+ bot.
+
+startBlocking(); // 阻塞启动
+
+ break;
+ }
+ }
+// highlight-end
+
+ application.
+
+joinBlocking(); // 阻塞直到被关闭
+```
+
+
+
+
+```java title='com.example.App'
+final ApplicationLauncher launcher = Applications.simbotApplication(Simple.INSTANCE, c -> { /* Application配置 */ }, (builder, configuration) -> {
+ // 安装QQ频道相关的组件和Bot管理器,并暂且忽略配置
+ builder.install(QQGuildComponent.Factory, (__, ___) -> Unit.INSTANCE);
+ builder.install(QQGuildBotManager.Factory, (__, ___) -> Unit.INSTANCE);
+});
+
+// 启动 application 结束后转化为 Future 并阻塞直到完成(application被关闭)
+launcher.
+
+launchAsync().
+
+thenCompose(application ->{
+ // 注册监听函数...
+ // highlight-start
+ for(
+BotManager> botManager :application.
+
+getBotManagers()){
+ // 找到第一个 QQGuildBotManager 并操作
+ if(botManager instanceof
+QQGuildBotManager qqGuildBotManager){
+QGBot bot = qqGuildBotManager.register("APP ID", "secret", "token", configuration -> {
+ // **组件BOT**的额外配置信息
+ configuration.setCacheConfig(...);
+ configuration.botConfig(botConfig -> {
+ // **此处为对应 stdlib bot 的配置信息
+ return Unit.INSTANCE; // 结束配置
+ });
+
+ return Unit.INSTANCE; // 结束配置
+});
+
+ bot.
+
+startAsync(); // 异步启动。此处异步直接放养,如果需要处理异常等则需要进行操作。
+
+ break;
+ }
+ }
+ // highlight-end
+
+ return application.
+
+asFuture();
+}).
+
+join();
+```
+
+
+
+
+## 启动
+
+接下来,启动程序并在你的沙箱频道中@它试试看吧。
+
+当然,如果遇到了预期外的问题也不要慌,积极反馈问题才能使我们变得更好,可以前往 [Issues](https://github.com/simple-robot/simpler-robot/issues)
+反馈问题、[社区](https://github.com/orgs/simple-robot/discussions) 提出疑问。
diff --git a/Writerside/topics/old/3.2.0.0/quickstart/old-spring-boot.md b/Writerside/topics/old/3.2.0.0/quickstart/old-spring-boot.md
new file mode 100644
index 00000000..2b3d1177
--- /dev/null
+++ b/Writerside/topics/old/3.2.0.0/quickstart/old-spring-boot.md
@@ -0,0 +1,284 @@
+# 使用 SpringBoot
+
+通过**core模块**配合 **simbot starter** 在 **Spring Boot** 中轻松使用。
+
+## 前提准备
+
+首先你应当准备至少一个可用的 [QQ频道机器人](https://q.qq.com/bot) 。
+
+## 项目构建
+
+首先准备一个SpringBoot项目。可以考虑前往 [start.spring.io](https://start.spring.io) 或借助IDE等工具。
+
+然后再额外添加我们需要的依赖:
+
+
+
+
+注意,在使用 Spring Boot 的时候你需要一些能够使程序保持运行的组件,例如通过 `spring-web` 启用一个服务器,否则程序可能会自动终止。
+因为simbot的 starter 并不提供维持程序运行的能力。
+
+下述示例我们选择使用 `spring-boot-starter-webflux`,具体选择请根据你的实际需求决定。
+
+
+
+> 下述配置示例基于 [start.spring.io](https://start.spring.io) 生成,版本号等信息请根据实际情况做修改。
+
+
+
+
+```kotlin
+// simbot core starter
+implementation("love.forte.simbot.boot:simboot-core-spring-boot-starter:3.3.0") // 版本请参考下文的参考链接
+// QQ频道组件
+implementation("love.forte.simbot.component:simbot-component-qq-guild-core:3.2.0.0") // 或参考下文的参考链接
+```
+
+
+
+
+```gradle
+// simbot core starter
+implementation 'love.forte.simbot.boot:simboot-core-spring-boot-starter:3.3.0' // 版本请参考下文的参考链接
+// QQ频道组件
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-core:3.2.0.0' // 或参考下文的参考链接
+```
+
+
+
+
+```xml
+
+
+ love.forte.simbot.boot
+ simboot-core-spring-boot-starter
+ \${SIMBOT_VERSION}
+
+
+
+love.forte.simbot.component
+simbot-component-qq-guild-core
+3.2.0.0
+
+```
+
+
+
+
+
+
+
+- `love.forte.simbot.boot:simboot-core-spring-boot-starter`
+ [**版本参考**](https://github.com/simple-robot/simpler-robot/releases)
+- `love.forte.simbot.component:simbot-component-qq-guild-core`
+ [**版本参考**](https://github.com/simple-robot/simbot-component-qq-guild/releases)
+
+
+
+## BOT配置
+
+接下来,在项目**资源文件**目录下的 `simbot-bots` 文件夹中创建一个用于配置bot的配置文件 `xxx.bot.json` (
+文件名随意,扩展名应为 `.bot` 或 `.bot.json` ) ,
+而配置文件的内容则参考章节 [**BOT配置文件**](old-bot-config.md) 。
+
+> 此路径以 IDEA 的项目结构风格为准,如果是其他IDE,使用对应的资源文件目录。
+
+```
+${PROJECT_SRC}/main/resources/simbot-bots/xxx.bot.json
+```
+
+
+
+如果想要修改此路径,可在 Spring Boot 的配置文件中进行配置:
+
+
+
+
+```
+# 自定义配置bot资源文件的扫描路径。
+# 默认为 classpath:simbot-bots/*.bot*
+# 如果要使用本地文件可以使用 `file:` 开头
+simbot.bot-configuration-resources[0]=classpath:simbot-bots/*.bot*
+```
+
+
+
+
+```yaml
+simbot:
+
+ # 自定义配置bot资源文件的扫描路径。
+ # 默认为 classpath:simbot-bots/*.bot*
+ # 如果要使用本地文件可以使用 `file:` 开头
+ bot-configuration-resources:
+ - 'classpath:simbot-bots/*.bot*'
+```
+
+
+
+
+
+
+## 启动类
+
+像每一个 Spring Boot 应用一样,你需要一个启动类,并通过标注 `@EnableSimbot` 来启用 `simbot` :
+
+
+
+
+```kotlin title='com.example.App'
+@EnableSimbot
+@SpringBootApplication
+class App
+
+fun main(vararg args: String) {
+ runApplication(args = args)
+}
+```
+
+
+
+
+> 如果你在Java中遇到了无法引用 `@EnableSimbot` 等情况,或许可以参考
+> [**这篇FAQ**](https://simple-robot-library.github.io/simbot3-website/faq/包引用异常/)。
+
+```java title='com.example.App'
+
+@EnableSimbot
+@SpringBootApplication
+public class App {
+ public static void main(String[] args) {
+ SpringApplication.run(App.class, args);
+ }
+}
+```
+
+
+
+
+
+## 监听事件
+
+接下来就是逻辑代码所在的地方了,编写一个监听函数并监听一个事件。
+
+此处我们监听 `ChannelMessageEvent`,也就是 **_子频道的消息事件_**。
+
+假设:要求bot必须**被AT**,并且说一句 `你好`,此时bot会**引用**用户发送的消息并回复 `你也好!` ,类似于:
+
+```text
+用户:
+@BOT 你好
+
+BOT:
+> 用户: @BOT 你好
+你也好!
+```
+
+
+
+
+```kotlin title='com.example.listener.ExampleListener.kt'
+import love.forte.simboot.annotation.ContentTrim
+import love.forte.simboot.annotation.Filter
+import love.forte.simboot.annotation.Listener
+import love.forte.simbot.event.ChannelMessageEvent
+
+@Component
+class ExampleListener {
+
+ @Listener
+ @Filter(value = "你好", targets = Filter.Targets(atBot = true))
+ @ContentTrim // 当匹配被at时,将'at'这个特殊消息移除后,剩余的文本消息大概率存在前后空格,通过此注解在匹配的时候忽略前后空格
+ suspend fun onChannelMessage(event: ChannelMessageEvent) { // 将要监听的事件类型放在参数里,即代表监听此类型的消息
+ event.reply("你也好!")
+ }
+}
+
+
+```
+
+
+
+
+```java title='com.example.listener.ExampleListener.java'
+import love.forte.simboot.annotation.ContentTrim
+import love.forte.simboot.annotation.Filter
+import love.forte.simboot.annotation.Listener
+import love.forte.simbot.event.ChannelMessageEvent
+
+@Component
+public class ExampleListener {
+
+ @Listener
+ @Filter(value = "你好", targets = @Filter.Targets(atBot = true))
+ @ContentTrim // 当匹配被at时,将'at'这个特殊消息移除后,剩余的文本消息大概率存在前后空格,通过此注解在匹配的时候忽略前后空格
+ public void onChannelMessage(ChannelMessageEvent event) { // 将要监听的事件类型放在参数里,即代表监听此类型的消息
+ // Java中的阻塞式API
+ event.replyBlocking("你也好!");
+ }
+
+}
+```
+
+
+
+
+```java title='com.example.listener.ExampleListener.java'
+import love.forte.simboot.annotation.ContentTrim
+import love.forte.simboot.annotation.Filter
+import love.forte.simboot.annotation.Listener
+import love.forte.simbot.event.ChannelMessageEvent
+
+@Component
+public class ExampleListener {
+
+ @Listener
+ @Filter(value = "你好", targets = @Filter.Targets(atBot = true))
+ @ContentTrim // 当匹配被at时,将'at'这个特殊消息移除后,剩余的文本消息大概率存在前后空格,通过此注解在匹配的时候忽略前后空格
+ public CompletableFuture> onChannelMessage(ChannelMessageEvent event) { // 将要监听的事件类型放在参数里,即代表监听此类型的消息
+ // 将 CompletableFuture 作为返回值,simbot会以非阻塞的形式处理它
+ return event.replyAsync("你也好!");
+ }
+
+}
+```
+
+
+
+
+> > 如果返回值是需要第三方库的响应式类型,那么你的项目环境依赖中必须存在 `Kotlin courotines` 对其的支持库才可使用。
+> 你可以参考文档中
+> [
+_响应式的处理结果_](https://simple-robot-library.github.io/simbot3-website/docs/basic/event-listener#可响应式的处理结果)
+> > 的内容。
+
+```java title='com.example.listener.ExampleListener.java'
+import love.forte.simboot.annotation.ContentTrim
+import love.forte.simboot.annotation.Filter
+import love.forte.simboot.annotation.Listener
+import love.forte.simbot.event.ChannelMessageEvent
+
+@Component
+public class ExampleListener {
+
+ @Listener
+ @Filter(value = "你好", targets = @Filter.Targets(atBot = true))
+ @ContentTrim // 当匹配被at时,将'at'这个特殊消息移除后,剩余的文本消息大概率存在前后空格,通过此注解在匹配的时候忽略前后空格
+ public Mono> onChannelMessage(ChannelMessageEvent event) { // 将要监听的事件类型放在参数里,即代表监听此类型的消息
+ // 将 Mono 等响应式类型作为返回值,simbot会以非阻塞的形式处理它
+ return Mono.fromCompletionStage(event.replyAsync("你也好!"));
+ }
+
+}
+```
+
+
+
+
+
+## 启动
+
+接下来,启动程序并在你的沙箱频道中@它试试看吧。
+
+当然,如果遇到了预期外的问题也不要慌,积极反馈问题才能使我们变得更好,可以前往 [Issues](https://github.com/simple-robot/simpler-robot/issues)
+反馈问题、[社区](https://github.com/orgs/simple-robot/discussions) 提出疑问。
diff --git a/Writerside/topics/old/3.2.0.0/quickstart/old-stdlib.md b/Writerside/topics/old/3.2.0.0/quickstart/old-stdlib.md
new file mode 100644
index 00000000..205f1e41
--- /dev/null
+++ b/Writerside/topics/old/3.2.0.0/quickstart/old-stdlib.md
@@ -0,0 +1,311 @@
+# 使用标准库
+
+**stdlib(标准库)模块** 在 `API` 模块的基础上提供简单而轻量级的事件订阅能力。
+
+## 前提准备
+
+首先你应当准备至少一个可用的 [QQ频道机器人](https://q.qq.com/bot) 。
+
+## 安装
+
+
+
+
+```kotlin
+// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。
+implementation("love.forte.simbot.component:simbot-component-qq-guild-stdlib:3.2.0.0") // 或参考下文所述的 Releases
+
+```
+
+
+
+
+
+```gradle
+// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-stdlib:3.2.0.0' // 版本参考下文所述的 Releases
+
+```
+
+
+
+
+```xml
+
+ love.forte.simbot.component
+
+ simbot-component-qq-guild-stdlib-jvm
+
+ 3.2.0.0
+
+
+```
+
+
+
+
+> 版本可前往 [**Releases**](https://github.com/simple-robot/simbot-component-qq-guild/releases) 查阅。
+
+## BOT配置&注册
+
+环境准备完毕后,接下来我们注册一个bot。
+
+
+
+
+```kotlin
+val bot = BotFactory.create("APP ID", "secret", "token") {
+ // config
+ this.wsClientEngine = ... // 进行事件订阅所使用的 Ktor client 引擎,默认情况下会**尝试**自动加载,或直接手动指定一个支持ws连接的引擎。
+ this.apiClientEngine = ... // 使用API时所使用的 Ktor client 引擎,默认情况下会**尝试**自动加载,或直接手动指定一个支持 HTTP API 的引擎。
+ this.serverUrl = QQGuild.URL // 使用正式环境,默认即为正式环境
+ this.useSandboxServerUrl() // 使用沙箱环境
+ this.intents = ... // 要订阅的事件标记。默认订阅 频道、频道成员、公域消息 三种事件
+ // 其他配置...
+}
+
+bot.start() // 启动bot
+bot.join() // 挂起bot直到bot终止
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("APP ID", "secret", "token", (configuration) -> {
+ configuration.setWsClientEngine(...); // 进行事件订阅所使用的 Ktor client 引擎,默认情况下会**尝试**自动加载,或直接手动指定一个支持ws连接的引擎。
+ configuration.setApiClientEngine(...); // 使用API时所使用的 Ktor client 引擎,默认情况下会**尝试**自动加载,或直接手动指定一个支持 HTTP API 的引擎。
+ configuration.setServerUrl(QQGuild.URL); // 使用正式环境,默认即为正式环境
+ configuration.useSandboxServerUrl(); // 使用沙箱环境
+ configuration.setIntentsValue(...); // 要订阅的事件标记值。默认订阅 频道、频道成员、公域消息 三种事件
+ // 其他配置...
+
+ return Unit.INSTANCE; // 结束配置
+});
+
+bot.startBlocking(); // 启动bot
+bot.joinBlocking(); // 阻塞t直到bot终止
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("APP ID", "secret", "token", (configuration) -> {
+ configuration.setWsClientEngine(...); // 进行事件订阅所使用的 Ktor client 引擎,默认情况下会**尝试**自动加载,或直接手动指定一个支持ws连接的引擎。
+ configuration.setApiClientEngine(...); // 使用API时所使用的 Ktor client 引擎,默认情况下会**尝试**自动加载,或直接手动指定一个支持 HTTP API 的引擎。
+ configuration.setServerUrl(QQGuild.URL); // 使用正式环境,默认即为正式环境
+ configuration.useSandboxServerUrl(); // 使用沙箱环境
+ configuration.setIntentsValue(...); // 要订阅的事件标记。默认订阅 频道、频道成员、公域消息 三种事件
+ // 其他配置...
+
+ return Unit.INSTANCE; // 结束配置
+});
+
+// 阻塞直到bot终止
+bot.startAsync().thenCompose(__ -> bot.joinAsync()).join();
+```
+
+
+
+
+
+
+引擎的选择可参考 [**Ktor文档**](https://ktor.io/docs/http-client-engines.html#limitations)。
+
+大多数情况下你需要手动指定一个具体的引擎
+(例如使用 `mingwX64` 目标时可选用 [**WinHttp**](https://ktor.io/docs/http-client-engines.html#winhttp) 引擎 ),
+或者至少保证程序的运行时环境中存在可用引擎(在JVM平台下的自动加载)。
+
+
+
+
+## 事件监听(订阅)
+
+在启动创建bot、启动bot这个过程中间,你可以注册一些**事件处理器**来对订阅的事件进行处理。
+
+
+
+
+```kotlin
+val bot = BotFactory.create("APP ID", "secret", "token") {
+ // ...
+}
+
+// 订阅所有类型的事件
+// highlight-start
+bot.registerProcessor { raw -> // this: Signal.Dispatch
+ // ...
+}
+// highlight-end
+
+// 订阅具体的事件类型
+// highlight-start
+bot.registerProcessor { raw -> // this: GuildMemberAdd
+ // ...
+}
+// highlight-end
+
+bot.start() // 启动bot
+bot.join() // 挂起bot直到bot终止
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("APP ID", "secret", "token", (configuration) -> {
+ // ...
+ return Unit.INSTANCE; // 结束配置
+});
+
+// 订阅所有事件类型
+// highlight-start
+bot.registerBlockingProcessor((Signal.Dispatch event, String raw) -> {
+ // ...
+});
+// highlight-end
+
+// 订阅具体的事件类型
+// highlight-start
+bot.registerBlockingProcessor(GuildMemberAdd.class, (GuildMemberAdd event, String raw) -> {
+ // ...
+});
+// highlight-end
+
+bot.startBlocking(); // 启动bot
+bot.joinBlocking(); // 阻塞直到bot终止
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("APP ID", "secret", "token", (configuration) -> {
+ // ...
+ return Unit.INSTANCE; // 结束配置
+});
+
+// 订阅所有事件类型
+// highlight-start
+bot.registerAsyncProcessor((Signal.Dispatch event, String raw) -> {
+ // ...
+ return CompletableFuture.completedFuture(null); // 异步事件处理器要求返回 CompletionStage 类型的结果
+});
+// highlight-end
+
+// 订阅具体的事件类型
+// highlight-start
+bot.registerAsyncProcessor(GuildMemberAdd.class, (GuildMemberAdd event, String raw) -> {
+ // ...
+ return CompletableFuture.completedFuture(null); // 异步事件处理器要求返回 CompletionStage 类型的结果
+});
+// highlight-end
+
+// 阻塞直到bot终止
+bot.startAsync().thenCompose(__ -> bot.joinAsync()).join();
+```
+
+
+
+当你选择了使用异步API,那就要尽最大努力来避免再使用阻塞API。
+
+
+
+
+
+
+可以看到,在进行事件处理的时候,你可以得到两个参数:
+一个是接收到的事件类型 `event`,它是类型 `Signal.Dispatch` 的字类;
+另外一个是字符串 `raw`,它代表是这个事件原始的JSON字符串。
+
+> 可以监听的事件类型参考 [`Signal.Dispatch`](https://simple-robot-library.github.io/simbot3-website/components/qq-guild/simbot-component-qq-guild-api/love.forte.simbot.qguild.event/-signal/-dispatch/index.html)
+以及它的所有子类型 (`Inheritors`) 。
+
+
+在事件监听的过程中,配合使用 `API` 来实现你的功能。
+
+举个例子,当监听到 **子频道更新事件** (`ChannelUpdate`) 时,查询一下这个子频道所属的 **频道服务器** (`Guild`) 是什么。
+
+
+
+
+```kotlin
+val bot = BotFactory.create("APP ID", "secret", "token") {
+ // ...
+}
+
+// 订阅 ChannelUpdate
+// highlight-start
+bot.registerProcessor { raw -> // this: ChannelUpdate
+ // 查询这个子频道所属的频道服务器
+ val guild = GetGuildApi.create(this.data.guildId).requestBy(bot)
+ println("guild: $guild")
+}
+// highlight-end
+
+bot.start() // 启动bot
+bot.join() // 挂起bot直到bot终止
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("APP ID", "secret", "token", (configuration) -> {
+ // ...
+ return Unit.INSTANCE; // 结束配置
+});
+
+// 订阅 ChannelUpdate
+// highlight-start
+bot.registerBlockingProcessor(ChannelUpdate.class, (event, raw) -> {
+ // 查询这个子频道所属的频道服务器
+ GetGuildApi getGuildApi = GetGuildApi.create(event.getData().getGuildId());
+ SimpleGuild guild = BotRequestUtil.requestBlocking(bot, getGuildApi);
+ System.out.println("guild: " + guild);
+});
+// highlight-end
+
+bot.startBlocking(); // 启动bot
+bot.joinBlocking(); // 阻塞直到bot终止
+```
+
+
+
+
+```java
+Bot bot = BotFactory.create("APP ID", "secret", "token", (configuration) -> {
+ // ...
+ return Unit.INSTANCE; // 结束配置
+});
+
+// 订阅 ChannelUpdate
+// highlight-start
+bot.registerAsyncProcessor(ChannelUpdate.class, (event, raw) -> {
+ // 查询这个子频道所属的频道服务器
+ GetGuildApi getGuildApi = GetGuildApi.create(event.getData().getGuildId());
+ return BotRequestUtil.requestAsync(bot, getGuildApi).thenAccept(guild -> {
+ System.out.println("guild: " + guild);
+ });
+});
+// highlight-end
+
+// 阻塞直到bot终止
+bot.startAsync().thenCompose(__ -> bot.joinAsync()).join();
+```
+
+
+
+当你选择了使用异步API,那就要尽最大努力来避免再使用阻塞API。
+
+
+
+
+
+
+## 启动
+
+接下来,启动程序并试试看吧。
+
+当然,如果遇到了预期外的问题也不要慌,积极反馈问题才能使我们变得更好,可以前往 [Issues](https://github.com/simple-robot/simpler-robot/issues) 反馈问题、[社区](https://github.com/orgs/simple-robot/discussions) 提出疑问。
diff --git a/Writerside/topics/role/api_role.md b/Writerside/topics/role/api_role.md
new file mode 100644
index 00000000..0ddf7b6b
--- /dev/null
+++ b/Writerside/topics/role/api_role.md
@@ -0,0 +1,4 @@
+# 角色 Role
+
+QQ频道中有一些针对 `角色` 的API。
+
diff --git a/Writerside/topics/snippets.md b/Writerside/topics/snippets.md
new file mode 100644
index 00000000..61775b85
--- /dev/null
+++ b/Writerside/topics/snippets.md
@@ -0,0 +1,205 @@
+[//]: # (Ktor 引擎选择)
+
+
+
+
+
+你可以前往 [Ktor文档](https://ktor.io/docs/http-client-engines.html)
+处选择一个对应所用平台下合适的 `Client Engine`。
+这里会根据不同平台提供几个示例,你可以选择其他可用目标。
+
+
+
+
+
+[CIO](https://ktor.io/docs/http-client-engines.html#cio) 是一个比较通用的引擎。
+在不知道选什么的情况下,可以考虑使用它。
+
+
+
+
+```kotlin
+runtimeOnly("io.ktor:ktor-client-cio-jvm:$ktor_version")
+```
+
+
+
+
+```groovy
+runtimeOnly 'io.ktor:ktor-client-cio-jvm:$ktor_version'
+```
+
+
+
+
+```xml
+
+ io.ktor
+ ktor-client-cio-jvm
+ ${ktor_version}
+ runtime
+
+```
+
+
+
+
+
+
+如果你打算使用 Java11+,也可以选择 [Java](https://ktor.io/docs/http-client-engines.html#java) 引擎。
+
+
+
+
+
+
+```kotlin
+runtimeOnly("io.ktor:ktor-client-java:$ktor_version")
+```
+
+
+
+> 如果你想要显式配置引擎,那么就不能使用 `runtimeOnly` 了。
+
+
+
+
+```groovy
+runtimeOnly 'io.ktor:ktor-client-java:$ktor_version'
+```
+
+
+
+> 如果你想要显式配置引擎,那么就不能使用 `runtimeOnly` 了。
+
+
+
+
+```xml
+
+ io.ktor
+ ktor-client-java-jvm
+ ${ktor_version}
+ runtime
+
+```
+
+
+
+> 如果你想要显式配置引擎,那么就不能使用 `runtime scope` 了。
+
+
+
+
+
+
+
+
+
+JavaScript 平台下可以选择 [Js](https://ktor.io/docs/http-client-engines.html#js) 引擎。
+
+
+
+
+```kotlin
+implementation("io.ktor:ktor-client-js:$ktor_version")
+```
+
+
+
+
+```groovy
+implementation 'io.ktor:ktor-client-js:$ktor_version'
+```
+
+
+
+
+
+
+
+
+
+native 平台目标下,可能需要根据不同的平台类型选择不同的引擎。
+
+
+
+
+
+可以选择 [WinHttp](https://ktor.io/docs/http-client-engines.html#winhttp) 引擎。
+
+
+
+
+```kotlin
+implementation("io.ktor:ktor-client-winhttp:$ktor_version")
+```
+
+
+
+
+```groovy
+implementation 'io.ktor:ktor-client-winhttp:$ktor_version'
+```
+
+
+
+
+
+
+
+
+Linux 下依旧可以选择 [CIO](https://ktor.io/docs/http-client-engines.html#cio) 引擎。
+
+
+
+
+```kotlin
+implementation("io.ktor:ktor-client-cio:$ktor_version")
+```
+
+
+
+
+```groovy
+implementation 'io.ktor:ktor-client-cio:$ktor_version'
+```
+
+
+
+
+
+
+
+
+可以选择 [Darwin](https://ktor.io/docs/http-client-engines.html#darwin) 引擎。
+
+
+
+
+```kotlin
+implementation("io.ktor:ktor-client-darwin:$ktor_version")
+```
+
+
+
+
+```groovy
+implementation 'io.ktor:ktor-client-darwin:$ktor_version'
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Writerside/topics/use-api.md b/Writerside/topics/use-api.md
new file mode 100644
index 00000000..ba205518
--- /dev/null
+++ b/Writerside/topics/use-api.md
@@ -0,0 +1,262 @@
+---
+switcher-label: Java API 风格
+---
+
+
+
+# 使用 API
+
+
+本章节介绍如何使用 API 模块 来构建、请求一个QQ频道的API。
+
+
+
+
+API 模块 是一个“基础”的模块,它仅提供针对 QQ频道 API 的封装,
+没有 Bot、事件处理等功能,是一种“底层库”。
+
+API 模块无法直接作为 Simple Robot 组件使用。
+
+
+
+
+
+当你不确定自己的应用场景是否应该选择 **直接使用** API 模块时,
+这里为你提供了一些参考:
+
+
+
+- 你的应用只需要一个 API 实现库,你希望使用更**原始的**风格调用API。
+- 你的应用**不需要**、或希望**自行处理**对事件的订阅与解析。(包括一切工作,例如建立网络连接)
+
+
+
+
+- 你希望库实现事件订阅能力,可以替你处理网络连接、事件调度等。
+- 你希望有一个 Bot 实现,它可以管理网络连接的生命周期、可以注册事件处理逻辑、替你接收事件,并进行处理。
+
+
+
+
+## 安装
+
+
+
+
+```Kotlin
+implementation("love.forte.simbot.component:simbot-component-qq-guild-api:%version%")
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要指定依赖的后缀为 `-jvm`。
+
+```Kotlin
+implementation("love.forte.simbot.component:simbot-component-qq-guild-api-jvm:%version%")
+```
+
+
+
+
+
+
+```Groovy
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-api:%version%'
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要指定依赖的后缀为 `-jvm`。
+
+```Groovy
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-api-jvm:%version%'
+```
+
+
+
+
+
+
+```xml
+
+ love.forte.simbot.component
+
+ simbot-component-qq-guild-api-jvm
+ %version%
+
+```
+
+
+
+
+### 引擎选择
+
+
+
+## 使用
+
+QQ频道组件的API模块提供了针对
+[QQ频道API](https://bot.q.qq.com/wiki/develop/api/)
+的基本对应封装。
+
+API封装的命名与API具有一定关联,例如 [`获取用户(BOT)频道服务器列表`](https://bot.q.qq.com/wiki/develop/api/openapi/user/guilds.html):
+
+
+
+```HTTP
+GET /users/@me/guilds
+```
+
+```
+love.forte.simbot.qguild.api.user.GetBotGuildListApi
+```
+
+
+> 所有的API实现均在包路径 `love.forte.simbot.qguild.api` 中。
+
+API的应用大差不差,因此此处仅使用部分类型作为示例,
+不会演示所有API。
+如果想浏览或寻找需要的 API,可前往 [APIDoc引导](https://docs.simbot.forte.love)
+中进入QQ频道组件的 KDoc 查阅,或可以简单的借助IDE的智能提示进行寻找。
+
+以 [获取用户(BOT)频道服务器列表](https://bot.q.qq.com/wiki/develop/api/openapi/user/guilds.html) 为例。
+
+
+
+
+```kotlin
+ // 准备参数
+// 用于请求的token
+val token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB"
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。
+// 参考:[[[Ktor Engines|https://ktor.io/docs/http-client-engines.html]]]
+val client = HttpClient()
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+val server = QQGuild.SANDBOX_URL
+
+// 使用 GetBotGuildListApi 获取频道列表
+// 创建了一个参数 limit=100 的 GetBotGuildListApi,并使用上述准备好的参数进行请求。
+val resultList = GetBotGuildListApi.create(limit = 100).requestData(client, token, server)
+
+resultList.forEach { // it: SimpleGuild
+ ...
+}
+```
+
+也可以通过额外的扩展函数来获得一个**全量数据**的数据流。
+
+```kotlin
+// 准备参数
+// 用于请求的token
+val token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB"
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。
+// 参考:[[[Ktor Engines|https://ktor.io/docs/http-client-engines.html]]]
+val client = HttpClient()
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+val server = QQGuild.SANDBOX_URL
+
+// 使用 GetBotGuildListApi 获取频道列表
+// 创建了一个基于 GetBotGuildListApi 获取全量数据的流,并使用上述准备好的参数进行请求。
+val resultFlow = GetBotGuildListApi.createFlow { requestData(client, token, server) }
+
+resultFlow.collect { // it: SimpleGuild
+ println(it)
+}
+```
+
+
+
+
+```java
+ // 准备参数
+// 用于请求的token
+var token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB";
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。
+// 参考:https://ktor.io/docs/http-client-engines.html
+var client = HttpClientJvmKt.HttpClient(($1) -> Unit.INSTANCE);
+// 或者通过jvm平台库提供的工具类来构建一个默认的 client。(需要环境中存在一种引擎)
+var newClient = ApiRequests.newHttpClient();
+
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+var server = QQGuild.SANDBOX_URL;
+
+// 使用 GetBotGuildListApi 获取频道列表,
+// 创建了一个 limit = 100 的 GetBotGuildListApi
+var api = GetBotGuildListApi.create(100);
+
+ApiRequests.requestDataAsync(api, client, token, server)
+ .thenAccept(guildList -> {
+ for (var guild : guildList) {
+ // ...
+ }
+ });
+```
+{switcher-key="%ja%"}
+
+```java
+// 准备参数
+// 用于请求的token
+var token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB";
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。
+// 参考:https://ktor.io/docs/http-client-engines.html
+var client = HttpClientJvmKt.HttpClient(($1) -> Unit.INSTANCE);
+// 或者通过jvm平台库提供的工具类来构建一个默认的 client。(需要环境中存在一种引擎)
+var newClient = ApiRequests.newHttpClient();
+
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+var server = QQGuild.SANDBOX_URL;
+
+// 使用 GetBotGuildListApi 获取频道列表,
+// 创建了一个 limit = 100 的 GetBotGuildListApi
+var api = GetBotGuildListApi.create(100);
+
+// 发起请求并得到结果
+var guildList = ApiRequests.requestDataBlocking(api, client, token, server);
+
+for (var guild : guildList) {
+ // ...
+}
+```
+{switcher-key="%jb%"}
+
+
+```java
+ // 准备参数
+// 用于请求的token
+var token = "Bot 123456789.ABABABABABABABABABABABABABABABABAB";
+// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。
+// 参考:https://ktor.io/docs/http-client-engines.html
+var client = HttpClientJvmKt.HttpClient(($1) -> Unit.INSTANCE);
+// 或者通过jvm平台库提供的工具类来构建一个默认的 client。(需要环境中存在一种引擎)
+var newClient = ApiRequests.newHttpClient();
+
+// 需要请求的环境的服务器地址,比如正式环境或沙箱环境,亦或是某个自己定义代理的第三方环境
+// 可以通过 QQGuild 得到一些预定义的常量信息
+var server = QQGuild.SANDBOX_URL;
+
+// 使用 GetBotGuildListApi 获取频道列表,
+// 创建了一个 limit = 100 的 GetBotGuildListApi
+var api = GetBotGuildListApi.create(100);
+
+// 发起请求并得到结果
+ApiRequests.requestDataReserve(api, client, token, server)
+ // 使用此转化器需要确保运行时环境中存在
+ // [[[kotlinx-coroutines-reactor|https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive]]] 的相关依赖。
+ .transform(SuspendReserves.mono())
+ .subscribe(guildList -> {
+ for (var guild : guildList) {
+ // ...
+ }
+ });
+```
+{switcher-key="%jr%"}
+
+
+
+
diff --git a/Writerside/topics/use-core.md b/Writerside/topics/use-core.md
new file mode 100644
index 00000000..7f41f1f4
--- /dev/null
+++ b/Writerside/topics/use-core.md
@@ -0,0 +1,245 @@
+---
+switcher-label: Java API 风格
+---
+
+# 使用核心库
+
+
+
+使用 核心库(core 模块) 配合 simbot4 核心库来将QQ频道作为 simbot4 的组件之一应用在 Application
中。
+
+
+
+站在 simbot 核心库的视角来看,“QQ频道组件的‘核心库’” 也可以被称为QQ频道组件库。
+
+
+## 安装
+
+首先,要配合使用 simbot4,就必须添加 `simbot-core` 的依赖。组件对于 simbot 的库依赖一般都是仅编译器的。
+
+
+
+simbot 核心库的版本尽量不要低于 `v%minimum-core-version%`,可前往
+[GitHub Releases](https://github.com/simple-robot/simpler-robot/releases)
+查看各版本及其说明。
+
+此处以 `simbot-core v%minimum-core-version%` 作为**示例**。
+
+
+
+
+
+
+
+```Kotlin
+// simbot4核心库
+implementation("love.forte.simbot:simbot-core:%minimum-core-version%")
+// QQ频道组件库
+implementation("love.forte.simbot.component:simbot-component-qq-guild-core:%version%")
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要指定依赖的后缀为 `-jvm`。
+
+```Kotlin
+// simbot4核心库
+implementation("love.forte.simbot:simbot-core-jvm:%minimum-core-version%")
+// QQ频道组件库
+implementation("love.forte.simbot.component:simbot-component-qq-guild-core-jvm:%version%")
+```
+
+
+
+
+
+
+```Groovy
+// simbot4核心库
+implementation 'love.forte.simbot:simbot-core:%minimum-core-version%'
+// QQ频道组件库
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-core:%version%'
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要指定依赖的后缀为 `-jvm`。
+
+```Groovy
+// simbot4核心库
+implementation 'love.forte.simbot:simbot-core-jvm:%minimum-core-version%'
+// QQ频道组件库
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-core-jvm:%version%'
+```
+
+
+
+
+
+
+```xml
+
+
+ love.forte.simbot
+ simbot-core-jvm
+ %minimum-core-version%
+
+
+
+ love.forte.simbot.component
+ simbot-component-qq-guild-core-jvm
+ %version%
+
+```
+
+
+
+
+### 引擎选择
+
+
+
+
+## 使用
+### 安装到 Application
+
+向 Application 中安装 `QQGuildComponent` 和 `QQGuildBotManager`。
+
+
+
+
+```kotlin
+val app = launchSimpleApplication {
+ // 使用 useQQGuild 简写,
+ // 代表同时安装 `QQGuildComponent` 和 `QQGuildBotManager`
+ useQQGuild()
+
+ // 其他配置..
+}
+```
+
+
+
+
+
+```java
+var appFuture = Applications.launchApplicationAsync(Simple.INSTANCE, appConfigurer -> {
+ // 安装 `QQGuildComponent` 和 `QQGuildBotManager`
+ appConfigurer.install(QQGuildComponent.Factory);
+ appConfigurer.install(QQGuildBotManager.Factory);
+}).asFuture();
+```
+{switcher-key="%ja%"}
+
+```java
+var app = Applications.launchApplicationBlocking(Simple.INSTANCE, appConfigurer -> {
+ // 安装 `QQGuildComponent` 和 `QQGuildBotManager`
+ appConfigurer.install(QQGuildComponent.Factory);
+ appConfigurer.install(QQGuildBotManager.Factory);
+});
+```
+{switcher-key="%jb%"}
+
+
+
+
+
+### 注册事件处理器
+
+
+
+
+```kotlin
+val app = ...
+
+// 注册各种事件处理器
+app.listeners {
+ // 注册一个事件处理器
+ // 所有子频道消息事件
+ // 其中就包括QQ频道的公域消息事件
+ listen {
+ println("context: $this")
+ println("context.event: $event")
+
+ // 返回事件处理结果
+ EventResult.empty()
+ }
+
+ // 再注册一个事件处理器
+ // 明确监听QQ频道的公域消息事件
+ // 使用 process 不需要返回值
+ process {
+ println("context: $this")
+ println("context.event: $event")
+ }
+}
+```
+
+
+
+
+
+```java
+// 假设通过 future 的 thenAccept 或其他什么地方得到了 Application
+var app = ...;
+
+// 注册一个事件处理器
+// 所有子频道消息事件
+// 其中就包括QQ频道的公域消息事件
+eventDispatcher.register(EventListeners.async(ChatChannelMessageEvent.class, (context, event) -> {
+ System.out.println("context: " + context);
+ System.out.println("context.event: " + event);
+
+ // 返回异步的事件处理结果
+ return CompletableFuture.completedFuture(EventResult.empty());
+}));
+
+// 再注册一个事件处理器
+// 明确监听QQ频道的公域消息事件
+eventDispatcher.register(EventListeners.async(QGAtMessageCreateEvent.class, (context, event) -> {
+ System.out.println("context: " + context);
+ System.out.println("context.event: " + event);
+
+ // 返回异步的事件处理结果
+ return CompletableFuture.completedFuture(EventResult.empty());
+}));
+```
+{switcher-key="%ja%"}
+
+```java
+var app = ...;
+
+// 注册一个事件处理器
+// 所有子频道消息事件
+// 其中就包括QQ频道的公域消息事件
+eventDispatcher.register(EventListeners.block(ChatChannelMessageEvent.class, (context, event) -> {
+ System.out.println("context: " + context);
+ System.out.println("context.event: " + event);
+
+ // 返回事件处理结果
+ return EventResult.empty();
+}));
+
+// 再注册一个事件处理器
+// 明确监听QQ频道的公域消息事件
+eventDispatcher.register(EventListeners.block(QGAtMessageCreateEvent.class, (context, event) -> {
+ System.out.println("context: " + context);
+ System.out.println("context.event: " + event);
+
+ // 返回异步的事件处理结果
+ return EventResult.empty();
+}));
+```
+{switcher-key="%jb%"}
+
+
+
+
+### 注册、启动Bot
+
+
+## 更多有关 simbot API
+
+前往 [simbot官方手册](https://simbot.forte.love/) 阅读有关 simbot API 的各种介绍与示例吧!
diff --git a/Writerside/topics/use-spring-boot.md b/Writerside/topics/use-spring-boot.md
new file mode 100644
index 00000000..c658db28
--- /dev/null
+++ b/Writerside/topics/use-spring-boot.md
@@ -0,0 +1,529 @@
+---
+switcher-label: Java API 风格
+---
+
+
+
+# 使用 Spring Boot
+
+
+
+使用 核心库(core 模块) 配合 simbot4 Spring Boot starter 来将QQ频道组件作为 simbot4 的组件之一应用在 Spring Boot 3
中。
+
+
+
+## 准备
+
+### Java 17
+
+simbot4 的 Spring Boot starter 基于 Spring Boot 3,因此 Java 的版本至少为 **Java17** 。
+
+### 创建 Spring Boot 3 项目
+
+首先你得有个 Spring Boot 3 项目, 你可以前往 [Spring Initializr][spring.start]
+或者借助 IDE (比如 IDEA) 的相关功能创建一个 Spring Boot 3 的项目。
+你可以自由选择需要添加的任何其他 Spring Boot 组件,比如 `spring-boot-starter-web` 之类的。
+
+
+
+- [Spring Initializr][spring.start]
+- [Spring Quickstart Guide](https://spring.io/quickstart/)
+
+
+
+## 安装
+
+
+
+simbot 核心库的版本尽量不要低于 `v%minimum-core-version%`,可前往
+[GitHub Releases](https://github.com/simple-robot/simpler-robot/releases)
+查看各版本及其说明。
+
+此处以 `v%minimum-core-version%` 作为**示例**。
+
+
+
+
+
+
+```Kotlin
+// simbot4核心库
+implementation("love.forte.simbot:simbot-core-spring-boot-starter:%minimum-core-version%")
+// QQ频道组件库
+implementation("love.forte.simbot.component:simbot-component-qq-guild-core:%version%")
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要为组件库指定依赖的后缀为 `-jvm`。
+
+```Kotlin
+// simbot4核心库
+implementation("love.forte.simbot:simbot-core-spring-boot-starter:%minimum-core-version%")
+// QQ频道组件库
+implementation("love.forte.simbot.component:simbot-component-qq-guild-core-jvm:%version%")
+```
+
+
+
+
+
+
+```Groovy
+// simbot4核心库
+implementation 'love.forte.simbot:simbot-core-spring-boot-starter:%minimum-core-version%'
+// QQ频道组件库
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-core:%version%'
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要为组件库指定依赖的后缀为 `-jvm`。
+
+```Kotlin
+// simbot4核心库
+implementation 'love.forte.simbot:simbot-core-spring-boot-starter:%minimum-core-version%'
+// QQ频道组件库
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-core-jvm:%version%'
+```
+
+
+
+
+
+
+```xml
+
+
+ love.forte.simbot
+ simbot-core-spring-boot-starter
+ %minimum-core-version%
+
+
+
+ love.forte.simbot.component
+ simbot-component-qq-guild-core-jvm
+ %version%
+
+```
+
+
+
+
+### 引擎选择
+
+
+
+
+## Bot 配置
+
+在你的资源目录中:
+resources/simbot-bots/
+中创建任意的一个或多个bot配置文件,并以 `.bot.json` 作为扩展名,
+例如 `mybot.bot.json`。
+
+配置文件的内容可前往参考 [Bot配置文件](bot-config.md) 章节。
+
+> 这个扫描目录是**可配置的**。
+> 这属于 simbot4 Spring Boot starter 的配置,可参考
+> [simbot手册: 使用 Spring Boot 3](https://simbot.forte.love/start-use-spring-boot-3.html)。
+
+## 使用
+### 添加启动注解
+
+在你的启动类上添加 `@EnableSimbot` 注解来启用 simbot。
+
+
+
+
+```Kotlin
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+class MyApplication
+
+fun main(args: Array) {
+ runApplicarion(*args)
+}
+```
+
+
+
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+}
+```
+
+
+
+
+
+QQ频道组件支持使用 SPI **自动加载** 组件和插件。
+添加依赖到项目环境中、编写完 Bot 配置文件后,可前往
+[simbot手册: 使用 Spring Boot 3](https://simbot.forte.love/start-use-spring-boot-3.html)
+了解更多 simbot4 Spring Boot starter 的可配置内容以及启动注解等信息。
+
+## 更多相关参考
+
+- 前往 [simbot官方手册](https://simbot.forte.love/) 阅读有关 simbot API 的相关介绍与示例。
+- 前往 [simbot手册: 使用 Spring Boot 3](https://simbot.forte.love/start-use-spring-boot-3.html)
+ 了解更多 simbot4 Spring Boot starter 的可配置内容以及启动注解等信息。
+
+
+## 简单示例
+
+几个简单的**事件监听**示例。
+
+
+
+
+
+
+```Kotlin
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+class MyApplication
+
+fun main(args: Array) {
+ runApplicarion(*args)
+}
+
+private val logger = LoggerFactory.getLogger(MyHandlers::class.java)
+
+@Component // 需要交给Spring管理
+class MyHandlers {
+ @Listener // 标记事件处理函数
+ suspend fun handle(event: Event) {
+ logger.info("Event: {}", event)
+ }
+}
+```
+
+
+
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+ @Component // 需要交给Spring管理
+ public static class MyHandlers {
+ private static final Logger logger = Logger.getLogger(MyHandlers.class);
+
+ @Listener // 标记事件处理函数
+ public void handle(Event event) {
+ logger.info("Event: {}", event)
+ }
+ }
+}
+```
+
+
+
+
+
+
+此处以 "子频道消息事件" 为例,此事件类型为 `ChatChannelMessageEvent`。
+
+事件逻辑:当收到文本内 **包含"你好"** 的消息,回复"你也好"。
+
+
+
+
+```Kotlin
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+class MyApplication
+
+fun main(args: Array) {
+ runApplicarion(*args)
+}
+
+@Component // 需要交给Spring管理
+class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ suspend fun handle(event: ChatChannelMessageEvent) {
+ event.reply("你也好")
+ }
+}
+```
+
+
+
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+ @Component // 需要交给Spring管理
+ public static class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ public CompletableFuture> handle(ChatChannelMessageEvent event) {
+ return event.replyAsync("你也好");
+ // 当使用异步API (CompletableFuture) 时,
+ // 你需要格外注意异常处理问题。
+ // 如果你不 return,
+ // 那么你就要处理异常,否则你无法感知到异步任务中出现的错误。
+ // 比如:
+ // .whenComplete((value, e) -> {
+ // if (e != null) {
+ // // 比如输出错误日志
+ // }
+ // })
+ }
+ }
+}
+```
+{switcher-key="%ja%"}
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+ @Component // 需要交给Spring管理
+ public static class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ public void handle(ChatChannelMessageEvent event) {
+ event.replyBlocking("你也好");
+ }
+ }
+}
+```
+{switcher-key="%jb%"}
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+ @Component // 需要交给Spring管理
+ public static class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ public Mono> handle(ChatChannelMessageEvent event) {
+ return event.replyReserve("你也好")
+ // 使用此转化器需要确保运行时环境中存在
+ // [[[kotlinx-coroutines-reactor|https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive]]] 的相关依赖。
+ .transform(SuspendReserves.mono());
+ // 当使用异步API (比如此处的 Mono) 时,
+ // 你需要格外注意异常处理问题。
+ // 如果你不 return,
+ // 那么你就要处理异常,否则你无法感知到异步任务中出现的错误。
+ // 比如:
+ // .doOnError(err -> {
+ // // 比如输出错误日志
+ // });
+ }
+ }
+}
+```
+{switcher-key="%jr%"}
+
+
+
+
+
+
+此处以 "QQ频道的公域子频道At消息事件" 为例,
+此事件类型为 `QGAtMessageCreateEvent`。
+
+这个事件是QQ频道组件里实现的专有事件类型,它继承
+`ChatChannelMessageEvent`。
+
+事件逻辑:当收到文本内 **包含"你好"** 的消息,回复"你也好"。
+
+
+
+
+```Kotlin
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+class MyApplication
+
+fun main(args: Array) {
+ runApplicarion(*args)
+}
+
+@Component // 需要交给Spring管理
+class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ suspend fun handle(event: QGAtMessageCreateEvent) {
+ event.reply("你也好")
+ }
+}
+```
+
+
+
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+ @Component // 需要交给Spring管理
+ public static class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ public CompletableFuture> handle(QGAtMessageCreateEvent event) {
+ return event.replyAsync("你也好");
+ // 当使用异步API (CompletableFuture) 时,
+ // 你需要格外注意异常处理问题。
+ // 如果你不 return,
+ // 那么你就要处理异常,否则你无法感知到异步任务中出现的错误。
+ // 比如:
+ // .whenComplete((value, e) -> {
+ // if (e != null) {
+ // // 比如输出错误日志
+ // }
+ // })
+ }
+ }
+}
+```
+{switcher-key="%ja%"}
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+ @Component // 需要交给Spring管理
+ public static class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ public void handle(QGAtMessageCreateEvent event) {
+ event.replyBlocking("你也好");
+ }
+ }
+}
+```
+{switcher-key="%jb%"}
+
+```Java
+@EnableSimbot // 启用 simbot
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+ @Component // 需要交给Spring管理
+ public static class MyHandlers {
+ @Listener // 标记事件处理函数
+ @Filter( // 简单的事件过滤注解
+ value = "你好", // 需要包含的文字
+ matchType = MatchType.TEXT_CONENT // 调整匹配模式为 "文本包含"
+ )
+ // 如果需要,添加此注解来去除匹配用的文本前后的空白字符。
+ // 由于 QQ 频道的公域 bot 都是需要被 at 的,
+ // 而被 at 时,文本消息很有可能存在一些前后空格,所以会比较有用
+ @ContentTrim
+ public Mono> handle(QGAtMessageCreateEvent event) {
+ return event.replyReserve("你也好")
+ // 使用此转化器需要确保运行时环境中存在
+ // [[[kotlinx-coroutines-reactor|https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive]]] 的相关依赖。
+ .transform(SuspendReserves.mono());
+ // 当使用响应式API (比如此处的 Mono) 时,
+ // 你需要格外注意异常处理问题。
+ // 如果你不 return,
+ // 那么你就要处理异常,否则你无法感知到异步任务中出现的错误。
+ // 甚至你如果不 return,可能都无法真正的执行逻辑,因为这个 Mono 没有被消费。
+ // 比如:
+ // .doOnError(err -> {
+ // // 比如输出错误日志
+ // });
+ }
+ }
+}
+```
+{switcher-key="%jr%"}
+
+
+
+
+
+
+
+[spring.start]: https://start.spring.io
diff --git a/Writerside/topics/use-stdlib.md b/Writerside/topics/use-stdlib.md
new file mode 100644
index 00000000..55b038e4
--- /dev/null
+++ b/Writerside/topics/use-stdlib.md
@@ -0,0 +1,299 @@
+---
+switcher-label: Java API 风格
+---
+
+# 使用标准库
+
+
+本章节介绍如何使用 标准库(stdlib模块) 来构建 Bot 实例、订阅并处理事件。
+
+
+
+
+标准库模块 是一个“较为基础”的模块,它在 API 模块之上,
+仅提供**最基础**的 Bot 实现和事件处理。是一种**轻量级实现库**。
+
+标准库模块无法直接作为 Simple Robot 组件使用。
+
+
+
+
+
+当你不确定自己的应用场景是否应该选择 **直接使用** 标准库模块时,
+这里为你提供了一些参考:
+
+
+
+- 你希望有一个 Bot 实现,它可以支持订阅事件、管理网络连接的生命周期、可以注册事件处理逻辑、替你接收事件,并进行处理/调度。
+- 你不需要太多额外的功能,例如处理事件时,如果你想要发消息,那么**自行构建** API 模块中提供的实现。
+- 你不需要多组件协同。
+- 你不需要 Simple Robot 标准库提供的任何功能。
+
+
+
+
+
+- 你希望使用 Simple Robot 标准库提供的功能。
+- 你希望使用一个有更多**高级功能**封装的库,而不是一个仅有基础功能的库。例如处理事件时,你只需要组装好消息文本或封装好的**消息元素对象**,并简单的调用 `send` 即可发送,不需要自行构建 API、自行发送请求。
+- 你希望能够支持多组件协同。
+- 你希望使用支持 Spring Boot 的库。
+
+
+
+
+## 安装
+
+
+
+
+```Kotlin
+implementation("love.forte.simbot.component:simbot-component-qq-guild-stdlib:%version%")
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要指定依赖的后缀为 `-jvm`。
+
+```Kotlin
+implementation("love.forte.simbot.component:simbot-component-qq-guild-stdlib-jvm:%version%")
+```
+
+
+
+
+
+
+```Groovy
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-stdlib:%version%'
+```
+
+
+
+如果你使用 Java 而不配合使用 Gradle 的 `kotlin` 插件,
+那么你需要指定依赖的后缀为 `-jvm`。
+
+```Groovy
+implementation 'love.forte.simbot.component:simbot-component-qq-guild-stdlib-jvm:%version%'
+```
+
+
+
+
+
+
+```xml
+
+ love.forte.simbot.component
+
+ simbot-component-qq-guild-stdlib-jvm
+ %version%
+
+```
+
+
+
+
+### 引擎选择
+
+
+
+
+
+## 使用
+
+QQ频道组件的标准库模块在 [API模块](use-api.md) 的基础之上提供了构建 Bot、订阅并处理事件的能力。
+
+
+
+
+```kotlin
+ // 准备 bot 的必要信息
+val botId = "xxxx"
+val botSecret = "" // secret 如果用不到可使用空字符串
+val botToken = "xxxx"
+// 用于注册 bot 的 “票据” 信息。
+val ticket = Bot.Ticket(botId, botSecret, botToken)
+
+// 构建一个 Bot,并可选的进行一些配置。
+val bot = BotFactory.create(ticket) {
+ // 各种配置...
+ // 比如切换服务地址为沙箱频道的服务地址
+ useSandboxServerUrl()
+
+ // 指定需要订阅的事件的 intents,默认会订阅:
+ // - 频道相关事件
+ // - 频道成员相关事件
+ // - 公域消息相关事件
+ intents // = xxx
+
+ // 自定义一个 shard,默认是 Shard.FULL
+ shard = Shard.FULL
+
+ // 其他各种配置...
+}
+
+// 注册事件有一些不同但类似的方式
+// 1️⃣ 通过 registerProcessor 注册一个普通的事件处理器,此处理器会接收并处理所有类型的事件
+// registerProcessor 是最基本的注册方式,也是其他方式的最终汇集点
+bot.registerProcessor { raw ->
+ // raw 代表事件的原始JSON字符串
+ // this: Signal.Dispatch, 也就是解析出来的事件结构体
+ println("event: $this")
+ println("event.data: $data")
+ println("raw: $raw")
+}
+
+// 2️⃣ 通过 processEvent 注册一个针对具体 Signal.Dispatch 事件类型的事件处理器,
+// 它只有在接收到的 Signal.Dispatch 与目标类型一致时才会处理。
+// 此示例展示处理 AtMessageCreate 也就公域是消息事件,并在对方发送了包含 'stop' 的文本时终止 bot。
+bot.process {
+ println("event message: $data")
+
+ if ("stop" in data.content) {
+ // 终止 bot
+ bot.cancel()
+ }
+}
+
+// 启动 bot, 此时会开始获取ws、连接并接收消息。
+bot.start()
+
+// 挂起 bot,直到它结束(被终止)
+bot.join()
+```
+
+
+
+
+
+```java
+// 准备 bot 的必要信息
+var botId = "xxxx";
+var botSecret = ""; // secret 如果用不到可使用空字符串
+var botToken = "xxxx";
+// 用于注册 bot 的 “票据” 信息。
+var ticket = new Bot.Ticket(botId, botSecret, botToken);
+
+// 构建一个 Bot,并可选的进行一些配置。
+Bot bot = BotFactory.create(ticket, config -> {
+ // 各种配置...
+ // 比如切换服务地址为沙箱频道的服务地址
+ config.useSandboxServerUrl();
+
+ // 指定需要订阅的事件的 intents,默认会订阅:
+ // - 频道相关事件
+ // - 频道成员相关事件
+ // - 公域消息相关事件
+ // config.setIntentsValue(...);
+
+ // 自定义一个 shard,默认是 Shard.FULL
+ config.setShard(Shard.FULL);
+
+ // 其他各种配置...
+});
+
+// 通过 registerProcessor 注册一个普通的事件处理器,
+// 此处理器会接收并处理所有类型的事件
+bot.registerProcessor(EventProcessors.async((event, raw) -> {
+ // raw 代表事件的原始JSON字符串
+ // event: Signal.Dispatch, 也就是解析出来的事件结构体
+ System.out.println("event: " + event);
+ System.out.println("event.data: " + event.getData());
+ System.out.println("raw: " + raw);
+
+ // 异步处理器必须返回 CompletableFuture
+ return CompletableFuture.completedFuture(null);
+}));
+
+// 通过 registerProcessor 注册一个普通的事件处理器,
+// 此处理器会接收并处理指定的类型 AtMessageCreate 的事件
+// 此示例展示处理 AtMessageCreate 也就公域是消息事件,并在对方发送了包含 'stop' 的文本时终止 bot。
+bot.registerProcessor(EventProcessors.async(AtMessageCreate.class, (event, raw) -> {
+ System.out.println("event message: $data");
+
+ if (event.getData().getContent().contains("stop")) {
+ // 终止 bot
+ bot.cancel();
+ }
+
+ // 异步处理器必须返回 CompletableFuture
+ return CompletableFuture.completedFuture(null);
+}));
+
+// 异步地启动bot,并在 bot 启动完成后,
+// 将 bot 转化为 future,这个 future 会在 bot 被终止时完成
+// 其实也可以把 startAsync 和 asFuture 拆开写,效果相同。
+var future = bot.startAsync()
+ .thenCompose(unit -> bot.asFuture());
+
+// 阻塞当前线程,直到 bot 被终止。
+future.join();
+```
+{switcher-key="%ja%"}
+
+```java
+// 准备 bot 的必要信息
+var botId = "xxxx";
+var botSecret = ""; // secret 如果用不到可使用空字符串
+var botToken = "xxxx";
+// 用于注册 bot 的 “票据” 信息。
+var ticket = new Bot.Ticket(botId, botSecret, botToken);
+
+// 构建一个 Bot,并可选的进行一些配置。
+Bot bot = BotFactory.create(ticket, config -> {
+ // 各种配置...
+ // 比如切换服务地址为沙箱频道的服务地址
+ config.useSandboxServerUrl();
+
+ // 指定需要订阅的事件的 intents,默认会订阅:
+ // - 频道相关事件
+ // - 频道成员相关事件
+ // - 公域消息相关事件
+ // config.setIntentsValue(...);
+
+ // 自定义一个 shard,默认是 Shard.FULL
+ config.setShard(Shard.FULL);
+
+ // 其他各种配置...
+});
+
+// 通过 registerProcessor 注册一个普通的事件处理器,
+// 此处理器会接收并处理所有类型的事件
+bot.registerProcessor(EventProcessors.block((event, raw) -> {
+ // raw 代表事件的原始JSON字符串
+ // event: Signal.Dispatch, 也就是解析出来的事件结构体
+ System.out.println("event: " + event);
+ System.out.println("event.data: " + event.getData());
+ System.out.println("raw: " + raw);
+}));
+
+// 通过 registerProcessor 注册一个普通的事件处理器,
+// 此处理器会接收并处理指定的类型 AtMessageCreate 的事件
+// 此示例展示处理 AtMessageCreate 也就公域是消息事件,并在对方发送了包含 'stop' 的文本时终止 bot。
+bot.registerProcessor(EventProcessors.block(AtMessageCreate.class, (event, raw) -> {
+ System.out.println("event message: $data");
+
+ if (event.getData().getContent().contains("stop")) {
+ // 终止 bot
+ bot.cancel();
+ }
+}));
+
+// 启动bot
+bot.startBlocking();
+
+// 阻塞当前线程,直到 bot 被终止。
+bot.joinBlocking();
+```
+{switcher-key="%jb%"}
+
+
+
+当使用异步API时候,请尽可能避免在异步的事件处理器中使用任何阻塞API。
+
+
+
+
+
+> 封装的事件的结构、属性以及属性类型都基本与大别野文档中的一致或具有对应关系。
diff --git a/Writerside/v.list b/Writerside/v.list
new file mode 100644
index 00000000..370db3ed
--- /dev/null
+++ b/Writerside/v.list
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/Writerside/writerside.cfg b/Writerside/writerside.cfg
new file mode 100644
index 00000000..35e746ff
--- /dev/null
+++ b/Writerside/writerside.cfg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/build.gradle.kts b/build.gradle.kts
index ea5966c2..60c1aadc 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -15,21 +15,23 @@
* If not, see .
*/
+import love.forte.gradle.common.core.project.setup
+import love.forte.gradle.common.core.repository.Repositories
+
+
plugins {
+ idea
id("simbot-tencent-guild.changelog-generator")
id("simbot-tencent-guild.dokka-multi-module")
- id("simbot-tencent-guild.root-module-conventions")
id("simbot-tencent-guild.nexus-publish")
}
+setup(P.ComponentQQGuild)
+
buildscript {
repositories {
mavenCentral()
}
-
- dependencies {
- classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${libs.versions.atomicfu.get()}")
- }
}
//group = P.ComponentTencentGuild.GROUP
@@ -37,15 +39,34 @@ buildscript {
logger.info("=== Current version: {} ===", version)
-subprojects {
+allprojects {
repositories {
mavenCentral()
- love.forte.gradle.common.core.repository.Repositories.Snapshot.Default.apply {
- configMaven {
- mavenContent {
- snapshotsOnly()
- }
+ maven {
+ url = uri(Repositories.Snapshot.URL)
+ mavenContent {
+ snapshotsOnly()
}
}
+ //mavenLocal()
}
+//
+// configurations.all {
+// resolutionStrategy.cacheChangingModulesFor(15, TimeUnit.MINUTES)
+// }
}
+
+idea {
+ module.apply {
+ isDownloadSources = true
+ }
+ project {
+ modules.forEach { module ->
+ module.apply {
+ isDownloadSources = true
+ }
+ }
+ }
+}
+
+
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 209d4681..b675d32a 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2023. ForteScarlet.
+ * Copyright (c) 2021-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -24,30 +24,24 @@ repositories {
gradlePluginPortal()
}
-val kotlinVersion = "1.9.21"
-val dokkaPluginVersion = "1.9.10"
-val suspendTransformVersion = "0.5.1"
-val gradleCommon = "0.1.1"
-//val atomicfuVersion = "0.20.0"
+val kotlinVersion: String = libs.versions.kotlin.get()
dependencies {
implementation(kotlin("gradle-plugin", kotlinVersion))
implementation(kotlin("serialization", kotlinVersion))
- implementation("org.jetbrains.dokka:dokka-gradle-plugin:$dokkaPluginVersion")
- implementation("org.jetbrains.dokka:dokka-base:$dokkaPluginVersion")
-
- // https://github.com/Kotlin/kotlinx-atomicfu
-// implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfuVersion")
+ implementation(libs.bundles.dokka)
// see https://github.com/gradle-nexus/publish-plugin
implementation("io.github.gradle-nexus:publish-plugin:1.1.0")
-// implementation("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:0.0.5")
- implementation("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:$suspendTransformVersion")
- implementation("love.forte.gradle.common:gradle-common-core:$gradleCommon")
- implementation("love.forte.gradle.common:gradle-common-kotlin-multiplatform:$gradleCommon")
- implementation("love.forte.gradle.common:gradle-common-publication:$gradleCommon")
+ // simbot suspend transform gradle common
+ implementation(libs.simbot.gradle)
+
+ // suspend transform
+ implementation(libs.suspend.transform.gradle)
+ // gradle common
+ implementation(libs.bundles.gradle.common)
}
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
new file mode 100644
index 00000000..f6a40f20
--- /dev/null
+++ b/buildSrc/settings.gradle.kts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-qq-guild.
+ *
+ * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
+ * If not, see .
+ */
+
+// https://stackoverflow.com/questions/67795324/gradle7-version-catalog-how-to-use-it-with-buildsrc
+dependencyResolutionManagement {
+ versionCatalogs {
+ create("libs") {
+ from(files("../gradle/libs.versions.toml"))
+ }
+ }
+}
diff --git a/buildSrc/src/main/kotlin/JVMConstants.kt b/buildSrc/src/main/kotlin/JVMConstants.kt
new file mode 100644
index 00000000..a1daba86
--- /dev/null
+++ b/buildSrc/src/main/kotlin/JVMConstants.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-qq-guild.
+ *
+ * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
+ * If not, see .
+ */
+
+object JVMConstants {
+ const val KT_JVM_TARGET_VALUE = 11
+ const val KT_JVM_TARGET = "11"
+}
diff --git a/buildSrc/src/main/kotlin/JsConfig.kt b/buildSrc/src/main/kotlin/JsConfig.kt
new file mode 100644
index 00000000..7bc685b7
--- /dev/null
+++ b/buildSrc/src/main/kotlin/JsConfig.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-qq-guild.
+ *
+ * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
+ * If not, see .
+ */
+
+import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
+
+
+inline fun KotlinJsTargetDsl.configJs(
+ nodeJs: Boolean = true,
+ browser: Boolean = true,
+ block: () -> Unit = {}
+) {
+ if (nodeJs) {
+ nodejs()
+// {
+//// testTask {
+//// useMocha {
+//// timeout = "10000"
+//// }
+//// }
+// }
+ }
+
+ if (browser) {
+ browser()
+// {
+// testTask{
+// useKarma {
+// useChromeHeadless()
+// // useConfigDirectory(File(project.rootProject.projectDir, "karma"))
+// }
+// }
+// }
+ }
+
+ binaries.library()
+ block()
+}
+
+
+fun Project.configJsTestTasks() {
+ // val shouldRunJsBrowserTest = !hasProperty("teamcity") || hasProperty("enable-js-tests")
+ // if (shouldRunJsBrowserTest) return
+ tasks.findByName("cleanJsBrowserTest")?.apply {
+ onlyIf { false }
+ }
+ tasks.findByName("jsBrowserTest")?.apply {
+ onlyIf { false }
+ }
+}
diff --git a/buildSrc/src/main/kotlin/JvmConfig.kt b/buildSrc/src/main/kotlin/JvmConfig.kt
new file mode 100644
index 00000000..434c9f88
--- /dev/null
+++ b/buildSrc/src/main/kotlin/JvmConfig.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-qq-guild.
+ *
+ * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
+ * If not, see .
+ */
+
+import org.gradle.api.Project
+import org.gradle.api.tasks.SourceSetContainer
+import org.gradle.api.tasks.compile.JavaCompile
+import org.gradle.kotlin.dsl.assign
+import org.gradle.kotlin.dsl.get
+import org.gradle.kotlin.dsl.getByName
+import org.gradle.kotlin.dsl.withType
+import org.gradle.process.CommandLineArgumentProvider
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
+import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
+
+
+inline fun KotlinJvmTarget.configJava(crossinline block: KotlinJvmTarget.() -> Unit = {}) {
+ withJava()
+ compilations.all {
+ kotlinOptions {
+ javaParameters = true
+ freeCompilerArgs = freeCompilerArgs + listOf("-Xjvm-default=all")
+ }
+ }
+
+ testRuns["test"].executionTask.configure {
+ useJUnitPlatform()
+ }
+ block()
+}
+
+
+fun KotlinTopLevelExtension.configJavaToolchain(jdkVersion: Int) {
+ jvmToolchain(jdkVersion)
+}
+
+inline fun KotlinMultiplatformExtension.configKotlinJvm(
+ jdkVersion: Int = JVMConstants.KT_JVM_TARGET_VALUE,
+ crossinline block: KotlinJvmTarget.() -> Unit = {}
+) {
+ configJavaToolchain(jdkVersion)
+ jvm {
+ configJava(block)
+ }
+}
+
+inline fun KotlinJvmProjectExtension.configKotlinJvm(
+ jdkVersion: Int = JVMConstants.KT_JVM_TARGET_VALUE,
+ crossinline block: KotlinJvmProjectExtension.() -> Unit = {}
+) {
+ configJavaToolchain(jdkVersion)
+ compilerOptions {
+ javaParameters = true
+ jvmTarget.set(JvmTarget.fromTarget(jdkVersion.toString()))
+ // freeCompilerArgs.addAll("-Xjvm-default=all", "-Xjsr305=strict")
+ freeCompilerArgs.set(freeCompilerArgs.getOrElse(emptyList()) + listOf("-Xjvm-default=all", "-Xjsr305=strict"))
+ }
+ block()
+}
+
+inline fun Project.configJavaCompileWithModule(
+ moduleName: String? = null,
+ jvmVersion: String = JVMConstants.KT_JVM_TARGET,
+ crossinline block: JavaCompile.() -> Unit = {}
+) {
+ tasks.withType {
+ options.encoding = "UTF-8"
+ sourceCompatibility = jvmVersion
+ targetCompatibility = jvmVersion
+
+ if (moduleName != null) {
+ options.compilerArgumentProviders.add(CommandLineArgumentProvider {
+ // Provide compiled Kotlin classes to javac – needed for Java/Kotlin mixed sources to work
+ listOf("--patch-module", "$moduleName=${sourceSets["main"].output.asPath}")
+ })
+ }
+
+ block()
+ }
+}
+
+@PublishedApi
+internal val Project.sourceSets: SourceSetContainer
+ get() = extensions.getByName("sourceSets")
diff --git a/buildSrc/src/main/kotlin/P.kt b/buildSrc/src/main/kotlin/P.kt
index 9e59f977..efdce511 100644
--- a/buildSrc/src/main/kotlin/P.kt
+++ b/buildSrc/src/main/kotlin/P.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -18,24 +18,25 @@
import love.forte.gradle.common.core.project.ProjectDetail
import love.forte.gradle.common.core.project.Version
import love.forte.gradle.common.core.project.minus
+import love.forte.gradle.common.core.property.systemProp
import love.forte.gradle.common.core.project.version as v
-val simbotVersion = v(3, 2, 0)
-//- v("RC", 3)
-
-fun simbot(name: String, version: String = simbotVersion.toString()): String = "love.forte.simbot:simbot-$name:$version"
-fun simboot(name: String, version: String = simbotVersion.toString()): String =
- "love.forte.simbot.boot:simboot-$name:$version"
-
-val simbotApi = simbot("api")
-val simbotCore = simbot("core")
-val simbotLogger = simbot("logger")
-val simbotLoggerJvm = simbot("logger-jvm")
-val simbotLoggerSlf4jImpl = simbot("logger-slf4j-impl")
-
-val simbotUtilLoop = "love.forte.simbot.util:simbot-util-stage-loop:$simbotVersion"
-val simbotUtilSuspendTransformer = "love.forte.simbot.util:simbot-util-suspend-transformer:$simbotVersion"
-val simbotUtilAnnotations = "love.forte.simbot.util:simbot-annotations:$simbotVersion"
+//val simbotVersion = v(3, 2, 0)
+////- v("RC", 3)
+//
+//fun simbot(name: String, version: String = simbotVersion.toString()): String = "love.forte.simbot:simbot-$name:$version"
+//fun simboot(name: String, version: String = simbotVersion.toString()): String =
+// "love.forte.simbot.boot:simboot-$name:$version"
+//
+//val simbotApi = simbot("api")
+//val simbotCore = simbot("core")
+//val simbotLogger = simbot("logger")
+//val simbotLoggerJvm = simbot("logger-jvm")
+//val simbotLoggerSlf4jImpl = simbot("logger-slf4j-impl")
+//
+//val simbotUtilLoop = "love.forte.simbot.util:simbot-util-stage-loop:$simbotVersion"
+//val simbotUtilSuspendTransformer = "love.forte.simbot.util:simbot-util-suspend-transformer:$simbotVersion"
+//val simbotUtilAnnotations = "love.forte.simbot.util:simbot-annotations:$simbotVersion"
const val SIMBOT_GROUP = "love.forte.simbot"
@@ -58,19 +59,10 @@ object P {
override val homepage: String get() = HOMEPAGE
- private val baseVersion = v(
- "${simbotVersion.major}.${simbotVersion.minor}",
- 0, 0
- )
-
- //private val alphaSuffix = v("beta", 2)
+ private val baseVersion = v(4, 0, 0) - v("dev6")
- override val version = baseVersion // - alphaSuffix
val snapshotVersion = baseVersion - Version.SNAPSHOT
-
- val versionIfSnap get() = (if (isSnapshot()) snapshotVersion else version).toString()
-
- val VERSION: String get() = versionIfSnap.toString()
+ override val version = if (isSnapshot()) snapshotVersion else baseVersion
override val developers: List = developers {
developer {
@@ -118,3 +110,5 @@ private fun initIsSnapshot(): Boolean {
}
fun isSnapshot(): Boolean = _isSnapshot
+
+fun isSimbotLocal(): Boolean = systemProp("SIMBOT_LOCAL").toBoolean()
diff --git a/buildSrc/src/main/kotlin/SuspendTransforms.kt b/buildSrc/src/main/kotlin/SuspendTransforms.kt
deleted file mode 100644
index 09051ee4..00000000
--- a/buildSrc/src/main/kotlin/SuspendTransforms.kt
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2023. ForteScarlet.
- *
- * This file is part of simbot-component-qq-guild.
- *
- * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
- * of the GNU Lesser General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
- * If not, see .
- */
-
-import love.forte.plugin.suspendtrans.*
-
-
-object SuspendTransforms {
- private val includeAnnotationApi4JClassInfo = ClassInfo("love.forte.simbot", "Api4J")
- private val includeAnnotationApi4J = IncludeAnnotation(includeAnnotationApi4JClassInfo)
- private val includeAnnotations = listOf(includeAnnotationApi4J)
-
- /**
- * JvmBlocking
- */
- val jvmBlockingTransformer = SuspendTransformConfiguration.jvmBlockingTransformer.copy(
- syntheticFunctionIncludeAnnotations = includeAnnotations,
- transformFunctionInfo = FunctionInfo("love.forte.simbot.utils", null, "$\$runInBlocking"),
- copyAnnotationExcludes = SuspendTransformConfiguration.jvmBlockingTransformer.copyAnnotationExcludes + SuspendTransformConfiguration.jvmBlockingTransformer.markAnnotation.classInfo
- )
-
- /**
- * JvmAsync
- */
- val jvmAsyncTransformer = SuspendTransformConfiguration.jvmAsyncTransformer.copy(
- syntheticFunctionIncludeAnnotations = includeAnnotations,
- transformFunctionInfo = FunctionInfo("love.forte.simbot.utils", null, "$\$runInAsync1"),
- copyAnnotationExcludes = SuspendTransformConfiguration.jvmAsyncTransformer.copyAnnotationExcludes + SuspendTransformConfiguration.jvmAsyncTransformer.markAnnotation.classInfo
- )
-
- //region @JvmSuspendTrans
- private val jvmSuspendTransMarkAnnotationClassInfo = ClassInfo("love.forte.simbot", "JvmSuspendTrans")
-
- private val jvmSuspendTransMarkAnnotationForBlocking = MarkAnnotation(
- jvmSuspendTransMarkAnnotationClassInfo,
- baseNameProperty = "blockingBaseName",
- suffixProperty = "blockingSuffix",
- asPropertyProperty = "blockingAsProperty",
- defaultSuffix = SuspendTransformConfiguration.jvmBlockingAnnotationInfo.defaultSuffix,
- )
- private val jvmSuspendTransMarkAnnotationForAsync = MarkAnnotation(
- jvmSuspendTransMarkAnnotationClassInfo,
- baseNameProperty = "asyncBaseName",
- suffixProperty = "asyncSuffix",
- asPropertyProperty = "asyncAsProperty",
- defaultSuffix = SuspendTransformConfiguration.jvmAsyncAnnotationInfo.defaultSuffix,
- )
-
- val jvmSuspendTransTransformerForBlocking = jvmBlockingTransformer.copy(
- markAnnotation = jvmSuspendTransMarkAnnotationForBlocking,
- copyAnnotationExcludes = SuspendTransformConfiguration.jvmBlockingTransformer.copyAnnotationExcludes + jvmSuspendTransMarkAnnotationForBlocking.classInfo
- )
-
- val jvmSuspendTransTransformerForAsync = jvmAsyncTransformer.copy(
- markAnnotation = jvmSuspendTransMarkAnnotationForAsync,
- copyAnnotationExcludes = SuspendTransformConfiguration.jvmAsyncTransformer.copyAnnotationExcludes + jvmSuspendTransMarkAnnotationForAsync.classInfo
- )
- //endregion
-
- //region @JvmSuspendTransProperty
- private val jvmSuspendTransPropMarkAnnotationClassInfo = ClassInfo("love.forte.simbot", "JvmSuspendTransProperty")
-
- private val jvmSuspendTransPropMarkAnnotationForBlocking = MarkAnnotation(
- jvmSuspendTransPropMarkAnnotationClassInfo,
- baseNameProperty = "blockingBaseName",
- suffixProperty = "blockingSuffix",
- asPropertyProperty = "blockingAsProperty",
- defaultSuffix = "",
- defaultAsProperty = true
- )
- private val jvmSuspendTransPropMarkAnnotationForAsync = MarkAnnotation(
- jvmSuspendTransPropMarkAnnotationClassInfo,
- baseNameProperty = "asyncBaseName",
- suffixProperty = "asyncSuffix",
- asPropertyProperty = "asyncAsProperty",
- defaultSuffix = SuspendTransformConfiguration.jvmAsyncAnnotationInfo.defaultSuffix,
- defaultAsProperty = true
- )
-
- val jvmSuspendTransPropTransformerForBlocking = jvmBlockingTransformer.copy(
- markAnnotation = jvmSuspendTransPropMarkAnnotationForBlocking,
- copyAnnotationExcludes = SuspendTransformConfiguration.jvmBlockingTransformer.copyAnnotationExcludes + jvmSuspendTransPropMarkAnnotationForBlocking.classInfo
- )
-
- val jvmSuspendTransPropTransformerForAsync = jvmAsyncTransformer.copy(
- markAnnotation = jvmSuspendTransPropMarkAnnotationForAsync,
- copyAnnotationExcludes = SuspendTransformConfiguration.jvmAsyncTransformer.copyAnnotationExcludes + jvmSuspendTransPropMarkAnnotationForAsync.classInfo
- )
- //endregion
-
-}
-
-
-
-
diff --git a/buildSrc/src/main/kotlin/qq-guild-dokka-partial-configure.gradle.kts b/buildSrc/src/main/kotlin/qq-guild-dokka-partial-configure.gradle.kts
index dfbcfe46..6670c383 100644
--- a/buildSrc/src/main/kotlin/qq-guild-dokka-partial-configure.gradle.kts
+++ b/buildSrc/src/main/kotlin/qq-guild-dokka-partial-configure.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -15,7 +15,6 @@
* If not, see .
*/
-import org.gradle.kotlin.dsl.withType
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.gradle.DokkaTaskPartial
import java.net.URL
@@ -50,10 +49,10 @@ tasks.withType().configureEach {
}
// samples
- samples.from(
- project.files(),
- project.files("src/samples"),
- )
+// samples.from(
+// project.files(),
+// project.files("src/samples"),
+// )
sourceLink {
localDirectory.set(projectDir.resolve("src"))
diff --git a/buildSrc/src/main/kotlin/qq-guild-multiplatform-maven-publish.gradle.kts b/buildSrc/src/main/kotlin/qq-guild-multiplatform-maven-publish.gradle.kts
index c4217d50..ab499aa3 100644
--- a/buildSrc/src/main/kotlin/qq-guild-multiplatform-maven-publish.gradle.kts
+++ b/buildSrc/src/main/kotlin/qq-guild-multiplatform-maven-publish.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,53 +19,46 @@ import love.forte.gradle.common.core.Gpg
import love.forte.gradle.common.core.project.setup
import love.forte.gradle.common.core.property.systemProp
import love.forte.gradle.common.publication.configure.multiplatformConfigPublishing
-import org.jetbrains.kotlin.konan.target.HostManager
-import org.jetbrains.kotlin.konan.target.KonanTarget
plugins {
- kotlin("multiplatform")
signing
`maven-publish`
}
-tasks.withType {
- sourceCompatibility = "1.8"
- targetCompatibility = "1.8"
- options.encoding = "UTF-8"
-}
setup(P.ComponentQQGuild)
-if (isSnapshot()) {
- version = P.ComponentQQGuild.snapshotVersion.toString()
-}
val p = project
multiplatformConfigPublishing {
project = P.ComponentQQGuild
+ isSnapshot = project.version.toString().contains("SNAPSHOT", true)
val jarJavadoc by tasks.registering(Jar::class) {
group = "documentation"
archiveClassifier.set("javadoc")
- from(tasks.findByName("dokkaHtml"))
+ if (!(isSnapshot || isSnapshot() || isSimbotLocal())) {
+ archiveClassifier.set("javadoc")
+ from(tasks.findByName("dokkaHtml"))
+ }
}
+
artifact(jarJavadoc)
- isSnapshot = project.version.toString().contains("SNAPSHOT", true)
releasesRepository = ReleaseRepository
snapshotRepository = SnapshotRepository
gpg = Gpg.ofSystemPropOrNull()
- if (systemProp("SIMBOT_LOCAL").toBoolean()) {
+ if (isSimbotLocal()) {
mainHost = null
}
-// else {
-//
-// mainHostSupportedTargets = mainHost?.supports(hostManager) ?: emptySet()
-// }
+ publicationsFromMainHost += listOf("wasm", "wasm32", "wasm_js")
+ mainHostSupportedTargets += listOf("wasm", "wasm32", "wasm_js")
}
-fun KonanTarget.supports(hostManager: HostManager): Set {
- return hostManager.enabledByHost[this]?.mapTo(mutableSetOf()) { target -> target.name } ?: emptySet()
+// TODO see https://github.com/gradle-nexus/publish-plugin/issues/208#issuecomment-1465029831
+val signingTasks: TaskCollection = tasks.withType()
+tasks.withType().configureEach {
+ mustRunAfter(signingTasks)
}
show()
@@ -89,3 +82,6 @@ fun show() {
inline val Project.sourceSets: SourceSetContainer
get() = extensions.getByName("sourceSets") as SourceSetContainer
+
+internal val TaskContainer.dokkaHtml: TaskProvider
+ get() = named("dokkaHtml")
diff --git a/buildSrc/src/main/kotlin/simbot-tcg-suspend-transform-configure.gradle.kts b/buildSrc/src/main/kotlin/simbot-tcg-suspend-transform-configure.gradle.kts
index a996744a..ea7af7fe 100644
--- a/buildSrc/src/main/kotlin/simbot-tcg-suspend-transform-configure.gradle.kts
+++ b/buildSrc/src/main/kotlin/simbot-tcg-suspend-transform-configure.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -15,22 +15,23 @@
* If not, see .
*/
-import love.forte.plugin.suspendtrans.SuspendTransformConfiguration
+import love.forte.simbot.gradle.suspendtransforms.SuspendTransforms
/*
- * Copyright (c) 2022 ForteScarlet
+ * Copyright (c) 2024. ForteScarlet.
*
- * 本文件是 simply-robot (或称 simple-robot 3.x 、simbot 3.x ) 的一部分。
- *
- * simply-robot 是自由软件:你可以再分发之和/或依照由自由软件基金会发布的 GNU 通用公共许可证修改之,无论是版本 3 许可证,还是(按你的决定)任何以后版都可以。
+ * This file is part of simbot-component-qq-guild.
*
- * 发布 simply-robot 是希望它能有用,但是并无保障;甚至连可销售和符合某个特定的目的都不保证。请参看 GNU 通用公共许可证,了解详情。
+ * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
*
- * 你应该随程序获得一份 GNU 通用公共许可证的复本。如果没有,请看:
- * https://www.gnu.org/licenses
- * https://www.gnu.org/licenses/gpl-3.0-standalone.html
- * https://www.gnu.org/licenses/lgpl-3.0-standalone.html
+ * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
*
+ * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
+ * If not, see .
*/
plugins {
@@ -39,19 +40,26 @@ plugins {
suspendTransform {
includeRuntime = false
-
+ includeAnnotation = false
+
addJvmTransformers(
// @JvmBlocking
SuspendTransforms.jvmBlockingTransformer,
// @JvmAsync
SuspendTransforms.jvmAsyncTransformer,
-
+
// @JvmSuspendTrans
- SuspendTransforms.jvmSuspendTransTransformerForBlocking,
- SuspendTransforms.jvmSuspendTransTransformerForAsync,
-
+ SuspendTransforms.suspendTransTransformerForJvmBlocking,
+ SuspendTransforms.suspendTransTransformerForJvmAsync,
+ SuspendTransforms.suspendTransTransformerForJvmReserve,
+
// @JvmSuspendTransProperty
SuspendTransforms.jvmSuspendTransPropTransformerForBlocking,
- SuspendTransforms.jvmSuspendTransPropTransformerForAsync
+ SuspendTransforms.jvmSuspendTransPropTransformerForAsync,
+ SuspendTransforms.jvmSuspendTransPropTransformerForReserve,
)
+
+ // addJsTransformers(
+ // SuspendTransforms.suspendTransTransformerForJsPromise,
+ // )
}
diff --git a/buildSrc/src/main/kotlin/simbot-tencent-guild.changelog-generator.gradle.kts b/buildSrc/src/main/kotlin/simbot-tencent-guild.changelog-generator.gradle.kts
index 2a385d59..69701064 100644
--- a/buildSrc/src/main/kotlin/simbot-tencent-guild.changelog-generator.gradle.kts
+++ b/buildSrc/src/main/kotlin/simbot-tencent-guild.changelog-generator.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -28,22 +28,38 @@ tasks.create("createChangelog") {
}
val file = File(changelogDir, "$version.md")
if (!file.exists()) {
- file.createNewFile()
+
+ val libs = rootProject.extensions.getByType()
+ .named("libs")
+
+ val simbotVersion = libs.findVersion("simbot").get()
+
val coreVersion = simbotVersion
- val autoGenerateText = """
- > 对应核心版本: [**v$coreVersion**](https://github.com/simple-robot/simpler-robot/releases/tag/v$coreVersion)
-
- > **Warning**
- > **目前版本处于 `BETA` 阶段,代表我们会尽量保证不再大面积变更API,且仍然可能存在一些未知问题、未完善的内容和落后于官方更新的内容。**
-
- 我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
- 感谢您的贡献与支持!
+ val autoGenerateText = buildString {
+ appendLine("> 对应核心版本: [**v$coreVersion**](https://github.com/simple-robot/simpler-robot/releases/tag/v$coreVersion)\n\n")
- 也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
-
- """.trimIndent()
+ if ("dev" in version) {
+ appendLine(
+ """
+ > [!warning]
+ > **目前版本处于 `dev` 阶段,代表此版本是一个开发预览版,可能不稳定、可能随时发生更改、且不保证可用性。**
+
+
+ """.trimIndent()
+ )
+ }
+ appendLine(
+ """
+ 我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-qq-guild/issues)或[协助](https://github.com/simple-robot/simbot-component-qq-guild/pulls),
+ 感谢您的贡献与支持!
+ 也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
+ """.trimIndent()
+ )
+ }
+
+ file.createNewFile()
file.writeText(autoGenerateText)
}
}
@@ -75,5 +91,15 @@ tasks.create("updateWebsiteVersionJson") {
fun repoRow(moduleName: String, group: String, id: String, version: String): String {
- return "| $moduleName | [$moduleName: v$version](https://repo1.maven.org/maven2/${group.replace(".", "/")}/${id.replace(".", "/")}/$version) | [$moduleName: v$version](https://search.maven.org/artifact/$group/$id/$version/jar) |"
+ return "| $moduleName | [$moduleName: v$version](https://repo1.maven.org/maven2/${
+ group.replace(
+ ".",
+ "/"
+ )
+ }/${
+ id.replace(
+ ".",
+ "/"
+ )
+ }/$version) | [$moduleName: v$version](https://search.maven.org/artifact/$group/$id/$version/jar) |"
}
diff --git a/buildSrc/src/main/kotlin/simbot-tencent-guild.dokka-multi-module.gradle.kts b/buildSrc/src/main/kotlin/simbot-tencent-guild.dokka-multi-module.gradle.kts
index bbd3983f..676781c7 100644
--- a/buildSrc/src/main/kotlin/simbot-tencent-guild.dokka-multi-module.gradle.kts
+++ b/buildSrc/src/main/kotlin/simbot-tencent-guild.dokka-multi-module.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,8 +17,6 @@
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.DokkaBaseConfiguration
-import org.gradle.api.plugins.JavaBasePlugin
-import java.io.File
import java.time.Year
plugins {
@@ -30,7 +28,7 @@ repositories {
}
fun org.jetbrains.dokka.gradle.AbstractDokkaTask.configOutput(format: String) {
- moduleName.set("Simple Robot Component Tencent Guild")
+ moduleName.set("Simple Robot Component | QQ Guild")
outputDirectory.set(rootProject.file("build/dokka/$format"))
}
diff --git a/buildSrc/src/main/kotlin/simbot-tencent-guild.maven-publish.gradle.kts b/buildSrc/src/main/kotlin/simbot-tencent-guild.maven-publish.gradle.kts
index 1724bd01..feed9fc9 100644
--- a/buildSrc/src/main/kotlin/simbot-tencent-guild.maven-publish.gradle.kts
+++ b/buildSrc/src/main/kotlin/simbot-tencent-guild.maven-publish.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -30,145 +30,50 @@ plugins {
val (isSnapshotOnly, isReleaseOnly, isPublishConfigurable) = checkPublishConfigurable()
-logger.info("isSnapshotOnly: $isSnapshotOnly")
-logger.info("isReleaseOnly: $isReleaseOnly")
-logger.info("isPublishConfigurable: $isPublishConfigurable")
-
-
+logger.info("isSnapshotOnly: {}", isSnapshotOnly)
+logger.info("isReleaseOnly: {}", isReleaseOnly)
+logger.info("isPublishConfigurable: {}", isPublishConfigurable)
if (!isCi || isLinux) {
checkPublishConfigurable {
jvmConfigPublishing {
project = P.ComponentQQGuild
- publicationName = "tencentGuildDist"
+ publicationName = "QQGuildDist"
+ isSnapshot = isSnapshot().also {
+ logger.info("jvmConfigPublishing.isSnapshot: {}", it)
+ }
+
val jarSources by tasks.registering(Jar::class) {
archiveClassifier.set("sources")
from(sourceSets["main"].allSource)
}
val jarJavadoc by tasks.registering(Jar::class) {
+ if (!(isSnapshot || isSnapshot())) {
+ dependsOn(tasks.dokkaHtml)
+ from(tasks.dokkaHtml.flatMap { it.outputDirectory })
+ }
archiveClassifier.set("javadoc")
}
artifact(jarSources)
artifact(jarJavadoc)
- isSnapshot = isSnapshot().also {
- logger.info("jvmConfigPublishing.isSnapshot: {}", it)
- }
releasesRepository = ReleaseRepository
snapshotRepository = SnapshotRepository
- gpg = if (isSnapshot()) null else Gpg.ofSystemPropOrNull()
+ gpg = Gpg.ofSystemPropOrNull()
}
-
- if (isSnapshot()) {
- publishing {
- publications.withType {
- version = P.ComponentQQGuild.snapshotVersion.toString()
- }
- }
- }
-
- publishing {
- publications.withType {
- show()
- }
- }
-
-
}
-}
-
-
-//
-//if (isPublishConfigurable) {
-// val sonatypeUsername: String? = systemProp("OSSRH_USER")
-// val sonatypePassword: String? = systemProp("OSSRH_PASSWORD")
-//
-// if (sonatypeUsername == null || sonatypePassword == null) {
-// println("[WARN] - sonatype.username or sonatype.password is null, cannot config nexus publishing.")
-// }
-//
-// val jarSources by tasks.registering(Jar::class) {
-// archiveClassifier.set("sources")
-// from(sourceSets["main"].allSource)
-// }
-//
-// val jarJavadoc by tasks.registering(Jar::class) {
-// archiveClassifier.set("javadoc")
-// }
-//
-// publishing {
-// publications {
-// create("tencentGuildDist") {
-// from(components["java"])
-// artifact(jarSources)
-// artifact(jarJavadoc)
-//
-// groupId = project.group.toString()
-// artifactId = project.name
-// version = project.version.toString()
-// description = project.description?.toString() ?: P.ComponentTencentGuild.DESCRIPTION
-//
-// pom {
-// show()
-//
-// name.set("${project.group}:${project.name}")
-// description.set(project.description?.toString() ?: P.ComponentTencentGuild.DESCRIPTION)
-// url.set("https://github.com/simple-robot/simbot-component-qq-guild")
-// licenses {
-// license {
-// name.set("GNU GENERAL PUBLIC LICENSE, Version 3")
-// url.set("https://www.gnu.org/licenses/gpl-3.0-standalone.html")
-// }
-// license {
-// name.set("GNU LESSER GENERAL PUBLIC LICENSE, Version 3")
-// url.set("https://www.gnu.org/licenses/lgpl-3.0-standalone.html")
-// }
-// }
-// scm {
-// url.set("https://github.com/simple-robot/simbot-component-qq-guild")
-// connection.set("scm:git:https://github.com/simple-robot/simbot-component-qq-guild.git")
-// developerConnection.set("scm:git:ssh://git@github.com/simple-robot/simbot-component-tencent-guild.git")
-// }
-//
-// setupDevelopers()
-// }
-// }
-//
-//
-//
-// repositories {
-// configMaven(Sonatype.Central, sonatypeUsername, sonatypePassword)
-// configMaven(Sonatype.Snapshot, sonatypeUsername, sonatypePassword)
-// }
-// }
-// }
-//
-//
-// signing {
-// val keyId = System.getenv("GPG_KEY_ID")
-// val secretKey = System.getenv("GPG_SECRET_KEY")
-// val password = System.getenv("GPG_PASSWORD")
-//
-// setRequired {
-// !project.version.toString().endsWith("SNAPSHOT")
-// }
-//
-// useInMemoryPgpKeys(keyId, secretKey, password)
-//
-// sign(publishing.publications["tencentGuildDist"])
-// }
-//
-//
-// println("[publishing-configure] - [$name] configured.")
-//}
+ show()
+}
inline val Project.sourceSets: SourceSetContainer
get() = extensions.getByName("sourceSets") as SourceSetContainer
+internal val TaskContainer.dokkaHtml: TaskProvider
+ get() = named("dokkaHtml")
fun Project.show() {
//// show project info
diff --git a/buildSrc/src/main/kotlin/simbot-tencent-guild.module-conventions.gradle.kts b/buildSrc/src/main/kotlin/simbot-tencent-guild.module-conventions.gradle.kts
index 5123f125..a725312d 100644
--- a/buildSrc/src/main/kotlin/simbot-tencent-guild.module-conventions.gradle.kts
+++ b/buildSrc/src/main/kotlin/simbot-tencent-guild.module-conventions.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -15,69 +15,27 @@
* If not, see .
*/
import love.forte.gradle.common.core.project.setup
-import love.forte.gradle.common.core.repository.Repositories
-import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.gradle.DokkaTaskPartial
-import java.net.URL
plugins {
- `java-library`
- kotlin("jvm")
- kotlin("plugin.serialization")
idea
}
setup(P.ComponentQQGuild)
-if (isSnapshot()) {
- version = P.ComponentQQGuild.snapshotVersion.toString()
-}
-
-repositories {
- mavenCentral()
- maven {
- url = uri(Repositories.Snapshot.URL)
- mavenContent {
- snapshotsOnly()
- }
- }
-}
-
-dependencies {
- testImplementation(kotlin("test-junit5"))
-}
-
-
-tasks.getByName("test") {
- useJUnitPlatform()
-}
-
-tasks.withType().configureEach {
- kotlinOptions {
- javaParameters = true
- jvmTarget = "1.8"
- freeCompilerArgs = freeCompilerArgs + listOf("-Xjvm-default=all")
- }
-}
-
-tasks.withType {
- sourceCompatibility = "1.8"
- targetCompatibility = "1.8"
- options.encoding = "UTF-8"
-}
-
-kotlin {
- explicitApi()
- sourceSets.configureEach {
- languageSettings {
- optIn("kotlin.RequiresOptIn")
- }
- }
- sourceSets.getByName("test").kotlin {
- srcDir("src/samples")
- }
-}
+//
+//kotlin {
+// explicitApi()
+// sourceSets.configureEach {
+// languageSettings {
+// optIn("kotlin.RequiresOptIn")
+// }
+// }
+//
+// sourceSets.getByName("test").kotlin {
+// srcDir("src/samples")
+// }
+//}
configurations.all {
// check for updates every build
@@ -91,11 +49,3 @@ idea {
isDownloadJavadoc = true
}
}
-
-
-//// show project info
-logger.info("========================================================")
-logger.info("== project.group: ${group}")
-logger.info("== project.name: ${name}")
-logger.info("== project.version: ${version}")
-logger.info("========================================================")
diff --git a/buildSrc/src/main/kotlin/simbot-tencent-guild.nexus-publish.gradle.kts b/buildSrc/src/main/kotlin/simbot-tencent-guild.nexus-publish.gradle.kts
index 109405d5..f93b89cb 100644
--- a/buildSrc/src/main/kotlin/simbot-tencent-guild.nexus-publish.gradle.kts
+++ b/buildSrc/src/main/kotlin/simbot-tencent-guild.nexus-publish.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -18,8 +18,6 @@
import love.forte.gradle.common.core.project.setup
import love.forte.gradle.common.core.repository.Repositories
import love.forte.gradle.common.publication.configure.nexusPublishConfig
-import util.checkPublishConfigurable
-import java.time.Duration
plugins {
id("io.github.gradle-nexus.publish-plugin")
@@ -27,16 +25,6 @@ plugins {
setup(P.ComponentQQGuild)
-if (isSnapshot()) {
- version = P.ComponentQQGuild.snapshotVersion.toString()
-}
-
-//val (isSnapshotOnly, isReleaseOnly, isPublishConfigurable) = checkPublishConfigurable()
-//
-//logger.info("isSnapshotOnly: {}", isSnapshotOnly)
-//logger.info("isReleaseOnly: {}", isReleaseOnly)
-//logger.info("isPublishConfigurable: {}", isPublishConfigurable)
-
val userInfo = love.forte.gradle.common.publication.sonatypeUserInfoOrNull
if (userInfo == null) {
@@ -54,43 +42,3 @@ nexusPublishConfig {
}
}
}
-
-//
-//if (isPublishConfigurable) {
-// val sonatypeUsername: String? = sonatypeUsername
-// val sonatypePassword: String? = sonatypePassword
-//
-// if (sonatypeUsername == null || sonatypePassword == null) {
-// logger.warn("sonatype.username or sonatype.password is null, cannot config nexus publishing.")
-// }
-//
-// nexusPublishing {
-// packageGroup.set(project.group.toString())
-//
-// useStaging.set(
-// project.provider { !project.version.toString().endsWith("SNAPSHOT", ignoreCase = true).also {
-// logger.info("UseStaging: {} (project version: {})", it, project.version.toString())
-// } }
-// )
-//
-// transitionCheckOptions {
-// maxRetries.set(100)
-// delayBetween.set(Duration.ofSeconds(30))
-// }
-//
-// repositories {
-// sonatype {
-// snapshotRepositoryUrl.set(uri(Repositories.Snapshot.URL))
-// username.set(sonatypeUsername)
-// password.set(sonatypePassword)
-// }
-// }
-// }
-//
-//
-// logger.info("[publishing-configure] - [{}] configured.", name)
-//}
-
-
-
-
diff --git a/buildSrc/src/main/kotlin/simbot-tencent-guild.root-module-conventions.gradle.kts b/buildSrc/src/main/kotlin/simbot-tencent-guild.root-module-conventions.gradle.kts
deleted file mode 100644
index 201a127e..00000000
--- a/buildSrc/src/main/kotlin/simbot-tencent-guild.root-module-conventions.gradle.kts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2022-2023. ForteScarlet.
- *
- * This file is part of simbot-component-tencent-guild.
- *
- * simbot-component-tencent-guild is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * simbot-component-tencent-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along with simbot-component-tencent-guild. If not, see .
- */
-plugins {
- idea
-}
-
-idea {
- module.apply {
- isDownloadSources = true
- isDownloadJavadoc = true
- }
- project {
- modules.forEach { module ->
- module.apply {
- isDownloadSources = true
- isDownloadJavadoc = true
- }
- }
- }
-}
-
-configurations.all {
- // check for updates every build
- resolutionStrategy.cacheChangingModulesFor(0, "seconds")
-}
diff --git a/gradle.properties b/gradle.properties
index 43390c50..ad34dc55 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,17 +1,29 @@
+
kotlin.code.style=official
+
kotlin.js.generate.executable.default=false
kotlin.mpp.stability.nowarn=true
+# w: The following Kotlin/Native targets cannot be built on this machine and are disabled
+# To hide this message, add 'kotlin.native.ignoreDisabledTargets=true' to the Gradle properties.
kotlin.native.ignoreDisabledTargets=true
-org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
-# -Xmx8g -Xms2g -XX:MaxMetaspaceSize=1g
-# https://kotlinlang.org/docs/native-improving-compilation-time.html
+# Such dependencies are not applicable for Kotlin/Native, consider changing the dependency type to 'implementation' or 'api'.
+# To disable this warning, set the kotlin.native.ignoreIncorrectDependencies=true project property
+kotlin.native.ignoreIncorrectDependencies=true
+
+# 'expect'/'actual' classes (including interfaces, objects, annotations, enums, and 'actual' typealiases) are in Beta. You can use -Xexpect-actual-classes flag to suppress this warning. Also see: https://youtrack.jetbrains.com/issue/KT-61573
+# "-Xexpect-actual-classes"
+org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=1G -Dfile.encoding=UTF-8
+# https://kotlinlang.org/docs/native-improving-compilation-time.html#gradle-configuration
+#org.gradle.workers.max=8
+org.gradle.parallel=true
org.gradle.caching=true
-org.gradle.workers.max=4
-#org.gradle.daemon=false
-#org.gradle.parallel=false
-# Hide: A compileOnly dependency is used in the Kotlin/Native target 'xxx'
-# Such dependencies are not applicable for Kotlin/Native, consider changing the dependency type to 'implementation' or 'api'.
-kotlin.native.ignoreIncorrectDependencies=true
+
+# https://kotlinlang.org/docs/gradle-compilation-and-caches.html#the-new-kotlin-compiler
+#kotlin.experimental.tryK2=true
+
+
+#http.proxyHost=localhost
+#http.proxyPort=7790
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 44732334..a67c2234 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,14 +1,34 @@
[versions]
-kotlinx-coroutines = "1.7.0"
-kotlinx-serialization = "1.5.0"
-kotlinx-datetime = "0.4.0"
+kotlin = "1.9.21"
+kotlinx-coroutines = "1.7.3"
+kotlinx-serialization = "1.6.2"
+kotlinx-datetime = "0.5.0"
+dokka = "1.9.10"
okio = "3.3.0"
-ktor = "2.3.0"
+ktor = "2.3.7"
openjdk-jmh = "1.35"
log4j = "2.20.0"
-atomicfu = "0.20.1"
+reactor = "3.6.2"
+# simbot
+simbot = "4.0.0-dev14"
+suspendTransform = "0.6.0"
+gradleCommon = "0.2.0"
[libraries]
+# simbot
+simbot-api = { group = "love.forte.simbot", name = "simbot-api", version.ref = "simbot" }
+simbot-core = { group = "love.forte.simbot", name = "simbot-core", version.ref = "simbot" }
+simbot-spring = { group = "love.forte.simbot", name = "simbot-core-spring-boot-starter", version.ref = "simbot" }
+simbot-logger = { group = "love.forte.simbot.logger", name = "simbot-logger", version.ref = "simbot" }
+simbot-logger-slf4jimpl = { group = "love.forte.simbot.logger", name = "simbot-logger-slf4j2-impl", version.ref = "simbot" }
+simbot-common-apidefinition = { group = "love.forte.simbot.common", name = "simbot-common-apidefinition", version.ref = "simbot" }
+simbot-common-atomic = { group = "love.forte.simbot.common", name = "simbot-common-atomic", version.ref = "simbot" }
+simbot-common-core = { group = "love.forte.simbot.common", name = "simbot-common-core", version.ref = "simbot" }
+simbot-common-suspend = { group = "love.forte.simbot.common", name = "simbot-common-suspend-runner", version.ref = "simbot" }
+simbot-common-annotations = { group = "love.forte.simbot.common", name = "simbot-common-annotations", version.ref = "simbot" }
+simbot-common-loop = { group = "love.forte.simbot.common", name = "simbot-common-stage-loop", version.ref = "simbot" }
+simbot-gradle = { group = "love.forte.simbot.gradle", name = "simbot-gradle-suspendtransforms", version.ref = "simbot" }
+
# jetbrains-annotation
jetbrains-annotations = "org.jetbrains:annotations:24.0.1"
@@ -48,6 +68,7 @@ ktor-client-ws = { group = "io.ktor", name = "ktor-client-websockets", version.r
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" }
ktor-client-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktor" }
+ktor-client-java = { group = "io.ktor", name = "ktor-client-java", version.ref = "ktor" }
# for linuxX64, macosX64, macosArm64, mingwX64
# see https://ktor.io/docs/http-client-engines.html#curl
@@ -71,3 +92,20 @@ log4j-slf4j2 = { group = "org.apache.logging.log4j", name = "log4j-slf4j2-impl",
openjdk-jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "openjdk-jmh" }
openjdk-jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "openjdk-jmh" }
+# reactor
+reactor-core = { group = "io.projectreactor", name = "reactor-core", version.ref = "reactor" }
+
+# dokka
+dokka-plugin = { group = "org.jetbrains.dokka", name = "dokka-gradle-plugin", version.ref = "dokka" }
+dokka-base = { group = "org.jetbrains.dokka", name = "dokka-base", version.ref = "dokka" }
+
+suspend-transform-gradle = { module = "love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle", version.ref = "suspendTransform" }
+
+# gradle-common
+gradle-common-core = { group = "love.forte.gradle.common", name = "gradle-common-core", version.ref = "gradleCommon" }
+gradle-common-multiplatform = { group = "love.forte.gradle.common", name = "gradle-common-kotlin-multiplatform", version.ref = "gradleCommon" }
+gradle-common-publication = { group = "love.forte.gradle.common", name = "gradle-common-publication", version.ref = "gradleCommon" }
+
+[bundles]
+gradle-common = ["gradle-common-core", "gradle-common-multiplatform", "gradle-common-publication"]
+dokka = ["dokka-plugin", "dokka-base"]
diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock
index df1559fa..fd7abab4 100644
--- a/kotlin-js-store/yarn.lock
+++ b/kotlin-js-store/yarn.lock
@@ -2,26 +2,15 @@
# yarn lockfile v1
-"@babel/code-frame@^7.10.4":
- version "7.21.4"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39"
- integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==
- dependencies:
- "@babel/highlight" "^7.18.6"
-
-"@babel/helper-validator-identifier@^7.18.6":
- version "7.19.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
- integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
+"@colors/colors@1.5.0":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
+ integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
-"@babel/highlight@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
- integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
- dependencies:
- "@babel/helper-validator-identifier" "^7.18.6"
- chalk "^2.0.0"
- js-tokens "^4.0.0"
+"@discoveryjs/json-ext@^0.5.0":
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
+ integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
"@jridgewell/gen-mapping@^0.3.0":
version "0.3.3"
@@ -37,15 +26,20 @@
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
"@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
-"@jridgewell/source-map@^0.3.2":
- version "0.3.3"
- resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda"
- integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==
+"@jridgewell/source-map@^0.3.3":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91"
+ integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==
dependencies:
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
@@ -55,11 +49,19 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
-"@jridgewell/sourcemap-codec@^1.4.10":
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+"@jridgewell/trace-mapping@^0.3.20":
+ version "0.3.21"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz#5dc1df7b3dc4a6209e503a924e1ca56097a2bb15"
+ integrity sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.18"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6"
@@ -68,79 +70,221 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
-"@rollup/plugin-commonjs@^21.0.1":
- version "21.1.0"
- resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz#45576d7b47609af2db87f55a6d4b46e44fc3a553"
- integrity sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA==
- dependencies:
- "@rollup/pluginutils" "^3.1.0"
- commondir "^1.0.1"
- estree-walker "^2.0.1"
- glob "^7.1.6"
- is-reference "^1.2.1"
- magic-string "^0.25.7"
- resolve "^1.17.0"
-
-"@rollup/plugin-node-resolve@^13.1.3":
- version "13.3.0"
- resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c"
- integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==
- dependencies:
- "@rollup/pluginutils" "^3.1.0"
- "@types/resolve" "1.17.1"
- deepmerge "^4.2.2"
- is-builtin-module "^3.1.0"
- is-module "^1.0.0"
- resolve "^1.19.0"
-
-"@rollup/plugin-typescript@^8.3.0":
- version "8.5.0"
- resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz#7ea11599a15b0a30fa7ea69ce3b791d41b862515"
- integrity sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==
- dependencies:
- "@rollup/pluginutils" "^3.1.0"
- resolve "^1.17.0"
+"@js-joda/core@3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273"
+ integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==
-"@rollup/pluginutils@^3.0.9", "@rollup/pluginutils@^3.1.0":
+"@socket.io/component-emitter@~3.1.0":
version "3.1.0"
- resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
- integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
+ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
+ integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
+
+"@types/cookie@^0.4.1":
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
+ integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
+
+"@types/cors@^2.8.12":
+ version "2.8.17"
+ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b"
+ integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==
+ dependencies:
+ "@types/node" "*"
+
+"@types/eslint-scope@^3.7.3":
+ version "3.7.7"
+ resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5"
+ integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==
+ dependencies:
+ "@types/eslint" "*"
+ "@types/estree" "*"
+
+"@types/eslint@*":
+ version "8.56.2"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.2.tgz#1c72a9b794aa26a8b94ad26d5b9aa51c8a6384bb"
+ integrity sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==
dependencies:
- "@types/estree" "0.0.39"
- estree-walker "^1.0.1"
- picomatch "^2.2.2"
+ "@types/estree" "*"
+ "@types/json-schema" "*"
"@types/estree@*":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194"
integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==
-"@types/estree@0.0.39":
- version "0.0.39"
- resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
- integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+"@types/estree@^1.0.0":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+ integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
+
+"@types/json-schema@*", "@types/json-schema@^7.0.8":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
"@types/node@*":
version "20.1.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.2.tgz#8fd63447e3f99aba6c3168fd2ec4580d5b97886f"
integrity sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g==
-"@types/node@^12.12.14":
- version "12.20.55"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
- integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
+"@types/node@>=10.0.0":
+ version "20.11.0"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.0.tgz#8e0b99e70c0c1ade1a86c4a282f7b7ef87c9552f"
+ integrity sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==
+ dependencies:
+ undici-types "~5.26.4"
+
+"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
+ integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==
+ dependencies:
+ "@webassemblyjs/helper-numbers" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+
+"@webassemblyjs/floating-point-hex-parser@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
+ integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
+
+"@webassemblyjs/helper-api-error@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
+ integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
+
+"@webassemblyjs/helper-buffer@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093"
+ integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==
+
+"@webassemblyjs/helper-numbers@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
+ integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
+ dependencies:
+ "@webassemblyjs/floating-point-hex-parser" "1.11.6"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
+ integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
+
+"@webassemblyjs/helper-wasm-section@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577"
+ integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+
+"@webassemblyjs/ieee754@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
+ integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
+ integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
+ integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
+
+"@webassemblyjs/wasm-edit@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab"
+ integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/helper-wasm-section" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+ "@webassemblyjs/wasm-opt" "1.11.6"
+ "@webassemblyjs/wasm-parser" "1.11.6"
+ "@webassemblyjs/wast-printer" "1.11.6"
+
+"@webassemblyjs/wasm-gen@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268"
+ integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wasm-opt@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2"
+ integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+ "@webassemblyjs/wasm-parser" "1.11.6"
+
+"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1"
+ integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wast-printer@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20"
+ integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@xtuc/long" "4.2.2"
+
+"@webpack-cli/configtest@^2.1.0":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646"
+ integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==
-"@types/resolve@1.17.1":
- version "1.17.1"
- resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
- integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
- dependencies:
- "@types/node" "*"
+"@webpack-cli/info@^2.0.1":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd"
+ integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==
-"@ungap/promise-all-settled@1.1.2":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
- integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
+"@webpack-cli/serve@^2.0.3":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e"
+ integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==
+
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+ integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+ integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+abab@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
+ integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
abort-controller@3.0.0:
version "3.0.0"
@@ -149,10 +293,38 @@ abort-controller@3.0.0:
dependencies:
event-target-shim "^5.0.0"
-acorn@^8.5.0:
- version "8.8.2"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
- integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
+accepts@~1.3.4:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+acorn-import-assertions@^1.7.6:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac"
+ integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==
+
+acorn@^8.7.1, acorn@^8.8.2:
+ version "8.11.3"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
+ integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
+
+ajv-keywords@^3.5.2:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
+ integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
+
+ajv@^6.12.5:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ 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"
ansi-colors@4.1.1:
version "4.1.1"
@@ -164,13 +336,6 @@ ansi-regex@^5.0.1:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
-ansi-styles@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
- integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
- dependencies:
- color-convert "^1.9.0"
-
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
@@ -191,21 +356,39 @@ argparse@^2.0.1:
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-atob@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
- integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
-
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+base64id@2.0.0, base64id@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
+ integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
+
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+body-parser@^1.19.0:
+ version "1.20.2"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
+ integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.5"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.11.0"
+ raw-body "2.5.2"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -221,7 +404,7 @@ brace-expansion@^2.0.1:
dependencies:
balanced-match "^1.0.0"
-braces@~3.0.2:
+braces@^3.0.2, braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
@@ -233,29 +416,44 @@ browser-stdout@1.3.1:
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
+browserslist@^4.14.5:
+ version "4.22.2"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b"
+ integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==
+ dependencies:
+ caniuse-lite "^1.0.30001565"
+ electron-to-chromium "^1.4.601"
+ node-releases "^2.0.14"
+ update-browserslist-db "^1.0.13"
+
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-builtin-modules@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
- integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+call-bind@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513"
+ integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==
+ dependencies:
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.1"
+ set-function-length "^1.1.1"
camelcase@^6.0.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-chalk@^2.0.0:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
+caniuse-lite@^1.0.30001565:
+ version "1.0.30001576"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz#893be772cf8ee6056d6c1e2d07df365b9ec0a5c4"
+ integrity sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==
chalk@^4.1.0:
version "4.1.2"
@@ -265,7 +463,7 @@ chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-chokidar@3.5.3:
+chokidar@3.5.3, chokidar@^3.5.1:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
@@ -280,6 +478,11 @@ chokidar@3.5.3:
optionalDependencies:
fsevents "~2.3.2"
+chrome-trace-event@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
+ integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
+
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
@@ -289,12 +492,14 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
-color-convert@^1.9.0:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
- integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+clone-deep@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
+ integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
dependencies:
- color-name "1.1.3"
+ is-plain-object "^2.0.4"
+ kind-of "^6.0.2"
+ shallow-clone "^3.0.0"
color-convert@^2.0.1:
version "2.0.1"
@@ -303,32 +508,86 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
-color-name@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
- integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
-
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+colorette@^2.0.14:
+ version "2.0.20"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
+ integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
+
+commander@^10.0.1:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
+ integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
+
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-commondir@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
- integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
-
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
-debug@4.3.4:
+connect@^3.7.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8"
+ integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==
+ dependencies:
+ debug "2.6.9"
+ finalhandler "1.1.2"
+ parseurl "~1.3.3"
+ utils-merge "1.0.1"
+
+content-type@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+cookie@~0.4.1:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
+ integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
+
+cors@~2.8.5:
+ version "2.8.5"
+ resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+ integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+ dependencies:
+ object-assign "^4"
+ vary "^1"
+
+cross-spawn@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+custom-event@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
+ integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==
+
+date-format@^4.0.14:
+ version "4.0.14"
+ resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400"
+ integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==
+
+debug@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@4.3.4, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -340,64 +599,184 @@ decamelize@^4.0.0:
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
-decode-uri-component@^0.2.0:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
- integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
+define-data-property@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3"
+ integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==
+ dependencies:
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+depd@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
-deepmerge@^4.2.2:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
- integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+destroy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+di@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
+ integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==
diff@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
-dukat@0.5.8-rc.4:
- version "0.5.8-rc.4"
- resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21"
- integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA==
+dom-serialize@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b"
+ integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==
dependencies:
- google-protobuf "3.12.2"
- typescript "3.9.5"
+ custom-event "~1.0.0"
+ ent "~2.2.0"
+ extend "^3.0.0"
+ void-elements "^2.0.0"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+electron-to-chromium@^1.4.601:
+ version "1.4.629"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.629.tgz#9cbffe1b08a5627b6a25118360f7fd3965416caf"
+ integrity sha512-5UUkr3k3CZ/k+9Sw7vaaIMyOzMC0XbPyprKI3n0tbKDqkzTDOjK4izm7DxlkueRMim6ZZQ1ja9F7hoFVplHihA==
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+engine.io-parser@~5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.1.tgz#9f213c77512ff1a6cc0c7a86108a7ffceb16fcfb"
+ integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==
+
+engine.io@~6.5.2:
+ version "6.5.4"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.5.4.tgz#6822debf324e781add2254e912f8568508850cdc"
+ integrity sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==
+ dependencies:
+ "@types/cookie" "^0.4.1"
+ "@types/cors" "^2.8.12"
+ "@types/node" ">=10.0.0"
+ accepts "~1.3.4"
+ base64id "2.0.0"
+ cookie "~0.4.1"
+ cors "~2.8.5"
+ debug "~4.3.1"
+ engine.io-parser "~5.2.1"
+ ws "~8.11.0"
+
+enhanced-resolve@^5.13.0:
+ version "5.15.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
+ integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==
+ dependencies:
+ graceful-fs "^4.2.4"
+ tapable "^2.2.0"
+
+ent@~2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
+ integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==
+
+envinfo@^7.7.3:
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.0.tgz#c3793f44284a55ff8c82faf1ffd91bc6478ea01f"
+ integrity sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==
+
+es-module-lexer@^1.2.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5"
+ integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==
+
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
escape-string-regexp@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-escape-string-regexp@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
- integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+eslint-scope@5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^4.1.1"
-estree-walker@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
- integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
-estree-walker@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
- integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
event-target-shim@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
+eventemitter3@^4.0.0:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
+events@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+ integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+extend@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+fast-deep-equal@^3.1.1:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fastest-levenshtein@^1.0.12:
+ version "1.0.16"
+ resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
+ integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
+
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@@ -405,6 +784,19 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
+finalhandler@1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+ integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.3"
+ statuses "~1.5.0"
+ unpipe "~1.0.0"
+
find-up@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
@@ -413,16 +805,43 @@ find-up@5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
+find-up@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
flat@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
-format-util@1.0.5, format-util@^1.0.5:
+flatted@^3.2.7:
+ version "3.2.9"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf"
+ integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
+
+follow-redirects@^1.0.0:
+ version "1.15.5"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
+ integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==
+
+format-util@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271"
integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==
+fs-extra@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
+ integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -433,16 +852,26 @@ fsevents@~2.3.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
- integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b"
+ integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==
+ dependencies:
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@@ -450,6 +879,11 @@ glob-parent@~5.1.2:
dependencies:
is-glob "^4.0.1"
+glob-to-regexp@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+ integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
glob@7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
@@ -462,7 +896,7 @@ glob@7.2.0:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.1.3, glob@^7.1.6:
+glob@^7.1.3, glob@^7.1.7:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@@ -474,33 +908,94 @@ glob@^7.1.3, glob@^7.1.6:
once "^1.3.0"
path-is-absolute "^1.0.0"
-google-protobuf@3.12.2:
- version "3.12.2"
- resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53"
- integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA==
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
-has-flag@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has@^1.0.3:
+has-property-descriptors@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340"
+ integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==
+ dependencies:
+ get-intrinsic "^1.2.2"
+
+has-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
+has-symbols@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+hasown@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
+ integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
dependencies:
- function-bind "^1.1.1"
+ function-bind "^1.1.2"
he@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+http-proxy@^1.18.1:
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+ integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
+ dependencies:
+ eventemitter3 "^4.0.0"
+ follow-redirects "^1.0.0"
+ requires-port "^1.0.0"
+
+iconv-lite@0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+iconv-lite@^0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
+ integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3.0.0"
+
+import-local@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4"
+ integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==
+ dependencies:
+ pkg-dir "^4.2.0"
+ resolve-cwd "^3.0.0"
+
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -509,11 +1004,16 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2:
+inherits@2, inherits@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+interpret@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4"
+ integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==
+
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
@@ -521,24 +1021,12 @@ is-binary-path@~2.1.0:
dependencies:
binary-extensions "^2.0.0"
-is-builtin-module@^3.1.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
- integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
- dependencies:
- builtin-modules "^3.3.0"
-
-is-core-module@^2.11.0:
- version "2.12.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4"
- integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==
+is-core-module@^2.13.0:
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+ integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
dependencies:
- has "^1.0.3"
-
-is-docker@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
- integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
+ hasown "^2.0.0"
is-extglob@^2.1.1:
version "2.1.1"
@@ -557,11 +1045,6 @@ is-glob@^4.0.1, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
-is-module@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
- integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
-
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
@@ -572,38 +1055,41 @@ is-plain-obj@^2.1.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
-is-reference@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
- integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
+is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
dependencies:
- "@types/estree" "*"
+ isobject "^3.0.1"
is-unicode-supported@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
-is-wsl@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
- integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
- dependencies:
- is-docker "^2.0.0"
+isbinaryfile@^4.0.8:
+ version "4.0.10"
+ resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3"
+ integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+ integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
-jest-worker@^26.2.1:
- version "26.6.2"
- resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
- integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
+jest-worker@^27.4.5:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
+ integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
- supports-color "^7.0.0"
-
-js-tokens@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
- integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+ supports-color "^8.0.0"
js-yaml@4.1.0:
version "4.1.0"
@@ -612,6 +1098,100 @@ js-yaml@4.1.0:
dependencies:
argparse "^2.0.1"
+json-parse-even-better-errors@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+karma-chrome-launcher@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz#eb9c95024f2d6dfbb3748d3415ac9b381906b9a9"
+ integrity sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==
+ dependencies:
+ which "^1.2.1"
+
+karma-mocha@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d"
+ integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==
+ dependencies:
+ minimist "^1.2.3"
+
+karma-sourcemap-loader@0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.4.0.tgz#b01d73f8f688f533bcc8f5d273d43458e13b5488"
+ integrity sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA==
+ dependencies:
+ graceful-fs "^4.2.10"
+
+karma-webpack@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840"
+ integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA==
+ dependencies:
+ glob "^7.1.3"
+ minimatch "^3.0.4"
+ webpack-merge "^4.1.5"
+
+karma@6.4.2:
+ version "6.4.2"
+ resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.2.tgz#a983f874cee6f35990c4b2dcc3d274653714de8e"
+ integrity sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==
+ dependencies:
+ "@colors/colors" "1.5.0"
+ body-parser "^1.19.0"
+ braces "^3.0.2"
+ chokidar "^3.5.1"
+ connect "^3.7.0"
+ di "^0.0.1"
+ dom-serialize "^2.2.1"
+ glob "^7.1.7"
+ graceful-fs "^4.2.6"
+ http-proxy "^1.18.1"
+ isbinaryfile "^4.0.8"
+ lodash "^4.17.21"
+ log4js "^6.4.1"
+ mime "^2.5.2"
+ minimatch "^3.0.4"
+ mkdirp "^0.5.5"
+ qjobs "^1.2.0"
+ range-parser "^1.2.1"
+ rimraf "^3.0.2"
+ socket.io "^4.4.1"
+ source-map "^0.6.1"
+ tmp "^0.2.1"
+ ua-parser-js "^0.7.30"
+ yargs "^16.1.1"
+
+kind-of@^6.0.2:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+loader-runner@^4.2.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
+ integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
+
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
locate-path@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
@@ -619,6 +1199,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
+lodash@^4.17.15, lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
log-symbols@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
@@ -627,18 +1212,44 @@ log-symbols@4.1.0:
chalk "^4.1.0"
is-unicode-supported "^0.1.0"
-magic-string@^0.25.7:
- version "0.25.9"
- resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
- integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
+log4js@^6.4.1:
+ version "6.9.1"
+ resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6"
+ integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==
dependencies:
- sourcemap-codec "^1.4.8"
+ date-format "^4.0.14"
+ debug "^4.3.4"
+ flatted "^3.2.7"
+ rfdc "^1.3.0"
+ streamroller "^3.1.5"
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mime@^2.5.2:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
+ integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
+
minimatch@5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
@@ -653,12 +1264,23 @@ minimatch@^3.0.4, minimatch@^3.1.1:
dependencies:
brace-expansion "^1.1.7"
-mocha@10.0.0:
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.0.0.tgz#205447d8993ec755335c4b13deba3d3a13c4def9"
- integrity sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==
+minimist@^1.2.3, minimist@^1.2.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+mkdirp@^0.5.5:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
+ integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
+ dependencies:
+ minimist "^1.2.6"
+
+mocha@10.2.0:
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8"
+ integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==
dependencies:
- "@ungap/promise-all-settled" "1.1.2"
ansi-colors "4.1.1"
browser-stdout "1.3.1"
chokidar "3.5.3"
@@ -681,6 +1303,11 @@ mocha@10.0.0:
yargs-parser "20.2.4"
yargs-unparser "2.0.0"
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@@ -696,6 +1323,16 @@ nanoid@3.3.3:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+neo-async@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
node-fetch@2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
@@ -703,11 +1340,40 @@ node-fetch@2.6.7:
dependencies:
whatwg-url "^5.0.0"
+node-releases@^2.0.14:
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
+ integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
+
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+object-assign@^4:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-inspect@^1.9.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
+
+on-finished@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+on-finished@~2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+ integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==
+ dependencies:
+ ee-first "1.1.1"
+
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -715,6 +1381,13 @@ once@^1.3.0:
dependencies:
wrappy "1"
+p-limit@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+ dependencies:
+ p-try "^2.0.0"
+
p-limit@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
@@ -722,6 +1395,13 @@ p-limit@^3.0.2:
dependencies:
yocto-queue "^0.1.0"
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
p-locate@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
@@ -729,6 +1409,16 @@ p-locate@^5.0.0:
dependencies:
p-limit "^3.0.2"
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@@ -739,16 +1429,50 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+pkg-dir@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+ integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
+ dependencies:
+ find-up "^4.0.0"
+
+punycode@^2.1.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+qjobs@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071"
+ integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==
+
+qs@6.11.0:
+ version "6.11.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
+ integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+ dependencies:
+ side-channel "^1.0.4"
+
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -756,6 +1480,21 @@ randombytes@^2.1.0:
dependencies:
safe-buffer "^5.1.0"
+range-parser@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.5.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+ integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@@ -763,57 +1502,75 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
+rechoir@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22"
+ integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==
+ dependencies:
+ resolve "^1.20.0"
+
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
-resolve@^1.17.0, resolve@^1.19.0:
- version "1.22.2"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
- integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
+requires-port@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+ integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
+
+resolve-cwd@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+ integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+ dependencies:
+ resolve-from "^5.0.0"
+
+resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve@^1.20.0:
+ version "1.22.8"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
dependencies:
- is-core-module "^2.11.0"
+ is-core-module "^2.13.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-rimraf@^3.0.0:
+rfdc@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
+ integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
+
+rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
-rollup-plugin-sourcemaps@^0.6.3:
- version "0.6.3"
- resolved "https://registry.yarnpkg.com/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz#bf93913ffe056e414419607f1d02780d7ece84ed"
- integrity sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw==
- dependencies:
- "@rollup/pluginutils" "^3.0.9"
- source-map-resolve "^0.6.0"
-
-rollup-plugin-terser@^7.0.2:
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
- integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
- dependencies:
- "@babel/code-frame" "^7.10.4"
- jest-worker "^26.2.1"
- serialize-javascript "^4.0.0"
- terser "^5.0.0"
-
-rollup@^2.68.0:
- version "2.79.1"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
- integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
- optionalDependencies:
- fsevents "~2.3.2"
-
safe-buffer@^5.1.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+schema-utils@^3.1.1, schema-utils@^3.1.2:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
+ integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ ajv "^6.12.5"
+ ajv-keywords "^3.5.2"
+
serialize-javascript@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
@@ -821,20 +1578,97 @@ serialize-javascript@6.0.0:
dependencies:
randombytes "^2.1.0"
-serialize-javascript@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
- integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
+serialize-javascript@^6.0.1:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
+ integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==
dependencies:
randombytes "^2.1.0"
-source-map-resolve@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2"
- integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==
+set-function-length@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed"
+ integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==
+ dependencies:
+ define-data-property "^1.1.1"
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+shallow-clone@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
+ integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
+ dependencies:
+ kind-of "^6.0.2"
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+side-channel@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+ integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies:
- atob "^2.1.2"
- decode-uri-component "^0.2.0"
+ call-bind "^1.0.0"
+ get-intrinsic "^1.0.2"
+ object-inspect "^1.9.0"
+
+socket.io-adapter@~2.5.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12"
+ integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==
+ dependencies:
+ ws "~8.11.0"
+
+socket.io-parser@~4.2.4:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
+ integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
+ dependencies:
+ "@socket.io/component-emitter" "~3.1.0"
+ debug "~4.3.1"
+
+socket.io@^4.4.1:
+ version "4.7.4"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.7.4.tgz#2401a2d7101e4bdc64da80b140d5d8b6a8c7738b"
+ integrity sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==
+ dependencies:
+ accepts "~1.3.4"
+ base64id "~2.0.0"
+ cors "~2.8.5"
+ debug "~4.3.2"
+ engine.io "~6.5.2"
+ socket.io-adapter "~2.5.2"
+ socket.io-parser "~4.2.4"
+
+source-map-js@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+ integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+source-map-loader@4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-4.0.1.tgz#72f00d05f5d1f90f80974eda781cbd7107c125f2"
+ integrity sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==
+ dependencies:
+ abab "^2.0.6"
+ iconv-lite "^0.6.3"
+ source-map-js "^1.0.2"
source-map-support@0.5.21, source-map-support@~0.5.20:
version "0.5.21"
@@ -844,15 +1678,29 @@ source-map-support@0.5.21, source-map-support@~0.5.20:
buffer-from "^1.0.0"
source-map "^0.6.0"
-source-map@^0.6.0:
+source-map@^0.6.0, source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-sourcemap-codec@^1.4.8:
- version "1.4.8"
- resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
- integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+statuses@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+statuses@~1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+
+streamroller@^3.1.5:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff"
+ integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==
+ dependencies:
+ date-format "^4.0.14"
+ debug "^4.3.4"
+ fs-extra "^8.1.0"
string-width@^4.1.0, string-width@^4.2.0:
version "4.2.3"
@@ -875,21 +1723,14 @@ strip-json-comments@3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-supports-color@8.1.1:
+supports-color@8.1.1, supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
-supports-color@^5.3.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
- integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^7.0.0, supports-color@^7.1.0:
+supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
@@ -901,16 +1742,39 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-terser@^5.0.0:
- version "5.17.3"
- resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.3.tgz#7f908f16b3cdf3f6c0f8338e6c1c674837f90d25"
- integrity sha512-AudpAZKmZHkG9jueayypz4duuCFJMMNGRMwaPvQKWfxKedh8Z2x3OCoDqIIi1xx5+iwx1u6Au8XQcc9Lke65Yg==
- dependencies:
- "@jridgewell/source-map" "^0.3.2"
- acorn "^8.5.0"
+tapable@^2.1.1, tapable@^2.2.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+ integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
+terser-webpack-plugin@^5.3.7:
+ version "5.3.10"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199"
+ integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.20"
+ jest-worker "^27.4.5"
+ schema-utils "^3.1.1"
+ serialize-javascript "^6.0.1"
+ terser "^5.26.0"
+
+terser@^5.26.0:
+ version "5.26.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.26.0.tgz#ee9f05d929f4189a9c28a0feb889d96d50126fe1"
+ integrity sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==
+ dependencies:
+ "@jridgewell/source-map" "^0.3.3"
+ acorn "^8.8.2"
commander "^2.20.0"
source-map-support "~0.5.20"
+tmp@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
+ integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
+ dependencies:
+ rimraf "^3.0.0"
+
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
@@ -918,36 +1782,162 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
-tslib@^2.3.1:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
- integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
+type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
-typescript@3.9.5:
- version "3.9.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
- integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==
+typescript@5.0.4:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
+ integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
-typescript@4.7.4:
- version "4.7.4"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
- integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
+ua-parser-js@^0.7.30:
+ version "0.7.37"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832"
+ integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==
+
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+update-browserslist-db@^1.0.13:
+ version "1.0.13"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
+ integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
+ dependencies:
+ escalade "^3.1.1"
+ picocolors "^1.0.0"
-typescript@^3.7.2:
- version "3.9.10"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
- integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+vary@^1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+void-elements@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
+ integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==
+
+watchpack@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
+ integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
+ dependencies:
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.1.2"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+webpack-cli@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.0.tgz#abc4b1f44b50250f2632d8b8b536cfe2f6257891"
+ integrity sha512-a7KRJnCxejFoDpYTOwzm5o21ZXMaNqtRlvS183XzGDUPRdVEzJNImcQokqYZ8BNTnk9DkKiuWxw75+DCCoZ26w==
+ dependencies:
+ "@discoveryjs/json-ext" "^0.5.0"
+ "@webpack-cli/configtest" "^2.1.0"
+ "@webpack-cli/info" "^2.0.1"
+ "@webpack-cli/serve" "^2.0.3"
+ colorette "^2.0.14"
+ commander "^10.0.1"
+ cross-spawn "^7.0.3"
+ envinfo "^7.7.3"
+ fastest-levenshtein "^1.0.12"
+ import-local "^3.0.2"
+ interpret "^3.1.1"
+ rechoir "^0.8.0"
+ webpack-merge "^5.7.3"
+
+webpack-merge@^4.1.5:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d"
+ integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==
+ dependencies:
+ lodash "^4.17.15"
+
+webpack-merge@^5.7.3:
+ version "5.10.0"
+ resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
+ integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==
+ dependencies:
+ clone-deep "^4.0.1"
+ flat "^5.0.2"
+ wildcard "^2.0.0"
+
+webpack-sources@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+ integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack@5.82.0:
+ version "5.82.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.82.0.tgz#3c0d074dec79401db026b4ba0fb23d6333f88e7d"
+ integrity sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==
+ dependencies:
+ "@types/eslint-scope" "^3.7.3"
+ "@types/estree" "^1.0.0"
+ "@webassemblyjs/ast" "^1.11.5"
+ "@webassemblyjs/wasm-edit" "^1.11.5"
+ "@webassemblyjs/wasm-parser" "^1.11.5"
+ acorn "^8.7.1"
+ acorn-import-assertions "^1.7.6"
+ browserslist "^4.14.5"
+ chrome-trace-event "^1.0.2"
+ enhanced-resolve "^5.13.0"
+ es-module-lexer "^1.2.1"
+ eslint-scope "5.1.1"
+ events "^3.2.0"
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.2.9"
+ json-parse-even-better-errors "^2.3.1"
+ loader-runner "^4.2.0"
+ mime-types "^2.1.27"
+ neo-async "^2.6.2"
+ schema-utils "^3.1.2"
+ tapable "^2.1.1"
+ terser-webpack-plugin "^5.3.7"
+ watchpack "^2.4.0"
+ webpack-sources "^3.2.3"
+
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
@@ -956,6 +1946,25 @@ whatwg-url@^5.0.0:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
+which@^1.2.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+wildcard@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"
+ integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==
+
workerpool@6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
@@ -980,6 +1989,11 @@ ws@8.5.0:
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
+ws@~8.11.0:
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
+ integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
+
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
@@ -1005,7 +2019,7 @@ yargs-unparser@2.0.0:
flat "^5.0.2"
is-plain-obj "^2.1.0"
-yargs@16.2.0:
+yargs@16.2.0, yargs@^16.1.1:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 18b57b61..50389de1 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -21,8 +21,14 @@ rootProject.name = "qq-guild"
//include(":builder-generator")
include(":simbot-component-qq-guild-api")
include(":simbot-component-qq-guild-stdlib")
-include(":simbot-component-qq-guild-core-common")
include(":simbot-component-qq-guild-core")
-include(":simbot-component-qq-guild-benchmark")
+//include(":simbot-component-qq-guild-core")
+//include(":simbot-component-qq-guild-benchmark")
+// tests
+//if (!System.getenv("IS_CI").toBoolean()) {
+// include(":tests:application-test")
+// include(":tests:spring-boot-test")
+// include(":tests:plugin-test")
+//}
diff --git a/simbot-component-qq-guild-api/build.gradle.kts b/simbot-component-qq-guild-api/build.gradle.kts
index f0e3a5c3..75e30b72 100644
--- a/simbot-component-qq-guild-api/build.gradle.kts
+++ b/simbot-component-qq-guild-api/build.gradle.kts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -15,191 +15,99 @@
* If not, see .
*/
-import love.forte.gradle.common.kotlin.multiplatform.NativeTargets
+import love.forte.gradle.common.core.project.setup
+import love.forte.gradle.common.kotlin.multiplatform.applyTier1
+import love.forte.gradle.common.kotlin.multiplatform.applyTier2
+import love.forte.gradle.common.kotlin.multiplatform.applyTier3
+import love.forte.plugin.suspendtrans.gradle.withKotlinTargets
plugins {
kotlin("multiplatform")
- `qq-guild-multiplatform-maven-publish`
-// id("simbot-tencent-guild.module-conventions")
-// id("simbot-tencent-guild.maven-publish")
kotlin("plugin.serialization")
`qq-guild-dokka-partial-configure`
}
-repositories {
- mavenCentral()
-}
+setup(P.ComponentQQGuild)
+
+configJavaCompileWithModule("simbot.component.qqguild.api")
+//apply(plugin = "qq-guild-dokka-partial-configure")
+apply(plugin = "qq-guild-multiplatform-maven-publish")
+
+//configJsTestTasks()
kotlin {
explicitApi()
+ applyDefaultHierarchyTemplate()
sourceSets.configureEach {
languageSettings {
- optIn("love.forte.simbot.qguild.InternalApi")
+ optIn("love.forte.simbot.qguild.QGInternalApi")
}
}
- jvm {
- withJava()
- compilations.all {
- kotlinOptions {
- jvmTarget = "1.8"
- javaParameters = true
- freeCompilerArgs = freeCompilerArgs + listOf("-Xjvm-default=all")
- }
- }
- testRuns["test"].executionTask.configure {
- useJUnitPlatform()
- }
- }
+ configKotlinJvm()
js(IR) {
- nodejs()
- binaries.library()
+ configJs()
}
+ applyTier1()
+ applyTier2()
+ applyTier3(supportKtorClient = true)
- val mainPresets = mutableSetOf()
- val testPresets = mutableSetOf()
-
- // https://kotlinlang.org/docs/native-target-support.html
- // 针对 kotlin target support 中的列表结合 ktor-client 平台的支持提供的平台能力。
- // 注释掉的内容是Ktor尚不支持的平台
-// val supportTargets = setOf(
-// // Tier 1
-// "linuxX64",
-// "macosX64",
-// "macosArm64",
-// "iosSimulatorArm64",
-// "iosX64",
-//
-// // Tier 2
-//// "linuxArm64",
-// "watchosSimulatorArm64",
-// "watchosX64",
-// "watchosArm32",
-// "watchosArm64",
-// "tvosSimulatorArm64",
-// "tvosX64",
-// "tvosArm64",
-// "iosArm64",
-//
-// // Tier 3
-//// "androidNativeArm32",
-//// "androidNativeArm64",
-//// "androidNativeX86",
-//// "androidNativeX64",
-// "mingwX64",
-//// "watchosDeviceArm64",
-// )
-
- val targets = NativeTargets.Official.all.intersect(NativeTargets.KtorClient.all) + setOf("mingwX64")
-
- targets {
- presets.filterIsInstance>()
- .filter { it.name in targets }
- .forEach { presets ->
- val target = fromPreset(presets, presets.name)
- val mainSourceSet = target.compilations["main"].kotlinSourceSets.first()
- val testSourceSet = target.compilations["test"].kotlinSourceSets.first()
-
- val tn = target.name
- when {
- // just for test
- // main中只使用HttpClient但用不到引擎,没必要指定
-
- // win
- tn.startsWith("mingw") -> {
- testSourceSet.dependencies {
- implementation(libs.ktor.client.winhttp)
- }
- }
- // linux: CIO..?
- tn.startsWith("linux") -> {
- testSourceSet.dependencies {
- implementation(libs.ktor.client.cio)
- }
- }
-
- // darwin based
- tn.startsWith("macos")
- || tn.startsWith("ios")
- || tn.startsWith("watchos")
- || tn.startsWith("tvos") -> {
- testSourceSet.dependencies {
- implementation(libs.ktor.client.darwin)
- }
- }
- }
-
- mainPresets.add(mainSourceSet)
- testPresets.add(testSourceSet)
- }
+ withKotlinTargets { target ->
+ targets.findByName(target.name)?.compilations?.all {
+ // 'expect'/'actual' classes (including interfaces, objects, annotations, enums, and 'actual' typealiases) are in Beta. You can use -Xexpect-actual-classes flag to suppress this warning. Also see: https://youtrack.jetbrains.com/issue/KT-61573
+ kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes"
+ }
}
sourceSets {
- val commonMain by getting {
- dependencies {
- api(libs.ktor.client.core)
- api(libs.ktor.client.contentNegotiation)
- api(libs.ktor.serialization.kotlinxJson)
- api(libs.kotlinx.serialization.json)
- api(simbotLogger)
- }
+ commonMain.dependencies {
+ api(libs.kotlinx.coroutines.core)
+
+ api(libs.simbot.logger)
+ api(libs.simbot.common.apidefinition)
+ api(libs.simbot.common.suspend)
+ api(libs.simbot.common.core)
+ compileOnly(libs.simbot.common.annotations)
+
+ api(libs.ktor.client.core)
+ api(libs.ktor.client.contentNegotiation)
+ api(libs.kotlinx.serialization.json)
}
- val commonTest by getting {
- dependencies {
- implementation(kotlin("test"))
- implementation(libs.kotlinx.coroutines.test)
- }
+ commonTest.dependencies {
+ implementation(kotlin("test"))
+ implementation(libs.kotlinx.coroutines.test)
}
- getByName("jvmMain") {
- dependencies {
- compileOnly(simbotApi) // use @Api4J annotation
- }
+ jvmMain.dependencies {
+// compileOnly(libs.simbot.api) // use @Api4J annotation
}
- getByName("jvmTest") {
- dependencies {
- implementation(libs.ktor.client.cio)
- implementation(simbotApi) // use @Api4J annotation
- implementation(libs.log4j.api)
- implementation(libs.log4j.core)
- implementation(libs.log4j.slf4j2)
- }
+ jvmTest.dependencies {
+ implementation(libs.ktor.client.cio)
+// implementation(simbotApi) // use @Api4J annotation
+ implementation(libs.log4j.api)
+ implementation(libs.log4j.core)
+ implementation(libs.log4j.slf4j2)
+ implementation(libs.kotlinx.coroutines.reactor)
+ implementation(libs.reactor.core)
}
- getByName("jsMain") {
- dependencies {
- api(libs.ktor.client.js)
- }
+ jsMain.dependencies {
+ api(libs.ktor.client.js)
}
- val nativeMain by creating {
- dependsOn(commonMain)
+ jsTest.dependencies {
+ api(libs.ktor.client.js)
}
- val nativeTest by creating {
- dependsOn(commonTest)
+ mingwTest.dependencies {
+ implementation(libs.ktor.client.winhttp)
}
-
- configure(mainPresets) { dependsOn(nativeMain) }
- configure(testPresets) { dependsOn(nativeTest) }
-
}
}
-// suppress all?
-//tasks.withType().configureEach {
-// dokkaSourceSets.configureEach {
-// suppress.set(true)
-// perPackageOption {
-// suppress.set(true)
-// }
-// }
-//}
-
-
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/OptAnnotations.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/OptAnnotations.kt
index f8853770..05492542 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/OptAnnotations.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/OptAnnotations.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -25,14 +25,14 @@ package love.forte.simbot.qguild
@Retention(AnnotationRetention.BINARY)
@MustBeDocumented
@RequiresOptIn("API marked for Java use, not recommended for Kotlin.", level = RequiresOptIn.Level.WARNING)
-public annotation class Api4J
+public annotation class QGApi4J
/**
* 一个仅服务于JS的API。对于Kotlin来讲通常有更优选择。
*/
@Retention(AnnotationRetention.BINARY)
@MustBeDocumented
@RequiresOptIn("API marked for JS use, not recommended for Kotlin.", level = RequiresOptIn.Level.WARNING)
-public annotation class Api4JS
+public annotation class QGApi4JS
// 好吧可能 OptIn 的 annotation 不能用 actual
@@ -42,4 +42,4 @@ public annotation class Api4JS
@Retention(AnnotationRetention.BINARY)
@MustBeDocumented
@RequiresOptIn("Internal API", level = RequiresOptIn.Level.WARNING)
-public annotation class InternalApi
+public annotation class QGInternalApi
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuild.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuild.kt
index c1ad1058..9cf7e309 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuild.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuild.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,9 +17,10 @@
package love.forte.simbot.qguild
+//import kotlin.js.ExperimentalJsExport
+//import kotlin.js.JsExport
import io.ktor.http.*
-import kotlin.js.ExperimentalJsExport
-import kotlin.js.JsExport
+import kotlinx.serialization.json.Json
import kotlin.jvm.JvmField
/**
@@ -29,9 +30,8 @@ import kotlin.jvm.JvmField
*
*
*/
-@OptIn(ExperimentalJsExport::class)
-@JsExport
-@Suppress("NON_EXPORTABLE_TYPE")
+//@OptIn(ExperimentalJsExport::class)
+//@JsExport
public object QQGuild {
/**
* 正式环境接口域名 `https://api.sgroup.qq.com`
@@ -66,6 +66,31 @@ public object QQGuild {
*/
@JvmField
public val SANDBOX_URL: Url = Url(SANDBOX_URL_STRING)
+
+ /**
+ * 部分API中默认使用的Json序列化器。
+ *
+ * ```kotlin
+ * Json {
+ * isLenient = true
+ * ignoreUnknownKeys = true
+ * allowSpecialFloatingPointValues = true
+ * allowStructuredMapKeys = true
+ * prettyPrint = false
+ * useArrayPolymorphism = false
+ * }
+ * ```
+ *
+ */
+ @JvmField
+ public val DefaultJson: Json = Json {
+ isLenient = true
+ ignoreUnknownKeys = true
+ allowSpecialFloatingPointValues = true
+ allowStructuredMapKeys = true
+ prettyPrint = false
+ useArrayPolymorphism = false
+ }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuildApiException.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuildApiException.kt
index 048b3c2a..fd35f906 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuildApiException.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/QQGuildApiException.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -26,9 +26,10 @@ import kotlinx.serialization.json.JsonNull
/**
* 初始化 cause, 并得到自身(或结果)
* 在 JVM 平台上生效。
+ * 在其他平台会使用 [addSuppressed] 添加 [cause]。
*/
-@PublishedApi
-internal expect inline fun T.initCause0(cause: Throwable): T
+@QGInternalApi
+public expect inline fun T.initCause0(cause: Throwable): T
/**
* QQ频道API请求过程中出现的异常
@@ -68,9 +69,9 @@ public fun QQGuildApiException.copyCurrent(): QQGuildApiException = addStackTrac
*
* @suppress internal API to add suppressed for api exception
*/
-@InternalApi
+@QGInternalApi
public inline fun E.addStackTrace(block: () -> String? = { null }): E {
- addSuppressed(APIStackException(block()))
+ addSuppressed(APIStack(block()))
return this
}
@@ -78,9 +79,9 @@ public inline fun E.addStackTrace(block: () -> String?
*
* @see addStackTrace
*/
-@InternalApi
+@QGInternalApi
@PublishedApi
-internal class APIStackException @PublishedApi internal constructor(message: String? = null) : Exception(message)
+internal class APIStack @PublishedApi internal constructor(message: String? = null) : Exception(message)
/**
* 判断 [QQGuildApiException.value] 的值是否为 `404`
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiDescription.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiDescription.kt
index d4d3fd34..c80620d4 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiDescription.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiDescription.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -31,7 +31,6 @@ import io.ktor.http.*
* @author ForteScarlet
*/
public interface ApiDescription {
-
/**
* API 接口名,例如 `/guilds/{guild_id}/members/{user_id}`
*/
@@ -77,3 +76,21 @@ public abstract class SimpleGetApiDescription(path: String) :
public abstract class SimplePostApiDescription(path: String) :
SimpleApiDescription(HttpMethod.Post, path)
+/**
+ * [SimpleApiDescription] 的基本抽象实现,[method] 提供为 [HttpMethod.Put]
+ */
+public abstract class SimplePutApiDescription(path: String) :
+ SimpleApiDescription(HttpMethod.Put, path)
+
+/**
+ * [SimpleApiDescription] 的基本抽象实现,[method] 提供为 [HttpMethod.Delete]
+ */
+public abstract class SimpleDeleteApiDescription(path: String) :
+ SimpleApiDescription(HttpMethod.Delete, path)
+
+/**
+ * [SimpleApiDescription] 的基本抽象实现,[method] 提供为 [HttpMethod.Patch]
+ */
+public abstract class SimplePatchApiDescription(path: String) :
+ SimpleApiDescription(HttpMethod.Patch, path)
+
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiRequestor.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiRequestor.kt
deleted file mode 100644
index e74700ee..00000000
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiRequestor.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2022-2023. ForteScarlet.
- *
- * This file is part of simbot-component-qq-guild.
- *
- * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
- * of the GNU Lesser General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
- * If not, see .
- */
-
-
-package love.forte.simbot.qguild.api
-
-import io.ktor.client.*
-import io.ktor.http.*
-import kotlinx.serialization.StringFormat
-import love.forte.simbot.logger.LoggerFactory
-import love.forte.simbot.qguild.QQGuild
-import kotlin.jvm.JvmSynthetic
-
-internal val apiRequestorLogger = LoggerFactory.getLogger("love.forte.simbot.qguild.api.ApiRequestor")
-
-/**
- *
- * 通过提供的参数,对此api进行请求并得到最终结果。
- *
- * @param client 提供一个 http client,默认使用 [QQGuildApi.DefaultHttpClient]。
- * @param server 提供一个目标服务器路径。See also: [QQGuild.URL]、[QQGuild.SANDBOX_URL]
- * @param token 提供一个 token.
- * @param decoder 如果有,提供一个decoder用于通过 [QQGuildApi.resultDeserializer] 进行反序列化,而不是通过 [client] 进行。
- *
- * @throws love.forte.simbot.qguild.QQGuildApiException 如果响应码不在 200..300 范围内。
- *
- */
-@JvmSynthetic
-public suspend fun QQGuildApi.request(
- client: HttpClient = QQGuildApi.DefaultHttpClient,
- server: Url,
- token: String,
- decoder: StringFormat = QQGuildApi.DefaultJsonDecoder,
-): R {
- return doRequest(client, server, token, decoder)
-}
-/**
- *
- * 通过提供的参数,对此api进行请求并得到最终结果。
- *
- * @param client 提供一个 http client,默认使用 [QQGuildApi.DefaultHttpClient]。
- * @param server 提供一个目标服务器路径。See also: [QQGuild.URL]、[QQGuild.SANDBOX_URL]
- * @param token 提供一个 token.
- *
- * @throws love.forte.simbot.qguild.QQGuildApiException 如果响应码不在 200..300 范围内。
- *
- */
-@JvmSynthetic
-public suspend fun QQGuildApi<*>.requestRaw(
- client: HttpClient = QQGuildApi.DefaultHttpClient,
- server: Url,
- token: String,
-): String {
- return doRequestRaw(client, server, token)
-}
-
-
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiRequests.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiRequests.kt
new file mode 100644
index 00000000..0442d987
--- /dev/null
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/ApiRequests.kt
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2024. ForteScarlet.
+ *
+ * This file is part of simbot-component-qq-guild.
+ *
+ * simbot-component-qq-guild is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * simbot-component-qq-guild is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with simbot-component-qq-guild.
+ * If not, see .
+ */
+
+@file:JvmName("ApiRequests")
+@file:JvmMultifileClass
+
+package love.forte.simbot.qguild.api
+
+import io.ktor.client.*
+import io.ktor.client.plugins.*
+import io.ktor.client.plugins.contentnegotiation.*
+import io.ktor.client.request.*
+import io.ktor.client.statement.*
+import io.ktor.client.utils.*
+import io.ktor.http.*
+import io.ktor.http.content.*
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.StringFormat
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.descriptors.StructureKind
+import kotlinx.serialization.json.Json
+import love.forte.simbot.common.serialization.guessSerializer
+import love.forte.simbot.logger.isDebugEnabled
+import love.forte.simbot.qguild.ErrInfo
+import love.forte.simbot.qguild.QQGuild
+import love.forte.simbot.qguild.QQGuildApiException
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
+import kotlin.jvm.JvmSynthetic
+
+/**
+ * 使用 [client] 向当前目标 API [QQGuildApi] 发起请求。
+ *
+ * @param server 如果不为 null 则会取 [server] 中的 [Url.protocol]、[Url.hostWithPort]
+ * 替换 [QQGuildApi.url] 中提供的值。
+ *
+ */
+@JvmSynthetic
+public suspend fun QQGuildApi.request(
+ client: HttpClient,
+ token: String,
+ server: Url? = null
+): HttpResponse {
+ val api = this
+
+ return client.request {
+ method = api.method
+
+ headers {
+ this[HttpHeaders.Authorization] = token
+ with(api.headers) {
+ if (!isEmpty()) {
+ appendAll(api.headers)
+ }
+ }
+ if (!contains(HttpHeaders.ContentType)) {
+ contentType(ContentType.Application.Json)
+ }
+ }
+
+ url {
+ takeFrom(api.url)
+
+ if (server != null) {
+ protocol = server.protocol
+ host = server.host
+ port = server.port
+ }
+ }
+
+ when (val body = api.body) {
+ null -> {
+ setBody(EmptyContent)
+ }
+
+ is OutgoingContent -> {
+ setBody(body)
+ }
+
+ else -> {
+ if (client.pluginOrNull(ContentNegotiation) != null) {
+ setBody(body)
+ } else {
+ try {
+ val json = QQGuild.DefaultJson
+ val ser = guessSerializer(body, json.serializersModule)
+ val bodyJson = json.encodeToString(ser, body)
+ setBody(bodyJson)
+ } catch (e: Throwable) {
+ try {
+ setBody(body)
+ } catch (e0: Throwable) {
+ e0.addSuppressed(e)
+ throw e0
+ }
+ }
+ }
+ }
+ }
+
+ apiLogger.debug("[{} {}] =====> {}, body: {}", method.logName, url.encodedPath, url.host, api.body)
+ }
+}
+
+
+/**
+ * 通过 [request] 得到响应,读取为文本并输出debug日志后返回。
+ * 不会进行校验。
+ */
+@OptIn(ExperimentalContracts::class)
+public suspend inline fun QQGuildApi.requestText(
+ client: HttpClient,
+ token: String,
+ server: Url = QQGuild.URL,
+ useResp: (HttpResponse) -> Unit = {}
+): String {
+ contract {
+ callsInPlace(useResp, InvocationKind.EXACTLY_ONCE)
+ }
+
+ val resp = request(client, token, server)
+ useResp(resp)
+
+ val text = resp.bodyAsText()
+
+ if (apiLogger.isDebugEnabled) {
+ val traceId = resp.headers[TRACE_ID_HEAD]
+ apiLogger.debug(
+ "[{} {}] <===== status: {}, body: {}, traceID: {}",
+ method.logName,
+ resp.request.url.encodedPath,
+ resp.status,
+ text,
+ traceId
+ )
+ }
+
+ return text
+}
+
+/**
+ * 使用此api发起一次请求,并得到预期中的结果。
+ *
+ * ## Body序列化
+ *
+ * 参数 [client] 不强制要求必须安装 [ContentNegotiation] 插件,
+ * 如果未安装此插件且 API 的请求过程中存在 body,则内部会使用一个默认的序列化器 (不是 [decoder])
+ * 进行一个与此插件 _类似的_ 逻辑去寻找 body 的序列化信息。此时要求 API 的 body 必须支持 Kotlinx 的序列化。
+ *
+ * @param client 用于本次http请求的client。
+ * @param server 请求目标服务器。See also: [QQGuild.URL]、[QQGuild.SANDBOX_URL]。
+ * @param token 用于本次请求鉴权的token。
+ * @param decoder 用于本次请求结果的反序列化器。不出意外的话应该是 [Json] 序列化器,默认使用 [QQGuild.DefaultJson]。
+ *
+ * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
+ * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误。
+ *
+ * @see ErrInfo
+ */
+@JvmSynthetic
+public suspend fun QQGuildApi.requestData(
+ client: HttpClient,
+ token: String,
+ server: Url = QQGuild.URL,
+ decoder: Json = QQGuild.DefaultJson,
+): R {
+ val resp: HttpResponse
+ val text = requestText(client, token, server) { resp = it }
+
+ checkStatus(text, QQGuild.DefaultJson, resp.status, resp)
+
+ return decodeResponse(decoder, text)
+}
+
+
+@Suppress("UNCHECKED_CAST")
+@OptIn(ExperimentalSerializationApi::class)
+internal fun QQGuildApi.decodeResponse(
+ decoder: Json, remainingText: String
+): R {
+ if (resultDeserializationStrategy === Unit.serializer()) {
+ return Unit as R
+ }
+
+ if (remainingText.isEmpty() && resultDeserializationStrategy.descriptor.kind is StructureKind.OBJECT) {
+ return decoder.decodeFromString(resultDeserializationStrategy, "{}")
+ }
+
+ return decoder.decodeFromString(resultDeserializationStrategy, remainingText)
+}
+
+internal fun checkStatus(
+ remainingText: String,
+ decoder: StringFormat,
+ status: HttpStatusCode,
+ resp: HttpResponse,
+) {
+ // TODO 201,202 异步操作成功,虽然说成功,但是会返回一个 error body,需要特殊处理
+ if (!status.isSuccess()) {
+ val info = decoder.decodeFromString(ErrInfo.serializer(), remainingText)
+ // throw err
+ throw QQGuildApiException(info, status.value, status.description)
+ }
+
+ // 202 消息审核
+ if (status == HttpStatusCode.Accepted) {
+ val info = decoder.decodeFromString(ErrInfo.serializer(), remainingText)
+ // maybe audited
+ if (MessageAuditedException.isAuditResultCode(info.code)) {
+ throw MessageAuditedException(
+ QQGuild.DefaultJson.decodeFromJsonElement(MessageAudit.serializer(), info.data).messageAudit,
+ info,
+ resp.status.value,
+ resp.status.description
+ )
+ }
+
+ throw QQGuildApiException(info, resp.status.value, resp.status.description)
+ }
+}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/GatewayApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/GatewayApi.kt
index fe627c77..10191d13 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/GatewayApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/GatewayApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,7 +17,9 @@
package love.forte.simbot.qguild.api
-import kotlinx.serialization.*
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.api.GatewayApis.Normal
import love.forte.simbot.qguild.api.GatewayApis.Shared
@@ -35,22 +37,18 @@ import love.forte.simbot.qguild.api.GatewayApis.Shared
* @author ForteScarlet
*/
public sealed class GatewayApis(
- protected val path: Array,
- override val resultDeserializer: DeserializationStrategy
+ override val path: Array,
+ override val resultDeserializationStrategy: DeserializationStrategy
) : GetQQGuildApi() {
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
+
/**
* 获取通用 WSS 接入点
*
* > [参考文档](https://bot.q.qq.com/wiki/develop/api/openapi/wss/url_get.html)
*/
public object Normal : GatewayApis(arrayOf("gateway"), Gateway.serializer())
-
-
+
+
/**
* 获取带分片 WSS 接入点
*
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/MessageAuditedException.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/MessageAuditedException.kt
index b6f9e36a..fce811d4 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/MessageAuditedException.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/MessageAuditedException.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -21,7 +21,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.ApiModel
import love.forte.simbot.qguild.ErrInfo
-import love.forte.simbot.qguild.InternalApi
+import love.forte.simbot.qguild.QGInternalApi
import love.forte.simbot.qguild.QQGuildApiException
import love.forte.simbot.qguild.api.message.MessageSendApi
import love.forte.simbot.qguild.api.message.direct.DmsSendApi
@@ -83,7 +83,7 @@ public class MessageAuditedException : QQGuildApiException {
public companion object {
private val AUDIT_ERROR_CODES = setOf(304023, 304024)
- @InternalApi
+ @QGInternalApi
internal fun isAuditResultCode(code: Int): Boolean = code in AUDIT_ERROR_CODES
}
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/QQGuildApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/QQGuildApi.kt
index f9d62e12..f8c7894a 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/QQGuildApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/QQGuildApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,31 +17,13 @@
package love.forte.simbot.qguild.api
-import io.ktor.client.*
-import io.ktor.client.plugins.*
-import io.ktor.client.plugins.contentnegotiation.*
-import io.ktor.client.request.*
-import io.ktor.client.statement.*
-import io.ktor.client.utils.*
import io.ktor.http.*
-import io.ktor.http.content.*
-import io.ktor.serialization.kotlinx.json.*
-import kotlinx.serialization.*
-import kotlinx.serialization.builtins.*
-import kotlinx.serialization.descriptors.StructureKind
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.builtins.serializer
+import love.forte.simbot.common.apidefinition.*
import love.forte.simbot.logger.Logger
import love.forte.simbot.logger.LoggerFactory
-import love.forte.simbot.logger.isDebugEnabled
-import love.forte.simbot.qguild.ErrInfo
-import love.forte.simbot.qguild.InternalApi
import love.forte.simbot.qguild.QQGuild
-import love.forte.simbot.qguild.QQGuildApiException
-import kotlin.contracts.ExperimentalContracts
-import kotlin.contracts.InvocationKind
-import kotlin.contracts.contract
-import kotlin.jvm.JvmSynthetic
@PublishedApi
internal val apiLogger: Logger = LoggerFactory.getLogger("love.forte.simbot.qguild.api")
@@ -58,68 +40,10 @@ internal val apiLogger: Logger = LoggerFactory.getLogger("love.forte.simbot.qgui
@PublishedApi
internal const val TRACE_ID_HEAD: String = "X-Tps-trace-ID"
-
-/**
- * 用于多平台实现的最小目标。
- *
- * 在JVM平台和JS平台中分别提供对应的 blocking/async 兼容函数。
- * 但是不应追加新的抽象函数。
- *
- * _仅内部平台实现用_
- *
- * @see QQGuildApi
- */
-@InternalApi
-public expect abstract class PlatformQQGuildApi() {
-
- /**
- * 使用此api发起一次请求,并得到预期中的结果。
- *
- * @param client 用于本次http请求的client。默认使用 [QQGuildApi.DefaultHttpClient]。
- * @param server 请求目标服务器。See also: [QQGuild.URL]、[QQGuild.SANDBOX_URL]。
- * @param token 用于本次请求鉴权的token。
- * @param decoder 用于本次请求结果的反序列化器。不出意外的话应该是 [Json] 序列化器,默认使用 [QQGuildApi.DefaultJsonDecoder]。
- *
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误(http状态码 !in 200 .. 300)
- *
- * @see ErrInfo
- */
- @JvmSynthetic
- public abstract suspend fun doRequest(
- client: HttpClient = QQGuildApi.DefaultHttpClient,
- server: Url,
- token: String,
- decoder: StringFormat = QQGuildApi.DefaultJsonDecoder,
- ): R
-
- /**
- * 使用此api发起一次请求,并得到响应结果的字符串。
- *
- * @param client 用于本次http请求的client。默认使用 [QQGuildApi.DefaultHttpClient]。
- * @param server 请求目标服务器。See also: [QQGuild.URL]、[QQGuild.SANDBOX_URL]。
- * @param token 用于本次请求鉴权的token。
- *
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误(http状态码 !in 200 .. 300)
- *
- * @see ErrInfo
- */
- @JvmSynthetic
- public abstract suspend fun doRequestRaw(
- client: HttpClient = QQGuildApi.DefaultHttpClient,
- server: Url,
- token: String,
- ): String
-
- public companion object
-}
-
-
/**
* 表示为一个QQ频道的API。
*
- * 通过 [doRequest] 发起一次请求。
+ * 通过 [requestData] 发起一次请求。
*
* ### 日志
*
@@ -139,346 +63,101 @@ public expect abstract class PlatformQQGuildApi() {
* -Dsimbot.qguild.api.logger.color.enable=false
* ```
*/
-public abstract class QQGuildApi : PlatformQQGuildApi() {
+public interface QQGuildApi : ApiDefinition {
/**
* 得到响应值的反序列化器.
*/
- public abstract val resultDeserializer: DeserializationStrategy
-
+ override val resultDeserializationStrategy: DeserializationStrategy
/**
- * 此api请求方式
+ * 最终用于请求的目标地址。
+ * 默认会使用 [QQGuild.URL]
+ * 作为其域名地址。
*/
- public abstract val method: HttpMethod
-
+ override val url: Url
/**
- * 此请求对应的api路由路径以及路径参数。
- * 例如:`/guild/list`
+ * 此api请求方式
*/
- public abstract fun route(builder: RouteInfoBuilder)
-
+ override val method: HttpMethod
/**
* 此次请求所发送的数据。为null则代表没有参数。
*/
- public abstract val body: Any?
-
-
- /**
- * 当通过 [doRequest] 得到成功结果后进行的操作。
- */
- public open fun post(resp: @UnsafeVariance R) {}
+ override val body: Any?
- /**
- * 使用此api发起一次请求,并得到预期中的结果。
- *
- * ## Body序列化
- *
- * 参数 [client] 不强制要求必须安装 [ContentNegotiation] 插件,
- * 如果未安装此插件且 API 的请求过程中存在 body,则内部会使用一个默认的序列化器 (不是 [decoder])
- * 进行一个与此插件 _类似的_ 逻辑去寻找 body 的序列化信息。此时要求 API 的 body 必须支持 Kotlinx 的序列化。
- *
- * @param client 用于本次http请求的client。默认使用 [QQGuildApi.DefaultHttpClient]。
- * @param server 请求目标服务器。See also: [QQGuild.URL]、[QQGuild.SANDBOX_URL]。
- * @param token 用于本次请求鉴权的token。
- * @param decoder 用于本次请求结果的反序列化器。不出意外的话应该是 [Json] 序列化器,默认使用 [QQGuildApi.DefaultJsonDecoder]。
- *
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误。
- *
- * @see ErrInfo
- */
- @JvmSynthetic
- public override suspend fun doRequest(
- client: HttpClient,
- server: Url,
- token: String,
- decoder: StringFormat,
- ): R {
- val text = doRequestRaw(client, server, token)
+ public companion object
+}
- return decodeResponse(decoder, text)
- }
+public interface QQGuildApiWithoutResult : QQGuildApi {
+ override val resultDeserializationStrategy: DeserializationStrategy
+ get() = Unit.serializer() //EmptyUnitSerializer
+}
+public abstract class GetQQGuildApi : GetApiDefinition(), QQGuildApi {
+ protected abstract val path: Array
/**
- * 使用此api发起一次请求,并得到响应结果的字符串。
- *
- * ## Body序列化
- *
- * 参数 [client] 不强制要求必须安装 [ContentNegotiation] 插件,
- * 如果未安装此插件且 API 的请求过程中存在 body,则内部会使用一个默认的序列化器进行一个与此插件
- * _类似的_ 逻辑去寻找 body 的序列化信息。此时要求 API 的 body 必须支持 Kotlinx 的序列化。
- *
- * @see ErrInfo
- *
- * @param client 用于本次http请求的client。默认使用 [QQGuildApi.DefaultHttpClient]。
- * @param server 请求目标服务器。See also: [QQGuild.URL]、[QQGuild.SANDBOX_URL]。
- * @param token 用于本次请求鉴权的token。
- *
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误(http状态码 !in 200 .. 300)
+ * 已经完成 [path] 拼接后、追加其他额外内容(例如parameter)时使用
*/
- @JvmSynthetic
- override suspend fun doRequestRaw(client: HttpClient, server: Url, token: String): String {
- val resp: HttpResponse
- val text = requestForText(client, server, token) { resp = it }
-
- checkStatus(text, DefaultErrInfoDecoder, resp.status)
-
- if (text.isEmpty() && resp.status.isSuccess()) {
- return "{}"
- }
-
- return text
- }
-
- public companion object {
-
- /**
- * 可以使用的默认 [HttpClient]。
- *
- * 通过 [`HttpClient()`][HttpClient] 构建懒加载并没有任何额外配置。
- *
- * JVM平台下需要添加可用的引擎依赖到classpath中以支持自动加载。
- *
- */
- public val DefaultHttpClient: HttpClient by lazy {
- HttpClient {
- install(ContentNegotiation) {
- json(DefaultJsonDecoder)
- }
- }
- }
-
- internal val DefaultErrInfoDecoder = Json {
- isLenient = true
- ignoreUnknownKeys = true
- allowSpecialFloatingPointValues = true
- allowStructuredMapKeys = true
- prettyPrint = false
- useArrayPolymorphism = false
- }
-
- /**
- * 部分API中默认使用的Json序列化器。
- *
- * ```kotlin
- * Json {
- * isLenient = true
- * ignoreUnknownKeys = true
- * allowSpecialFloatingPointValues = true
- * allowStructuredMapKeys = true
- * prettyPrint = false
- * useArrayPolymorphism = false
- * }
- * ```
- *
- */
- @InternalApi
- public val DefaultJsonDecoder: Json = Json(DefaultErrInfoDecoder) {}
- }
-
-
- protected suspend fun requestForResponse(client: HttpClient, server: Url, token: String, json: Json = DefaultJsonDecoder): HttpResponse {
- val api = this
+ protected open fun URLBuilder.buildUrl() {}
- return client.request {
- method = api.method
-
- headers {
- this[HttpHeaders.Authorization] = token
- }
-
-
- url {
- takeFrom(server)
-
- // route builder
- val routeBuilder = RouteInfoBuilder { name, value ->
- parameters.append(name, value.toString())
- }
-
- api.route(routeBuilder)
-
- when (val body = api.body) {
- null -> {
- setBody(EmptyContent)
- }
- is OutgoingContent -> {
- setBody(body)
- }
-
- else -> {
- if (client.pluginOrNull(ContentNegotiation) != null) {
- setBody(body)
- } else {
- try {
- val ser = guessSerializer(body, json.serializersModule)
- val bodyJson = json.encodeToString(ser, body)
- setBody(bodyJson)
- } catch (e: Throwable) {
- try {
- setBody(body)
- } catch (e0: Throwable) {
- e0.addSuppressed(e)
- throw e0
- }
- }
-
- }
- }
- }
-
-
-
- routeBuilder.apiPath?.let { apiPath -> appendPathSegments(components = apiPath) }
- routeBuilder.contentType?.let {
- headers {
- this[HttpHeaders.ContentType] = it.toString()
- }
- }
- }
-
- apiLogger.debug("[{} /{}] =====> {}, body: {}", method.logName, url.encodedPath, url.host, api.body)
- }
- }
+ override val url: Url
+ get() = URLBuilder(QQGuild.URL).apply {
+ appendEncodedPathSegments(components = path)
+ buildUrl()
+ }.build()
+}
+public abstract class PostQQGuildApi : PostApiDefinition(), QQGuildApi {
+ protected abstract val path: Array
/**
- * 通过 [requestForResponse] 得到响应,读取为文本并输出debug日志后返回。
- * 不会进行校验。
+ * 已经完成 [path] 拼接后、追加其他额外内容(例如parameter)时使用
*/
- @OptIn(ExperimentalContracts::class)
- protected suspend inline fun requestForText(client: HttpClient, server: Url, token: String, useResp: (HttpResponse) -> Unit = {}): String {
- contract {
- callsInPlace(useResp, InvocationKind.EXACTLY_ONCE)
- }
-
- val resp = requestForResponse(client, server, token)
- useResp(resp)
-
- val text = resp.bodyAsText()
-
- if (apiLogger.isDebugEnabled) {
- val traceId = resp.headers[TRACE_ID_HEAD]
- apiLogger.debug(
- "[{} {}] <===== status: {}, body: {}, traceID: {}",
- method.logName,
- resp.request.url.encodedPath,
- resp.status,
- text,
- traceId
- )
- }
+ protected open fun URLBuilder.buildUrl() {}
- return text
- }
+ override val url: Url
+ get() = URLBuilder(QQGuild.URL).apply {
+ appendEncodedPathSegments(components = path)
+ buildUrl()
+ }.build()
}
+public abstract class PutQQGuildApi : PutApiDefinition(), QQGuildApi {
+ protected abstract val path: Array
+ /**
+ * 已经完成 [path] 拼接后、追加其他额外内容(例如parameter)时使用
+ */
+ protected open fun URLBuilder.buildUrl() {}
-
-//region Ktor ContentNegotiation guessSerializer
-// see KotlinxSerializationJsonExtensions.kt
-// see SerializerLookup.kt
-
-@Suppress("UNCHECKED_CAST")
-private fun guessSerializer(value: Any?, module: SerializersModule): KSerializer = when (value) {
- null -> String.serializer().nullable
- is List<*> -> ListSerializer(value.elementSerializer(module))
- is Array<*> -> value.firstOrNull()?.let { guessSerializer(it, module) } ?: ListSerializer(String.serializer())
- is Set<*> -> SetSerializer(value.elementSerializer(module))
- is Map<*, *> -> {
- val keySerializer = value.keys.elementSerializer(module)
- val valueSerializer = value.values.elementSerializer(module)
- MapSerializer(keySerializer, valueSerializer)
- }
-
- else -> {
- @OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
- module.getContextual(value::class) ?: value::class.serializer()
- }
-} as KSerializer
-
-
-@OptIn(ExperimentalSerializationApi::class)
-private fun Collection<*>.elementSerializer(module: SerializersModule): KSerializer<*> {
- val serializers: List> =
- filterNotNull().map { guessSerializer(it, module) }.distinctBy { it.descriptor.serialName }
-
- if (serializers.size > 1) {
- error(
- "Serializing collections of different element types is not yet supported. " +
- "Selected serializers: ${serializers.map { it.descriptor.serialName }}",
- )
- }
-
- val selected = serializers.singleOrNull() ?: String.serializer()
-
- if (selected.descriptor.isNullable) {
- return selected
- }
-
- @Suppress("UNCHECKED_CAST")
- selected as KSerializer
-
- if (any { it == null }) {
- return selected.nullable
- }
-
- return selected
-}
-//endregion
-
-@Suppress("UNCHECKED_CAST")
-@OptIn(ExperimentalSerializationApi::class)
-internal fun QQGuildApi.decodeResponse(
- decoder: StringFormat, remainingText: String
-): R {
- if (resultDeserializer === Unit.serializer()) {
- return Unit as R
- }
-
- if (remainingText.isEmpty() && resultDeserializer.descriptor.kind is StructureKind.OBJECT) {
- return decoder.decodeFromString(resultDeserializer, "{}")
- }
-
- return decoder.decodeFromString(resultDeserializer, remainingText)
-}
-
-internal fun checkStatus(
- remainingText: String,
- decoder: StringFormat,
- status: HttpStatusCode
-) {
- // TODO 201,202 异步操作成功,虽然说成功,但是会返回一个 error body,需要特殊处理
- if (!status.isSuccess()) {
- val info = decoder.decodeFromString(ErrInfo.serializer(), remainingText)
- // throw err
- throw QQGuildApiException(info, status.value, status.description)
- }
+ override val url: Url
+ get() = URLBuilder(QQGuild.URL).apply {
+ appendEncodedPathSegments(components = path)
+ buildUrl()
+ }.build()
}
-public abstract class QQGuildApiWithoutResult : QQGuildApi() {
- override val resultDeserializer: DeserializationStrategy
- get() = Unit.serializer()
-}
+public abstract class DeleteQQGuildApi : DeleteApiDefinition(), QQGuildApi {
+ protected abstract val path: Array
-public abstract class GetQQGuildApi : QQGuildApi() {
- override val method: HttpMethod
- get() = HttpMethod.Get
+ /**
+ * 已经完成 [path] 拼接后、追加其他额外内容(例如parameter)时使用
+ */
+ protected open fun URLBuilder.buildUrl() {}
- override val body: Any?
- get() = null
+ override val url: Url
+ get() = URLBuilder(QQGuild.URL).apply {
+ appendEncodedPathSegments(components = path)
+ buildUrl()
+ }.build()
}
-public abstract class PostQQGuildApi : QQGuildApi() {
+public abstract class PatchQQGuildApi : PutQQGuildApi(), QQGuildApi {
override val method: HttpMethod
- get() = HttpMethod.Post
-
+ get() = HttpMethod.Patch
}
internal fun HttpMethod.defaultForLogName(): String = when (this) {
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/Serializers.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/Serializers.kt
index 897452d8..334ac01a 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/Serializers.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/Serializers.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -18,6 +18,7 @@
package love.forte.simbot.qguild.api
import kotlinx.serialization.KSerializer
+import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
@@ -44,3 +45,18 @@ public object NumberAsBooleanSerializer : KSerializer {
*/
private fun Boolean.toNumber(): Int = if (this) 1 else 0
}
+
+
+internal object EmptyUnitSerializer : KSerializer {
+ private val ser = Unit.serializer()
+ override fun deserialize(decoder: Decoder) {
+ // Just do nothing?
+ }
+
+ override val descriptor: SerialDescriptor
+ get() = ser.descriptor
+
+ override fun serialize(encoder: Encoder, value: Unit) {
+ ser.serialize(encoder, value)
+ }
+}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/CreateAnnouncesApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/CreateAnnouncesApi.kt
index eb3096f3..b9c5b1a4 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/CreateAnnouncesApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/CreateAnnouncesApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,12 +17,10 @@
package love.forte.simbot.qguild.api.announces
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.api.PostQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.model.Announces
import kotlin.jvm.JvmStatic
@@ -39,7 +37,7 @@ import kotlin.jvm.JvmStatic
*/
public class CreateAnnouncesApi private constructor(
channelId: String,
- messageId: String,
+ private val messageId: String,
) : PostQQGuildApi() {
public companion object Factory : SimplePostApiDescription(
@@ -57,19 +55,12 @@ public class CreateAnnouncesApi private constructor(
}
+ override val path: Array = arrayOf("channels", channelId, "announces")
- // POST /channels/{channel_id}/announces
- private val path = arrayOf("channels", channelId, "announces")
-
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = Announces.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any = Body(messageId)
-
+ override fun createBody(): Any = Body(messageId)
@Serializable
private data class Body(
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/DeleteAnnouncesApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/DeleteAnnouncesApi.kt
index dcb742ee..31853ab9 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/DeleteAnnouncesApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/announces/DeleteAnnouncesApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,9 @@
package love.forte.simbot.qguild.api.announces
-import io.ktor.http.*
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmStatic
@@ -35,10 +34,10 @@ import kotlin.jvm.JvmStatic
public class DeleteAnnouncesApi private constructor(
channelId: String,
messageId: String,
-) : QQGuildApiWithoutResult() {
+) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Delete, "/channels/{channel_id}/announces/{message_id}"
+ public companion object Factory : SimpleDeleteApiDescription(
+ "/channels/{channel_id}/announces/{message_id}"
) {
/**
@@ -49,14 +48,5 @@ public class DeleteAnnouncesApi private constructor(
DeleteAnnouncesApi(channelId, messageId)
}
- private val path = arrayOf("channels", channelId, "announces", messageId)
-
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any? = null
+ override val path: Array = arrayOf("channels", channelId, "announces", messageId)
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/DemandApiPermissionApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/DemandApiPermissionApi.kt
index ac87f67e..73cfc7a1 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/DemandApiPermissionApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/DemandApiPermissionApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -22,7 +22,6 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.api.ApiDescription
import love.forte.simbot.qguild.api.PostQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.model.ApiPermissionDemand
import love.forte.simbot.qguild.model.ApiPermissionDemandIdentify
@@ -81,14 +80,13 @@ public class DemandApiPermissionApi private constructor(
}
- private val path = arrayOf("guilds", guildId, "api_permission", "demand")
+ override val path: Array = arrayOf("guilds", guildId, "api_permission", "demand")
- override val resultDeserializer: DeserializationStrategy
+ override fun createBody(): Any? = null
+
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = ApiPermissionDemand.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
/**
* 用于在 [DemandApiPermissionApi] 中进行请求的
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/GetApiPermissionListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/GetApiPermissionListApi.kt
index 0d451782..7c1540ae 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/GetApiPermissionListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/apipermission/GetApiPermissionListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -22,7 +22,6 @@ import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.ApiModel
import love.forte.simbot.qguild.api.ApiDescription
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.ApiPermission
import love.forte.simbot.qguild.model.isAuthorized
@@ -53,14 +52,10 @@ public class GetApiPermissionListApi private constructor(
public fun create(guildId: String): GetApiPermissionListApi = GetApiPermissionListApi(guildId)
}
- private val path = arrayOf("guilds", guildId, "api_permission")
+ override val path: Array = arrayOf("guilds", guildId, "api_permission")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = ApiPermissions.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
/**
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/CreateChannelApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/CreateChannelApi.kt
index 322d0578..fbde7ca2 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/CreateChannelApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/CreateChannelApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -22,10 +22,10 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.PrivateDomainOnly
import love.forte.simbot.qguild.api.PostQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.model.*
import kotlin.jvm.JvmStatic
+import kotlin.jvm.JvmSynthetic
/**
@@ -52,16 +52,22 @@ public class CreateChannelApi private constructor(
*/
@JvmStatic
public fun create(guildId: String, body: Body): CreateChannelApi = CreateChannelApi(guildId, body)
+
+ /**
+ * 构造 [CreateChannelApi]
+ *
+ */
+ @JvmSynthetic
+ public inline fun create(guildId: String, block: Body.Builder.() -> Unit): CreateChannelApi =
+ create(guildId, Body.builder().also(block).build())
}
- private val path = arrayOf("guilds", guildId, "channels")
+ override val path: Array = arrayOf("guilds", guildId, "channels")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = SimpleChannel.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override fun createBody(): Any? = null
/**
* [CreateChannelApi] 的请求体。
@@ -115,5 +121,118 @@ public class CreateChannelApi private constructor(
*/
@SerialName("application_id")
val applicationId: String? = null
- )
+ ) {
+ /**
+ * Builder for [Body].
+ *
+ * 其中除了 [applicationId] 以外的属性都是必选的。
+ */
+ public class Builder {
+ /**
+ * @see Body.name
+ */
+ public var name: String? = null
+
+ /**
+ * @see Body.type
+ */
+ public var type: ChannelType? = null
+
+ /**
+ * @see Body.subType
+ */
+ public var subType: ChannelSubType? = null
+
+ /**
+ * @see Body.position
+ */
+ public var position: Int? = null
+
+ /**
+ * @see Body.parentId
+ */
+ public var parentId: String? = null
+
+ /**
+ * @see Body.privateType
+ */
+ public var privateType: PrivateType? = null
+
+ /**
+ * @see Body.privateUserIds
+ */
+ public var privateUserIds: List? = null
+
+ /**
+ * @see Body.speakPermission
+ */
+ public var speakPermission: SpeakPermission? = null
+
+ /**
+ * @see Body.applicationId
+ */
+ public var applicationId: String? = null
+
+ public fun name(value: String?): Builder = apply {
+ this.name = value
+ }
+
+ public fun type(value: ChannelType?): Builder = apply {
+ this.type = value
+ }
+
+ public fun subType(value: ChannelSubType?): Builder = apply {
+ this.subType = value
+ }
+
+ public fun position(value: Int?): Builder = apply {
+ this.position = value
+ }
+
+ public fun parentId(value: String?): Builder = apply {
+ this.parentId = value
+ }
+
+ public fun privateType(value: PrivateType?): Builder = apply {
+ this.privateType = value
+ }
+
+ public fun privateUserIds(value: List?): Builder = apply {
+ this.privateUserIds = value
+ }
+
+ public fun speakPermission(value: SpeakPermission?): Builder = apply {
+ this.speakPermission = value
+ }
+
+ public fun applicationId(value: String?): Builder = apply {
+ this.applicationId = value
+ }
+
+ public fun build(): Body = Body(
+ name = name ?: mismatchProp("name"),
+ type = type ?: mismatchProp("type"),
+ subType = subType ?: mismatchProp("subType"),
+ position = position ?: mismatchProp("position"),
+ parentId = parentId ?: mismatchProp("parentId"),
+ privateType = privateType ?: mismatchProp("privateType"),
+ privateUserIds = privateUserIds ?: mismatchProp("privateUserIds"),
+ speakPermission = speakPermission ?: mismatchProp("speakPermission"),
+ applicationId = applicationId,
+ )
+ }
+
+ public companion object {
+ /**
+ * 创建 [Builder]
+ */
+ @JvmStatic
+ public fun builder(): Builder = Builder()
+ }
+ }
+}
+
+
+private fun mismatchProp(name: String): Nothing {
+ throw IllegalArgumentException("Required '$name' was null")
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/DeleteChannelApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/DeleteChannelApi.kt
index fc2e7b8c..506d4445 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/DeleteChannelApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/DeleteChannelApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,13 +17,10 @@
package love.forte.simbot.qguild.api.channel
-import io.ktor.http.*
-import kotlinx.serialization.DeserializationStrategy
-import kotlinx.serialization.builtins.serializer
import love.forte.simbot.qguild.PrivateDomainOnly
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
+import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmStatic
@@ -41,9 +38,10 @@ import kotlin.jvm.JvmStatic
* @author ForteScarlet
*/
@PrivateDomainOnly
-public class DeleteChannelApi private constructor(channelId: String) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Delete, "/channels/{channel_id}"
+public class DeleteChannelApi private constructor(channelId: String) : QQGuildApiWithoutResult,
+ DeleteQQGuildApi() {
+ public companion object Factory : SimpleDeleteApiDescription(
+ "/channels/{channel_id}"
) {
/**
@@ -55,18 +53,5 @@ public class DeleteChannelApi private constructor(channelId: String) : QQGuildAp
}
- private val path = arrayOf("channels", channelId)
-
- override val resultDeserializer: DeserializationStrategy
- get() = Unit.serializer()
-
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any?
- get() = null
+ override val path: Array = arrayOf("channels", channelId)
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelApi.kt
index 2f72ca17..1edde513 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.channel
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.SimpleChannel
import kotlin.jvm.JvmStatic
@@ -43,12 +42,8 @@ public class GetChannelApi private constructor(channelId: String) : GetQQGuildAp
public fun create(channelId: String): GetChannelApi = GetChannelApi(channelId)
}
- private val path = arrayOf("channels", channelId)
+ override val path: Array = arrayOf("channels", channelId)
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = SimpleChannel.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelOnlineNumsApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelOnlineNumsApi.kt
index 910996c0..71fd75a4 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelOnlineNumsApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetChannelOnlineNumsApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -20,12 +20,7 @@ package love.forte.simbot.qguild.api.channel
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import kotlinx.serialization.descriptors.PrimitiveKind
-import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.encoding.Decoder
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import kotlin.jvm.JvmStatic
@@ -37,11 +32,10 @@ import kotlin.jvm.JvmStatic
*
* @author ForteScarlet
*/
-public class GetChannelOnlineNumsApi(channelId: String) : GetQQGuildApi() {
+public class GetChannelOnlineNumsApi(channelId: String) : GetQQGuildApi() {
public companion object Factory : SimpleGetApiDescription(
"/channels/{channel_id}/online_nums"
) {
-
/**
* 构造 [GetChannelOnlineNumsApi]
*/
@@ -49,25 +43,15 @@ public class GetChannelOnlineNumsApi(channelId: String) : GetQQGuildApi() {
public fun create(channelId: String): GetChannelOnlineNumsApi = GetChannelOnlineNumsApi(channelId)
}
- private val path = arrayOf("channels", channelId, "online_nums")
-
- override val resultDeserializer: DeserializationStrategy
- get() = OnlineNumsToIntDeserializationStrategy
+ override val path: Array = arrayOf("channels", channelId, "online_nums")
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override val resultDeserializationStrategy: DeserializationStrategy
+ get() = OnlineNumsResult.serializer()
}
-private object OnlineNumsToIntDeserializationStrategy : DeserializationStrategy {
- @Serializable
- private data class OnlineNumsResult(@SerialName("online_nums") val onlineNums: Int)
-
- override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("OnlineNums", PrimitiveKind.INT)
-
- override fun deserialize(decoder: Decoder): Int {
- val decoded = OnlineNumsResult.serializer().deserialize(decoder)
- return decoded.onlineNums
- }
-}
+/**
+ * Result of [GetChannelOnlineNumsApi]
+ */
+@Serializable
+public data class OnlineNumsResult(@SerialName("online_nums") val onlineNums: Int)
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetGuildChannelListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetGuildChannelListApi.kt
index dfe0a9c1..085ca709 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetGuildChannelListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/GetGuildChannelListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -20,7 +20,6 @@ package love.forte.simbot.qguild.api.channel
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.builtins.ListSerializer
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.SimpleChannel
import kotlin.jvm.JvmStatic
@@ -47,13 +46,8 @@ public class GetGuildChannelListApi private constructor(guildId: String) : GetQQ
public fun create(guildId: String): GetGuildChannelListApi = GetGuildChannelListApi(guildId)
}
- private val path = arrayOf("guilds", guildId, "channels")
+ override val path: Array = arrayOf("guilds", guildId, "channels")
- override val resultDeserializer: DeserializationStrategy>
+ override val resultDeserializationStrategy: DeserializationStrategy>
get() = serializer
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/ModifyChannelApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/ModifyChannelApi.kt
index 8a800bba..4721723c 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/ModifyChannelApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/ModifyChannelApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,18 +17,17 @@
package love.forte.simbot.qguild.api.channel
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.PrivateDomainOnly
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.PatchQQGuildApi
+import love.forte.simbot.qguild.api.SimplePatchApiDescription
import love.forte.simbot.qguild.model.PrivateType
import love.forte.simbot.qguild.model.SimpleChannel
import love.forte.simbot.qguild.model.SpeakPermission
import kotlin.jvm.JvmStatic
+import kotlin.jvm.JvmSynthetic
/**
@@ -44,9 +43,9 @@ import kotlin.jvm.JvmStatic
@PrivateDomainOnly
public class ModifyChannelApi private constructor(
channelId: String, override val body: Body
-) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Patch, "/channels/{channel_id}"
+) : PatchQQGuildApi() {
+ public companion object Factory : SimplePatchApiDescription(
+ "/channels/{channel_id}"
) {
/**
@@ -54,21 +53,23 @@ public class ModifyChannelApi private constructor(
*
*/
@JvmStatic
- public fun create(channelId: String, body: Body): ModifyChannelApi = ModifyChannelApi(channelId, body)
+ public fun create(channelId: String, body: Body): ModifyChannelApi =
+ ModifyChannelApi(channelId, body)
+ /**
+ * 使用 [Body.Builder] 构造 [Body] 并将其作为参数构造 [ModifyChannelApi].
+ */
+ @JvmSynthetic
+ public inline fun create(channelId: String, block: Body.Builder.() -> Unit): ModifyChannelApi =
+ create(channelId, Body.builder().also(block).build())
}
- private val path = arrayOf("channels", channelId)
-
- override val resultDeserializer: DeserializationStrategy
- get() = SimpleChannel.serializer()
+ override val path: Array = arrayOf("channels", channelId)
- override val method: HttpMethod
- get() = HttpMethod.Patch
+ override fun createBody(): Any? = null
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override val resultDeserializationStrategy: DeserializationStrategy
+ get() = SimpleChannel.serializer()
/**
* 用于 [ModifyChannelApi] 的请求体。
@@ -98,5 +99,74 @@ public class ModifyChannelApi private constructor(
* 子频道发言权限 [SpeakPermission]
*/
@SerialName("speak_permission") val speakPermission: SpeakPermission? = null
- )
+ ) {
+ /**
+ * [Builder] for [Body]
+ */
+ @Suppress("MemberVisibilityCanBePrivate")
+ public class Builder {
+ /**
+ * @see Body.name
+ */
+ public var name: String? = null
+
+ /**
+ * @see Body.position
+ */
+ public var position: Int? = null
+
+ /**
+ * @see Body.parentId
+ */
+ public var parentId: String? = null
+
+ /**
+ * @see Body.privateType
+ */
+ public var privateType: PrivateType? = null
+
+ /**
+ * @see Body.speakPermission
+ */
+ public var speakPermission: SpeakPermission? = null
+
+ public fun name(value: String?): Builder = apply {
+ this.name = value
+ }
+
+ public fun position(value: Int?): Builder = apply {
+ this.position = value
+ }
+
+ public fun parentId(value: String?): Builder = apply {
+ this.parentId = value
+ }
+
+ public fun privateType(value: PrivateType?): Builder = apply {
+ this.privateType = value
+ }
+
+ public fun speakPermission(value: SpeakPermission?): Builder = apply {
+ this.speakPermission = value
+ }
+
+ public fun build(): Body = Body(
+ name = name,
+ position = position,
+ parentId = parentId,
+ privateType = privateType,
+ speakPermission = speakPermission,
+ )
+
+ }
+
+ public companion object {
+ /**
+ * 创建一个 [Builder].
+ */
+ @JvmStatic
+ public fun builder(): Builder = Builder()
+ }
+
+ }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelMemberPermissionsApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelMemberPermissionsApi.kt
index 4e609159..937aa4fb 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelMemberPermissionsApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelMemberPermissionsApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.channel.permissions
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.ChannelPermissions
import kotlin.jvm.JvmStatic
@@ -49,12 +48,8 @@ public class GetChannelMemberPermissionsApi private constructor(
GetChannelMemberPermissionsApi(channelId, memberId)
}
- private val path = arrayOf("channels", channelId, "members", memberId, "permissions")
+ override val path: Array = arrayOf("channels", channelId, "members", memberId, "permissions")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = ChannelPermissions.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelRolePermissionsApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelRolePermissionsApi.kt
index de880744..3af64dd5 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelRolePermissionsApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/GetChannelRolePermissionsApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.channel.permissions
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.ChannelPermissions
import kotlin.jvm.JvmStatic
@@ -47,15 +46,10 @@ public class GetChannelRolePermissionsApi(
@JvmStatic
public fun create(channelId: String, roleId: String): GetChannelRolePermissionsApi =
GetChannelRolePermissionsApi(channelId, roleId)
-
}
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = ChannelPermissions.serializer()
- private val path = arrayOf("channels", channelId, "roles", roleId, "permissions")
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override val path: Array = arrayOf("channels", channelId, "roles", roleId, "permissions")
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelMemberPermissionsApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelMemberPermissionsApi.kt
index fa9a85bf..b87bc25d 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelMemberPermissionsApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelMemberPermissionsApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,11 +17,10 @@
package love.forte.simbot.qguild.api.channel.permissions
-import io.ktor.http.*
import kotlinx.serialization.Serializable
+import love.forte.simbot.qguild.api.PutQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimplePutApiDescription
import love.forte.simbot.qguild.model.Permissions
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
@@ -41,9 +40,9 @@ import kotlin.jvm.JvmStatic
public class ModifyChannelMemberPermissionsApi private constructor(
channelId: String, memberId: String,
private val _body: Body
-) : QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Put, "/channels/{channel_id}/members/{user_id}/permissions"
+) : QQGuildApiWithoutResult, PutQQGuildApi() {
+ public companion object Factory : SimplePutApiDescription(
+ "/channels/{channel_id}/members/{user_id}/permissions"
) {
/**
* 构造 [ModifyChannelMemberPermissionsApi].
@@ -81,17 +80,9 @@ public class ModifyChannelMemberPermissionsApi private constructor(
}
- private val path = arrayOf("channels", channelId, "members", memberId, "permissions")
+ override val path: Array = arrayOf("channels", channelId, "members", memberId, "permissions")
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val method: HttpMethod
- get() = HttpMethod.Put
-
- override val body: Any
- get() = _body
+ override fun createBody(): Any = _body
@Serializable
private data class Body(
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelRolePermissionsApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelRolePermissionsApi.kt
index 00ca64a9..28b66952 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelRolePermissionsApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/permissions/ModifyChannelRolePermissionsApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,11 +17,10 @@
package love.forte.simbot.qguild.api.channel.permissions
-import io.ktor.http.*
import kotlinx.serialization.Serializable
+import love.forte.simbot.qguild.api.PutQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimplePutApiDescription
import love.forte.simbot.qguild.model.Permissions
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
@@ -42,9 +41,9 @@ import kotlin.jvm.JvmStatic
public class ModifyChannelRolePermissionsApi private constructor(
channelId: String, roleId: String,
private val _body: Body
-) : QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Put, "/channels/{channel_id}/roles/{role_id}/permissions"
+) : QQGuildApiWithoutResult, PutQQGuildApi() {
+ public companion object Factory : SimplePutApiDescription(
+ "/channels/{channel_id}/roles/{role_id}/permissions"
) {
/**
@@ -82,17 +81,9 @@ public class ModifyChannelRolePermissionsApi private constructor(
): ModifyChannelRolePermissionsApi = create(channelId, memberId, remove = remove)
}
- private val path = arrayOf("channels", channelId, "roles", roleId, "permissions")
+ override val path: Array = arrayOf("channels", channelId, "roles", roleId, "permissions")
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val method: HttpMethod
- get() = HttpMethod.Put
-
- override val body: Any
- get() = _body
+ override fun createBody(): Any = _body
@Serializable
private data class Body(val add: Permissions?, val remove: Permissions?) {
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/AddPinsMessageApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/AddPinsMessageApi.kt
index cf669def..fc11a787 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/AddPinsMessageApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/AddPinsMessageApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,11 +17,9 @@
package love.forte.simbot.qguild.api.channel.pins
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.PutQQGuildApi
+import love.forte.simbot.qguild.api.SimplePutApiDescription
import love.forte.simbot.qguild.model.PinsMessage
import kotlin.jvm.JvmStatic
@@ -39,8 +37,8 @@ import kotlin.jvm.JvmStatic
*/
public class AddPinsMessageApi private constructor(
channelId: String, messageId: String
-) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(HttpMethod.Put, "/channels/{channel_id}/pins/{message_id}") {
+) : PutQQGuildApi() {
+ public companion object Factory : SimplePutApiDescription("/channels/{channel_id}/pins/{message_id}") {
/**
* 构造一个 [AddPinsMessageApi]
@@ -53,16 +51,9 @@ public class AddPinsMessageApi private constructor(
AddPinsMessageApi(channelId, messageId)
}
- private val path = arrayOf("channels", channelId, "pins", messageId)
+ override val path: Array = arrayOf("channels", channelId, "pins", messageId)
+ override val resultDeserializationStrategy: DeserializationStrategy get() = PinsMessage.serializer()
- override val resultDeserializer: DeserializationStrategy get() = PinsMessage.serializer()
-
- override val method: HttpMethod get() = HttpMethod.Put
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any? get() = null
+ override fun createBody(): Any? = null
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/DeletePinsMessageApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/DeletePinsMessageApi.kt
index aea885d1..753b4492 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/DeletePinsMessageApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/DeletePinsMessageApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,9 @@
package love.forte.simbot.qguild.api.channel.pins
-import io.ktor.http.*
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import love.forte.simbot.qguild.api.channel.pins.DeletePinsMessageApi.Factory.DELETE_ALL_MESSAGE_ID
import kotlin.jvm.JvmStatic
@@ -36,8 +35,8 @@ import kotlin.jvm.JvmStatic
*/
public class DeletePinsMessageApi private constructor(
channelId: String, messageId: String
-) : QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(HttpMethod.Delete, "/channels/{channel_id}/pins/{message_id}") {
+) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
+ public companion object Factory : SimpleDeleteApiDescription("/channels/{channel_id}/pins/{message_id}") {
/**
* 当要删除的目标为全部时使用的 `message_id` 。
@@ -68,13 +67,5 @@ public class DeletePinsMessageApi private constructor(
DeletePinsMessageApi(channelId, DELETE_ALL_MESSAGE_ID)
}
- private val path = arrayOf("channels", channelId, "pins", messageId)
-
- override val method: HttpMethod get() = HttpMethod.Delete
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any? get() = null
+ override val path: Array = arrayOf("channels", channelId, "pins", messageId)
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/GetPinsMessageApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/GetPinsMessageApi.kt
index 0fb7c640..917390a2 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/GetPinsMessageApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/pins/GetPinsMessageApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,8 @@
package love.forte.simbot.qguild.api.channel.pins
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
+import love.forte.simbot.qguild.api.GetQQGuildApi
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.PinsMessage
import kotlin.jvm.JvmStatic
@@ -35,7 +33,7 @@ import kotlin.jvm.JvmStatic
*/
public class GetPinsMessageApi private constructor(
channelId: String
-) : QQGuildApi() {
+) : GetQQGuildApi() {
public companion object Factory : SimpleGetApiDescription("/channels/{channel_id}/pins") {
/**
@@ -47,16 +45,7 @@ public class GetPinsMessageApi private constructor(
public fun create(channelId: String): GetPinsMessageApi = GetPinsMessageApi(channelId)
}
- private val path = arrayOf("channels", channelId, "pins")
+ override val path: Array = arrayOf("channels", channelId, "pins")
-
- override val resultDeserializer: DeserializationStrategy get() = PinsMessage.serializer()
-
- override val method: HttpMethod get() = HttpMethod.Get
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any? get() = null
+ override val resultDeserializationStrategy: DeserializationStrategy get() = PinsMessage.serializer()
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/CreateScheduleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/CreateScheduleApi.kt
index 368fdeee..a62ee5cc 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/CreateScheduleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/CreateScheduleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.channel.schedules
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.PostQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.api.channel.schedules.ScheduleRequestBody.Companion.toCreateBody
import love.forte.simbot.qguild.model.Schedule
@@ -65,16 +64,12 @@ public class CreateScheduleApi private constructor(
@JvmStatic
public fun create(channelId: String, schedule: Schedule): CreateScheduleApi =
create(channelId, schedule.toCreateBody())
-
}
- override val resultDeserializer: DeserializationStrategy get() = Schedule.serializer()
-
- private val path = arrayOf("channels", channelId, "schedules")
+ override val resultDeserializationStrategy: DeserializationStrategy get() = Schedule.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override val path: Array = arrayOf("channels", channelId, "schedules")
+ override fun createBody(): Any? = null
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/DeleteScheduleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/DeleteScheduleApi.kt
index b76c5d44..8f6bc59c 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/DeleteScheduleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/DeleteScheduleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,9 @@
package love.forte.simbot.qguild.api.channel.schedules
-import io.ktor.http.*
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmStatic
@@ -35,9 +34,9 @@ import kotlin.jvm.JvmStatic
*/
public class DeleteScheduleApi private constructor(
channelId: String, scheduleId: String
-) : QQGuildApiWithoutResult() {
+) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
public companion object Factory :
- SimpleApiDescription(HttpMethod.Delete, "/channels/{channel_id}/schedules/{schedule_id}") {
+ SimpleDeleteApiDescription("/channels/{channel_id}/schedules/{schedule_id}") {
/**
* 构造 [DeleteScheduleApi]
@@ -49,17 +48,8 @@ public class DeleteScheduleApi private constructor(
@JvmStatic
public fun create(channelId: String, scheduleId: String): DeleteScheduleApi =
DeleteScheduleApi(channelId, scheduleId)
-
}
- override val method: HttpMethod get() = HttpMethod.Delete
-
- private val path = arrayOf("channels", channelId, "schedules", scheduleId)
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override val path: Array = arrayOf("channels", channelId, "schedules", scheduleId)
- override val body: Any?
- get() = null
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleApi.kt
index 76a4a8ea..1a1e7d3e 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.channel.schedules
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.Schedule
import kotlin.jvm.JvmStatic
@@ -48,11 +47,8 @@ public class GetScheduleApi private constructor(
public fun create(channelId: String, scheduleId: String): GetScheduleApi = GetScheduleApi(channelId, scheduleId)
}
- override val resultDeserializer: DeserializationStrategy get() = Schedule.serializer()
+ override val resultDeserializationStrategy: DeserializationStrategy get() = Schedule.serializer()
- private val path = arrayOf("channels", channelId, "schedules", scheduleId)
+ override val path: Array = arrayOf("channels", channelId, "schedules", scheduleId)
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleListApi.kt
index 1edf3065..65c5236d 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/GetScheduleListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,10 @@
package love.forte.simbot.qguild.api.channel.schedules
+import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.builtins.ListSerializer
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.Schedule
import kotlin.jvm.JvmStatic
@@ -82,14 +82,13 @@ public class GetScheduleListApi private constructor(
}
}
- override val resultDeserializer: DeserializationStrategy> get() = serializer
+ override val resultDeserializationStrategy: DeserializationStrategy> get() = serializer
- private val path = arrayOf("channels", channelId, "schedules")
+ override val path: Array = arrayOf("channels", channelId, "schedules")
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
+ override fun URLBuilder.buildUrl() {
if (sinceMark) {
- builder.parametersAppender.append("since", since)
+ parameters.append("since", since.toString())
}
}
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/ModifyScheduleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/ModifyScheduleApi.kt
index 6cb081fe..b26f921f 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/ModifyScheduleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/channel/schedules/ModifyScheduleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,9 +19,8 @@ package love.forte.simbot.qguild.api.channel.schedules
import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.PatchQQGuildApi
+import love.forte.simbot.qguild.api.SimplePatchApiDescription
import love.forte.simbot.qguild.api.channel.schedules.ScheduleRequestBody.Companion.toCreateBody
import love.forte.simbot.qguild.model.Schedule
import kotlin.jvm.JvmStatic
@@ -37,9 +36,11 @@ import kotlin.jvm.JvmStatic
* @author ForteScarlet
*/
public class ModifyScheduleApi private constructor(
- channelId: String, scheduleId: String, override val body: ScheduleRequestBody
-) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(HttpMethod.Patch, "/channels/{channel_id}/schedules/{schedule_id}") {
+ channelId: String, scheduleId: String,
+ override val body: ScheduleRequestBody
+) : PatchQQGuildApi() {
+ public companion object Factory :
+ SimplePatchApiDescription("/channels/{channel_id}/schedules/{schedule_id}") {
/**
* 构造 [ModifyScheduleApi]
@@ -78,12 +79,10 @@ public class ModifyScheduleApi private constructor(
}
- override val resultDeserializer: DeserializationStrategy get() = Schedule.serializer()
+ override val resultDeserializationStrategy: DeserializationStrategy get() = Schedule.serializer()
override val method: HttpMethod get() = HttpMethod.Patch
- private val path = arrayOf("channels", channelId, "schedules", scheduleId)
+ override val path: Array = arrayOf("channels", channelId, "schedules", scheduleId)
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override fun createBody(): Any? = null
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/DeleteThreadApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/DeleteThreadApi.kt
index 47c78760..0fe42ba2 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/DeleteThreadApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/DeleteThreadApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,11 +17,10 @@
package love.forte.simbot.qguild.api.forum
-import io.ktor.http.*
import love.forte.simbot.qguild.PrivateDomainOnly
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmStatic
/**
@@ -32,9 +31,9 @@ import kotlin.jvm.JvmStatic
* @author ForteScarlet
*/
@PrivateDomainOnly
-public class DeleteThreadApi(channelId: String, threadId: String) : QQGuildApiWithoutResult() {
+public class DeleteThreadApi(channelId: String, threadId: String) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
public companion object Factory :
- SimpleApiDescription(HttpMethod.Delete, "/channels/{channel_id}/threads/{thread_id}") {
+ SimpleDeleteApiDescription("/channels/{channel_id}/threads/{thread_id}") {
/**
* 构造 [DeleteThreadApi].
@@ -46,17 +45,7 @@ public class DeleteThreadApi(channelId: String, threadId: String) : QQGuildApiWi
@JvmStatic
public fun create(channelId: String, threadId: String): DeleteThreadApi =
DeleteThreadApi(channelId, threadId)
-
- }
-
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
- private val path = arrayOf("channels", channelId, "threads", threadId)
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
}
- override val body: Any? get() = null
+ override val path: Array = arrayOf("channels", channelId, "threads", threadId)
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadApi.kt
index 1f69065b..1544bb80 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -21,7 +21,6 @@ import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.PrivateDomainOnly
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.forum.Thread
import kotlin.jvm.JvmStatic
@@ -50,14 +49,10 @@ public class GetThreadApi(channelId: String, threadId: String) : GetQQGuildApi = arrayOf("channels", channelId, "threads", threadId)
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = ThreadInfoResult.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
/**
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadListApi.kt
index 9ea5cf9a..061e1ef7 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/GetThreadListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -24,7 +24,6 @@ import love.forte.simbot.qguild.ApiModel
import love.forte.simbot.qguild.PrivateDomainOnly
import love.forte.simbot.qguild.api.GetQQGuildApi
import love.forte.simbot.qguild.api.NumberAsBooleanSerializer
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.forum.Thread
import kotlin.jvm.JvmStatic
@@ -51,15 +50,10 @@ public class GetThreadListApi private constructor(channelId: String) : GetQQGuil
GetThreadListApi(channelId)
}
- private val path = arrayOf("channels", channelId, "threads")
+ override val path: Array = arrayOf("channels", channelId, "threads")
-
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = ThreadListResult.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
/**
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/PublishThreadApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/PublishThreadApi.kt
index 4528ab94..692dd04f 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/PublishThreadApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/forum/PublishThreadApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,14 +17,12 @@
package love.forte.simbot.qguild.api.forum
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.ApiModel
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.PutQQGuildApi
+import love.forte.simbot.qguild.api.SimplePutApiDescription
import kotlin.jvm.JvmStatic
/**
@@ -35,8 +33,8 @@ import kotlin.jvm.JvmStatic
*/
public class PublishThreadApi private constructor(
channelId: String, private val _body: Body
-) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(HttpMethod.Put, "/channels/{channel_id}/threads") {
+) : PutQQGuildApi() {
+ public companion object Factory : SimplePutApiDescription("/channels/{channel_id}/threads") {
/**
* 构造 [PublishThreadApi]
@@ -59,7 +57,12 @@ public class PublishThreadApi private constructor(
* @param format 帖子文本格式。see [ThreadPublishFormat]
*/
@JvmStatic
- public fun create(channelId: String, title: String, content: String, format: ThreadPublishFormat): PublishThreadApi =
+ public fun create(
+ channelId: String,
+ title: String,
+ content: String,
+ format: ThreadPublishFormat
+ ): PublishThreadApi =
create(channelId, title, content, format.value)
/**
@@ -116,19 +119,12 @@ public class PublishThreadApi private constructor(
}
- override val method: HttpMethod
- get() = HttpMethod.Put
+ override val path: Array = arrayOf("channels", channelId, "threads")
- private val path = arrayOf("channels", channelId, "threads")
-
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = ThreadPublishResult.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any get() = _body
+ override fun createBody(): Any = _body
@Serializable
private data class Body(val title: String, val content: String, val format: Int)
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/GetGuildApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/GetGuildApi.kt
index 0f6f088d..4600aff5 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/GetGuildApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/GetGuildApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,8 @@
package love.forte.simbot.qguild.api.guild
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
+import love.forte.simbot.qguild.api.GetQQGuildApi
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.SimpleGuild
import kotlin.jvm.JvmStatic
@@ -31,7 +29,7 @@ import kotlin.jvm.JvmStatic
* 用于获取 `guildId` 指定的频道的详情。
*
*/
-public class GetGuildApi private constructor(guildId: String) : QQGuildApi() {
+public class GetGuildApi private constructor(guildId: String) : GetQQGuildApi() {
public companion object Factory : SimpleGetApiDescription(
"/guilds/{guild_id}"
) {
@@ -44,18 +42,8 @@ public class GetGuildApi private constructor(guildId: String) : QQGuildApi = arrayOf("guilds", guildId)
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = SimpleGuild.serializer()
-
- override val method: HttpMethod
- get() = HttpMethod.Get
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any? get() = null
-
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteAllApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteAllApi.kt
index 0dfc5caf..320b8c8c 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteAllApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteAllApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,13 +17,10 @@
package love.forte.simbot.qguild.api.guild.mute
-import io.ktor.http.*
-import kotlinx.serialization.DeserializationStrategy
-import kotlinx.serialization.builtins.serializer
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
-import love.forte.simbot.qguild.time.TimeUnit
+import love.forte.simbot.common.time.TimeUnit
+import love.forte.simbot.qguild.api.PatchQQGuildApi
+import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
+import love.forte.simbot.qguild.api.SimplePatchApiDescription
import kotlin.jvm.JvmStatic
import kotlin.jvm.JvmSynthetic
import kotlin.time.Duration
@@ -32,15 +29,11 @@ import kotlin.time.Duration
/**
* @suppress
*/
-public abstract class BaseMuteAllApi internal constructor(guildId: String, body: MuteBody) : QQGuildApi() {
- override val method: HttpMethod get() = HttpMethod.Patch
- private val path = arrayOf("guilds", guildId, "mute")
- override val resultDeserializer: DeserializationStrategy get() = Unit.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any = body
+public abstract class BaseMuteAllApi internal constructor(guildId: String, private val _body: MuteBody) :
+ QQGuildApiWithoutResult,
+ PatchQQGuildApi() {
+ override val path: Array = arrayOf("guilds", guildId, "mute")
+ override fun createBody(): Any = _body
}
/**
@@ -56,10 +49,9 @@ public abstract class BaseMuteAllApi internal constructor(guildId: String, body:
* @author ForteScarlet
*/
public class MuteAllApi private constructor(guildId: String, body: MuteBody) : BaseMuteAllApi(guildId, body) {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Patch, "/guilds/{guild_id}/mute"
+ public companion object Factory : SimplePatchApiDescription(
+ "/guilds/{guild_id}/mute"
) {
-
/**
* 使用 `mute_seconds` 的方式构建 [MuteAllApi]
* @param muteSeconds 禁言多少秒
@@ -70,7 +62,6 @@ public class MuteAllApi private constructor(guildId: String, body: MuteBody) : B
public fun create(guildId: String, muteSeconds: Duration): MuteAllApi =
createBySeconds(guildId, muteSeconds.inWholeSeconds)
-
/**
* 使用 `mute_seconds` 的方式构建 [MuteAllApi]
* @param muteTime 禁言时长
@@ -88,7 +79,6 @@ public class MuteAllApi private constructor(guildId: String, body: MuteBody) : B
@JvmStatic
public fun createUnmute(guildId: String): MuteAllApi = MuteAllApi(guildId, MuteBody.Unmute)
-
private fun createBySeconds(guildId: String, seconds: Long): MuteAllApi {
return when {
seconds == 0L -> MuteAllApi(guildId, MuteBody.Unmute)
@@ -98,19 +88,4 @@ public class MuteAllApi private constructor(guildId: String, body: MuteBody) : B
}
}
-
- override val method: HttpMethod
- get() = HttpMethod.Patch
-
- private val path = arrayOf("guilds", guildId, "mute")
-
- override val resultDeserializer: DeserializationStrategy
- get() = Unit.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any = body
-
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMemberApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMemberApi.kt
index 61738c54..8a9eda75 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMemberApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMemberApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,11 +17,10 @@
package love.forte.simbot.qguild.api.guild.mute
-import io.ktor.http.*
+import love.forte.simbot.common.time.TimeUnit
+import love.forte.simbot.qguild.api.PatchQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
-import love.forte.simbot.qguild.time.TimeUnit
+import love.forte.simbot.qguild.api.SimplePatchApiDescription
import kotlin.jvm.JvmStatic
import kotlin.jvm.JvmSynthetic
import kotlin.time.Duration
@@ -37,10 +36,10 @@ import kotlin.time.Duration
*
* @author ForteScarlet
*/
-public class MuteMemberApi private constructor(guildId: String, userId: String, body: MuteBody) :
- QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Patch, "/guilds/{guild_id}/members/{user_id}/mute"
+public class MuteMemberApi private constructor(guildId: String, userId: String, private val _body: MuteBody) :
+ QQGuildApiWithoutResult, PatchQQGuildApi() {
+ public companion object Factory : SimplePatchApiDescription(
+ "/guilds/{guild_id}/members/{user_id}/mute"
) {
/**
@@ -82,15 +81,8 @@ public class MuteMemberApi private constructor(guildId: String, userId: String,
}
}
- private val path = arrayOf("guilds", guildId, "members", userId, "mute")
+ override val path: Array = arrayOf("guilds", guildId, "members", userId, "mute")
- override val method: HttpMethod
- get() = HttpMethod.Patch
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any = body
+ override fun createBody(): Any = _body
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMultiMemberApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMultiMemberApi.kt
index 77ba938b..40a5af7e 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMultiMemberApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/guild/mute/MuteMultiMemberApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,15 +17,13 @@
package love.forte.simbot.qguild.api.guild.mute
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
+import love.forte.simbot.common.time.TimeUnit
import love.forte.simbot.qguild.ApiModel
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
-import love.forte.simbot.qguild.time.TimeUnit
+import love.forte.simbot.qguild.api.PatchQQGuildApi
+import love.forte.simbot.qguild.api.SimplePatchApiDescription
import kotlin.jvm.JvmStatic
import kotlin.jvm.JvmSynthetic
import kotlin.time.Duration
@@ -41,9 +39,10 @@ import kotlin.time.Duration
*
* @author ForteScarlet
*/
-public class MuteMultiMemberApi private constructor(guildId: String, body: MuteBody) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Patch, "/guilds/{guild_id}/mute"
+public class MuteMultiMemberApi private constructor(guildId: String, private val _body: MuteBody) :
+ PatchQQGuildApi() {
+ public companion object Factory : SimplePatchApiDescription(
+ "/guilds/{guild_id}/mute"
) {
/**
@@ -84,19 +83,12 @@ public class MuteMultiMemberApi private constructor(guildId: String, body: MuteB
}
}
- private val path = arrayOf("guilds", guildId, "mute")
+ override val path: Array = arrayOf("guilds", guildId, "mute")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = MultiMuteResult.serializer()
- override val method: HttpMethod
- get() = HttpMethod.Patch
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any = body
+ override fun createBody(): Any = _body
}
/**
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/DeleteMemberApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/DeleteMemberApi.kt
index 577d6eef..0aa9ac74 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/DeleteMemberApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/DeleteMemberApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,15 +17,12 @@
package love.forte.simbot.qguild.api.member
-import io.ktor.http.*
-import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import kotlinx.serialization.builtins.serializer
import love.forte.simbot.qguild.PrivateDomainOnly
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
+import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic
@@ -47,9 +44,9 @@ public class DeleteMemberApi private constructor(
guildId: String,
userId: String,
private val _body: Body
-) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Delete, "/guilds/{guild_id}/members/{user_id}"
+) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
+ public companion object Factory : SimpleDeleteApiDescription(
+ "/guilds/{guild_id}/members/{user_id}"
) {
/**
@@ -71,17 +68,7 @@ public class DeleteMemberApi private constructor(
}
- private val path = arrayOf("guilds", guildId, "members", userId)
-
- override val resultDeserializer: DeserializationStrategy
- get() = Unit.serializer()
-
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
+ override val path: Array = arrayOf("guilds", guildId, "members", userId)
override val body: Any
get() = _body
@@ -104,11 +91,11 @@ public class DeleteMemberApi private constructor(
}
companion object {
- private const val deleteHistoryMsgDaysRange =
+ private const val DELETE_HISTORY_MSG_DAYS_RANGE =
0 or (1 shl 3) or (1 shl 7) or (1 shl 15) or (1 shl 30) or (1 shl 0)
private fun deleteHistoryMsgDaysRangeContains(value: Int): Boolean {
- return value <= 30 && (deleteHistoryMsgDaysRange and (1 shl value)) != 0
+ return value <= 30 && (DELETE_HISTORY_MSG_DAYS_RANGE and (1 shl value)) != 0
}
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildMemberListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildMemberListApi.kt
index 1d571fe3..3aa805eb 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildMemberListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildMemberListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,6 +17,7 @@
package love.forte.simbot.qguild.api.member
+import io.ktor.http.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.serialization.DeserializationStrategy
@@ -25,7 +26,6 @@ import love.forte.simbot.logger.LoggerFactory
import love.forte.simbot.logger.logger
import love.forte.simbot.qguild.PrivateDomainOnly
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.SimpleMember
import kotlin.jvm.JvmOverloads
@@ -61,9 +61,9 @@ public class GetGuildMemberListApi private constructor(
) : GetQQGuildApi>() {
init {
require(limit > 0) { "limit must > 0, but $limit" }
- if (limit > 400) {
+ if (limit > MAX_LIMIT) {
// or throw error? or ignore?
- logger.warn("The maximum value of the limit is 400, but {}", limit)
+ logger.warn("The maximum value of the limit is $MAX_LIMIT, but {}", limit)
}
}
@@ -96,16 +96,14 @@ public class GetGuildMemberListApi private constructor(
GetGuildMemberListApi(guildId, null, limit)
}
- private val path = arrayOf("guilds", guildId, "members")
+ override val path: Array = arrayOf("guilds", guildId, "members")
- override val resultDeserializer: DeserializationStrategy>
+ override val resultDeserializationStrategy: DeserializationStrategy>
get() = deserializer
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
-
- after?.also { builder.parametersAppender.append("after", it) }
- builder.parametersAppender.append("limit", limit)
+ override fun URLBuilder.buildUrl() {
+ after?.also { parameters.append("after", it) }
+ parameters.append("limit", limit.toString())
}
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildRoleMemberListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildRoleMemberListApi.kt
index 36dd1dbc..ecaddec7 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildRoleMemberListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetGuildRoleMemberListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,6 +17,7 @@
package love.forte.simbot.qguild.api.member
+import io.ktor.http.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.serialization.DeserializationStrategy
@@ -26,7 +27,6 @@ import love.forte.simbot.logger.logger
import love.forte.simbot.qguild.ApiModel
import love.forte.simbot.qguild.PrivateDomainOnly
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.SimpleMember
import kotlin.jvm.JvmOverloads
@@ -92,15 +92,14 @@ public class GetGuildRoleMemberListApi private constructor(
): GetGuildRoleMemberListApi = GetGuildRoleMemberListApi(guildId, roleId, null, limit)
}
- private val path = arrayOf("guilds", guildId, "roles", roleId, "members")
+ override val path: Array = arrayOf("guilds", guildId, "roles", roleId, "members")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = GuildRoleMemberList.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- startIndex?.also { builder.parametersAppender.append("start_index", startIndex) }
- builder.parametersAppender.append("limit", limit)
+ override fun URLBuilder.buildUrl() {
+ startIndex?.also { parameters.append("start_index", startIndex) }
+ parameters.append("limit", limit.toString())
}
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetMemberApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetMemberApi.kt
index 72d752b8..48450838 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetMemberApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/member/GetMemberApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.member
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.SimpleMember
import kotlin.jvm.JvmStatic
@@ -46,12 +45,8 @@ public class GetMemberApi private constructor(
public fun create(guildId: String, userId: String): GetMemberApi = GetMemberApi(guildId, userId)
}
- private val path = arrayOf("guilds", guildId, "members", userId)
+ override val path: Array = arrayOf("guilds", guildId, "members", userId)
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = SimpleMember.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/DeleteMessageApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/DeleteMessageApi.kt
index adf06a34..fc3b24ea 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/DeleteMessageApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/DeleteMessageApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,9 +19,9 @@ package love.forte.simbot.qguild.api.message
import io.ktor.http.*
import love.forte.simbot.qguild.PrivateDomainOnly
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic
@@ -38,9 +38,9 @@ import kotlin.jvm.JvmStatic
@PrivateDomainOnly
public class DeleteMessageApi private constructor(
channelId: String, messageId: String, private val hidetip: Boolean? = null
-) : QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Delete, "/channels/{channel_id}/messages/{message_id}"
+) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
+ public companion object Factory : SimpleDeleteApiDescription(
+ "/channels/{channel_id}/messages/{message_id}"
) {
/**
@@ -54,18 +54,11 @@ public class DeleteMessageApi private constructor(
DeleteMessageApi(channelId, messageId, hidetip)
}
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
// /channels/{channel_id}/messages/{message_id}?hidetip=false
- private val path = arrayOf("channels", channelId, "messages", messageId)
+ override val path: Array = arrayOf("channels", channelId, "messages", messageId)
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- hidetip?.also { builder.parametersAppender.append("hidetip", it) }
+ override fun URLBuilder.buildUrl() {
+ hidetip?.also { parameters.append("hidetip", it.toString()) }
}
-
- override val body: Any?
- get() = null
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/GetMessageApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/GetMessageApi.kt
index 02c6d7fc..18592b40 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/GetMessageApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/GetMessageApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.message
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.Message
import kotlin.jvm.JvmStatic
@@ -43,12 +42,8 @@ public class GetMessageApi private constructor(channelId: String, messageId: Str
public fun create(channelId: String, messageId: String): GetMessageApi = GetMessageApi(channelId, messageId)
}
- private val path = arrayOf("channels", channelId, "messages", messageId)
+ override val path: Array = arrayOf("channels", channelId, "messages", messageId)
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = Message.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/MessageSendApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/MessageSendApi.kt
index cfe26473..1fa1b967 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/MessageSendApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/MessageSendApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -18,10 +18,7 @@
package love.forte.simbot.qguild.api.message
-import io.ktor.client.*
-import io.ktor.client.request.*
import io.ktor.client.request.forms.*
-import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.utils.io.core.*
import kotlinx.serialization.*
@@ -30,10 +27,11 @@ import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
-import love.forte.simbot.qguild.ErrInfo
-import love.forte.simbot.qguild.InternalApi
-import love.forte.simbot.qguild.QQGuildApiException
-import love.forte.simbot.qguild.api.*
+import love.forte.simbot.qguild.QGInternalApi
+import love.forte.simbot.qguild.QQGuild
+import love.forte.simbot.qguild.api.MessageAuditedException
+import love.forte.simbot.qguild.api.PostQQGuildApi
+import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.api.message.MessageSendApi.Body.Builder
import love.forte.simbot.qguild.message.ContentTextDecoder
import love.forte.simbot.qguild.message.ContentTextEncoder
@@ -134,93 +132,35 @@ import kotlin.jvm.JvmSynthetic
*/
public class MessageSendApi private constructor(
channelId: String,
- body: Body, // TencentMessageForSending || MultiPartFormDataContent
-) : QQGuildApi() {
+ private val _body: Body, // TencentMessageForSending || MultiPartFormDataContent
+) : PostQQGuildApi() {
public companion object Factory : SimplePostApiDescription(
"/channels/{channel_id}/messages"
) {
- /** 类似于 [io.ktor.serialization.kotlinx.json.DefaultJson] */
+ internal val FormDataHeader = headers {
+ append(HttpHeaders.ContentType, ContentType.MultiPart.FormData)
+ }
+
internal val defaultJson: Json
- get() = Json {
- encodeDefaults = true
- isLenient = true
- allowSpecialFloatingPointValues = true
- allowStructuredMapKeys = true
- prettyPrint = false
- useArrayPolymorphism = false
- }
+ get() = QQGuild.DefaultJson
/**
- * 构造 [MessageSendApi]
+ * 提供 [Body] 构造 [MessageSendApi]
*/
@JvmStatic
public fun create(channelId: String, body: Body): MessageSendApi = MessageSendApi(channelId, body)
}
- override val body: Any = body.toRealBody(defaultJson)
+ override fun createBody(): Any = _body.toRealBody(defaultJson)
- private val path = arrayOf("channels", channelId, "messages")
+ override val path: Array = arrayOf("channels", channelId, "messages")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = Message.serializer()
- override val method: HttpMethod
- get() = HttpMethod.Post
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- if (body is MultiPartFormDataContent) {
- builder.contentType = ContentType.MultiPart.FormData
- }
- }
-
- /**
- * 使用当前API发送消息
- *
- * @throws MessageAuditedException 当响应状态为表示消息审核的 `304023`、`304024` 时
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误(http状态码 !in 200 .. 300)
- */
- override suspend fun doRequest(client: HttpClient, server: Url, token: String, decoder: StringFormat): Message {
- return super.doRequest(client, server, token, decoder)
- }
-
- /**
- * 使用当前API发送消息
- *
- *
- * @throws MessageAuditedException 当响应状态为表示消息审核的 `304023`、`304024` 时
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误(http状态码 !in 200 .. 300)
- */
- override suspend fun doRequestRaw(client: HttpClient, server: Url, token: String): String {
- val resp: HttpResponse
- val text = requestForText(client, server, token) { resp = it }
-
- checkStatus(text, DefaultErrInfoDecoder, resp.status)
-
- if (text.isEmpty() && resp.status.isSuccess()) {
- return "{}"
- }
-
- if (resp.status == HttpStatusCode.Accepted) {
- // decode as error data
- val errorInfo = DefaultErrInfoDecoder.decodeFromString(ErrInfo.serializer(), text)
- // maybe audited
- if (MessageAuditedException.isAuditResultCode(errorInfo.code)) {
- throw MessageAuditedException(
- DefaultErrInfoDecoder.decodeFromJsonElement(MessageAudit.serializer(), errorInfo.data).messageAudit,
- errorInfo,
- resp.status.value,
- resp.status.description
- )
- }
+ override val headers: Headers
+ get() = if (body is MultiPartFormDataContent) FormDataHeader else Headers.Empty
- throw QQGuildApiException(errorInfo, resp.status.value, resp.status.description)
- }
-
- return text
- }
/**
* [MessageSendApi] 所需参数。详情参考 [文档](https://bot.q.qq.com/wiki/develop/api/openapi/message/post_messages.html#%E9%80%9A%E7%94%A8%E5%8F%82%E6%95%B0)
@@ -300,9 +240,54 @@ public class MessageSendApi private constructor(
* 各属性参考 [Body] 内同名属性。
*
*/
- @OptIn(InternalApi::class)
@Suppress("MemberVisibilityCanBePrivate")
- public class Builder : BaseMessageSendBodyBuilder() {
+ public class Builder {
+ /**
+ * [fileImage] 直接set时支持的类型:
+ *
+ * 所有平台:
+ * - [ByteArray]
+ * - [InputProvider]
+ * - [ByteReadPacket]
+ * - [ChannelProvider]
+ *
+ * JVM 平台:
+ * - `java.nio.Path`
+ * - `java.io.File`
+ * - `java.net.URL`
+ * - `java.net.URI`
+ */
+ public var fileImage: Any? = null
+ set(value) {
+ when (value) {
+ null -> {
+ field = value
+ }
+
+ is ByteArray -> {
+ field = value
+ }
+
+ is InputProvider -> {
+ field = value
+ }
+
+ is ByteReadPacket -> {
+ field = value
+ }
+
+ is ChannelProvider -> {
+ field = value
+ }
+
+ else -> {
+ checkFileImage(value)
+ field = value
+ }
+ }
+
+ }
+
public var content: String? = null
public var embed: Message.Embed? = null
public var ark: Message.Ark? = null
@@ -366,6 +351,12 @@ public class MessageSendApi private constructor(
public companion object {
+ /**
+ * 得到一个 [Builder]。
+ */
+ @JvmStatic
+ public fun builder(): Builder = Builder()
+
/**
* 构造一个 [Body].
*
@@ -401,20 +392,7 @@ public inline fun MessageSendApi.Factory.create(channelId: String, builder: Buil
create(channelId, MessageSendApi.Body.invoke(builder))
-/**
- * 提供一些需要由不同平台额外实现的基类。
- * 主要针对 `fileImage`。
- */
-@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
-@InternalApi
-public expect abstract class BaseMessageSendBodyBuilder() {
- public open var fileImage: Any?
- protected set
- /*
- * 追加额外的平台功能,但是不能有抽象方法
- */
-}
-
+internal expect fun checkFileImage(fileImage: Any)
// // TencentMessageForSending || MultiPartFormDataContent
/**
@@ -448,7 +426,6 @@ private const val FILE_IMAGE_PROPERTY_NAME = "file_image"
* - [resolveOther] support other platform type.
*/
-@OptIn(InternalApi::class)
private fun FormBuilder.appendFileImage(fileImage: Any?) {
when (fileImage) {
is ByteArray -> {
@@ -500,7 +477,7 @@ private fun FormBuilder.appendFileImage(fileImage: Any?) {
* 类型以外可能支持的类型。
*
*/
-@InternalApi
+@QGInternalApi
public expect fun FormBuilder.resolveOther(fileImage: Any?)
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/QGMessageForSending.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/QGMessageForSending.kt
index 3102e111..dae61e19 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/QGMessageForSending.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/QGMessageForSending.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -23,48 +23,49 @@ import love.forte.simbot.qguild.model.Message
import kotlin.jvm.JvmOverloads
+// TODO?
/**
* 用于发送的普通消息.
*
* _content, embed, ark, image/file_image, markdown 至少需要有一个字段,否则无法下发消息。_
*/
@Serializable
-public data class QGMessageForSending @JvmOverloads constructor(
+internal data class QGMessageForSending @JvmOverloads constructor(
/**
* 消息内容,文本内容,支持内嵌格式
*/
- public var content: String? = null,
+ var content: String? = null,
/**
* MessageEmbed embed 消息,一种特殊的 ark
*/
- public var embed: Message.Embed? = null,
+ var embed: Message.Embed? = null,
/**
* ark消息对象 ark 消息
*/
- public var ark: Message.Ark? = null,
+ var ark: Message.Ark? = null,
/**
* 图片url地址
*/
- public var image: String? = null,
+ var image: String? = null,
/**
* 要回复的消息id(Message.id), 在 CREATE_MESSAGE 事件中获取。带了 msg_id 视为被动回复消息,否则视为主动推送消息
*/
@SerialName("msg_id")
- public var msgId: String? = null,
+ var msgId: String? = null,
/**
* 选填,要回复的事件id, 在各事件对象中获取。
*/
@SerialName("event_id")
- public var eventId: String? = null,
+ var eventId: String? = null,
/**
* 选填,markdown 消息
*/
- public var markdown: Message.Markdown? = null,
+ var markdown: Message.Markdown? = null,
)
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/CreateDmsApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/CreateDmsApi.kt
index af232498..244f4a09 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/CreateDmsApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/CreateDmsApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,12 +17,10 @@
package love.forte.simbot.qguild.api.message.direct
-import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.api.PostQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.model.DirectMessageSession
import kotlin.jvm.JvmStatic
@@ -45,8 +43,8 @@ import kotlin.jvm.JvmStatic
* @author ForteScarlet
*/
public class CreateDmsApi private constructor(
- recipientId: String,
- sourceGuildId: String,
+ private val recipientId: String,
+ private val sourceGuildId: String,
) : PostQQGuildApi() {
public companion object Factory : SimplePostApiDescription(
"/users/@me/dms"
@@ -66,14 +64,13 @@ public class CreateDmsApi private constructor(
CreateDmsApi(recipientId, sourceGuildId)
}
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = DirectMessageSession.serializer()
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = pathSegments
- }
+ override val path: Array
+ get() = pathSegments
- override val body: Any = Body(recipientId, sourceGuildId)
+ override fun createBody(): Any = Body(recipientId, sourceGuildId)
@Serializable
private data class Body(
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DeleteDmsApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DeleteDmsApi.kt
index 32575e8f..4a1d6cd7 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DeleteDmsApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DeleteDmsApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -18,12 +18,10 @@
package love.forte.simbot.qguild.api.message.direct
import io.ktor.http.*
-import kotlinx.serialization.DeserializationStrategy
-import kotlinx.serialization.builtins.serializer
import love.forte.simbot.qguild.PrivateDomainOnly
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
+import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic
@@ -41,9 +39,9 @@ public class DeleteDmsApi private constructor(
guildId: String,
messageId: String,
private val hidetip: Boolean? = null,
-) : QQGuildApi() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Delete, "/dms/{guild_id}/messages/{message_id}"
+) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
+ public companion object Factory : SimpleDeleteApiDescription(
+ "/dms/{guild_id}/messages/{message_id}"
) {
/**
@@ -56,23 +54,11 @@ public class DeleteDmsApi private constructor(
@JvmOverloads
public fun create(guildId: String, messageId: String, hidetip: Boolean? = null): DeleteDmsApi =
DeleteDmsApi(guildId, messageId, hidetip)
-
}
- override val resultDeserializer: DeserializationStrategy
- get() = Unit.serializer()
-
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
- private val path = arrayOf("dms", guildId, "messages", messageId)
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- hidetip?.also { builder.parametersAppender.append("hidetip", it) }
+ override val path: Array = arrayOf("dms", guildId, "messages", messageId)
+ override fun URLBuilder.buildUrl() {
+ hidetip?.also { parameters.append("hidetip", it.toString()) }
}
-
- override val body: Any?
- get() = null
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DmsSendApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DmsSendApi.kt
index b883db1a..4f0a66dd 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DmsSendApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/direct/DmsSendApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,16 +17,11 @@
package love.forte.simbot.qguild.api.message.direct
-import io.ktor.client.*
-import io.ktor.client.request.*
import io.ktor.client.request.forms.*
-import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
-import kotlinx.serialization.StringFormat
-import love.forte.simbot.qguild.ErrInfo
-import love.forte.simbot.qguild.QQGuildApiException
-import love.forte.simbot.qguild.api.*
+import love.forte.simbot.qguild.api.PostQQGuildApi
+import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.api.message.MessageSendApi
import love.forte.simbot.qguild.api.message.toRealBody
import love.forte.simbot.qguild.model.Message
@@ -59,7 +54,7 @@ import kotlin.jvm.JvmSynthetic
*/
public class DmsSendApi private constructor(
guildId: String,
- body: MessageSendApi.Body, // TencentMessageForSending || MultiPartFormDataContent
+ private val _body: MessageSendApi.Body, // TencentMessageForSending || MultiPartFormDataContent
) : PostQQGuildApi() {
public companion object Factory : SimplePostApiDescription(
"/channels/{channel_id}/messages"
@@ -72,71 +67,15 @@ public class DmsSendApi private constructor(
public fun create(guildId: String, body: MessageSendApi.Body): DmsSendApi = DmsSendApi(guildId, body)
}
- override val body: Any = body.toRealBody(MessageSendApi.defaultJson)
+ override fun createBody(): Any = _body.toRealBody(MessageSendApi.defaultJson)
- private val path = arrayOf("dms", guildId, "messages")
+ override val path: Array = arrayOf("dms", guildId, "messages")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = Message.serializer()
- override val method: HttpMethod
- get() = HttpMethod.Post
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- if (body is MultiPartFormDataContent) {
- builder.contentType = ContentType.MultiPart.FormData
- }
- }
-
- /**
- * 使用当前API发送消息
- *
- * @throws MessageAuditedException 当响应状态为表示消息审核的 `304023`、`304024` 时
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误(http状态码 !in 200 .. 300)
- */
- override suspend fun doRequest(client: HttpClient, server: Url, token: String, decoder: StringFormat): Message {
- return super.doRequest(client, server, token, decoder)
- }
-
- /**
- * 使用当前API发送消息
- *
- *
- * @throws MessageAuditedException 当响应状态为表示消息审核的 `304023`、`304024` 时
- * @throws Exception see [HttpClient.request], 可能会抛出任何ktor请求过程中的异常。
- * @throws love.forte.simbot.qguild.QQGuildApiException 请求过程中出现了错误(http状态码 !in 200 .. 300)
- */
- override suspend fun doRequestRaw(client: HttpClient, server: Url, token: String): String {
- val resp: HttpResponse
- val text = requestForText(client, server, token) { resp = it }
-
- checkStatus(text, DefaultErrInfoDecoder, resp.status)
-
- if (text.isEmpty() && resp.status.isSuccess()) {
- return "{}"
- }
-
- if (resp.status == HttpStatusCode.Accepted) {
- // decode as error data
- val errorInfo = DefaultErrInfoDecoder.decodeFromString(ErrInfo.serializer(), text)
- // maybe audited
- if (MessageAuditedException.isAuditResultCode(errorInfo.code)) {
- throw MessageAuditedException(
- DefaultErrInfoDecoder.decodeFromJsonElement(MessageAudit.serializer(), errorInfo.data).messageAudit,
- errorInfo,
- resp.status.value,
- resp.status.description
- )
- }
-
- throw QQGuildApiException(errorInfo, resp.status.value, resp.status.description)
- }
-
- return text
- }
-
+ override val headers: Headers
+ get() = if (body is MultiPartFormDataContent) MessageSendApi.FormDataHeader else Headers.Empty
}
/**
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/setting/GetMessageSettingApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/setting/GetMessageSettingApi.kt
index 15c0fd93..71f5f035 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/setting/GetMessageSettingApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/message/setting/GetMessageSettingApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023. ForteScarlet.
+ * Copyright (c) 2023-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -19,7 +19,6 @@ package love.forte.simbot.qguild.api.message.setting
import kotlinx.serialization.DeserializationStrategy
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.MessageSetting
import kotlin.jvm.JvmStatic
@@ -43,12 +42,8 @@ public class GetMessageSettingApi private constructor(guildId: String) : GetQQGu
public fun create(guildId: String): GetMessageSettingApi = GetMessageSettingApi(guildId)
}
- private val path = arrayOf("guilds", guildId, "message", "setting")
+ override val path: Array = arrayOf("guilds", guildId, "message", "setting")
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = MessageSetting.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/AddMemberRoleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/AddMemberRoleApi.kt
index 4f289c0d..61323297 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/AddMemberRoleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/AddMemberRoleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,11 +17,10 @@
package love.forte.simbot.qguild.api.role
-import io.ktor.http.*
import kotlinx.serialization.Serializable
+import love.forte.simbot.qguild.api.PutQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimplePutApiDescription
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic
@@ -41,10 +40,10 @@ public class AddMemberRoleApi private constructor(
guildId: String,
userId: String,
roleId: String,
- channelId: String?,
-) : QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Put, "/guilds/{guild_id}/members/{user_id}/roles/{role_id}"
+ private val channelId: String?,
+) : QQGuildApiWithoutResult, PutQQGuildApi() {
+ public companion object Factory : SimplePutApiDescription(
+ "/guilds/{guild_id}/members/{user_id}/roles/{role_id}"
) {
/**
@@ -56,28 +55,20 @@ public class AddMemberRoleApi private constructor(
@JvmStatic
@JvmOverloads
public fun create(
- guildId: String,
- userId: String,
- roleId: String,
+ guildId: String, userId: String, roleId: String,
channelId: String? = null
): AddMemberRoleApi =
AddMemberRoleApi(guildId, userId, roleId, channelId)
}
- private val path = arrayOf(
+ override val path: Array = arrayOf(
"guilds", guildId,
"members", userId,
"roles", roleId,
)
- override val method: HttpMethod
- get() = HttpMethod.Put
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any? = channelId?.let { cid -> Body(ChannelId(cid)) }
+ override fun createBody(): Any? =
+ channelId?.let { cid -> Body(ChannelId(cid)) }
@Serializable
private data class Body(val channel: ChannelId)
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/CreateGuildRoleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/CreateGuildRoleApi.kt
index 52282abc..c6a39521 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/CreateGuildRoleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/CreateGuildRoleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -22,7 +22,6 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.qguild.ApiModel
import love.forte.simbot.qguild.api.PostQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimplePostApiDescription
import love.forte.simbot.qguild.model.ColorIntSerializer
import love.forte.simbot.qguild.model.Role
@@ -68,16 +67,12 @@ public class CreateGuildRoleApi private constructor(
CreateGuildRoleApi(guildId, NewBody(name, color, hoist))
}
- private val path = arrayOf("guilds", guildId, "roles")
+ override val path: Array = arrayOf("guilds", guildId, "roles")
- override val resultDeserializer: DeserializationStrategy get() = GuildRoleCreated.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any get() = _body
+ override val resultDeserializationStrategy: DeserializationStrategy
+ get() = GuildRoleCreated.serializer()
+ override fun createBody(): Any? = _body
@Serializable
private data class NewBody(
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/DeleteGuildRoleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/DeleteGuildRoleApi.kt
index 925fbd57..3ec57960 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/DeleteGuildRoleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/DeleteGuildRoleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,9 @@
package love.forte.simbot.qguild.api.role
-import io.ktor.http.*
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmStatic
/**
@@ -32,26 +31,19 @@ import kotlin.jvm.JvmStatic
* 需要使用的 `token` 对应的用户具备删除身份组权限。如果是机器人,要求被添加为管理员。
* @author ForteScarlet
*/
-public class DeleteGuildRoleApi(guildId: String, roleId: String) : QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Delete, "/guilds/{guild_id}/roles/{role_id}"
+public class DeleteGuildRoleApi(guildId: String, roleId: String) :
+ QQGuildApiWithoutResult, DeleteQQGuildApi() {
+ public companion object Factory : SimpleDeleteApiDescription(
+ "/guilds/{guild_id}/roles/{role_id}"
) {
-
+
/**
* 构造 [DeleteGuildRoleApi]
*/
@JvmStatic
- public fun create(guildId: String, roleId: String): DeleteGuildRoleApi = DeleteGuildRoleApi(guildId, roleId)
+ public fun create(guildId: String, roleId: String): DeleteGuildRoleApi =
+ DeleteGuildRoleApi(guildId, roleId)
}
- private val path = arrayOf("guilds", guildId, "roles", roleId)
-
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any? get() = null
+ override val path: Array = arrayOf("guilds", guildId, "roles", roleId)
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/GetGuildRoleListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/GetGuildRoleListApi.kt
index 368d7d63..ed382b4e 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/GetGuildRoleListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/GetGuildRoleListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,10 +17,12 @@
package love.forte.simbot.qguild.api.role
-import kotlinx.serialization.*
-import love.forte.simbot.*
-import love.forte.simbot.qguild.*
-import love.forte.simbot.qguild.api.*
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import love.forte.simbot.qguild.ApiModel
+import love.forte.simbot.qguild.api.GetQQGuildApi
+import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.Role
import kotlin.jvm.JvmStatic
@@ -44,14 +46,9 @@ public class GetGuildRoleListApi private constructor(guildId: String) : GetQQGui
public fun create(guildId: String): GetGuildRoleListApi = GetGuildRoleListApi(guildId)
}
- private val path = arrayOf("guilds", guildId, "roles")
- override val resultDeserializer: DeserializationStrategy get() = GuildRoleList.serializer()
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
-
+ override val path: Array = arrayOf("guilds", guildId, "roles")
+ override val resultDeserializationStrategy: DeserializationStrategy
+ get() = GuildRoleList.serializer()
}
/**
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/ModifyGuildRoleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/ModifyGuildRoleApi.kt
index fb997ae3..a1a3ed32 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/ModifyGuildRoleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/ModifyGuildRoleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -21,8 +21,7 @@ import io.ktor.http.*
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import love.forte.simbot.qguild.api.QQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
+import love.forte.simbot.qguild.api.PatchQQGuildApi
import love.forte.simbot.qguild.api.SimpleApiDescription
import love.forte.simbot.qguild.model.ColorIntSerializer
import love.forte.simbot.qguild.model.Role
@@ -42,7 +41,7 @@ import kotlin.jvm.JvmStatic
public class ModifyGuildRoleApi private constructor(
guildId: String, roleId: String,
private val _body: Body,
-) : QQGuildApi() {
+) : PatchQQGuildApi() {
public companion object Factory : SimpleApiDescription(
HttpMethod.Patch, "/guilds/{guild_id}/roles/{role_id}"
) {
@@ -64,22 +63,19 @@ public class ModifyGuildRoleApi private constructor(
}
- private val path = arrayOf("guilds", guildId, "roles", roleId)
+ override val path: Array = arrayOf("guilds", guildId, "roles", roleId)
- override val resultDeserializer: DeserializationStrategy
+ override val resultDeserializationStrategy: DeserializationStrategy
get() = GuildRoleModified.serializer()
- override val method: HttpMethod
- get() = HttpMethod.Patch
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
-
- override val body: Any get() = _body
+ override fun createBody(): Any = _body
@Serializable
- private data class Body(val name: String?, @Serializable(ColorIntSerializer::class) val color: Int?, val hoist: Int?) {
+ private data class Body(
+ val name: String?,
+ @Serializable(ColorIntSerializer::class) val color: Int?,
+ val hoist: Int?
+ ) {
init {
require(name != null || color != null || hoist != null) {
"At least one of the parameters should not be null"
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/RemoveMemberRoleApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/RemoveMemberRoleApi.kt
index 6f82c81c..d777c335 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/RemoveMemberRoleApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/role/RemoveMemberRoleApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,11 +17,10 @@
package love.forte.simbot.qguild.api.role
-import io.ktor.http.*
import kotlinx.serialization.Serializable
+import love.forte.simbot.qguild.api.DeleteQQGuildApi
import love.forte.simbot.qguild.api.QQGuildApiWithoutResult
-import love.forte.simbot.qguild.api.RouteInfoBuilder
-import love.forte.simbot.qguild.api.SimpleApiDescription
+import love.forte.simbot.qguild.api.SimpleDeleteApiDescription
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic
@@ -41,11 +40,11 @@ public class RemoveMemberRoleApi private constructor(
userId: String,
roleId: String,
channelId: String?,
-) : QQGuildApiWithoutResult() {
- public companion object Factory : SimpleApiDescription(
- HttpMethod.Delete, "/guilds/{guild_id}/members/{user_id}/roles/{role_id}"
+) : QQGuildApiWithoutResult, DeleteQQGuildApi() {
+ public companion object Factory : SimpleDeleteApiDescription(
+ "/guilds/{guild_id}/members/{user_id}/roles/{role_id}"
) {
-
+
/**
* 构造 [RemoveMemberRoleApi]
*
@@ -61,29 +60,19 @@ public class RemoveMemberRoleApi private constructor(
channelId: String? = null,
): RemoveMemberRoleApi = RemoveMemberRoleApi(guildId, userId, roleId, channelId)
}
-
- private val path = arrayOf(
- "guilds",
- guildId,
- "members",
- userId,
- "roles",
- roleId,
+
+ override val path: Array = arrayOf(
+ "guilds", guildId,
+ "members", userId,
+ "roles", roleId,
)
-
- override val method: HttpMethod
- get() = HttpMethod.Delete
-
- override fun route(builder: RouteInfoBuilder) {
- builder.apiPath = path
- }
- override val body: Any? = channelId?.let { cid -> Body(ChannelId(cid)) }
+ override val body: Any? =
+ channelId?.let { cid -> Body(ChannelId(cid)) }
@Serializable
private data class Body(val channel: ChannelId)
@Serializable
private data class ChannelId(val id: String)
-
}
diff --git a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/user/GetBotGuildListApi.kt b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/user/GetBotGuildListApi.kt
index a354eb3f..fc64edfc 100644
--- a/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/user/GetBotGuildListApi.kt
+++ b/simbot-component-qq-guild-api/src/commonMain/kotlin/love/forte/simbot/qguild/api/user/GetBotGuildListApi.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2023. ForteScarlet.
+ * Copyright (c) 2022-2024. ForteScarlet.
*
* This file is part of simbot-component-qq-guild.
*
@@ -17,12 +17,12 @@
package love.forte.simbot.qguild.api.user
+import io.ktor.http.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.builtins.ListSerializer
import love.forte.simbot.qguild.api.GetQQGuildApi
-import love.forte.simbot.qguild.api.RouteInfoBuilder
import love.forte.simbot.qguild.api.SimpleGetApiDescription
import love.forte.simbot.qguild.model.SimpleGuild
import kotlin.jvm.JvmOverloads
@@ -106,30 +106,28 @@ public class GetBotGuildListApi private constructor(
public fun createByAfter(after: String, limit: Int = DEFAULT_LIMIT): GetBotGuildListApi =
create(before = null, after = after, limit)
-
}
-
- override val resultDeserializer: DeserializationStrategy>
+ override val resultDeserializationStrategy: DeserializationStrategy