nonebot-plugin-htmlrender 0.7.1__tar.gz → 0.7.2__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 (163) hide show
  1. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/docs.yml +3 -38
  2. nonebot_plugin_htmlrender-0.7.2/.github/workflows/publish.yml +231 -0
  3. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/CONTRIBUTING.md +3 -6
  4. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/PKG-INFO +1 -1
  5. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/quality/ci-actions.md +15 -15
  6. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/quality/versioning.md +7 -5
  7. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/api.md +7 -0
  8. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/index.md +1 -0
  9. nonebot_plugin_htmlrender-0.7.2/docs/users/migration-v072.md +46 -0
  10. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/migration.md +4 -0
  11. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/security.md +18 -2
  12. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/mkdocs.yml +1 -0
  13. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/operations.py +24 -11
  14. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/markdown.html +3 -3
  15. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/text/text.html +1 -1
  16. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/pyproject.toml +1 -1
  17. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_operations.py +77 -9
  18. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/remote_smoke.py +6 -0
  19. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_render_api.py +2 -0
  20. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/uv.lock +1 -1
  21. nonebot_plugin_htmlrender-0.7.1/.github/workflows/publish.yml +0 -129
  22. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/auto-tag.yml +0 -0
  23. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/ci.yml +0 -0
  24. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/coverage.yml +0 -0
  25. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/docs-pr-preview.yml +0 -0
  26. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/prek.yml +0 -0
  27. {nonebot_plugin_htmlrender-0.7.1/.github/workflows → nonebot_plugin_htmlrender-0.7.2/.github/workflows-disabled}/publish-test.yml +0 -0
  28. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.gitignore +0 -0
  29. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.markdownlint.json +0 -0
  30. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.pre-commit-config.yaml +0 -0
  31. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.python-version +0 -0
  32. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/CODE_OF_CONDUCT.md +0 -0
  33. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/CODING_STANDARDS.md +0 -0
  34. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/COMMIT_MESSAGE.md +0 -0
  35. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/LICENSE +0 -0
  36. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/Makefile +0 -0
  37. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/README.md +0 -0
  38. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/SECURITY.md +0 -0
  39. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docker-compose.dev.yaml +0 -0
  40. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/assets/logo.png +0 -0
  41. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/assets/nonebot_plugin.svg +0 -0
  42. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/html2pic.png +0 -0
  43. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/index.md +0 -0
  44. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/architecture.md +0 -0
  45. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/custom-backends.md +0 -0
  46. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/filehost-resource-resolution.md +0 -0
  47. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/render-backend-development.md +0 -0
  48. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/coding-standards.md +0 -0
  49. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/commit-message.md +0 -0
  50. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/contributing.md +0 -0
  51. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/engineering-guide.md +0 -0
  52. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/index.md +0 -0
  53. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/quality/testing-matrix.md +0 -0
  54. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/md2pic.png +0 -0
  55. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/overrides/main.html +0 -0
  56. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/stylesheets/extra.css +0 -0
  57. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/template2pic.png +0 -0
  58. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/text2pic.png +0 -0
  59. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/best-practices.md +0 -0
  60. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/core.md +0 -0
  61. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/index.md +0 -0
  62. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/integrations.md +0 -0
  63. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/playwright.md +0 -0
  64. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/examples.md +0 -0
  65. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/faq.md +0 -0
  66. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/quickstart.md +0 -0
  67. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/remote-playwright.md +0 -0
  68. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/troubleshooting.md +0 -0
  69. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/.env.prod +0 -0
  70. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/README.md +0 -0
  71. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/docker-compose.yml +0 -0
  72. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/plugins/remote_render/__init__.py +0 -0
  73. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/pyproject.toml +0 -0
  74. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/screenshot/README.md +0 -0
  75. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/screenshot/plugins/screenshot/__init__.py +0 -0
  76. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/screenshot/pyproject.toml +0 -0
  77. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/README.md +0 -0
  78. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/plugins/template_render/__init__.py +0 -0
  79. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/plugins/template_render/templates/profile.html +0 -0
  80. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/plugins/template_render/templates/style.css +0 -0
  81. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/pyproject.toml +0 -0
  82. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/__init__.py +0 -0
  83. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/_bootstrap.py +0 -0
  84. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/_compat.py +0 -0
  85. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/__init__.py +0 -0
  86. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/base.py +0 -0
  87. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/factory.py +0 -0
  88. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/__init__.py +0 -0
  89. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/_page.py +0 -0
  90. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/config.py +0 -0
  91. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/data_source.py +0 -0
  92. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/install.py +0 -0
  93. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/models.py +0 -0
  94. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/render.py +0 -0
  95. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/runtime.py +0 -0
  96. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/telemetry.py +0 -0
  97. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/types.py +0 -0
  98. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/browser.py +0 -0
  99. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/config.py +0 -0
  100. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/consts.py +0 -0
  101. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/data_source.py +0 -0
  102. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/py.typed +0 -0
  103. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/render.py +0 -0
  104. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/__init__.py +0 -0
  105. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/config.py +0 -0
  106. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/__init__.py +0 -0
  107. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/cache.py +0 -0
  108. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/guard.py +0 -0
  109. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/warmup.py +0 -0
  110. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/resolve.py +0 -0
  111. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/template.py +0 -0
  112. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/github-markdown-light.css +0 -0
  113. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/katex.min.b64_fonts.css +0 -0
  114. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/katex.min.js +0 -0
  115. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/mathtex-script-type.min.js +0 -0
  116. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/mhchem.min.js +0 -0
  117. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/pygments-default.css +0 -0
  118. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/text/text.css +0 -0
  119. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/__init__.py +0 -0
  120. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/install.py +0 -0
  121. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/process.py +0 -0
  122. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/signal.py +0 -0
  123. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/__init__.py +0 -0
  124. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/common.py +0 -0
  125. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/prometheus.py +0 -0
  126. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/sentry.py +0 -0
  127. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/__init__.py +0 -0
  128. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_backend.py +0 -0
  129. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_config.py +0 -0
  130. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_install.py +0 -0
  131. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_runtime_extra.py +0 -0
  132. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_telemetry.py +0 -0
  133. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/test_factory.py +0 -0
  134. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/conftest.py +0 -0
  135. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_config_compat.py +0 -0
  136. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_data_source_wrappers.py +0 -0
  137. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_install_more.py +0 -0
  138. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_lazy_imports.py +0 -0
  139. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_plugin_install.py +0 -0
  140. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_plugin_module.py +0 -0
  141. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_process.py +0 -0
  142. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_reexports.py +0 -0
  143. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_common.py +0 -0
  144. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_prometheus.py +0 -0
  145. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_sentry.py +0 -0
  146. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_track_render.py +0 -0
  147. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_utils_runtime.py +0 -0
  148. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/docker-compose.remote-test.yaml +0 -0
  149. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/dockerfile.playwright-server +0 -0
  150. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/dockerfile.remote-test +0 -0
  151. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/playwright-server.mjs +0 -0
  152. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_browser_compat.py +0 -0
  153. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_render_concurrency.py +0 -0
  154. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_render_unit.py +0 -0
  155. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_filehost_extra.py +0 -0
  156. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_resources.py +0 -0
  157. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_resources_extra.py +0 -0
  158. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_template_filter.png +0 -0
  159. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/markdown.css +0 -0
  160. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/mystyle.css +0 -0
  161. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/progress.html.jinja2 +0 -0
  162. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/remote_filehost.html.jinja2 +0 -0
  163. {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/text.html +0 -0
@@ -18,11 +18,11 @@ on:
18
18
  type: boolean
19
19
 
20
20
  permissions:
21
- contents: write
21
+ contents: read
22
22
 
23
23
  jobs:
24
- deploy:
25
- name: Build & Deploy Docs
24
+ build:
25
+ name: Build Docs
26
26
  runs-on: ubuntu-latest
27
27
  timeout-minutes: 20
28
28
  env:
@@ -68,38 +68,3 @@ jobs:
68
68
  path: ${{ env.DOCS_LOG }}
69
69
  if-no-files-found: warn
70
70
  retention-days: 14
71
-
72
- - name: Configure git
73
- run: |
74
- git config user.name "github-actions[bot]"
75
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
76
-
77
- - name: Configure authenticated origin
78
- env:
79
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
80
- run: |
81
- git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
82
-
83
- - name: Get project version
84
- id: version
85
- run: |
86
- VERSION=$(uv version --short)
87
- echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
88
-
89
- - name: Deploy versioned docs
90
- env:
91
- VERSION: ${{ steps.version.outputs.version }}
92
- run: |
93
- uv run mike deploy --push --update-aliases "${VERSION}" latest
94
-
95
- - name: Set default version
96
- run: |
97
- uv run mike set-default --push latest
98
-
99
- - name: Show docs url
100
- env:
101
- DOCS_OWNER: ${{ github.repository_owner }}
102
- DOCS_REPO: ${{ github.event.repository.name }}
103
- VERSION: ${{ steps.version.outputs.version }}
104
- run: |
105
- echo "Docs deployed: https://${DOCS_OWNER}.github.io/${DOCS_REPO}/${VERSION}/"
@@ -0,0 +1,231 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ debug_enabled:
10
+ description: Enable extra debug diagnostics
11
+ required: false
12
+ default: false
13
+ type: boolean
14
+ release_tag:
15
+ description: Tag to publish as GitHub Release when manually triggered (e.g. v0.7.0)
16
+ required: false
17
+ default: ""
18
+ type: string
19
+
20
+ jobs:
21
+ pypi-publish:
22
+ name: Upload release to PyPI
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 30
25
+ outputs:
26
+ release_tag: ${{ steps.release_tag.outputs.tag }}
27
+ environment: release
28
+ permissions:
29
+ # IMPORTANT: this permission is mandatory for trusted publishing
30
+ id-token: write
31
+ contents: write
32
+ env:
33
+ BUILD_LOG: publish-build.log
34
+ steps:
35
+ - name: Resolve Release Tag
36
+ id: release_tag
37
+ shell: bash
38
+ env:
39
+ RELEASE_TAG_INPUT: ${{ github.event.inputs.release_tag }}
40
+ run: |
41
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
42
+ TAG="${GITHUB_REF_NAME}"
43
+ elif [[ -n "${RELEASE_TAG_INPUT}" ]]; then
44
+ TAG="${RELEASE_TAG_INPUT}"
45
+ else
46
+ echo "::error::No release tag found. Use a tag push or provide workflow_dispatch input 'release_tag'."
47
+ exit 1
48
+ fi
49
+ echo "tag=${TAG}" >> "${GITHUB_OUTPUT}"
50
+ echo "Resolved release tag: ${TAG}"
51
+
52
+ - name: Checkout
53
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
54
+ with:
55
+ ref: refs/tags/${{ steps.release_tag.outputs.tag }}
56
+ fetch-depth: 0
57
+ persist-credentials: false
58
+
59
+ - name: Verify tagged commit is on master
60
+ shell: bash
61
+ env:
62
+ RELEASE_TAG: ${{ steps.release_tag.outputs.tag }}
63
+ run: |
64
+ git fetch --no-tags origin master:refs/remotes/origin/master
65
+ TAG_COMMIT=$(git rev-list -n 1 "${RELEASE_TAG}")
66
+ if [[ "$(git rev-parse HEAD)" != "${TAG_COMMIT}" ]]; then
67
+ echo "::error::Checkout does not match ${RELEASE_TAG}. Refusing to publish."
68
+ exit 1
69
+ fi
70
+ if ! git merge-base --is-ancestor "${TAG_COMMIT}" origin/master; then
71
+ echo "::error::Tagged commit ${TAG_COMMIT} is not an ancestor of master. Refusing to publish."
72
+ exit 1
73
+ fi
74
+ echo "Tagged commit ${TAG_COMMIT} is on master."
75
+
76
+ - name: Install the latest version of uv
77
+ uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78
78
+ with:
79
+ enable-cache: false
80
+
81
+ - name: Set up Python
82
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
83
+ with:
84
+ python-version-file: ".python-version"
85
+
86
+ - name: Show Runner Context
87
+ run: |
88
+ echo "Runner: $RUNNER_NAME ($RUNNER_OS/$RUNNER_ARCH)"
89
+ python --version
90
+ uv --version
91
+
92
+ - name: Verify tag matches package version
93
+ shell: bash
94
+ env:
95
+ RELEASE_TAG: ${{ steps.release_tag.outputs.tag }}
96
+ run: |
97
+ VERSION=$(uv version --short)
98
+ EXPECTED_TAG="v${VERSION}"
99
+ if [[ "${RELEASE_TAG}" != "${EXPECTED_TAG}" ]]; then
100
+ echo "::error::Release tag ${RELEASE_TAG} does not match package version ${VERSION}. Expected ${EXPECTED_TAG}."
101
+ exit 1
102
+ fi
103
+ echo "Release tag ${RELEASE_TAG} matches package version ${VERSION}."
104
+
105
+ - name: Sync deps
106
+ run: uv sync
107
+ shell: bash
108
+
109
+ - name: Debug Dependency Snapshot
110
+ if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
111
+ run: |
112
+ uv pip list
113
+ uv tree
114
+
115
+ - name: Build Package
116
+ run: |
117
+ set -o pipefail
118
+ uv build 2>&1 | tee "${BUILD_LOG}"
119
+
120
+ - name: Show built distributions
121
+ run: |
122
+ ls -la dist
123
+ sha256sum dist/* || true
124
+
125
+ - name: Upload build artifacts
126
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
127
+ with:
128
+ name: artifact
129
+ path: dist/
130
+
131
+ - name: Upload build logs
132
+ if: ${{ always() }}
133
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
134
+ with:
135
+ name: publish-build-logs
136
+ path: ${{ env.BUILD_LOG }}
137
+ if-no-files-found: warn
138
+ retention-days: 14
139
+
140
+ - name: pypi-publish
141
+ uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
142
+
143
+ - name: Publish GitHub Release
144
+ env:
145
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146
+ RELEASE_TAG: ${{ steps.release_tag.outputs.tag }}
147
+ run: |
148
+ gh release create "${RELEASE_TAG}" \
149
+ dist/*.whl \
150
+ dist/*.tar.gz \
151
+ --title "${RELEASE_TAG}" \
152
+ --generate-notes
153
+
154
+ docs-deploy:
155
+ name: Deploy versioned docs
156
+ needs: pypi-publish
157
+ runs-on: ubuntu-latest
158
+ timeout-minutes: 20
159
+ permissions:
160
+ contents: write
161
+ env:
162
+ DOCS_LOG: docs-build.log
163
+ RELEASE_TAG: ${{ needs.pypi-publish.outputs.release_tag }}
164
+ steps:
165
+ - name: Checkout release tag
166
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
167
+ with:
168
+ ref: refs/tags/${{ needs.pypi-publish.outputs.release_tag }}
169
+ fetch-depth: 0
170
+ persist-credentials: false
171
+
172
+ - name: Set up uv
173
+ uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78
174
+ with:
175
+ python-version: "3.12"
176
+ enable-cache: false
177
+
178
+ - name: Sync docs deps
179
+ run: uv sync --locked --group docs
180
+
181
+ - name: Verify docs version
182
+ id: version
183
+ shell: bash
184
+ run: |
185
+ VERSION=$(uv version --short)
186
+ EXPECTED_TAG="v${VERSION}"
187
+ if [[ "${RELEASE_TAG}" != "${EXPECTED_TAG}" ]]; then
188
+ echo "::error::Release tag ${RELEASE_TAG} does not match docs version ${VERSION}."
189
+ exit 1
190
+ fi
191
+ echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
192
+
193
+ - name: Build docs
194
+ run: |
195
+ set -o pipefail
196
+ uv run zensical build --strict 2>&1 | tee "${DOCS_LOG}"
197
+
198
+ - name: Upload docs build logs
199
+ if: ${{ always() }}
200
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
201
+ with:
202
+ name: release-docs-build-logs
203
+ path: ${{ env.DOCS_LOG }}
204
+ if-no-files-found: warn
205
+ retention-days: 14
206
+
207
+ - name: Configure git
208
+ run: |
209
+ git config user.name "github-actions[bot]"
210
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
211
+
212
+ - name: Configure authenticated origin
213
+ env:
214
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
215
+ run: |
216
+ git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
217
+
218
+ - name: Deploy versioned docs
219
+ env:
220
+ VERSION: ${{ steps.version.outputs.version }}
221
+ run: |
222
+ uv run mike deploy --push --update-aliases "${VERSION}" latest
223
+ uv run mike set-default --push latest
224
+
225
+ - name: Show docs URL
226
+ env:
227
+ DOCS_OWNER: ${{ github.repository_owner }}
228
+ DOCS_REPO: ${{ github.event.repository.name }}
229
+ VERSION: ${{ steps.version.outputs.version }}
230
+ run: |
231
+ echo "Docs deployed: https://${DOCS_OWNER}.github.io/${DOCS_REPO}/${VERSION}/"
@@ -46,14 +46,11 @@ If docs were changed:
46
46
  make docs-build
47
47
  ```
48
48
 
49
- ## PR Previews
49
+ ## PR Documentation Preview
50
50
 
51
- When opening a PR from a branch in this repository (not a fork), the following previews are produced automatically:
51
+ When opening a PR from a branch in this repository (not a fork), documentation changes under `docs/**`, `mkdocs.yml`, or `README.md` are deployed automatically. A sticky comment shows the preview URL under `pr-preview/pr-<NUMBER>/` of the Pages site. The preview is removed automatically when the PR is closed.
52
52
 
53
- - **TestPyPI build**: each push to the PR is published to TestPyPI under a dev-suffixed version. A sticky comment on the PR shows the install command.
54
- - **Docs preview** (only when `docs/**`, `mkdocs.yml`, or `README.md` change): a sticky comment on the PR shows the preview URL under `pr-preview/pr-<NUMBER>/` of the Pages site. The preview is removed automatically when the PR is closed.
55
-
56
- PRs from forks skip both because the workflow tokens cannot write to gh-pages or use TestPyPI trusted publishing.
53
+ PRs from forks skip the deployment because the workflow token cannot write to `gh-pages`. TestPyPI publishing is currently suspended for all PRs.
57
54
 
58
55
  ## Commit Message Format
59
56
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-htmlrender
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: 通过浏览器渲染图片
5
5
  Project-URL: Homepage, https://github.com/kexue-z/nonebot-plugin-htmlrender
6
6
  Project-URL: Bug Tracker, https://github.com/kexue-z/nonebot-plugin-htmlrender/issues
@@ -18,11 +18,11 @@ tags:
18
18
  | ------------------ | --------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------- |
19
19
  | CI | `.github/workflows/ci.yml` | lint、类型检查、打包校验、远程浏览器 smoke | push master、pull request、手动触发 |
20
20
  | Coverage | `.github/workflows/coverage.yml` | Python 版本 + CPU 架构覆盖率矩阵 | push master、pull request、手动触发 |
21
- | Docs | `.github/workflows/docs.yml` | master 推送时构建文档并执行版本化部署 | push master(文档路径)、手动触发 |
21
+ | Docs | `.github/workflows/docs.yml` | master 推送时严格构建文档 | push master(文档路径)、手动触发 |
22
22
  | Docs PR Preview | `.github/workflows/docs-pr-preview.yml` | PR 文档预览部署与关闭清理 | pull request open/sync/close(文档路径) |
23
- | Publish (TestPyPI) | `.github/workflows/publish-test.yml` | PR 注入 dev 版本号发到 TestPyPI 并在 PR 评论安装命令 | pull request、手动触发 |
23
+ | Publish (TestPyPI) | `.github/workflows-disabled/publish-test.yml` | 保留 TestPyPI 发布实现,当前挂起 | |
24
24
  | Auto Tag | `.github/workflows/auto-tag.yml` | PR 合并到 master 后读取 `pyproject.toml` 版本号自动打 tag 并触发 Publish | pull request closed on master |
25
- | Publish | `.github/workflows/publish.yml` | 构建分发包、PyPI trusted publishing、GitHub Release | tag push、手动触发 |
25
+ | Publish | `.github/workflows/publish.yml` | 构建分发包、PyPI、GitHub Release,并在成功后部署版本化文档 | tag push、手动触发 |
26
26
 
27
27
  ## CI
28
28
 
@@ -63,15 +63,13 @@ pytest-py<python-version>-<arch>.log
63
63
  - `README.md`
64
64
  - `.github/workflows/docs.yml`
65
65
 
66
- 它会执行严格文档构建并通过 `mike` 部署到 `gh-pages`:
66
+ 它只执行严格文档构建:
67
67
 
68
68
  ```bash
69
69
  uv run zensical build --strict
70
- uv run mike deploy --push --update-aliases <version> latest
71
- uv run mike set-default --push latest
72
70
  ```
73
71
 
74
- 版本号从 `pyproject.toml` `project.version` 字段读取。多版本管理细节见 [文档版本管理](versioning.md)。
72
+ 版本化部署由 Publish workflow 在正式发布成功后执行,避免未发布版本提前成为 `latest`。多版本管理细节见 [文档版本管理](versioning.md)。
75
73
 
76
74
  非 master 分支或 PR 上的文档预览由 `Docs PR Preview` 负责,不再走分支名预览。
77
75
 
@@ -93,12 +91,9 @@ https://<owner>.github.io/<repo>/pr-preview/pr-<NUMBER>/
93
91
 
94
92
  ## Publish (TestPyPI)
95
93
 
96
- `Publish (TestPyPI)` workflow PR 上为同仓库分支构建一份带唯一 dev 后缀的包,发布到 TestPyPI,便于评审者快速安装验证。
94
+ TestPyPI 发布当前挂起。完整 workflow 保留在 `.github/workflows-disabled/publish-test.yml`,不位于 GitHub Actions 注册目录,因此没有 PR 或手动触发入口。
97
95
 
98
- - 触发:`pull_request` `opened` / `synchronize` / `reopened``workflow_dispatch`;
99
- - fork PR 跳过:trusted publishing 需要 `id-token: write`,fork 不可用;
100
- - 版本注入:以 `pyproject.toml` 中的当前版本为 base,附加 UTC 时间戳后缀,例如 `0.7.0.dev20260509120000`,保证 TestPyPI 单调递增不撞包;
101
- - 发布完成后用 `marocchino/sticky-pull-request-comment` 在 PR 上贴一条固定评论,给出装包命令。
96
+ 保留实现仍会以 `pyproject.toml` 的当前版本为 base,附加 UTC 时间戳 dev 后缀,构建 wheel sdist,并通过 trusted publishing 上传 TestPyPI。恢复时需将文件移回 `.github/workflows/`,再明确配置所需触发器;不能只修改文档或 environment。
102
97
 
103
98
  ```bash
104
99
  pip install -i https://test.pypi.org/simple/ \
@@ -106,7 +101,7 @@ pip install -i https://test.pypi.org/simple/ \
106
101
  nonebot-plugin-htmlrender==<dev-version>
107
102
  ```
108
103
 
109
- `environment: testpypi` 与 `https://test.pypi.org/legacy/` 仓库 URL 已在 workflow 中固化。需要在 TestPyPI 与 GitHub 仓库的 `testpypi` environment 上各自完成一次 trusted publisher 配置。
104
+ `environment: testpypi` 与 `https://test.pypi.org/legacy/` 仓库 URL 仍保留在挂起的 workflow 中。
110
105
 
111
106
  ## Auto Tag
112
107
 
@@ -126,11 +121,13 @@ pip install -i https://test.pypi.org/simple/ \
126
121
 
127
122
  `Publish` workflow 负责正式发布产物:
128
123
 
129
- 1. **校验 commit 在 master 历史上**:`git merge-base --is-ancestor` 校验,挡住误从其他分支推 tag 的发布;
124
+ 1. 解析并检出待发布 tag
125
+ 1. 校验 tag 指向 `master` 历史、tag 名与包版本完全一致;
130
126
  1. 使用 `uv build` 构建 wheel 与 sdist;
131
127
  1. 上传构建产物和构建日志 artifact;
132
128
  1. 通过 PyPI trusted publishing 发布;
133
129
  1. 根据 tag 或 `release_tag` 输入创建 GitHub Release。
130
+ 1. GitHub Release 创建成功后严格构建 tag 对应文档,通过 `mike` 部署该版本并更新 `latest`。
134
131
 
135
132
  触发方式:
136
133
 
@@ -138,6 +135,8 @@ pip install -i https://test.pypi.org/simple/ \
138
135
  - 也可以维护者手动 push 一个 tag 到 master 上的 commit;
139
136
  - 也可以手动 `workflow_dispatch` 并提供 `release_tag` 输入。
140
137
 
138
+ 无论通过哪种方式触发,Publish 都从 tag 检出源码,不会用 dispatch 所在分支的工作树替代发布内容。Mike 部署是发布的后置 job;PyPI 或 GitHub Release 失败时不会运行。
139
+
141
140
  ## 本地对应命令
142
141
 
143
142
  | CI 项 | 本地命令 |
@@ -169,5 +168,6 @@ pip install -i https://test.pypi.org/simple/ \
169
168
  - 对文档构建失败,下载 `docs-build-logs`;
170
169
  - 对打包失败,下载 `package-dist` 与 `package-build-logs`;
171
170
  - 对正式发布失败,下载 `publish-build-logs`;
172
- - TestPyPI 发布失败,下载 `publish-test-build-logs` 与 `artifact-testpypi`;
171
+ - 对正式发布后的文档部署失败,下载 `release-docs-build-logs`;
172
+ - TestPyPI workflow 恢复后若发布失败,下载 `publish-test-build-logs` 与 `artifact-testpypi`;
173
173
  - 对 Auto Tag 失败(tag 推送或 publish dispatch 失败),查看 job 日志中的 `gh` 命令输出。
@@ -15,7 +15,8 @@ tags:
15
15
 
16
16
  ## 工作原理
17
17
 
18
- - 推送到 `master` 分支且涉及文档相关路径时,Docs workflow 自动读取 `pyproject.toml` 中的版本号,通过 `mike deploy` 发布到 `gh-pages` 分支
18
+ - 推送到 `master` 分支且涉及文档相关路径时,Docs workflow 只执行严格构建,阻止无效文档进入主分支
19
+ - Publish workflow 完成 PyPI 发布和 GitHub Release 后,才读取 tag 对应版本并通过 `mike deploy` 发布到 `gh-pages` 分支
19
20
  - 版本以子目录形式存在,例如 `docs.example.com/0.7.0/`、`docs.example.com/0.8.0/`
20
21
  - `latest` 别名始终指向最新版本,根路径自动重定向到 `latest`
21
22
  - 旧版本页面顶部会显示过期提醒横幅
@@ -26,9 +27,10 @@ PR 阶段的文档预览由独立的 `Docs PR Preview` workflow 部署到 `gh-pa
26
27
 
27
28
  发版时不需要手动打 tag。维护者只需在 PR 中改好 `pyproject.toml` 的 `project.version` 后合并到 `master`:
28
29
 
29
- 1. 合并到 `master` 触发 `Docs` workflow,将新版本通过 `mike` 部署为版本化文档;
30
- 2. 同时触发 `Auto Tag` workflow,读取版本号自动创建 `v<version>` tag;
31
- 3. `Auto Tag` 通过 `gh workflow run` 调起 `Publish`,完成 PyPI 发布与 GitHub Release
30
+ 1. 合并到 `master` 后,`Auto Tag` workflow 读取版本号并创建 `v<version>` tag;
31
+ 2. `Auto Tag` 通过 `gh workflow run` 调起 `Publish`;
32
+ 3. `Publish` 检出 tag,校验 tag、包版本和 `master` 祖先关系,再完成 PyPI 发布与 GitHub Release
33
+ 4. 只有前述发布成功后,Publish 的文档 job 才通过 `mike` 部署版本化文档并更新 `latest`。
32
34
 
33
35
  完整 workflow 触发条件与排障入口见 [CI Actions](ci-actions.md)。
34
36
 
@@ -37,7 +39,7 @@ mike deploy --push --update-aliases <version> latest
37
39
  mike set-default --push latest
38
40
  ```
39
41
 
40
- 版本号从 `pyproject.toml` `project.version` 字段读取。
42
+ 版本号从 tag 对应提交的 `pyproject.toml` 中读取,且必须与 `v<version>` tag 完全一致。
41
43
 
42
44
  ## 本地操作
43
45
 
@@ -86,6 +86,13 @@ async def render_markdown(
86
86
 
87
87
  **返回值:** `bytes` — 图片二进制数据
88
88
 
89
+ !!! warning "Markdown 中的原始 HTML 会进入页面"
90
+
91
+ `render_markdown` 会保留 Markdown 中的原始 HTML,并将转换结果作为 HTML
92
+ 片段插入页面;它不是 HTML 消毒器。若内容来自不可信用户或模型输出,调用方
93
+ 应先按业务需要做标签、属性和 URL 白名单清洗,或在不需要富文本时改用
94
+ `render_text`。详见[安全须知](security.md)。
95
+
89
96
  ---
90
97
 
91
98
  ### `render_html`
@@ -67,6 +67,7 @@ tags:
67
67
 
68
68
  === "迁移旧项目"
69
69
 
70
+ - [v0.7.2 迁移说明](migration-v072.md):远程 Playwright 的 Markdown 渲染修复
70
71
  - [旧版本迁移指南](migration.md):从旧 API、旧配置和历史行为迁移到新路径
71
72
 
72
73
  ## 新项目建议
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: v0.7.2 迁移说明
3
+ description: 从 v0.7.1 升级到 v0.7.2 时需要了解的远程 Markdown 修复
4
+ icon: lucide/bug-off
5
+ tags:
6
+ - Users
7
+ - Migration
8
+ - Release
9
+ ---
10
+
11
+ # v0.7.2 迁移说明
12
+
13
+ v0.7.2 是面向远程 Playwright 部署的兼容性修复版本,不包含公共 API 或配置项变更。
14
+
15
+ ## 修复内容
16
+
17
+ 使用远程 Playwright 渲染 Markdown 时,默认模板此前会让远端浏览器导航到 Bot
18
+ 进程所在主机的 `file://` 地址。浏览器与 Bot 不共享文件系统时,该地址不可达,
19
+ 渲染会以 `ERR_FILE_NOT_FOUND` 失败。
20
+
21
+ v0.7.2 在远程模式下直接通过 `page.set_content()` 注入默认 Markdown HTML,
22
+ 不再导航到本地模板文件。自定义的 HTTP(S) 基址和显式传入的渲染配置保持原有行为。
23
+
24
+ ## 是否需要修改配置
25
+
26
+ 通常不需要。符合以下条件的部署可直接升级:
27
+
28
+ - 使用 Playwright WS 或 CDP 连接远端浏览器;
29
+ - 调用 `render_markdown` 或兼容入口 `md_to_pic`;
30
+ - 使用内置 Markdown 模板和样式。
31
+
32
+ 若 Markdown 引用了本地图片、字体或其他静态资源,仍需确保远端浏览器能够访问这些
33
+ 资源;本次修复只消除了默认模板文件本身的跨主机 `file://` 导航。
34
+
35
+ ## 升级后验证
36
+
37
+ 在实际远程浏览器环境执行一次最小渲染即可:
38
+
39
+ ```python
40
+ from nonebot_plugin_htmlrender import render_markdown
41
+
42
+ image = await render_markdown("# remote markdown")
43
+ assert image
44
+ ```
45
+
46
+ 本地 Playwright、HTML 渲染和模板渲染行为不受影响。
@@ -10,6 +10,10 @@ tags:
10
10
 
11
11
  # 旧版本迁移指南
12
12
 
13
+ !!! info "v0.7.2 补丁版本"
14
+ 从 v0.7.1 升级时,请先阅读 [v0.7.2 迁移说明](migration-v072.md)。
15
+ 该版本仅修复远程 Playwright 的 Markdown 模板导航,不改变公共 API 或配置。
16
+
13
17
  新版本将渲染逻辑与底层驱动解耦,引入分层架构(Render / Backend / Runtime / Session / Context)。
14
18
  旧 API 仍保留为兼容层,但调用时会触发弃用警告,且不再承载新能力。
15
19
  新项目请直接使用新 API;存量项目按本页对照表逐步迁移即可。
@@ -19,6 +19,7 @@ tags:
19
19
  | 入口 | 威胁 | 默认行为 | 责任方 |
20
20
  | --- | --- | --- | --- |
21
21
  | `render_html(...)` | 攻击者构造 HTML/JS 在浏览器进程执行 | 直接装载到 Page | 调用方 |
22
+ | `render_markdown(...)` | Markdown 携带原始 HTML、脚本或外链资源 | 转换后作为 HTML 片段装载到 Page,不做消毒 | 调用方 |
22
23
  | `render_template(..., templates=...)` | 模板变量未转义被插入 HTML | Jinja2 `select_autoescape()` 仅对 `.html/.xml` 自动转义 | 调用方 |
23
24
  | `capture_html_element(url, ...)` | 任意 URL 被远端浏览器请求 | 直接 `goto(url)` | 调用方 |
24
25
  | filehost `/filehost/*` | 浏览器/外部请求读取本地文件 | 路径白名单 + 请求头守卫 | 配置方 |
@@ -35,9 +36,22 @@ tags:
35
36
  - 模板内的外链可能拉取攻击者控制的资源;
36
37
  - 浏览器进程可对内网发起请求(参考下文 SSRF)。
37
38
 
39
+ ### Markdown 原始 HTML
40
+
41
+ `render_markdown` 使用 Python-Markdown 生成 HTML。为了让段落、标题、引用块和
42
+ KaTeX 等转换结果形成真实 DOM,生成的 HTML 片段不会再经过 Jinja2 转义。
43
+ Python-Markdown 会保留输入中的原始 HTML,因此 `render_markdown` **不提供 HTML
44
+ 消毒或安全边界**:输入中的 `<script>`、事件处理属性和带外链的元素可能进入页面,
45
+ 脚本执行与网络访问风险和 `render_html` 相同。
46
+
47
+ 模型输出也应视为不可信内容。用户可以通过提示词诱导模型输出原始 HTML、脚本或
48
+ 指向内网的资源 URL;“内容由模型生成”不能替代输入校验。
49
+
38
50
  建议:
39
51
 
40
- - 业务输入直接走 `render_markdown`(CommonMark 解析过滤大部分原始 HTML)或 `render_template` 配合 Jinja2 变量;
52
+ - 不需要富文本时使用 `render_text`,其文本插槽保持 HTML 转义;
53
+ - 需要 Markdown 时,在调用 `render_markdown` 前按业务需求对原始 HTML 的标签、属性和 URL 做白名单清洗;
54
+ - 不可信数据需要进入自定义布局时,使用 `render_template` 的模板变量,不要拼接模板或 HTML 字符串;
41
55
  - 不要拼字符串。`render_template` 默认 `select_autoescape()` 对 `.html/.xml` 后缀模板启用 HTML 转义,模板变量中的 `<` / `>` / `&` 会被转义;
42
56
  - 自定义模板后缀(如 `.j2`)时显式开 `autoescape=True`,否则等于零防护;
43
57
  - 需要原始 HTML 的字段,明确定义白名单标签集合后再交给模板,不要走 `|safe`。
@@ -53,7 +67,8 @@ env = jinja2.Environment(
53
67
 
54
68
  ## SSRF 与外部请求
55
69
 
56
- `render_html` / `render_template` / `capture_html_element` 触发的浏览器内网请求不受 NoneBot HTTP 客户端的限制。
70
+ `render_html` / `render_markdown` / `render_template` / `capture_html_element`
71
+ 触发的浏览器内网请求不受 NoneBot HTTP 客户端的限制。
57
72
  攻击者可以让你的浏览器请求:
58
73
 
59
74
  - 内网管理界面(`http://10.0.0.1/admin`);
@@ -172,6 +187,7 @@ await render_template_html(template=user_supplied_template_string)
172
187
  部署前快速复核:
173
188
 
174
189
  - [ ] 渲染入口已与不可信用户输入解耦(用模板变量而非字符串拼接);
190
+ - [ ] 传给 `render_markdown` 的不可信内容已经过 HTML 标签、属性和 URL 白名单清洗;
175
191
  - [ ] 自定义模板后缀时显式开 `autoescape=True`;
176
192
  - [ ] 不要使用 `filehost_allow_any_path=true`,除非环境严格隔离;
177
193
  - [ ] `filehost_allowed_paths` 显式列出可暴露目录,且不包含 `~`、`/etc`、`/var`、`/srv` 整目录;
@@ -169,6 +169,7 @@ nav:
169
169
  - 常见问题: users/faq.md
170
170
  - 安全须知: users/security.md
171
171
  - 迁移:
172
+ - v0.7.2 迁移说明: users/migration-v072.md
172
173
  - 旧版本迁移指南: users/migration.md
173
174
  - 面向开发者:
174
175
  - 概览: maintainers/index.md
@@ -110,6 +110,11 @@ def _enum_value(raw: object) -> str:
110
110
  return str(getattr(raw, "value", raw))
111
111
 
112
112
 
113
+ def _should_navigate_to_base_url(base_url: str) -> bool:
114
+ """判断浏览器是否应先导航到页面的 base URL。"""
115
+ return base_url != "about:blank"
116
+
117
+
113
118
  async def read_file(path: str) -> str:
114
119
  """异步读取文件内容。"""
115
120
  f = await anyio.open_file(path, mode="r", encoding="utf-8")
@@ -264,7 +269,8 @@ async def render_html(
264
269
  ),
265
270
  ) as page,
266
271
  ):
267
- if is_remote_playwright_mode() and (
272
+ remote_mode = is_remote_playwright_mode()
273
+ if remote_mode and (
268
274
  _enum_value(get_playwright_config().remote_local_resource_policy)
269
275
  == RemoteLocalResourcePolicy.FILEHOST.value
270
276
  ):
@@ -274,7 +280,9 @@ async def render_html(
274
280
  )
275
281
 
276
282
  _setup_page_logging(page)
277
- await page.goto(render_request.render.page.base_url)
283
+ base_url = render_request.render.page.base_url
284
+ if _should_navigate_to_base_url(base_url):
285
+ await page.goto(base_url)
278
286
  await page.set_content(
279
287
  render_request.content.html,
280
288
  wait_until=render_request.content.wait_until,
@@ -444,17 +452,16 @@ async def render_markdown(
444
452
  )
445
453
  css = github_css + pygments_css
446
454
 
447
- render_request = HtmlRenderRequest(
448
- content=ContentConfig(
449
- html=await template.render_async(md=md, css=css, extra=extra)
450
- ),
451
- render=render
452
- or RenderConfig(
455
+ if render is None:
456
+ base_url = (
457
+ _path_to_uri(css_path) if css_path else MARKDOWN_TEMPLATE_FILE.as_uri()
458
+ )
459
+ if is_remote_playwright_mode():
460
+ base_url = "about:blank"
461
+ render = RenderConfig(
453
462
  page=PageConfig(
454
463
  viewport=ViewportConfig(width=width, height=10),
455
- base_url=_path_to_uri(css_path)
456
- if css_path
457
- else MARKDOWN_TEMPLATE_FILE.as_uri(),
464
+ base_url=base_url,
458
465
  ),
459
466
  screenshot=_build_screenshot_config(
460
467
  image_type,
@@ -464,7 +471,13 @@ async def render_markdown(
464
471
  full_page=True,
465
472
  wait_before_screenshot=0,
466
473
  ),
474
+ )
475
+
476
+ render_request = HtmlRenderRequest(
477
+ content=ContentConfig(
478
+ html=await template.render_async(md=md, css=css, extra=extra)
467
479
  ),
480
+ render=render,
468
481
  )
469
482
 
470
483
  return await render_html(render_request, session=session)