SVG2DrawIOLib 1.2.2__tar.gz → 1.3.4__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. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/.gitignore +5 -4
  2. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/CHANGELOG.md +82 -0
  3. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/PKG-INFO +55 -1
  4. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/QUICKSTART.md +53 -0
  5. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/README.md +49 -0
  6. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/pyproject.toml +45 -0
  7. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/__about__.py +1 -1
  8. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/__init__.py +1 -0
  9. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/dependencies.py +19 -0
  10. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/exceptions.py +27 -0
  11. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/main.py +95 -0
  12. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/models/__init__.py +1 -0
  13. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/models/responses.py +64 -0
  14. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/__init__.py +1 -0
  15. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/add.py +102 -0
  16. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/create.py +84 -0
  17. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/extract.py +71 -0
  18. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/inspect.py +71 -0
  19. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/list.py +38 -0
  20. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/remove.py +55 -0
  21. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/rename.py +74 -0
  22. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/split_paths.py +62 -0
  23. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/routers/validate.py +60 -0
  24. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/services/__init__.py +1 -0
  25. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/api/services/processing.py +281 -0
  26. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/cli/web.py +111 -0
  27. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/404/index.html +1 -0
  28. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/404.html +1 -0
  29. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/__next.__PAGE__.txt +9 -0
  30. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/__next._full.txt +20 -0
  31. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/__next._head.txt +5 -0
  32. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/__next._index.txt +8 -0
  33. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/__next._tree.txt +2 -0
  34. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/05be8470af537e1f.js +1 -0
  35. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/1627bf2f54f2038d.js +4 -0
  36. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/25d8eaefeee06316.js +5 -0
  37. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/31674d9a34dac40b.js +2 -0
  38. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/3650d5168a6ef170.js +5 -0
  39. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/39c7ed480da232e5.js +5 -0
  40. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/43e71249fcda7b06.css +1 -0
  41. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/8d392274dc4eebdc.js +5 -0
  42. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/92ae03676f2ba60b.js +5 -0
  43. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/98972599ae0898f2.js +1 -0
  44. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  45. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
  46. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/cabf41855a3523b5.js +5 -0
  47. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/d2be314c3ece3fbe.js +1 -0
  48. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/e3831ae40009cd4c.js +1 -0
  49. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/f2f58a7e93290fbb.js +1 -0
  50. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/ff1a16fafef87110.js +1 -0
  51. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/chunks/turbopack-6ce0a7a6834ef0a1.js +4 -0
  52. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/u3W_d4CFznT12yceuuF-1/_buildManifest.js +11 -0
  53. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/u3W_d4CFznT12yceuuF-1/_clientMiddlewareManifest.json +1 -0
  54. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_next/static/u3W_d4CFznT12yceuuF-1/_ssgManifest.js +1 -0
  55. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/__next._full.txt +16 -0
  56. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/__next._head.txt +5 -0
  57. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/__next._index.txt +8 -0
  58. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/__next._not-found.__PAGE__.txt +5 -0
  59. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/__next._not-found.txt +4 -0
  60. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/__next._tree.txt +2 -0
  61. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/index.html +1 -0
  62. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/_not-found/index.txt +16 -0
  63. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/__next._full.txt +17 -0
  64. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/__next._head.txt +5 -0
  65. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/__next._index.txt +8 -0
  66. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/__next._tree.txt +2 -0
  67. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/__next.create.__PAGE__.txt +6 -0
  68. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/__next.create.txt +4 -0
  69. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/index.html +1 -0
  70. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/create/index.txt +17 -0
  71. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/__next._full.txt +17 -0
  72. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/__next._head.txt +5 -0
  73. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/__next._index.txt +8 -0
  74. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/__next._tree.txt +2 -0
  75. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/__next.extract.__PAGE__.txt +6 -0
  76. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/__next.extract.txt +4 -0
  77. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/index.html +1 -0
  78. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/extract/index.txt +17 -0
  79. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/index.html +1 -0
  80. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/index.txt +20 -0
  81. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/__next._full.txt +17 -0
  82. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/__next._head.txt +5 -0
  83. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/__next._index.txt +8 -0
  84. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/__next._tree.txt +2 -0
  85. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/__next.inspect.__PAGE__.txt +6 -0
  86. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/__next.inspect.txt +4 -0
  87. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/index.html +1 -0
  88. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/inspect/index.txt +17 -0
  89. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/__next._full.txt +17 -0
  90. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/__next._head.txt +5 -0
  91. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/__next._index.txt +8 -0
  92. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/__next._tree.txt +2 -0
  93. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/__next.manage.__PAGE__.txt +6 -0
  94. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/__next.manage.txt +4 -0
  95. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/index.html +1 -0
  96. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/manage/index.txt +17 -0
  97. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/__next._full.txt +17 -0
  98. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/__next._head.txt +5 -0
  99. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/__next._index.txt +8 -0
  100. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/__next._tree.txt +2 -0
  101. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/__next.split-paths.__PAGE__.txt +6 -0
  102. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/__next.split-paths.txt +4 -0
  103. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/index.html +1 -0
  104. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/split-paths/index.txt +17 -0
  105. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/__next._full.txt +17 -0
  106. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/__next._head.txt +5 -0
  107. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/__next._index.txt +8 -0
  108. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/__next._tree.txt +2 -0
  109. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/__next.validate.__PAGE__.txt +6 -0
  110. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/__next.validate.txt +4 -0
  111. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/index.html +1 -0
  112. svg2drawiolib-1.3.4/src/SVG2DrawIOLib/web/validate/index.txt +17 -0
  113. svg2drawiolib-1.3.4/tests/test_api_processing.py +339 -0
  114. svg2drawiolib-1.3.4/tests/test_api_routers.py +613 -0
  115. svg2drawiolib-1.3.4/tests/test_cli_web.py +297 -0
  116. svg2drawiolib-1.2.2/.github/workflows/ci.yml +0 -82
  117. svg2drawiolib-1.2.2/.github/workflows/publish.yml +0 -95
  118. svg2drawiolib-1.2.2/.github/workflows/release.yml +0 -86
  119. svg2drawiolib-1.2.2/.pre-commit-config.yaml +0 -36
  120. svg2drawiolib-1.2.2/ARCHITECTURE.md +0 -833
  121. svg2drawiolib-1.2.2/MANIFEST.in +0 -19
  122. svg2drawiolib-1.2.2/Makefile +0 -66
  123. svg2drawiolib-1.2.2/uv.lock +0 -900
  124. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/CONTRIBUTING.md +0 -0
  125. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/LICENSE.txt +0 -0
  126. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/__init__.py +0 -0
  127. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/__init__.py +0 -0
  128. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/add.py +0 -0
  129. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/create.py +0 -0
  130. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/create_helpers.py +0 -0
  131. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/extract.py +0 -0
  132. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/helpers.py +0 -0
  133. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/inspect.py +0 -0
  134. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/list.py +0 -0
  135. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/remove.py +0 -0
  136. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/rename.py +0 -0
  137. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/split_paths.py +0 -0
  138. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/cli/validate.py +0 -0
  139. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/icon_analyzer.py +0 -0
  140. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/library_manager.py +0 -0
  141. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/models.py +0 -0
  142. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/path_splitter.py +0 -0
  143. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/svg_processor.py +0 -0
  144. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/validator.py +0 -0
  145. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/src/SVG2DrawIOLib/xml_utils.py +0 -0
  146. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/__init__.py +0 -0
  147. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/conftest.py +0 -0
  148. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli.py +0 -0
  149. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli_create_helpers.py +0 -0
  150. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli_create_split.py +0 -0
  151. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli_extract.py +0 -0
  152. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli_helpers.py +0 -0
  153. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli_inspect.py +0 -0
  154. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli_rename.py +0 -0
  155. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_cli_validate.py +0 -0
  156. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_css_modes.py +0 -0
  157. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_library_manager.py +0 -0
  158. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_models.py +0 -0
  159. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_path_splitter.py +0 -0
  160. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_svg_processor.py +0 -0
  161. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_svg_processor_coverage.py +0 -0
  162. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_viewbox_improvements.py +0 -0
  163. {svg2drawiolib-1.2.2 → svg2drawiolib-1.3.4}/tests/test_xml_utils.py +0 -0
