nitro-framework 0.2.0__tar.gz → 0.3.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 (142) hide show
  1. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/Cargo.lock +30 -29
  2. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/Cargo.toml +5 -5
  3. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/PKG-INFO +3 -2
  4. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/websocket.rs +60 -0
  5. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/protocol.rs +12 -1
  6. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/__init__.py +1 -1
  7. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/__init__.py +40 -1
  8. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/pyproject.toml +6 -2
  9. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/LICENSE-APACHE +0 -0
  10. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/LICENSE-MIT +0 -0
  11. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/README.md +0 -0
  12. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/Cargo.toml +0 -0
  13. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/LICENSE-APACHE +0 -0
  14. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/LICENSE-MIT +0 -0
  15. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/src/channel.rs +0 -0
  16. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/src/codec.rs +0 -0
  17. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/src/intercom_core.rs +0 -0
  18. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/src/redis.rs +0 -0
  19. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/intercom-core/tests/redis_backend.rs +0 -0
  20. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/Cargo.toml +0 -0
  21. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/LICENSE-APACHE +0 -0
  22. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/LICENSE-MIT +0 -0
  23. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/examples/floor.rs +0 -0
  24. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/config.rs +0 -0
  25. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/disconnect.rs +0 -0
  26. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/files.rs +0 -0
  27. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/headers.rs +0 -0
  28. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/hosts.rs +0 -0
  29. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/lifecycle/drain.rs +0 -0
  30. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/lifecycle/signals.rs +0 -0
  31. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/lifecycle.rs +0 -0
  32. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/nitro_core.rs +0 -0
  33. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/router/matcher.rs +0 -0
  34. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/router/route.rs +0 -0
  35. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/router.rs +0 -0
  36. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/streaming.rs +0 -0
  37. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/transport/accept.rs +0 -0
  38. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/transport/connection.rs +0 -0
  39. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/transport/quic.rs +0 -0
  40. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/transport/tls.rs +0 -0
  41. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/transport.rs +0 -0
  42. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/src/webtransport.rs +0 -0
  43. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/tests/observability.rs +0 -0
  44. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/tests/serving.rs +0 -0
  45. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/tests/signals.rs +0 -0
  46. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-core/tests/webtransport.rs +0 -0
  47. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-observability/Cargo.toml +0 -0
  48. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-observability/LICENSE-APACHE +0 -0
  49. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-observability/LICENSE-MIT +0 -0
  50. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-observability/src/exporter.rs +0 -0
  51. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-observability/src/metrics.rs +0 -0
  52. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-observability/src/nitro_observability.rs +0 -0
  53. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/Cargo.toml +0 -0
  54. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/LICENSE-APACHE +0 -0
  55. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/LICENSE-MIT +0 -0
  56. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/config.rs +0 -0
  57. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/dispatch.rs +0 -0
  58. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/handoff.rs +0 -0
  59. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/headers.rs +0 -0
  60. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/intercom_bridge.rs +0 -0
  61. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/lifecycle.rs +0 -0
  62. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/nitro_py.rs +0 -0
  63. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/scope.rs +0 -0
  64. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/crates/nitro-py/src/server.rs +0 -0
  65. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/app.py +0 -0
  66. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cache/__init__.py +0 -0
  67. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cache/backends/__init__.py +0 -0
  68. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cache/backends/memcached.py +0 -0
  69. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cache/backends/memory.py +0 -0
  70. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cache/backends/redis.py +0 -0
  71. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cache/base.py +0 -0
  72. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cache/handler.py +0 -0
  73. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/__main__.py +0 -0
  74. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/commands/__init__.py +0 -0
  75. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/commands/check.py +0 -0
  76. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/commands/shell.py +0 -0
  77. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/commands/static.py +0 -0
  78. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/commands/version.py +0 -0
  79. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/cli/serve.py +0 -0
  80. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/di/__init__.py +0 -0
  81. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/endpoints.py +0 -0
  82. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/intercom/__init__.py +0 -0
  83. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/intercom/backends.py +0 -0
  84. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/log.py +0 -0
  85. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/__init__.py +0 -0
  86. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/backends/__init__.py +0 -0
  87. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/backends/base.py +0 -0
  88. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/backends/console.py +0 -0
  89. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/backends/oauth_smtp.py +0 -0
  90. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/backends/sendgrid.py +0 -0
  91. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/backends/ses.py +0 -0
  92. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/backends/smtp.py +0 -0
  93. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/message.py +0 -0
  94. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/mail/utils.py +0 -0
  95. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/middleware/__init__.py +0 -0
  96. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/middleware/base.py +0 -0
  97. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/middleware/common.py +0 -0
  98. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/middleware/stack.py +0 -0
  99. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/protocols/__init__.py +0 -0
  100. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/protocols/exceptions.py +0 -0
  101. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/protocols/http.py +0 -0
  102. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/protocols/websocket.py +0 -0
  103. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/protocols/webtransport.py +0 -0
  104. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/reload.py +0 -0
  105. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/routing/__init__.py +0 -0
  106. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/routing/converters.py +0 -0
  107. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/routing/mount.py +0 -0
  108. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/routing/parameters.py +0 -0
  109. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/routing/patterns.py +0 -0
  110. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/routing/reverse.py +0 -0
  111. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/routing/router.py +0 -0
  112. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/sessions.py +0 -0
  113. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/settings/__init__.py +0 -0
  114. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/settings/defaults.py +0 -0
  115. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/shortcuts.py +0 -0
  116. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/staticfiles.py +0 -0
  117. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/__init__.py +0 -0
  118. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/backends/__init__.py +0 -0
  119. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/backends/azure.py +0 -0
  120. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/backends/filesystem.py +0 -0
  121. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/backends/memory.py +0 -0
  122. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/backends/s3.py +0 -0
  123. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/base.py +0 -0
  124. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/storage/handler.py +0 -0
  125. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/templates/__init__.py +0 -0
  126. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/templates/engine.py +0 -0
  127. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/templates/exceptions.py +0 -0
  128. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/templates/templates.py +0 -0
  129. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/testing.py +0 -0
  130. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/__init__.py +0 -0
  131. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/archives.py +0 -0
  132. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/content.py +0 -0
  133. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/crypto.py +0 -0
  134. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/datetime.py +0 -0
  135. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/decorators.py +0 -0
  136. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/http.py +0 -0
  137. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/json.py +0 -0
  138. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/utils/modules.py +0 -0
  139. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/views/__init__.py +0 -0
  140. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/views/debug.py +0 -0
  141. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/views/templates/error_404.html +0 -0
  142. {nitro_framework-0.2.0 → nitro_framework-0.3.1}/nitro/views/templates/error_500.html +0 -0
