ErisPulse 2.8.0.dev1__tar.gz → 2.8.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/.gitignore +2 -0
  2. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/PKG-INFO +9 -4
  3. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/README.pypi.md +2 -2
  4. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/pyproject.toml +11 -3
  5. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/create.py +28 -2
  6. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/init.py +4 -116
  7. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/run.py +1 -1
  8. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/config_wizard.py +26 -4
  9. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/package_manager.py +18 -97
  10. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/scaffold_text.py +10 -0
  11. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/__init__.py +30 -1
  12. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/adapter.py +84 -8
  13. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/config_schema.py +336 -79
  14. erispulse-2.8.1/src/ErisPulse/Core/Bases/errors.py +328 -0
  15. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/kv_builder.py +28 -22
  16. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/module.py +13 -5
  17. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/router.py +3 -1
  18. erispulse-2.8.1/src/ErisPulse/Core/Bases/sql_base.py +1612 -0
  19. erispulse-2.8.1/src/ErisPulse/Core/Bases/storage.py +1171 -0
  20. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/__init__.py +17 -0
  21. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/base.py +164 -108
  22. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/command.py +191 -123
  23. erispulse-2.8.1/src/ErisPulse/Core/Event/interaction.py +924 -0
  24. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/overrides.py +114 -10
  25. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/wrapper.py +585 -24
  26. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/__init__.py +34 -1
  27. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/adapter.py +169 -10
  28. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/client.py +35 -10
  29. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/config.py +303 -63
  30. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/constants.py +158 -0
  31. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/__init__.py +25 -0
  32. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/en.py +85 -3
  33. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/ja.py +85 -3
  34. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/ru.py +85 -3
  35. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/zh_cn.py +85 -3
  36. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/zh_tw.py +85 -3
  37. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/lifecycle.py +162 -33
  38. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/module.py +520 -19
  39. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/router.py +31 -12
  40. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/scope.py +149 -13
  41. erispulse-2.8.1/src/ErisPulse/Core/storage/__init__.py +89 -0
  42. erispulse-2.8.1/src/ErisPulse/Core/storage/mysql.py +279 -0
  43. erispulse-2.8.1/src/ErisPulse/Core/storage/postgres.py +282 -0
  44. erispulse-2.8.1/src/ErisPulse/Core/storage/sqlite.py +261 -0
  45. erispulse-2.8.1/src/ErisPulse/Core/transcript.py +375 -0
  46. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/__init__.py +24 -7
  47. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/bases/finder.py +5 -2
  48. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/adapter.py +20 -4
  49. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/bases/loader.py +90 -1
  50. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/module.py +48 -13
  51. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/plugin_folder.py +29 -1
  52. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/strict.py +1 -17
  53. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/__init__.py +21 -0
  54. erispulse-2.8.1/src/ErisPulse/runtime/context.py +200 -0
  55. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/diagnostics.py +11 -2
  56. erispulse-2.8.1/src/ErisPulse/runtime/example_config.py +266 -0
  57. {erispulse-2.8.0.dev1/src/ErisPulse/CLI/utils → erispulse-2.8.1/src/ErisPulse/runtime}/file_watcher.py +1 -1
  58. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/frame_config.py +68 -19
  59. erispulse-2.8.1/src/ErisPulse/runtime/owner_cleanup.py +171 -0
  60. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/plugin_reload.py +2 -2
  61. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/tasks.py +19 -1
  62. erispulse-2.8.1/src/ErisPulse/runtime/version.py +166 -0
  63. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/sdk.py +95 -6
  64. erispulse-2.8.0.dev1/src/ErisPulse/Core/Bases/errors.py +0 -137
  65. erispulse-2.8.0.dev1/src/ErisPulse/Core/Bases/storage.py +0 -534
  66. erispulse-2.8.0.dev1/src/ErisPulse/Core/storage.py +0 -1520
  67. erispulse-2.8.0.dev1/src/ErisPulse/runtime/context.py +0 -104
  68. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/LICENSE +0 -0
  69. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/__init__.py +0 -0
  70. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/base.py +0 -0
  71. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/cli.py +0 -0
  72. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/__init__.py +0 -0
  73. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/config.py +0 -0
  74. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/doctor.py +0 -0
  75. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/install.py +0 -0
  76. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/language.py +0 -0
  77. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/list.py +0 -0
  78. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
  79. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/self_update.py +0 -0
  80. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/types.py +0 -0
  81. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
  82. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
  83. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/console.py +0 -0
  84. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/constants.py +0 -0
  85. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/hints.py +0 -0
  86. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/__init__.py +0 -0
  87. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
  88. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/en.py +0 -0
  89. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/ja.py +0 -0
  90. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/ru.py +0 -0
  91. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +0 -0
  92. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +0 -0
  93. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/registry.py +0 -0
  94. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/__init__.py +0 -0
  95. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/CLI/utils/display.py +0 -0
  96. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/client.py +0 -0
  97. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/converter.py +0 -0
  98. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/i18n_schema.py +0 -0
  99. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/manager.py +0 -0
  100. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
  101. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/send_rules.py +0 -0
  102. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Bases/websocket.py +0 -0
  103. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/message.py +0 -0
  104. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/message_builder.py +0 -0
  105. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/meta.py +0 -0
  106. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/notice.py +0 -0
  107. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/request.py +0 -0
  108. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/Event/session_type.py +0 -0
  109. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/__init__.py +0 -0
  110. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/error.css +0 -0
  111. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/error.html +0 -0
  112. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/root.css +0 -0
  113. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/assets/root.html +0 -0
  114. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/constants.py +0 -0
  115. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
  116. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/logger.py +0 -0
  117. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/master.py +0 -0
  118. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/Core/text_match.py +0 -0
  119. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/__main__.py +0 -0
  120. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/__init__.py +0 -0
  121. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/adapter.py +0 -0
  122. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/bases/__init__.py +0 -0
  123. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/finders/module.py +0 -0
  124. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/__init__.py +0 -0
  125. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/bases/__init__.py +0 -0
  126. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/loaders/strategy.py +0 -0
  127. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/py.typed +0 -0
  128. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/config_schema.py +0 -0
  129. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/exceptions.py +0 -0
  130. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/hints.py +0 -0
  131. {erispulse-2.8.0.dev1 → erispulse-2.8.1}/src/ErisPulse/runtime/memory.py +0 -0