@@ -39,13 +39,14 @@ debug/
39
39
  /test_*.xml
40
40
  /test_*.py
41
41
 
42
+ # Bundled web UI (built artifact — not source)
43
+ src/SVG2DrawIOLib/web/*
44
+ !src/SVG2DrawIOLib/web/.gitkeep
45
+
42
46
  # web-ui (Next.js)
43
47
  web-ui/node_modules/
44
48
  web-ui/.next/
45
49
  web-ui/out/
46
50
  web-ui/.env.local
47
51
  web-ui/.env*.local
48
-
49
- # api (FastAPI)
50
- api/__pycache__/
51
- api/**/__pycache__/
52
+ !web-ui/.env.production
@@ -5,6 +5,82 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.3.4] - 2026-02-22
9
+
10
+ ### Fixed
11
+
12
+ - **PyPI wheel packaging**: Fixed project build file to remove web includes/excludes that were breaking CI/CD
13
+
14
+ ### Changed
15
+
16
+ - **`Makefile`**: Simplified `build-release` target to remove `.gitkeep` preservation logic since the placeholder is not needed in distribution builds.
17
+
18
+
19
+ ## [1.3.3] - 2026-02-22
20
+
21
+ ### Fixed
22
+
23
+ - **PyPI wheel packaging**: Fixed duplicate `.gitkeep` file in wheel that caused PyPI upload rejection. Modified `build-release` Makefile target to not preserve the `.gitkeep` placeholder file when copying web UI build artifacts, as it's only needed for development and editable installs.
24
+
25
+ ### Changed
26
+
27
+ - **`Makefile`**: Simplified `build-release` target to remove `.gitkeep` preservation logic since the placeholder is not needed in distribution builds.
28
+
29
+ ## [1.3.2] - 2026-02-22
30
+
31
+ ### Fixed
32
+
33
+ - **Editable install compatibility**: Added `.gitkeep` placeholder file in `src/SVG2DrawIOLib/web/` directory to enable editable installs (`pip install -e .`) to work before the web UI is built. This fixes CI/CD workflows that install in editable mode for testing before building the web UI.
34
+ - **Web UI packaging**: Fixed `pyproject.toml` hatchling configuration to properly include the web UI static files in the built wheel and sdist. Changed from `artifacts` to `force-include` configuration for both wheel and sdist targets. The web UI directory (`src/SVG2DrawIOLib/web/`) is now correctly included in PyPI releases, ensuring `pip install SVG2DrawIOLib[web]` followed by `svg2drawiolib web` works out of the box.
35
+
36
+ ### Changed
37
+
38
+ - **`.gitignore`**: Updated web directory exclusion pattern to allow `.gitkeep` placeholder file while still ignoring all build artifacts.
39
+ - **`Makefile`**: Updated `build-release` target to preserve `.gitkeep` file when copying web UI build artifacts.
40
+
41
+ ## [1.3.1] - 2026-02-22
42
+
43
+ ### Fixed
44
+
45
+ - **Security: Data URI sanitization** (Bug #27): Updated SVG sanitization to only block dangerous data: URIs (`data:text/html`, `data:text/javascript`, `data:application/javascript`, `data:application/x-javascript`) while allowing safe image data: URIs (`data:image/png`, `data:image/jpeg`, `data:image/svg+xml`, etc.) for legitimate embedded images.
46
+ - **Security: Case-insensitive element filtering** (Bug #28): Made dangerous element checking case-insensitive to prevent sanitization bypass via case variants like `<Script>`, `<SCRIPT>`, or `<ForeignObject>`. Updated `_DANGEROUS_ELEMENTS` set to store lowercase values and added `.lower()` call during comparison.
47
+ - **API: Duplicate error handling** (Bug #29): Extracted duplicate library error handling logic into shared `handle_library_value_error()` helper function in `processing.py`. Updated five routers (`add`, `remove`, `list`, `extract`, `inspect`) to use the centralized helper, eliminating code duplication.
48
+ - **API: Type safety** (Bug #31): Changed `handle_library_value_error()` return type from `-> None` to `-> NoReturn` to accurately reflect that the function always raises an exception and never returns, improving type checker guarantees.
49
+ - **API: Rename endpoint error handling** (Bug #32): Added "Invalid library" error check to rename endpoint to return 422 for malformed library files instead of 500 internal server error, consistent with other endpoints.
50
+ - **API: Icon names validation** (Bug #26): Added element type validation to `parse_icon_names()` to ensure all list elements are strings, preventing unhashable type errors downstream when non-string values are passed.
51
+ - **Next.js dev mode warning** (Bug #30): Made `output: "export"` conditional in `next.config.ts` (only set in production) to eliminate Next.js warning about rewrites not working with static exports during development.
52
+
53
+ ### Changed
54
+
55
+ - **Web UI default**: Changed "Inject CSS classes" checkbox default from `false` to `true` in both CreateTab and ManageTab components for better out-of-box experience.
56
+
57
+ ## [1.3.0] - 2026-02-21
58
+
59
+ ### Added
60
+
61
+ - **Browser-based Web UI**: New optional web interface that exposes all CLI commands as a browser UI. Install with `pip install "SVG2DrawIOLib[web]"` and launch with `svg2drawio web`. The server automatically opens the browser and serves both the API and frontend from a single process on port 8000.
62
+ - **Six tabs**: Create (convert SVGs to a new library), Manage (add icons, remove icons, rename icons), Extract (save icons as SVG files), Inspect (view icon details and SVG previews), Validate (structural integrity report), Split Paths (split compound paths for per-path color control)
63
+ - **FastAPI sidecar** (`src/SVG2DrawIOLib/api/`): Nine REST endpoints under `/api/*` wrapping the same Python services used by the CLI. Reuses `process_svg_files()`, `determine_sizing_strategy()`, `sanitize_filename()`, and `safe_path_join()` directly — no logic duplication.
64
+ - **SVG sanitization**: Uploaded SVG files are stripped of `<script>`, `<foreignObject>`, `javascript:` hrefs, and event-handler attributes before processing. Enforces a 10 MB per-file size limit.
65
+ - **Bundled static export**: The pre-built Next.js UI is copied into `src/SVG2DrawIOLib/web/` at release time and included in the Python wheel via hatchling artifacts — no Node.js required at runtime.
66
+ - **`[web]` optional dependency group**: `fastapi>=0.115.0`, `uvicorn[standard]>=0.32.0`, `python-multipart>=0.0.12`.
67
+ - **`svg2drawio` entry point**: Added as a shorter alias alongside `SVG2DrawIOLib` and `svg2drawiolib`.
68
+ - **Web UI Makefile targets**: `make dev-api` (FastAPI with hot-reload), `make dev-web` (Next.js dev server), `make dev-all` (both together), `make build-web` (Next.js static export), `make build-release` (build + copy into package), `make start-web` (build then launch).
69
+
70
+ ### Fixed
71
+
72
+ - **Windows `FileResponse` race condition** (`api/routers/`): All file-returning endpoints (`create`, `add`, `remove`, `rename`, `split-paths`) now use `Response(content=path.read_bytes())` instead of `FileResponse(path)`. `FileResponse` streams lazily — on Windows the `get_temp_dir()` dependency's `finally` cleanup block could delete the temp directory before the file body was streamed, causing "Failed to fetch" in the browser with no server-side error logged.
73
+ - **Static build CORS mismatch** (`web-ui/src/lib/api.ts`): Changed the `API_BASE` fallback from `"http://localhost:8000"` to `""` so the static export uses relative URLs (`/api/create` instead of `http://localhost:8000/api/create`). This fixes "Failed to fetch" when the browser opens to `http://127.0.0.1:8000` (the CLI's default bind address) while the hardcoded URL pointed to `http://localhost:8000` — a cross-origin mismatch the CORS policy rejected.
74
+ - **Dev-mode API routing** (`web-ui/next.config.ts`): Added a conditional dev-mode proxy rewrite that forwards `/api/*` to the FastAPI server (`http://localhost:8000`) when running `next dev`, so `make dev-all` works without a `.env.local` file. The rewrite is omitted during `next build` (static export does not support rewrites).
75
+ - **Next.js RSC `__PAGE__.txt` 404s**: `make build-release` now renames RSC page payload files from their on-disk subdirectory form (`create/__next.create/__PAGE__.txt`) to the flat dot-separated form (`create/__next.create.__PAGE__.txt`) that the browser requests. Starlette's `StaticFiles` serves paths literally, so the mismatched filenames caused 404s that silently broke client-side navigation.
76
+ - **Cross-platform `build-release` target**: Replaced Unix-only `rm -rf` and `cp -r` shell commands in the Makefile with a Python one-liner using `shutil.rmtree` and `shutil.copytree`, which works on Windows without Git Bash or WSL.
77
+
78
+ ### Changed
79
+
80
+ - **`pyproject.toml`**: Added `[web]` optional dependency group; added `svg2drawio` script entry point; added `[tool.hatch.build.targets.wheel] artifacts` to include the gitignored `src/SVG2DrawIOLib/web/` directory in the built wheel.
81
+ - **`.gitignore`**: Added `src/SVG2DrawIOLib/web/` (generated build artifact); removed stale `api/__pycache__/` entries from the old top-level `api/` directory.
82
+ - **Documentation**: Updated `README.md`, `QUICKSTART.md`, and `ARCHITECTURE.md` to document the web UI feature, installation, tab-to-command mapping, developer build workflow, FastAPI sidecar architecture, and bundled static export path resolution.
83
+
8
84
  ## [1.2.1] - 2026-02-09
9
85
 
10
86
  ### Changed
@@ -203,5 +279,11 @@ The project follows SOLID principles with clear module boundaries:
203
279
  - `library_manager.py`: Library file management
204
280
  - `cli/`: Modular CLI with dynamic command loading
205
281
 
282
+ [1.3.0]: https://github.com/jamesbconner/SVG2DrawIOLib/compare/v1.2.1...v1.3.0
283
+ [1.2.1]: https://github.com/jamesbconner/SVG2DrawIOLib/compare/v1.2.0...v1.2.1
284
+ [1.2.0]: https://github.com/jamesbconner/SVG2DrawIOLib/compare/v1.1.2...v1.2.0
285
+ [1.1.2]: https://github.com/jamesbconner/SVG2DrawIOLib/compare/v1.1.1...v1.1.2
286
+ [1.1.1]: https://github.com/jamesbconner/SVG2DrawIOLib/compare/v1.1.0...v1.1.1
287
+ [1.1.0]: https://github.com/jamesbconner/SVG2DrawIOLib/compare/v1.0.1...v1.1.0
206
288
  [1.0.1]: https://github.com/jamesbconner/SVG2DrawIOLib/compare/v1.0.0...v1.0.1
207
289
  [1.0.0]: https://github.com/jamesbconner/SVG2DrawIOLib/releases/tag/v1.0.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SVG2DrawIOLib
3
- Version: 1.2.2
3
+ Version: 1.3.4
4
4
  Summary: Generate DrawIO shape libraries from SVGs
5
5
  Project-URL: Homepage, https://github.com/jamesbconner/SVG2DrawIOLib
6
6
  Project-URL: Documentation, https://github.com/jamesbconner/SVG2DrawIOLib#readme
@@ -23,6 +23,7 @@ Requires-Dist: rich>=13.0.0
23
23
  Requires-Dist: svgelements>=1.9.0
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: bandit>=1.7.0; extra == 'dev'
26
+ Requires-Dist: httpx>=0.27.0; extra == 'dev'
26
27
  Requires-Dist: mypy>=1.18.0; extra == 'dev'
27
28
  Requires-Dist: pip>=26.0.1; extra == 'dev'
28
29
  Requires-Dist: pre-commit>=4.4.0; extra == 'dev'
@@ -31,6 +32,10 @@ Requires-Dist: pytest>=8.4.2; extra == 'dev'
31
32
  Requires-Dist: ruff>=0.14.4; extra == 'dev'
32
33
  Requires-Dist: twine>=5.0.0; extra == 'dev'
33
34
  Requires-Dist: uv>=0.10.0; extra == 'dev'
35
+ Provides-Extra: web
36
+ Requires-Dist: fastapi>=0.115.0; extra == 'web'
37
+ Requires-Dist: python-multipart>=0.0.12; extra == 'web'
38
+ Requires-Dist: uvicorn[standard]>=0.32.0; extra == 'web'
34
39
  Description-Content-Type: text/markdown
35
40
 
36
41
  # SVG2DrawIOLib
@@ -55,6 +60,7 @@ Convert SVG files into DrawIO/diagrams.net shape libraries with support for colo
55
60
  - 🎨 **Color Customization**: Inject CSS classes to enable color editing directly in DrawIO's interface
56
61
  - 📏 **Flexible Sizing**: Proportional scaling with aspect ratio preservation, or fixed dimensions
57
62
  - 📚 **Library Management**: Create new libraries, add/remove icons, and list contents
63
+ - 🌐 **Browser-based Web UI**: All commands available in a local web interface — no command line required
58
64
  - 🚀 **Modern CLI**: Beautiful, colorful output with rich-click
59
65
  - 🔧 **Modern Python Stack**: Built with ruff, mypy, bandit, pytest, and pre-commit hooks
60
66
 
@@ -93,6 +99,54 @@ SVG2DrawIOLib create icons/ --css -o colorable-icons.xml
93
99
  SVG2DrawIOLib create icons/ --max-size 64 -o large-icons.xml -R
94
100
  ```
95
101
 
102
+ ## Web UI
103
+
104
+ All CLI commands are available as a browser-based interface. Install with the `web` optional dependencies and launch with a single command:
105
+
106
+ ```bash
107
+ pip install 'SVG2DrawIOLib[web]'
108
+ svg2drawio web
109
+ ```
110
+
111
+ This starts a local FastAPI server and opens the UI automatically in your default browser at `http://127.0.0.1:8000`.
112
+
113
+ **Available tabs:**
114
+
115
+ | Tab | Equivalent CLI command |
116
+ |-----|------------------------|
117
+ | Create | `svg2drawio create` |
118
+ | Manage (Add / Remove / Rename) | `svg2drawio add` / `remove` / `rename` |
119
+ | Extract | `svg2drawio extract` |
120
+ | Inspect | `svg2drawio inspect` |
121
+ | Validate | `svg2drawio validate` |
122
+ | Split Paths | `svg2drawio split-paths` |
123
+
124
+ **Options:**
125
+
126
+ ```bash
127
+ svg2drawio web --host 0.0.0.0 # Listen on all interfaces
128
+ svg2drawio web --port 9000 # Custom port
129
+ svg2drawio web --no-browser # Don't open browser automatically
130
+ ```
131
+
132
+ ### Building from Source
133
+
134
+ If you are working from a source checkout, build the Next.js frontend first, then launch:
135
+
136
+ ```bash
137
+ make build-release # builds web-ui/ and copies output into the Python package
138
+ svg2drawio web
139
+ ```
140
+
141
+ Or run the frontend and API separately during development:
142
+
143
+ ```bash
144
+ make dev-api # FastAPI on :8000 (terminal 1)
145
+ make dev-web # Next.js on :3000 (terminal 2)
146
+ ```
147
+
148
+ ---
149
+
96
150
  ## Documentation
97
151
 
98
152
  - [Quick Start Guide](QUICKSTART.md) - Get started quickly for users and developers
@@ -231,6 +231,41 @@ Options:
231
231
  -q, --quiet Suppress output except errors
232
232
  ```
233
233
 
234
+ ## Web UI
235
+
236
+ ### Installation
237
+ ```bash
238
+ pip install "SVG2DrawIOLib[web]"
239
+ ```
240
+
241
+ ### Launch
242
+ ```bash
243
+ svg2drawio web
244
+ # Opens http://127.0.0.1:8000 in your browser automatically
245
+ ```
246
+
247
+ ### Options
248
+ ```bash
249
+ svg2drawio web --port 9000 # Use a different port
250
+ svg2drawio web --host 0.0.0.0 # Listen on all interfaces
251
+ svg2drawio web --no-browser # Don't auto-open the browser
252
+ svg2drawio web --ui-dir /path/to/ui # Use a custom pre-built UI directory
253
+ ```
254
+
255
+ ### Tabs
256
+ | Tab | Equivalent CLI Command |
257
+ |-----|----------------------|
258
+ | Create | `svg2drawio create` |
259
+ | Manage → Add Icons | `svg2drawio add` |
260
+ | Manage → Remove Icons | `svg2drawio remove` |
261
+ | Manage → Rename Icon | `svg2drawio rename` |
262
+ | Extract | `svg2drawio extract` |
263
+ | Inspect | `svg2drawio inspect` |
264
+ | Validate | `svg2drawio validate` |
265
+ | Split Paths | `svg2drawio split-paths` |
266
+
267
+ ---
268
+
234
269
  ## For Developers
235
270
 
236
271
  ### Setup
@@ -267,6 +302,24 @@ make all # Run all checks
267
302
  make clean # Clean build artifacts
268
303
  ```
269
304
 
305
+ ### Web UI Development
306
+ ```bash
307
+ # Install web dependencies and start FastAPI + Next.js dev servers
308
+ make dev-api # FastAPI only on port 8000 (with --reload)
309
+ make dev-web # Next.js dev server only (port 3000)
310
+
311
+ # Build the static export and copy into the Python package
312
+ make build-release # Runs npm build + copies output to src/SVG2DrawIOLib/web/
313
+
314
+ # Build and launch the web UI from the source tree
315
+ make start-web
316
+ ```
317
+
318
+ The `web-ui/` directory contains the Next.js frontend source. The built static export
319
+ is copied to `src/SVG2DrawIOLib/web/` (gitignored — generated artifact) for bundling
320
+ into the Python wheel via `make build-release`. The FastAPI server at
321
+ `SVG2DrawIOLib.api.main:app` serves both the API (`/api/*`) and the static UI (`/`).
322
+
270
323
  ### Running Tests
271
324
  ```bash
272
325
  # All tests
@@ -20,6 +20,7 @@ Convert SVG files into DrawIO/diagrams.net shape libraries with support for colo
20
20
  - 🎨 **Color Customization**: Inject CSS classes to enable color editing directly in DrawIO's interface
21
21
  - 📏 **Flexible Sizing**: Proportional scaling with aspect ratio preservation, or fixed dimensions
22
22
  - 📚 **Library Management**: Create new libraries, add/remove icons, and list contents
23
+ - 🌐 **Browser-based Web UI**: All commands available in a local web interface — no command line required
23
24
  - 🚀 **Modern CLI**: Beautiful, colorful output with rich-click
24
25
  - 🔧 **Modern Python Stack**: Built with ruff, mypy, bandit, pytest, and pre-commit hooks
25
26
 
@@ -58,6 +59,54 @@ SVG2DrawIOLib create icons/ --css -o colorable-icons.xml
58
59
  SVG2DrawIOLib create icons/ --max-size 64 -o large-icons.xml -R
59
60
  ```
60
61
 
62
+ ## Web UI
63
+
64
+ All CLI commands are available as a browser-based interface. Install with the `web` optional dependencies and launch with a single command:
65
+
66
+ ```bash
67
+ pip install 'SVG2DrawIOLib[web]'
68
+ svg2drawio web
69
+ ```
70
+
71
+ This starts a local FastAPI server and opens the UI automatically in your default browser at `http://127.0.0.1:8000`.
72
+
73
+ **Available tabs:**
74
+
75
+ | Tab | Equivalent CLI command |
76
+ |-----|------------------------|
77
+ | Create | `svg2drawio create` |
78
+ | Manage (Add / Remove / Rename) | `svg2drawio add` / `remove` / `rename` |
79
+ | Extract | `svg2drawio extract` |
80
+ | Inspect | `svg2drawio inspect` |
81
+ | Validate | `svg2drawio validate` |
82
+ | Split Paths | `svg2drawio split-paths` |
83
+
84
+ **Options:**
85
+
86
+ ```bash
87
+ svg2drawio web --host 0.0.0.0 # Listen on all interfaces
88
+ svg2drawio web --port 9000 # Custom port
89
+ svg2drawio web --no-browser # Don't open browser automatically
90
+ ```
91
+
92
+ ### Building from Source
93
+
94
+ If you are working from a source checkout, build the Next.js frontend first, then launch:
95
+
96
+ ```bash
97
+ make build-release # builds web-ui/ and copies output into the Python package
98
+ svg2drawio web
99
+ ```
100
+
101
+ Or run the frontend and API separately during development:
102
+
103
+ ```bash
104
+ make dev-api # FastAPI on :8000 (terminal 1)
105
+ make dev-web # Next.js on :3000 (terminal 2)
106
+ ```
107
+
108
+ ---
109
+
61
110
  ## Documentation
62
111
 
63
112
  - [Quick Start Guide](QUICKSTART.md) - Get started quickly for users and developers
@@ -38,6 +38,11 @@ dependencies = [
38
38
  dynamic = ["version"]
39
39
 
40
40
  [project.optional-dependencies]
41
+ web = [
42
+ "fastapi>=0.115.0",
43
+ "uvicorn[standard]>=0.32.0",
44
+ "python-multipart>=0.0.12",
45
+ ]
41
46
  dev = [
42
47
  "pytest>=8.4.2",
43
48
  "pytest-cov>=6.0.0",
@@ -48,6 +53,7 @@ dev = [
48
53
  "twine>=5.0.0",
49
54
  "pip>=26.0.1",
50
55
  "uv>=0.10.0",
56
+ "httpx>=0.27.0",
51
57
  ]
52
58
 
53
59
  [project.urls]
@@ -60,10 +66,36 @@ Changelog = "https://github.com/jamesbconner/SVG2DrawIOLib/blob/main/CHANGELOG.m
60
66
  [project.scripts]
61
67
  SVG2DrawIOLib = "SVG2DrawIOLib.cli:cli"
62
68
  svg2drawiolib = "SVG2DrawIOLib.cli:cli"
69
+ svg2drawio = "SVG2DrawIOLib.cli:cli"
63
70
 
64
71
  [tool.hatch.version]
65
72
  path = "src/SVG2DrawIOLib/__about__.py"
66
73
 
74
+ [tool.hatch.build.targets.wheel]
75
+ packages = ["src/SVG2DrawIOLib"]
76
+
77
+ [tool.hatch.build.targets.wheel.force-include]
78
+ "src/SVG2DrawIOLib/web" = "SVG2DrawIOLib/web"
79
+
80
+ [tool.hatch.build.targets.sdist]
81
+ include = [
82
+ "/src",
83
+ "/tests",
84
+ "/README.md",
85
+ "/LICENSE.txt",
86
+ "/CHANGELOG.md",
87
+ "/CONTRIBUTING.md",
88
+ "/QUICKSTART.md",
89
+ "/pyproject.toml",
90
+ ]
91
+
92
+ [tool.hatch.build.targets.sdist.force-include]
93
+ "src/SVG2DrawIOLib/web" = "src/SVG2DrawIOLib/web"
94
+
95
+ # Editable installs work without the web directory
96
+ [tool.hatch.build.targets.editable]
97
+ packages = ["src/SVG2DrawIOLib"]
98
+
67
99
  [tool.hatch.envs.default]
68
100
  dependencies = [
69
101
  "pytest>=8.0.0",
@@ -126,6 +158,7 @@ ignore = [
126
158
 
127
159
  [tool.ruff.lint.per-file-ignores]
128
160
  "tests/**/*.py" = ["ARG", "S101"]
161
+ "src/SVG2DrawIOLib/api/routers/*.py" = ["B008"] # Depends() in defaults is standard FastAPI pattern
129
162
 
130
163
  [tool.mypy]
131
164
  python_version = "3.13"
@@ -144,6 +177,18 @@ ignore_missing_imports = true
144
177
  module = "rich_click.*"
145
178
  ignore_missing_imports = true
146
179
 
180
+ [[tool.mypy.overrides]]
181
+ module = "pydantic.*"
182
+ ignore_missing_imports = true
183
+
184
+ [[tool.mypy.overrides]]
185
+ module = "fastapi.*"
186
+ ignore_missing_imports = true
187
+
147
188
  [[tool.mypy.overrides]]
148
189
  module = "SVG2DrawIOLib.cli.*"
149
190
  disable_error_code = ["untyped-decorator"]
191
+
192
+ [[tool.mypy.overrides]]
193
+ module = "SVG2DrawIOLib.api.*"
194
+ disable_error_code = ["untyped-decorator"]
@@ -1,3 +1,3 @@
1
1
  """Package version information."""
2
2
 
3
- __version__ = "1.2.2"
3
+ __version__ = "1.3.4"
@@ -0,0 +1 @@
1
+ """SVG2DrawIOLib FastAPI sidecar."""
@@ -0,0 +1,19 @@
1
+ """FastAPI dependency providers."""
2
+
3
+ import shutil
4
+ import tempfile
5
+ from collections.abc import AsyncGenerator
6
+ from pathlib import Path
7
+
8
+
9
+ async def get_temp_dir() -> AsyncGenerator[Path]:
10
+ """Provide a temporary directory that is cleaned up after the request.
11
+
12
+ Yields:
13
+ Path to a temporary directory.
14
+ """
15
+ tmp = tempfile.mkdtemp(prefix="svg2drawio_")
16
+ try:
17
+ yield Path(tmp)
18
+ finally:
19
+ shutil.rmtree(tmp, ignore_errors=True)
@@ -0,0 +1,27 @@
1
+ """Exception handlers for the FastAPI application."""
2
+
3
+ import xml.etree.ElementTree as ET
4
+
5
+ from fastapi import Request
6
+ from fastapi.responses import JSONResponse
7
+
8
+
9
+ class ConflictError(Exception):
10
+ """Exception raised when a resource conflict occurs (e.g., duplicate name)."""
11
+
12
+ pass
13
+
14
+
15
+ async def file_not_found_handler(_request: Request, exc: FileNotFoundError) -> JSONResponse:
16
+ """Handle FileNotFoundError as HTTP 404."""
17
+ return JSONResponse(status_code=404, content={"detail": str(exc)})
18
+
19
+
20
+ async def conflict_error_handler(_request: Request, exc: ConflictError) -> JSONResponse:
21
+ """Handle ConflictError as HTTP 409."""
22
+ return JSONResponse(status_code=409, content={"detail": str(exc)})
23
+
24
+
25
+ async def parse_error_handler(_request: Request, exc: ET.ParseError) -> JSONResponse:
26
+ """Handle XML ParseError as HTTP 422."""
27
+ return JSONResponse(status_code=422, content={"detail": f"Invalid XML: {exc}"})
@@ -0,0 +1,95 @@
1
+ """FastAPI application for SVG2DrawIOLib web UI."""
2
+
3
+ import os
4
+ import xml.etree.ElementTree as ET
5
+ from pathlib import Path
6
+
7
+ from fastapi import FastAPI
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from fastapi.staticfiles import StaticFiles
10
+
11
+ from SVG2DrawIOLib.__about__ import __version__
12
+ from SVG2DrawIOLib.api.exceptions import (
13
+ ConflictError,
14
+ conflict_error_handler,
15
+ file_not_found_handler,
16
+ parse_error_handler,
17
+ )
18
+ from SVG2DrawIOLib.api.models.responses import HealthResponse
19
+ from SVG2DrawIOLib.api.routers import (
20
+ add,
21
+ create,
22
+ extract,
23
+ inspect,
24
+ remove,
25
+ rename,
26
+ split_paths,
27
+ validate,
28
+ )
29
+ from SVG2DrawIOLib.api.routers import list as list_router
30
+
31
+ app = FastAPI(
32
+ title="SVG2DrawIOLib API",
33
+ description="Browser-based UI for converting SVG files into DrawIO shape libraries.",
34
+ version=__version__,
35
+ )
36
+
37
+ # CORS — allow origins from env var, defaulting to local Next.js dev server
38
+ allow_origins = os.getenv("CORS_ORIGINS", "http://localhost:3000").split(",")
39
+
40
+ app.add_middleware(
41
+ CORSMiddleware,
42
+ allow_origins=allow_origins,
43
+ allow_credentials=True,
44
+ allow_methods=["*"],
45
+ allow_headers=["*"],
46
+ expose_headers=["*"],
47
+ )
48
+
49
+ # Exception handlers
50
+ app.add_exception_handler(FileNotFoundError, file_not_found_handler) # type: ignore[arg-type]
51
+ app.add_exception_handler(ConflictError, conflict_error_handler) # type: ignore[arg-type]
52
+ # Note: ValueError is NOT handled globally to avoid masking internal processing errors.
53
+ # Endpoints should catch and handle ValueError explicitly when it represents user input validation.
54
+ # Note: ImportError is NOT handled globally to avoid masking genuine import bugs.
55
+ # The split_paths endpoint explicitly catches ImportError for missing optional dependencies.
56
+ app.add_exception_handler(ET.ParseError, parse_error_handler) # type: ignore[arg-type]
57
+
58
+ # Routers
59
+ app.include_router(create.router, prefix="/api")
60
+ app.include_router(add.router, prefix="/api")
61
+ app.include_router(remove.router, prefix="/api")
62
+ app.include_router(rename.router, prefix="/api")
63
+ app.include_router(list_router.router, prefix="/api")
64
+ app.include_router(extract.router, prefix="/api")
65
+ app.include_router(inspect.router, prefix="/api")
66
+ app.include_router(validate.router, prefix="/api")
67
+ app.include_router(split_paths.router, prefix="/api")
68
+
69
+
70
+ @app.get("/api/health", response_model=HealthResponse)
71
+ async def health() -> HealthResponse:
72
+ """Health check endpoint.
73
+
74
+ Returns:
75
+ Service status and current package version.
76
+ """
77
+ return HealthResponse(status="ok", version=__version__)
78
+
79
+
80
+ # Mount the pre-built Next.js static export when available.
81
+ # This is mounted AFTER all /api/* routes so API routes always take priority.
82
+ #
83
+ # Resolution order:
84
+ # 1. SVG2DRAWIO_UI_DIR env var (explicit override)
85
+ # 2. Bundled web/ directory next to this package (pip install SVG2DrawIOLib[web])
86
+ # 3. web-ui/out/ relative to CWD (source checkout / make start-web)
87
+ _env_ui = os.getenv("SVG2DRAWIO_UI_DIR")
88
+ if _env_ui:
89
+ _ui_dir = Path(_env_ui)
90
+ else:
91
+ _pkg_ui = Path(__file__).parent.parent / "web"
92
+ _ui_dir = _pkg_ui if _pkg_ui.is_dir() else Path("web-ui/out")
93
+
94
+ if _ui_dir.is_dir():
95
+ app.mount("/", StaticFiles(directory=_ui_dir, html=True), name="ui")
@@ -0,0 +1 @@
1
+ """API response models."""
@@ -0,0 +1,64 @@
1
+ """Pydantic response models for API endpoints."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class HealthResponse(BaseModel):
7
+ """Health check response."""
8
+
9
+ status: str
10
+ version: str
11
+
12
+
13
+ class ListResponse(BaseModel):
14
+ """Response for listing icons in a library."""
15
+
16
+ icon_names: list[str]
17
+ count: int
18
+
19
+
20
+ class IconIssue(BaseModel):
21
+ """A validation issue for a specific icon."""
22
+
23
+ severity: str # "error" or "warning"
24
+ icon: str
25
+ message: str
26
+
27
+
28
+ class ValidationChecks(BaseModel):
29
+ """Summary of validation checks performed."""
30
+
31
+ xml_structure: bool
32
+ json_format: bool
33
+ icon_count: int
34
+ icons_validated: int
35
+ icons_failed: int
36
+
37
+
38
+ class ValidateResponse(BaseModel):
39
+ """Response for library validation."""
40
+
41
+ valid: bool
42
+ errors: list[str]
43
+ warnings: list[str]
44
+ checks: ValidationChecks
45
+ icon_issues: list[IconIssue]
46
+
47
+
48
+ class IconInfo(BaseModel):
49
+ """Information about a single icon."""
50
+
51
+ name: str
52
+ width: float
53
+ height: float
54
+ shape_type: str | None = None
55
+ css_classes: list[str] = []
56
+ inline_styles: str | None = None
57
+ svg_content: str | None = None
58
+
59
+
60
+ class InspectResponse(BaseModel):
61
+ """Response for inspecting library icons."""
62
+
63
+ icons: list[IconInfo]
64
+ count: int
@@ -0,0 +1 @@
1
+ """API routers."""