@@ -214,9 +214,9 @@ dependencies = [
214
214
 
215
215
  [[package]]
216
216
  name = "combine"
217
- version = "4.6.7"
217
+ version = "4.6.8"
218
218
  source = "registry+https://github.com/rust-lang/crates.io-index"
219
- checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
219
+ checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e"
220
220
  dependencies = [
221
221
  "bytes",
222
222
  "futures-core",
@@ -690,16 +690,17 @@ dependencies = [
690
690
 
691
691
  [[package]]
692
692
  name = "hyper-util"
693
- version = "0.1.20"
693
+ version = "0.1.21"
694
694
  source = "registry+https://github.com/rust-lang/crates.io-index"
695
- checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
695
+ checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff"
696
696
  dependencies = [
697
- "base64 0.22.1",
697
+ "base64 0.23.1",
698
698
  "bytes",
699
699
  "futures-channel",
700
700
  "futures-util",
701
701
  "http",
702
702
  "http-body",
703
+ "httparse",
703
704
  "hyper",
704
705
  "ipnet",
705
706
  "libc",
@@ -826,7 +827,7 @@ dependencies = [
826
827
 
827
828
  [[package]]
828
829
  name = "intercom-core"
829
- version = "0.2.0"
830
+ version = "0.3.1"
830
831
  dependencies = [
831
832
  "bytes",
832
833
  "futures-util",
@@ -841,7 +842,7 @@ dependencies = [
841
842
 
842
843
  [[package]]
843
844
  name = "intercom-py"
844
- version = "0.2.0"
845
+ version = "0.3.1"
845
846
  dependencies = [
846
847
  "bytes",
847
848
  "futures-util",
@@ -1029,7 +1030,7 @@ dependencies = [
1029
1030
 
1030
1031
  [[package]]
1031
1032
  name = "nitro-core"
1032
- version = "0.2.0"
1033
+ version = "0.3.1"
1033
1034
  dependencies = [
1034
1035
  "base64 0.23.1",
1035
1036
  "bytes",
@@ -1071,7 +1072,7 @@ dependencies = [
1071
1072
 
1072
1073
  [[package]]
1073
1074
  name = "nitro-observability"
1074
- version = "0.2.0"
1075
+ version = "0.3.1"
1075
1076
  dependencies = [
1076
1077
  "bytes",
1077
1078
  "futures-util",
@@ -1089,7 +1090,7 @@ dependencies = [
1089
1090
 
1090
1091
  [[package]]
1091
1092
  name = "nitro-py"
1092
- version = "0.2.0"
1093
+ version = "0.3.1"
1093
1094
  dependencies = [
1094
1095
  "bytes",
1095
1096
  "futures-util",
@@ -1368,9 +1369,9 @@ dependencies = [
1368
1369
 
1369
1370
  [[package]]
1370
1371
  name = "quinn"
1371
- version = "0.11.11"
1372
+ version = "0.11.12"
1372
1373
  source = "registry+https://github.com/rust-lang/crates.io-index"
1373
- checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8"
1374
+ checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11"
1374
1375
  dependencies = [
1375
1376
  "bytes",
1376
1377
  "cfg_aliases",
@@ -1389,9 +1390,9 @@ dependencies = [
1389
1390
 
1390
1391
  [[package]]
1391
1392
  name = "quinn-proto"
1392
- version = "0.11.16"
1393
+ version = "0.11.19"
1393
1394
  source = "registry+https://github.com/rust-lang/crates.io-index"
1394
- checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560"
1395
+ checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe"
1395
1396
  dependencies = [
1396
1397
  "bytes",
1397
1398
  "getrandom 0.4.3",
@@ -1480,9 +1481,9 @@ dependencies = [
1480
1481
 
1481
1482
  [[package]]
1482
1483
  name = "redis"
1483
- version = "1.6.0"
1484
+ version = "1.7.1"
1484
1485
  source = "registry+https://github.com/rust-lang/crates.io-index"
1485
- checksum = "e37a4ca5c6ca42aa3e6df2fd32b987a65d32a4c2159a6f3fe0fd1df306a2658f"
1486
+ checksum = "ed5b98ae99461e02895c3a96a25dbe4d852a3d5e5b815d31d5d9e4b5344d99e9"
1486
1487
  dependencies = [
1487
1488
  "arc-swap",
1488
1489
  "arcstr",
@@ -1544,11 +1545,11 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
1544
1545
 
1545
1546
  [[package]]
1546
1547
  name = "reqwest"
1547
- version = "0.13.4"
1548
+ version = "0.13.5"
1548
1549
  source = "registry+https://github.com/rust-lang/crates.io-index"
1549
- checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
1550
+ checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029"
1550
1551
  dependencies = [
1551
- "base64 0.22.1",
1552
+ "base64 0.23.1",
1552
1553
  "bytes",
1553
1554
  "futures-core",
1554
1555
  "futures-util",
@@ -1661,9 +1662,9 @@ dependencies = [
1661
1662
 
1662
1663
  [[package]]
1663
1664
  name = "rustls"
1664
- version = "0.23.43"
1665
+ version = "0.23.45"
1665
1666
  source = "registry+https://github.com/rust-lang/crates.io-index"
1666
- checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06"
1667
+ checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634"
1667
1668
  dependencies = [
1668
1669
  "aws-lc-rs",
1669
1670
  "log",
@@ -1735,9 +1736,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
1735
1736
 
1736
1737
  [[package]]
1737
1738
  name = "rustls-webpki"
1738
- version = "0.103.13"
1739
+ version = "0.103.15"
1739
1740
  source = "registry+https://github.com/rust-lang/crates.io-index"
1740
- checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
1741
+ checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
1741
1742
  dependencies = [
1742
1743
  "aws-lc-rs",
1743
1744
  "ring",
@@ -2013,18 +2014,18 @@ dependencies = [
2013
2014
 
2014
2015
  [[package]]
2015
2016
  name = "thiserror"
2016
- version = "2.0.20"
2017
+ version = "2.0.21"
2017
2018
  source = "registry+https://github.com/rust-lang/crates.io-index"
2018
- checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
2019
+ checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
2019
2020
  dependencies = [
2020
2021
  "thiserror-impl",
2021
2022
  ]
2022
2023
 
2023
2024
  [[package]]
2024
2025
  name = "thiserror-impl"
2025
- version = "2.0.20"
2026
+ version = "2.0.21"
2026
2027
  source = "registry+https://github.com/rust-lang/crates.io-index"
2027
- checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
2028
+ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
2028
2029
  dependencies = [
2029
2030
  "proc-macro2",
2030
2031
  "quote",
@@ -2125,9 +2126,9 @@ dependencies = [
2125
2126
 
2126
2127
  [[package]]
2127
2128
  name = "tokio-rustls"
2128
- version = "0.26.4"
2129
+ version = "0.26.6"
2129
2130
  source = "registry+https://github.com/rust-lang/crates.io-index"
2130
- checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
2131
+ checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db"
2131
2132
  dependencies = [
2132
2133
  "rustls",
2133
2134
  "tokio",
@@ -5,14 +5,14 @@ members = ["crates/nitro-core", "crates/nitro-observability", "crates/nitro-py",
5
5
  [workspace.package]
6
6
  edition = "2024"
7
7
  license = "MIT OR Apache-2.0"
8
- version = "0.2.0"
8
+ version = "0.3.1"
9
9
  authors = ["Mario Ritzerfeld <oss@jaldis.com>"]
10
10
  repository = "https://github.com/jaldisdev/nitro"
11
11
 
12
12
  [workspace.dependencies]
13
- nitro-core = { path = "crates/nitro-core", version = "0.2.0" }
14
- nitro-observability = { path = "crates/nitro-observability", version = "0.2.0" }
15
- intercom-core = { path = "crates/intercom-core", version = "0.2.0" }
13
+ nitro-core = { path = "crates/nitro-core", version = "0.3.1" }
14
+ nitro-observability = { path = "crates/nitro-observability", version = "0.3.1" }
15
+ intercom-core = { path = "crates/intercom-core", version = "0.3.1" }
16
16
 
17
17
  # Async runtime
18
18
  tokio = { version = "1.53.1", features = ["full"] }
@@ -34,7 +34,7 @@ h3-webtransport = "0.1.2"
34
34
  h3-datagram = "0.0.2"
35
35
 
36
36
  # TLS
37
- rustls = { version = "0.23.43", default-features = false, features = ["tls12", "ring", "logging", "std"] }
37
+ rustls = { version = "0.23.45", default-features = false, features = ["tls12", "ring", "logging", "std"] }
38
38
  rustls-pemfile = "2.2.0"
39
39
  # Default features would bring aws-lc-rs. Everything here uses ring, and a
40
40
  # second crypto provider compiled into the wheel is weight nothing calls.
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nitro-framework
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Framework :: AsyncIO
6
6
  Classifier: Intended Audience :: Developers
7
7
  Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Programming Language :: Python :: 3.13
9
9
  Classifier: Programming Language :: Python :: 3.14
10
+ Classifier: Programming Language :: Python :: 3.15
10
11
  Classifier: Programming Language :: Rust
11
12
  Classifier: Topic :: Internet :: WWW/HTTP
12
13
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
@@ -34,7 +35,7 @@ Requires-Dist: pytest-asyncio>=1.0 ; extra == 'dev'
34
35
  Requires-Dist: pytest-timeout>=2.4 ; extra == 'dev'
35
36
  Requires-Dist: cryptography>=50.0.0 ; extra == 'dev'
36
37
  Requires-Dist: websockets>=15 ; extra == 'dev'
37
- Requires-Dist: aioquic>=1.3 ; extra == 'dev'
38
+ Requires-Dist: aioquic>=1.3,<1.6 ; extra == 'dev'
38
39
  Requires-Dist: authlib>=1.7.2 ; extra == 'email-oauth'
39
40
  Requires-Dist: emcache>=1.3.3 ; python_full_version < '3.14' and extra == 'memcached'
40
41
  Requires-Dist: redis[hiredis]>=8.0.0 ; extra == 'redis'
@@ -384,11 +384,29 @@ impl WebSocketReceiver {
384
384
  }
385
385
  }
386
386
 
387
+ /// A peer that goes away without closing is an ended connection, not a failure:
388
+ /// a browser tab closing, a reloading server, a dropped network. Reporting those
389
+ /// as transport failures would make every handler recognise them by their text.
387
390
  fn transport_error(error: tokio_tungstenite::tungstenite::Error) -> WebSocketError {
391
+ use std::io::ErrorKind;
392
+
388
393
  use tokio_tungstenite::tungstenite::Error;
394
+ use tokio_tungstenite::tungstenite::error::ProtocolError;
389
395
 
390
396
  match error {
391
397
  Error::ConnectionClosed | Error::AlreadyClosed => WebSocketError::Closed,
398
+ Error::Protocol(ProtocolError::ResetWithoutClosingHandshake) => WebSocketError::Closed,
399
+ Error::Io(failure)
400
+ if matches!(
401
+ failure.kind(),
402
+ ErrorKind::ConnectionReset
403
+ | ErrorKind::ConnectionAborted
404
+ | ErrorKind::BrokenPipe
405
+ | ErrorKind::UnexpectedEof
406
+ ) =>
407
+ {
408
+ WebSocketError::Closed
409
+ }
392
410
  other => WebSocketError::Transport(other.to_string()),
393
411
  }
394
412
  }
@@ -413,6 +431,48 @@ mod tests {
413
431
  headers
414
432
  }
415
433
 
434
+ #[test]
435
+ fn a_peer_that_vanishes_reads_as_a_closed_connection() {
436
+ use std::io::ErrorKind;
437
+
438
+ use tokio_tungstenite::tungstenite::Error;
439
+ use tokio_tungstenite::tungstenite::error::ProtocolError;
440
+
441
+ let vanished = [
442
+ Error::ConnectionClosed,
443
+ Error::AlreadyClosed,
444
+ Error::Protocol(ProtocolError::ResetWithoutClosingHandshake),
445
+ Error::Io(ErrorKind::ConnectionReset.into()),
446
+ Error::Io(ErrorKind::BrokenPipe.into()),
447
+ Error::Io(ErrorKind::UnexpectedEof.into()),
448
+ ];
449
+
450
+ for error in vanished {
451
+ let reported = transport_error(error);
452
+ assert!(
453
+ matches!(reported, WebSocketError::Closed),
454
+ "expected a closed connection, got {reported:?}"
455
+ );
456
+ }
457
+ }
458
+
459
+ #[test]
460
+ fn a_real_transport_failure_is_still_reported_as_one() {
461
+ use std::io::ErrorKind;
462
+
463
+ use tokio_tungstenite::tungstenite::Error;
464
+ use tokio_tungstenite::tungstenite::error::ProtocolError;
465
+
466
+ assert!(matches!(
467
+ transport_error(Error::Io(ErrorKind::PermissionDenied.into())),
468
+ WebSocketError::Transport(_)
469
+ ));
470
+ assert!(matches!(
471
+ transport_error(Error::Protocol(ProtocolError::WrongHttpMethod)),
472
+ WebSocketError::Transport(_)
473
+ ));
474
+ }
475
+
416
476
  #[test]
417
477
  fn a_complete_upgrade_request_is_recognised() {
418
478
  assert!(is_upgrade_request(&upgrade_headers()));
@@ -610,7 +610,18 @@ async fn next_message(
610
610
  return Ok(None);
611
611
  };
612
612
 
613
- match message.map_err(socket_error)? {
613
+ let message = match message {
614
+ Ok(message) => message,
615
+ // The connection ending is the end of the stream, however it ended
616
+ Err(WebSocketError::Closed) => {
617
+ *guard = None;
618
+ phase.store(PHASE_CLOSED, Ordering::Release);
619
+ return Ok(None);
620
+ }
621
+ Err(failure) => return Err(socket_error(failure)),
622
+ };
623
+
624
+ match message {
614
625
  WebSocketMessage::Text(text) => {
615
626
  return Python::attach(|python| {
616
627
  Ok(Some(text.into_pyobject(python)?.into_any().unbind()))
@@ -21,6 +21,6 @@
21
21
 
22
22
  from nitro.app import Nitro
23
23
 
24
- __version__ = "0.2.0"
24
+ __version__ = "0.3.1"
25
25
 
26
26
  __all__ = ["Nitro", "__version__"]
@@ -71,6 +71,32 @@ class RootCommand(click.Group):
71
71
  }
72
72
  settings.update(kwargs.pop("context_settings", None) or {})
73
73
  super().__init__(*args, context_settings=settings, **kwargs)
74
+ self._project_commands_loaded = False
75
+
76
+ def get_command(self, context: click.Context, name: str) -> click.Command | None:
77
+ command = super().get_command(context, name)
78
+ # An application specifier always carries a colon, and naming one is
79
+ # no reason to import the project's commands.
80
+ if command is None and ":" not in name and self._load_project_commands():
81
+ command = super().get_command(context, name)
82
+ return command
83
+
84
+ def list_commands(self, context: click.Context) -> list[str]:
85
+ self._load_project_commands()
86
+ return super().list_commands(context)
87
+
88
+ def _load_project_commands(self) -> bool:
89
+ """Register the project's commands the first time one could be meant.
90
+
91
+ Importing them imports the project, which neither a built-in command
92
+ nor serving has any use for — and a reload supervisor would pay for it
93
+ on every start. Returns whether this call was the one that loaded them.
94
+ """
95
+ if self._project_commands_loaded:
96
+ return False
97
+ self._project_commands_loaded = True
98
+ load_project_commands(self)
99
+ return True
74
100
 
75
101
  def resolve_command(
76
102
  self, context: click.Context, args: list[str]
@@ -165,7 +191,21 @@ def _commands_in_module(module: object) -> list[click.Command]:
165
191
 
166
192
 
167
193
  def register_commands(group: click.Group, package_name: str) -> None:
194
+ """Add the commands of `package_name` to `group`, never replacing one.
195
+
196
+ Project commands are registered only once one is asked for, so a built-in
197
+ has already answered to its name by then; letting a project command take
198
+ it over would make the name mean one thing or the other depending on what
199
+ was run first.
200
+ """
168
201
  for command in commands_in(package_name):
202
+ if command.name in group.commands:
203
+ logger.warning(
204
+ "command %r from %r is already taken; keeping the one registered first",
205
+ command.name,
206
+ package_name,
207
+ )
208
+ continue
169
209
  group.add_command(command)
170
210
 
171
211
 
@@ -200,5 +240,4 @@ def main() -> None:
200
240
 
201
241
  configure_logging()
202
242
  register_commands(cli, BUILTIN_COMMAND_PACKAGE)
203
- load_project_commands(cli)
204
243
  cli()
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "nitro-framework"
7
- version = "0.2.0"
7
+ version = "0.3.1"
8
8
  description = "Async-first Python web framework with a bundled Rust server"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -19,6 +19,7 @@ classifiers = [
19
19
  "Programming Language :: Python :: 3",
20
20
  "Programming Language :: Python :: 3.13",
21
21
  "Programming Language :: Python :: 3.14",
22
+ "Programming Language :: Python :: 3.15",
22
23
  "Programming Language :: Rust",
23
24
  "Topic :: Internet :: WWW/HTTP",
24
25
  "Topic :: Software Development :: Libraries :: Application Frameworks",
@@ -61,7 +62,10 @@ dev = [
61
62
  "pytest-timeout>=2.4",
62
63
  "cryptography>=50.0.0",
63
64
  "websockets>=15",
64
- "aioquic>=1.3",
65
+ # 1.6.0 checks a response's content-length against the bytes it
66
+ # received without exempting HEAD, so it rejects the HEAD responses
67
+ # RFC 9110 §9.3.2 asks for and drops the events for them.
68
+ "aioquic>=1.3,<1.6",
65
69
  ]
66
70
 
67
71
  [project.urls]