@@ -3,6 +3,7 @@ devs/videos
3
3
  main.py
4
4
  plugins/
5
5
  venvs
6
+ config.full.example
6
7
  config.toml
7
8
  uv.lock
8
9
  snapshots/
@@ -16,6 +17,7 @@ config/config.db
16
17
  config/config.db-journal
17
18
  config/config.db-wal
18
19
  config/config.db-shm
20
+ .erispulse_config.lock
19
21
 
20
22
  # site-packages
21
23
  config/.packages
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ErisPulse
3
- Version: 2.8.0.dev1
3
+ Version: 2.8.1
4
4
  Summary: Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署
5
5
  Project-URL: Homepage, https://github.com/ErisPulse/ErisPulse
6
6
  Project-URL: Documentation, https://www.erisdev.com#docs
@@ -29,11 +29,16 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
29
29
  Classifier: Typing :: Typed
30
30
  Requires-Python: >=3.10
31
31
  Requires-Dist: aiohttp>=3.9.0
32
+ Requires-Dist: aiosqlite>=0.20.0
32
33
  Requires-Dist: fastapi>=0.116.1
33
34
  Requires-Dist: rich>=13.0.0
34
- Requires-Dist: toml>=0.10.2
35
+ Requires-Dist: tomlkit>=0.15.1
35
36
  Requires-Dist: uvicorn>=0.30.0
36
37
  Requires-Dist: websockets>=12.0
38
+ Provides-Extra: mysql
39
+ Requires-Dist: aiomysql>=0.2.0; extra == 'mysql'
40
+ Provides-Extra: postgres
41
+ Requires-Dist: asyncpg>=0.29.0; extra == 'postgres'
37
42
  Provides-Extra: test
38
43
  Requires-Dist: httpx>=0.24.0; extra == 'test'
39
44
  Requires-Dist: pytest-asyncio>=0.21.0; extra == 'test'
@@ -44,8 +49,6 @@ Requires-Dist: pytest-xdist>=3.0.0; extra == 'test'
44
49
  Requires-Dist: pytest>=7.0.0; extra == 'test'
45
50
  Description-Content-Type: text/markdown
46
51
 
47
- ![ErisPulse](https://raw.githubusercontent.com/ErisPulse/ErisPulse/main/.github/assets/mascot-hero.png)
48
-
49
52
  # ErisPulse
50
53
 
51
54
  **Write once, deploy on multiple platforms.**
@@ -54,6 +57,8 @@ An event-driven, multi-platform chatbot development framework based on the OneBo
54
57
 
55
58
  [![PyPI](https://img.shields.io/pypi/v/ErisPulse?style=for-the-badge&logo=pypi&logoColor=white)](https://pypi.org/project/ErisPulse/)
56
59
  [![Python](https://img.shields.io/badge/Python-3.10+-FFD43B?style=for-the-badge&logo=python&logoColor=blue)](https://pypi.org/project/ErisPulse/)
60
+ [![OneBot 11](https://img.shields.io/badge/OneBot-11-black?style=for-the-badge)](https://github.com/botuniverse/onebot-11)
61
+ [![OneBot 12](https://img.shields.io/badge/OneBot-12-black?style=for-the-badge)](https://12.onebot.dev/)
57
62
  [![License](https://img.shields.io/badge/License-MIT-blue?style=for-the-badge)](https://github.com/ErisPulse/ErisPulse/blob/main/LICENSE)
58
63
  [![Docs](https://img.shields.io/badge/docs-erisdev.com-FF6B9D?style=for-the-badge&logo=bookstack&logoColor=white)](https://www.erisdev.com)
59
64
  [![Stars](https://img.shields.io/github/stars/ErisPulse/ErisPulse?style=for-the-badge&logo=github&color=brightgreen)](https://github.com/ErisPulse/ErisPulse)
@@ -1,5 +1,3 @@
1
- ![ErisPulse](https://raw.githubusercontent.com/ErisPulse/ErisPulse/main/.github/assets/mascot-hero.png)
2
-
3
1
  # ErisPulse
4
2
 
5
3
  **Write once, deploy on multiple platforms.**
@@ -8,6 +6,8 @@ An event-driven, multi-platform chatbot development framework based on the OneBo
8
6
 
9
7
  [![PyPI](https://img.shields.io/pypi/v/ErisPulse?style=for-the-badge&logo=pypi&logoColor=white)](https://pypi.org/project/ErisPulse/)
10
8
  [![Python](https://img.shields.io/badge/Python-3.10+-FFD43B?style=for-the-badge&logo=python&logoColor=blue)](https://pypi.org/project/ErisPulse/)
9
+ [![OneBot 11](https://img.shields.io/badge/OneBot-11-black?style=for-the-badge)](https://github.com/botuniverse/onebot-11)
10
+ [![OneBot 12](https://img.shields.io/badge/OneBot-12-black?style=for-the-badge)](https://12.onebot.dev/)
11
11
  [![License](https://img.shields.io/badge/License-MIT-blue?style=for-the-badge)](https://github.com/ErisPulse/ErisPulse/blob/main/LICENSE)
12
12
  [![Docs](https://img.shields.io/badge/docs-erisdev.com-FF6B9D?style=for-the-badge&logo=bookstack&logoColor=white)](https://www.erisdev.com)
13
13
  [![Stars](https://img.shields.io/github/stars/ErisPulse/ErisPulse?style=for-the-badge&logo=github&color=brightgreen)](https://github.com/ErisPulse/ErisPulse)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ErisPulse"
7
- version = "2.8.0-dev.1"
7
+ version = "2.8.1"
8
8
  description = "Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署"
9
9
  readme = "README.pypi.md"
10
10
  requires-python = ">=3.10"
@@ -61,13 +61,14 @@ classifiers = [
61
61
 
62
62
  dependencies = [
63
63
  "rich>=13.0.0",
64
- "toml>=0.10.2",
65
-
64
+ "tomlkit>=0.15.1",
66
65
  # network 相关
67
66
  "websockets>=12.0",
68
67
  "aiohttp>=3.9.0",
69
68
  "fastapi>=0.116.1",
70
69
  "uvicorn>=0.30.0",
70
+ # storage 相关(默认 SQLite 后端异步驱动,开箱即用)
71
+ "aiosqlite>=0.20.0",
71
72
  ]
72
73
 
73
74
  [project.urls]
@@ -79,6 +80,13 @@ Issues = "https://github.com/ErisPulse/ErisPulse/issues"
79
80
  Changelog = "https://github.com/ErisPulse/ErisPulse/blob/main/CHANGELOG.md"
80
81
 
81
82
  [project.optional-dependencies]
83
+ # 存储后端可选驱动:pip install ErisPulse[mysql] / ErisPulse[postgres]
84
+ mysql = [
85
+ "aiomysql>=0.2.0",
86
+ ]
87
+ postgres = [
88
+ "asyncpg>=0.29.0",
89
+ ]
82
90
  test = [
83
91
  "pytest>=7.0.0",
84
92
  "pytest-cov>=4.0.0",
@@ -86,7 +86,11 @@ class Main(BaseModule):
86
86
  # {text[module.config_hint]}
87
87
  @dataclass
88
88
  class ConfigClass(BaseConfig):
89
- \"\"\"{text[module.config_doc]}\"\"\"
89
+ \"\"\"
90
+ {text[module.config_doc]}
91
+
92
+ :ivar advanced_threshold: 高级阈值(docstring :ivar: 声明即为字段描述,无需 metadata)
93
+ \"\"\"
90
94
 
91
95
  enabled: bool = field(
92
96
  default=True,
@@ -94,6 +98,11 @@ class Main(BaseModule):
94
98
  \"description\": {{\"i18n\": \"module.{name}.enabled\", \"default\": \"Enable module\"}},
95
99
  }},
96
100
  )
101
+ # example 字段:默认不写入 config.toml(仅记录在 config.full.example,用户按需启用)
102
+ advanced_threshold: int = field(
103
+ default=100,
104
+ metadata={{\"example\": True, \"min\": 0}},
105
+ )
97
106
 
98
107
  # {text[module.i18n_hint]}
99
108
  class I18nClass(BaseI18n):
@@ -157,8 +166,13 @@ class Main(BaseModule):
157
166
  description={{\"i18n\": \"module.{name}.meta.description\", \"default\": \"{name} module\"}},
158
167
  version=\"0.1.0\",
159
168
  author=\"ErisDev\",
169
+ # 最低 SDK 版本(可选):不满足时框架在加载期明确报错并跳过本模块
170
+ min_sdk_version=\"2.8.0\",
160
171
  group=\"default\",
161
172
  tags=[\"{name}\"],
173
+ # 对外服务白名单(可选):声明后其他模块可经 sdk.module.call() 调用这些方法;
174
+ # 缺省时公开方法全开放(限制由用户通过 scope.actions 配置)
175
+ # services=[\"get_welcome_message\"],
162
176
  )
163
177
 
164
178
  @staticmethod
@@ -285,10 +299,17 @@ class {name}(BaseAdapter):
285
299
  depends: ClassVar[dict] = {{}}
286
300
  optional_modules: ClassVar[list] = []
287
301
 
302
+ # 声明所需最低 SDK 版本:不满足时框架在加载期明确报错并跳过本适配器(可选)
303
+ min_sdk_version = "2.8.0"
304
+
288
305
  # {text[adapter.config_hint]}
289
306
  @dataclass
290
307
  class ConfigClass(BaseConfig):
291
- \"\"\"{text[adapter.config_doc]}\"\"\"
308
+ \"\"\"
309
+ {text[adapter.config_doc]}
310
+
311
+ :ivar request_timeout: 请求超时秒数(docstring :ivar: 声明即为字段描述,无需 metadata)
312
+ \"\"\"
292
313
 
293
314
  endpoint: str = field(
294
315
  default="https://api.example.com",
@@ -307,6 +328,11 @@ class {name}(BaseAdapter):
307
328
  "ui": {{"widget": "password", "group": "basic", "order": 2}},
308
329
  }},
309
330
  )
331
+ # example 字段:默认不写入 config.toml(仅记录在 config.full.example,用户按需启用)
332
+ request_timeout: int = field(
333
+ default=30,
334
+ metadata={{"example": True, "min": 1, "max": 300}},
335
+ )
310
336
 
311
337
  # {text[adapter.i18n_hint]}
312
338
  class I18nClass(BaseI18n):
@@ -175,128 +175,16 @@ class InitCommand(Command):
175
175
  """
176
176
  生成完整的配置示例文本
177
177
 
178
- 配置注释跟随 CLI 语言(缺失语言回退英文),
179
- 文案键集中于 ``scaffold_text`` 的 ``cfg.*`` 键族维护。
178
+ 生成逻辑收归 ``ErisPulse.runtime.example_config``(框架运行与 CLI 共用:
179
+ 含自维护首行标记、静态框架段与已安装组件声明式段)。此处仅保留调用入口。
180
180
 
181
181
  :param adapter_list: [list] 适配器名称列表 (默认: None)
182
182
  :return: [str] 完整配置示例字符串
183
183
  """
184
- from ..utils.scaffold_text import ScaffoldText
185
-
186
- st = ScaffoldText()
187
- lines = [
188
- st.t("cfg.header.title"),
189
- st.t("cfg.header.desc"),
190
- st.t("cfg.header.usage"),
191
- "",
192
- st.t("cfg.section.server"),
193
- "",
194
- "[ErisPulse.server]",
195
- f'host = "0.0.0.0" # {st.t("cfg.server.host")}',
196
- f"port = 8000 # {st.t('cfg.server.port')}",
197
- f"auto_start = true # {st.t('cfg.server.auto_start')}",
198
- f'ssl_certfile = "config/ssl/cert.pem" # {st.t("cfg.server.ssl_certfile")}',
199
- f'ssl_keyfile = "config/ssl/key.pem" # {st.t("cfg.server.ssl_keyfile")}',
200
- st.t("cfg.server.ssl_inline_hint"),
201
- '# ssl_cert = """-----BEGIN CERTIFICATE-----',
202
- "# ...",
203
- '# -----END CERTIFICATE-----"""',
204
- '# ssl_key = """-----BEGIN PRIVATE KEY-----',
205
- "# ...",
206
- '# -----END PRIVATE KEY-----"""',
207
- "",
208
- st.t("cfg.section.logger"),
209
- "",
210
- "[ErisPulse.logger]",
211
- f'level = "INFO" # {st.t("cfg.logger.level")}',
212
- f"log_files = [] # {st.t('cfg.logger.log_files')}",
213
- f'log_dir = "" # {st.t("cfg.logger.log_dir")}',
214
- f'log_rotation = "size" # {st.t("cfg.logger.log_rotation")}',
215
- f"log_max_size_mb = 10 # {st.t('cfg.logger.log_max_size_mb')}",
216
- f"log_backup_count = 5 # {st.t('cfg.logger.log_backup_count')}",
217
- f'log_rotation_when = "midnight" # {st.t("cfg.logger.log_rotation_when")}',
218
- f"memory_limit = 1000 # {st.t('cfg.logger.memory_limit')}",
219
- "",
220
- st.t("cfg.section.storage"),
221
- "",
222
- "[ErisPulse.storage]",
223
- f"use_global_db = false # {st.t('cfg.storage.use_global_db')}",
224
- "",
225
- st.t("cfg.section.event"),
226
- "",
227
- "[ErisPulse.event.message]",
228
- f"ignore_self = true # {st.t('cfg.event.ignore_self')}",
229
- "",
230
- "[ErisPulse.event.command]",
231
- f'prefix = "/" # {st.t("cfg.command.prefix")}',
232
- f"case_sensitive = true # {st.t('cfg.command.case_sensitive')}",
233
- f"allow_space_prefix = false # {st.t('cfg.command.allow_space_prefix')}",
234
- f"must_at_bot = false # {st.t('cfg.command.must_at_bot')}",
235
- "",
236
- st.t("cfg.section.framework"),
237
- "",
238
- "[ErisPulse.framework]",
239
- f"enable_lazy_loading = true # {st.t('cfg.framework.enable_lazy_loading')}",
240
- f'plugins_dir = "plugins" # {st.t("cfg.framework.plugins_dir")}',
241
- f"uninit_timeout = 30 # {st.t('cfg.framework.uninit_timeout')}",
242
- f" {st.t('cfg.framework.uninit_timeout_line1')}",
243
- f" {st.t('cfg.framework.uninit_timeout_line2')}",
244
- f"strict_mode = false # {st.t('cfg.framework.strict_mode')}",
245
- f"strict_mode_exceptions = {{ modules = [], adapters = [] }} # {st.t('cfg.framework.strict_mode_exceptions')}",
246
- f"handler_max_concurrency = 64 # {st.t('cfg.framework.handler_max_concurrency')}",
247
- f"proactive_gc_interval = 300 # {st.t('cfg.framework.proactive_gc_interval')}",
248
- f"proactive_gc_generation = 2 # {st.t('cfg.framework.proactive_gc_generation')}",
249
- f"proactive_gc_full_every = 10 # {st.t('cfg.framework.proactive_gc_full_every')}",
250
- f"proactive_gc_memory_growth_mb = 100 # {st.t('cfg.framework.proactive_gc_memory_growth_mb')}",
251
- f"proactive_gc_idle_only = true # {st.t('cfg.framework.proactive_gc_idle_only')}",
252
- f"proactive_gc_gen0_min = 100 # {st.t('cfg.framework.proactive_gc_gen0_min')}",
253
- f"offline_bot_expiry = 3600 # {st.t('cfg.framework.offline_bot_expiry')}",
254
- "",
255
- st.t("cfg.section.router"),
256
- "",
257
- "[ErisPulse.router.cors]",
258
- "enabled = false",
259
- 'allow_origins = ["*"]',
260
- 'allow_methods = ["*"]',
261
- 'allow_headers = ["*"]',
262
- "allow_credentials = false",
263
- "max_age = 600",
264
- "",
265
- "[ErisPulse.router.security]",
266
- "enabled = false",
267
- "",
268
- "[ErisPulse.router.security.headers]",
269
- 'X-Content-Type-Options = "nosniff"',
270
- 'X-Frame-Options = "DENY"',
271
- "",
272
- st.t("cfg.section.adapter_status"),
273
- "",
274
- "[ErisPulse.adapters.status]",
275
- ]
276
-
277
- if adapter_list:
278
- lines.extend(f"# {adapter} = false" for adapter in adapter_list)
279
- else:
280
- lines.extend(
281
- [
282
- "# yunhu = false",
283
- "# telegram = false",
284
- "# onebot11 = false",
285
- ]
286
- )
184
+ from ErisPulse.runtime.example_config import render_full_example
287
185
 
288
- lines.extend(
289
- [
290
- "",
291
- st.t("cfg.section.module_status"),
292
- "",
293
- "[ErisPulse.modules.status]",
294
- "# MyModule = true",
295
- "",
296
- ]
297
- )
186
+ return render_full_example(adapter_list=adapter_list)
298
187
 
299
- return "\n".join(lines)
300
188
 
301
189
  async def _fetch_available_adapters(self):
302
190
  """
@@ -16,11 +16,11 @@ from pathlib import Path
16
16
 
17
17
  from rich.panel import Panel
18
18
 
19
+ from ...runtime.file_watcher import FileSystemEventHandler, PollingObserver
19
20
  from ..base import Command
20
21
  from ..console import console
21
22
  from ..constants import ENV_SUPERVISED, HARD_RESTART_EXIT_CODE
22
23
  from ..i18n import i18n
23
- from ..utils.file_watcher import FileSystemEventHandler, PollingObserver
24
24
 
25
25
 
26
26
  class ReloadHandler(FileSystemEventHandler):
@@ -524,6 +524,9 @@ def fill_config_fields(config_class, current_values: dict) -> dict:
524
524
  """
525
525
  渲染整个配置类的表单并收集用户输入
526
526
 
527
+ ``example`` 字段不进入向导(默认值不落盘,仅记录在 config.full.example);
528
+ 嵌套 dataclass 字段(schema 含 ``fields`` 子树)递归渲染为子表单。
529
+
527
530
  :param config_class: dataclass 配置类
528
531
  :param current_values: 当前存储的配置字典(作为各字段初值)
529
532
  :return: 收集后的配置字典
@@ -531,12 +534,31 @@ def fill_config_fields(config_class, current_values: dict) -> dict:
531
534
  from ErisPulse.Core.Bases.config_schema import resolve_config_schema
532
535
 
533
536
  schema = resolve_config_schema(config_class)
534
- current_store = dict(current_values or {})
535
- values = dict(current_store)
536
- for name, field_schema in _sort_fields(schema.get("fields", {})):
537
+ values = dict(current_values or {})
538
+ _fill_from_schema_fields(schema.get("fields", {}), values)
539
+ return values
540
+
541
+
542
+ def _fill_from_schema_fields(fields_dict: dict, values: dict) -> None:
543
+ """
544
+ {!--< internal-use >!--}
545
+ 按 schema 字段树渲染表单并就地收集到 values(嵌套子树递归)
546
+ """
547
+ current_store = dict(values)
548
+ for name, field_schema in _sort_fields(fields_dict):
549
+ if field_schema.get("example") and name not in current_store:
550
+ # example 字段仅当用户已显式设置时保留原值,不主动询问
551
+ continue
552
+ nested_fields = field_schema.get("fields")
553
+ if isinstance(nested_fields, dict):
554
+ sub_values = current_store.get(name)
555
+ if not isinstance(sub_values, dict):
556
+ sub_values = {}
557
+ _fill_from_schema_fields(nested_fields, sub_values)
558
+ values[name] = sub_values
559
+ continue
537
560
  has_value = name in current_store
538
561
  values[name] = _prompt_field(name, field_schema, values.get(name), has_value)
539
- return values
540
562
 
541
563
 
542
564
  def _validate_dataclass(config_class, data: dict) -> list[str]:
@@ -26,54 +26,8 @@ from ..console import console
26
26
  from ..constants import PYPI_PACKAGE_JSON_URL_TEMPLATE
27
27
  from ..i18n import i18n
28
28
 
29
- # 版本号解析正则(PEP 440 子集,纯标准库,不依赖 packaging):
30
- # 支持 epoch (1!)、release 段、预发布后缀 (dev/a/alpha/b/beta/rc/c/pre)、
31
- # post 版本 (1.0.postN) 与本地版本 (1.0+local)。
32
- # 例如 2.5.0-dev.1 / 2.5.0a1 / 1.0rc1 / 1.0.post1 / 1.0+local / 1!1.0 均可解析。
33
- # 不支持的格式(如 1.0.post1.dev1 这类 post 后跟 dev)由 _parse_version 返回 None 退化处理。
34
- _VERSION_RE = re.compile(
35
- r"^\s*v?(?P<epoch>\d+!)?(?P<release>\d+(?:\.\d+)*)"
36
- r"(?:[-._]?(?P<pre>dev|alpha|beta|rc|a|b|c|pre)[-._]?(?P<num>\d*))?"
37
- r"(?:[-._]?post[-._]?(?P<post>\d+))?"
38
- r"(?:\+(?P<local>[a-zA-Z0-9]+(?:[.-][a-zA-Z0-9]+)*))?",
39
- re.IGNORECASE,
40
- )
41
- # 预发布类型排序权重:正式版 > rc > beta > alpha > dev
42
- _PRE_RELEASE_RANK = {
43
- "dev": 0,
44
- "alpha": 1,
45
- "a": 1,
46
- "beta": 2,
47
- "b": 2,
48
- "rc": 3,
49
- "c": 3,
50
- "pre": 3,
51
- }
52
-
53
-
54
- def _parse_version(version: str) -> dict | None:
55
- """
56
- 将版本号解析为结构化组件(PEP 440 子集,纯标准库)。
57
-
58
- 与 :meth:`PackageManager._version_key` / :meth:`PackageManager._is_pre_release`
59
- 共用同一解析口径,避免不同正则导致判定分歧(如 ``1.0c2`` 此前在
60
- ``_is_pre_release`` 与 ``_version_key`` 间判定口径不一致)。
61
-
62
- :param version: [str] 版本号字符串
63
- :return: [Optional[dict]] 含 epoch/release/pre_type/pre_num/post/local 的字典,
64
- 无法解析时返回 None
65
- """
66
- match = _VERSION_RE.match(str(version).strip().lstrip("vV"))
67
- if not match:
68
- return None
69
- return {
70
- "epoch": int((match.group("epoch") or "0").rstrip("!") or 0),
71
- "release": match.group("release"),
72
- "pre_type": match.group("pre"),
73
- "pre_num": match.group("num"),
74
- "post": match.group("post"),
75
- "local": match.group("local"),
76
- }
29
+ # 版本号解析与比较的唯一实现在 runtime/version.py(PEP 440 子集,纯标准库);
30
+ # 本模块经下方方法级委托复用同一解析口径,避免双正则导致判定分歧
77
31
 
78
32
 
79
33
  class PackageManager:
@@ -853,63 +807,28 @@ class PackageManager:
853
807
  """
854
808
  将版本号解析为可比较的元组键
855
809
 
856
- 遵循项目命名规则排序:正式版 > post > rc > beta > alpha > dev;
857
- epoch 优先于一切 release 段;本地版本 (+local) 不影响主排序,
858
- 但同一版本号带 local 段者 > 不带 local 段者。
859
- 例如 2.4.5-dev.1 先于 2.4.5 正式版,1.0 < 1.0.post1 < 1.1。
810
+ 委托 :func:`ErisPulse.runtime.version.version_key`(框架内唯一实现)。
860
811
 
861
812
  :param version: [str] 版本号字符串
862
- :return: [tuple] 可直接用于排序/比较的元组键
813
+ :return: [tuple] 逐段可比较的比较键元组
863
814
  """
864
- parsed = _parse_version(version)
865
- if parsed is None:
866
- # 无法解析时退化为基础键,保证不抛异常
867
- return (0, (0, 0, 0, 0), (1,), (0,), ((1, str(version).lower()),))
868
-
869
- release = tuple(int(x) for x in parsed["release"].split("."))
870
- # release 段对齐到固定长度,确保 (2.5) 与 (2.5.0) 可正确比较
871
- padded = release + (0,) * max(0, 4 - len(release))
872
-
873
- pre_type = parsed["pre_type"]
874
- if pre_type is None:
875
- # 正式版:预发布键高于任何预发布版本
876
- pre_key = (1,)
877
- else:
878
- rank = _PRE_RELEASE_RANK.get(pre_type.lower(), 1)
879
- pre_num = int(parsed["pre_num"] or 0)
880
- pre_key = (0, rank, pre_num)
881
-
882
- # post 段:无 post 视为 post0,保证 1.0 == 1.0.post0 < 1.0.post1
883
- post_num = int(parsed["post"] or 0)
884
- post_key = (post_num,)
885
-
886
- local = parsed["local"]
887
- if local:
888
- # 本地段按 "数值段 < 字母段" 拆分,避免 int/str 直接比较抛异常
889
- local_key = tuple(
890
- (0, int(part)) if part.isdigit() else (1, part.lower())
891
- for part in local.split(".")
892
- )
893
- else:
894
- local_key = ()
815
+ from ...runtime.version import version_key
895
816
 
896
- return (parsed["epoch"], padded, pre_key, post_key, local_key)
817
+ return version_key(version)
897
818
 
898
819
  def _compare_versions(self, version1: str, version2: str) -> int:
899
820
  """
900
821
  比较两个版本号的大小
901
822
 
823
+ 委托 :func:`ErisPulse.runtime.version.compare_versions`(框架内唯一实现)。
824
+
902
825
  :param version1: [str] 第一个版本号
903
826
  :param version2: [str] 第二个版本号
904
827
  :return: [int] version1 大于/等于/小于 version2 时分别返回 1/0/-1
905
828
  """
906
- k1 = self._version_key(version1)
907
- k2 = self._version_key(version2)
908
- if k1 > k2:
909
- return 1
910
- if k1 < k2:
911
- return -1
912
- return 0
829
+ from ...runtime.version import compare_versions
830
+
831
+ return compare_versions(version1, version2)
913
832
 
914
833
  def _check_sdk_compatibility(self, min_sdk_version: str) -> tuple[bool, str]:
915
834
  """
@@ -1435,14 +1354,16 @@ class PackageManager:
1435
1354
  """
1436
1355
  判断版本号是否为预发布版本
1437
1356
 
1438
- 与 :meth:`_version_key` 复用同一解析口径(:func:`_parse_version`):
1439
- 仅当版本含预发布段 (dev/alpha/beta/rc/c/pre) 时返回 True;
1440
- post 版本 (1.0.post1) 与本地版本 (1.0+local) 不计为预发布。
1357
+ 与 :meth:`_version_key` 共用同一解析口径(:func:`ErisPulse.runtime.version.parse_version`)。
1358
+ 当版本号含预发布段 (dev/alpha/beta/rc/c/pre) 时返回 True。
1359
+ post 版本 (1.0.post1) 与本地版本 (1.0+local) 不视为预发布版本
1441
1360
 
1442
1361
  :param version: [str] 版本号字符串
1443
- :return: [bool] 是预发布版本返回 True
1362
+ :return: [bool] 是预发布版本时返回 True
1444
1363
  """
1445
- parsed = _parse_version(version)
1364
+ from ...runtime.version import parse_version
1365
+
1366
+ parsed = parse_version(version)
1446
1367
  return parsed is not None and parsed["pre_type"] is not None
1447
1368
 
1448
1369
  def update_self(self, target_version: str | None = None, force: bool = False) -> bool:
@@ -96,6 +96,8 @@ _EN_FALLBACK: dict[str, str] = {
96
96
  "cfg.section.router": "# ==================== Router ====================",
97
97
  "cfg.section.adapter_status": "# ==================== Adapter Status ====================",
98
98
  "cfg.section.module_status": "# ==================== Module Status ====================",
99
+ "cfg.section.components": "# ==================== Installed Components (declarative, auto-generated) ====================",
100
+ "cfg.section.components_hint": "# Rendered from each installed adapter/module ConfigClass; example: fields only live here (not auto-persisted to config.toml)",
99
101
  "cfg.server.host": "Listen address",
100
102
  "cfg.server.port": "Listen port",
101
103
  "cfg.server.auto_start": "Auto start HTTP server (set false for pure WS/polling adapters)",
@@ -112,6 +114,9 @@ _EN_FALLBACK: dict[str, str] = {
112
114
  "cfg.logger.log_rotation_when": "date mode: rotation period S/M/H/D/midnight",
113
115
  "cfg.logger.memory_limit": "In-memory log entries limit",
114
116
  "cfg.storage.use_global_db": "Use global database",
117
+ "cfg.storage.backend": "Storage backend: \"sqlite\" / \"mysql\" / \"postgres\"",
118
+ "cfg.storage.mysql": "MySQL connection params (effective when backend = \"mysql\"), requires: pip install ErisPulse[mysql]",
119
+ "cfg.storage.postgres": "PostgreSQL connection params (effective when backend = \"postgres\"), requires: pip install ErisPulse[postgres]",
115
120
  "cfg.event.ignore_self": "Ignore self messages",
116
121
  "cfg.command.prefix": "Command prefix",
117
122
  "cfg.command.case_sensitive": "Case sensitive",
@@ -196,6 +201,8 @@ _TRANSLATIONS: dict[str, dict[str, str]] = {
196
201
  "cfg.section.router": "# ==================== 路由增强 ====================",
197
202
  "cfg.section.adapter_status": "# ==================== 适配器状态 ====================",
198
203
  "cfg.section.module_status": "# ==================== 模块状态 ====================",
204
+ "cfg.section.components": "# ==================== 已安装组件(声明式自动生成) ====================",
205
+ "cfg.section.components_hint": "# 由各已安装适配器/模块的 ConfigClass 渲染;example: 字段仅记录于此(不会自动写入 config.toml)",
199
206
  "cfg.server.host": "监听地址",
200
207
  "cfg.server.port": "监听端口",
201
208
  "cfg.server.auto_start": "是否自动启动 HTTP 服务器 (纯 WS/轮询适配器可设 false)",
@@ -211,6 +218,9 @@ _TRANSLATIONS: dict[str, dict[str, str]] = {
211
218
  "cfg.logger.log_rotation_when": "date 模式轮转周期: S/M/H/D/midnight",
212
219
  "cfg.logger.memory_limit": "内存日志条数上限",
213
220
  "cfg.storage.use_global_db": "是否使用全局数据库",
221
+ "cfg.storage.backend": "存储后端: \"sqlite\" / \"mysql\" / \"postgres\"",
222
+ "cfg.storage.mysql": "MySQL 连接参数(backend = \"mysql\" 时生效),需安装: pip install ErisPulse[mysql]",
223
+ "cfg.storage.postgres": "PostgreSQL 连接参数(backend = \"postgres\" 时生效),需安装: pip install ErisPulse[postgres]",
214
224
  "cfg.event.ignore_self": "忽略自身消息",
215
225
  "cfg.command.prefix": "命令前缀",
216
226
  "cfg.command.case_sensitive": "区分大小写",
@@ -9,7 +9,8 @@ from .converter import BaseConverter
9
9
  from .send_rules import SendContext
10
10
  from .send_builder import SendBuilder, BatchContext
11
11
  from .module import BaseModule, ModuleMeta
12
- from .storage import BaseStorage, BaseQueryBuilder
12
+ from .storage import AsyncBridge, BaseStorage, BaseQueryBuilder
13
+ from .sql_base import AlterTableBuilder, SQLDialect, SQLQueryBuilder, SQLStorageBase
13
14
  from .kv_builder import KVQueryBuilder
14
15
  from .errors import (
15
16
  ErisPulseError,
@@ -17,6 +18,17 @@ from .errors import (
17
18
  ClientConnectionError,
18
19
  ClientTimeoutError,
19
20
  HTTPStatusError,
21
+ InteractionCancelled,
22
+ InteractionError,
23
+ ModuleCallError,
24
+ ModuleCallTimeoutError,
25
+ ModuleError,
26
+ ModuleNotAvailableError,
27
+ ServiceNotProvidedError,
28
+ SessionOccupiedError,
29
+ StorageError,
30
+ StorageUnreachableError,
31
+ StrictModeError,
20
32
  WebSocketError,
21
33
  WebSocketDisconnect,
22
34
  )
@@ -66,16 +78,33 @@ __all__ = [
66
78
  "I18nConfig",
67
79
  # i18n 单键声明
68
80
  "I18nKey",
81
+ "AsyncBridge",
82
+ "InteractionCancelled",
83
+ "InteractionError",
69
84
  "KVQueryBuilder",
85
+ "ModuleCallError",
86
+ "ModuleCallTimeoutError",
87
+ "ModuleError",
70
88
  "ModuleMeta",
89
+ "ModuleNotAvailableError",
71
90
  "RequestDSL",
72
91
  "SendBuilder",
73
92
  "SendContext",
74
93
  "SendDSL",
94
+ "ServiceNotProvidedError",
95
+ "SessionOccupiedError",
75
96
  "SseEmitter",
97
+ "StorageError",
98
+ "StorageUnreachableError",
99
+ "StrictModeError",
76
100
  "WSMessage",
77
101
  "WebSocketConnection",
78
102
  "WebSocketConnectionBase",
79
103
  "WebSocketDisconnect",
80
104
  "WebSocketError",
105
+ # SQL 存储基类(自定义 SQL 后端扩展用)
106
+ "AlterTableBuilder",
107
+ "SQLDialect",
108
+ "SQLQueryBuilder",
109
+ "SQLStorageBase",
81
110
  ]