spikard 0.3.1 → 0.3.2

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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/ext/spikard_rb/Cargo.toml +1 -1
  3. data/lib/spikard/version.rb +1 -1
  4. data/vendor/crates/spikard-core/Cargo.toml +40 -0
  5. data/vendor/crates/spikard-core/src/bindings/mod.rs +3 -0
  6. data/vendor/crates/spikard-core/src/bindings/response.rs +133 -0
  7. data/vendor/crates/spikard-core/src/debug.rs +63 -0
  8. data/vendor/crates/spikard-core/src/di/container.rs +726 -0
  9. data/vendor/crates/spikard-core/src/di/dependency.rs +273 -0
  10. data/vendor/crates/spikard-core/src/di/error.rs +118 -0
  11. data/vendor/crates/spikard-core/src/di/factory.rs +538 -0
  12. data/vendor/crates/spikard-core/src/di/graph.rs +545 -0
  13. data/vendor/crates/spikard-core/src/di/mod.rs +192 -0
  14. data/vendor/crates/spikard-core/src/di/resolved.rs +411 -0
  15. data/vendor/crates/spikard-core/src/di/value.rs +283 -0
  16. data/vendor/crates/spikard-core/src/errors.rs +39 -0
  17. data/vendor/crates/spikard-core/src/http.rs +153 -0
  18. data/vendor/crates/spikard-core/src/lib.rs +29 -0
  19. data/vendor/crates/spikard-core/src/lifecycle.rs +422 -0
  20. data/vendor/crates/spikard-core/src/parameters.rs +722 -0
  21. data/vendor/crates/spikard-core/src/problem.rs +310 -0
  22. data/vendor/crates/spikard-core/src/request_data.rs +189 -0
  23. data/vendor/crates/spikard-core/src/router.rs +249 -0
  24. data/vendor/crates/spikard-core/src/schema_registry.rs +183 -0
  25. data/vendor/crates/spikard-core/src/type_hints.rs +304 -0
  26. data/vendor/crates/spikard-core/src/validation.rs +699 -0
  27. data/vendor/crates/spikard-http/Cargo.toml +58 -0
  28. data/vendor/crates/spikard-http/src/auth.rs +247 -0
  29. data/vendor/crates/spikard-http/src/background.rs +249 -0
  30. data/vendor/crates/spikard-http/src/bindings/mod.rs +3 -0
  31. data/vendor/crates/spikard-http/src/bindings/response.rs +1 -0
  32. data/vendor/crates/spikard-http/src/body_metadata.rs +8 -0
  33. data/vendor/crates/spikard-http/src/cors.rs +490 -0
  34. data/vendor/crates/spikard-http/src/debug.rs +63 -0
  35. data/vendor/crates/spikard-http/src/di_handler.rs +423 -0
  36. data/vendor/crates/spikard-http/src/handler_response.rs +190 -0
  37. data/vendor/crates/spikard-http/src/handler_trait.rs +228 -0
  38. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +284 -0
  39. data/vendor/crates/spikard-http/src/lib.rs +529 -0
  40. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +149 -0
  41. data/vendor/crates/spikard-http/src/lifecycle.rs +428 -0
  42. data/vendor/crates/spikard-http/src/middleware/mod.rs +285 -0
  43. data/vendor/crates/spikard-http/src/middleware/multipart.rs +86 -0
  44. data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +147 -0
  45. data/vendor/crates/spikard-http/src/middleware/validation.rs +287 -0
  46. data/vendor/crates/spikard-http/src/openapi/mod.rs +309 -0
  47. data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +190 -0
  48. data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +308 -0
  49. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +195 -0
  50. data/vendor/crates/spikard-http/src/parameters.rs +1 -0
  51. data/vendor/crates/spikard-http/src/problem.rs +1 -0
  52. data/vendor/crates/spikard-http/src/query_parser.rs +369 -0
  53. data/vendor/crates/spikard-http/src/response.rs +399 -0
  54. data/vendor/crates/spikard-http/src/router.rs +1 -0
  55. data/vendor/crates/spikard-http/src/schema_registry.rs +1 -0
  56. data/vendor/crates/spikard-http/src/server/handler.rs +87 -0
  57. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +98 -0
  58. data/vendor/crates/spikard-http/src/server/mod.rs +805 -0
  59. data/vendor/crates/spikard-http/src/server/request_extraction.rs +119 -0
  60. data/vendor/crates/spikard-http/src/sse.rs +447 -0
  61. data/vendor/crates/spikard-http/src/testing/form.rs +14 -0
  62. data/vendor/crates/spikard-http/src/testing/multipart.rs +60 -0
  63. data/vendor/crates/spikard-http/src/testing/test_client.rs +285 -0
  64. data/vendor/crates/spikard-http/src/testing.rs +377 -0
  65. data/vendor/crates/spikard-http/src/type_hints.rs +1 -0
  66. data/vendor/crates/spikard-http/src/validation.rs +1 -0
  67. data/vendor/crates/spikard-http/src/websocket.rs +324 -0
  68. data/vendor/crates/spikard-rb/Cargo.toml +42 -0
  69. data/vendor/crates/spikard-rb/build.rs +8 -0
  70. data/vendor/crates/spikard-rb/src/background.rs +63 -0
  71. data/vendor/crates/spikard-rb/src/config.rs +294 -0
  72. data/vendor/crates/spikard-rb/src/conversion.rs +453 -0
  73. data/vendor/crates/spikard-rb/src/di.rs +409 -0
  74. data/vendor/crates/spikard-rb/src/handler.rs +625 -0
  75. data/vendor/crates/spikard-rb/src/lib.rs +2771 -0
  76. data/vendor/crates/spikard-rb/src/lifecycle.rs +274 -0
  77. data/vendor/crates/spikard-rb/src/server.rs +283 -0
  78. data/vendor/crates/spikard-rb/src/sse.rs +231 -0
  79. data/vendor/crates/spikard-rb/src/test_client.rs +404 -0
  80. data/vendor/crates/spikard-rb/src/test_sse.rs +143 -0
  81. data/vendor/crates/spikard-rb/src/test_websocket.rs +221 -0
  82. data/vendor/crates/spikard-rb/src/websocket.rs +233 -0
  83. data/vendor/spikard-core/Cargo.toml +40 -0
  84. data/vendor/spikard-core/src/bindings/mod.rs +3 -0
  85. data/vendor/spikard-core/src/bindings/response.rs +133 -0
  86. data/vendor/spikard-core/src/debug.rs +63 -0
  87. data/vendor/spikard-core/src/di/container.rs +726 -0
  88. data/vendor/spikard-core/src/di/dependency.rs +273 -0
  89. data/vendor/spikard-core/src/di/error.rs +118 -0
  90. data/vendor/spikard-core/src/di/factory.rs +538 -0
  91. data/vendor/spikard-core/src/di/graph.rs +545 -0
  92. data/vendor/spikard-core/src/di/mod.rs +192 -0
  93. data/vendor/spikard-core/src/di/resolved.rs +411 -0
  94. data/vendor/spikard-core/src/di/value.rs +283 -0
  95. data/vendor/spikard-core/src/http.rs +153 -0
  96. data/vendor/spikard-core/src/lib.rs +28 -0
  97. data/vendor/spikard-core/src/lifecycle.rs +422 -0
  98. data/vendor/spikard-core/src/parameters.rs +719 -0
  99. data/vendor/spikard-core/src/problem.rs +310 -0
  100. data/vendor/spikard-core/src/request_data.rs +189 -0
  101. data/vendor/spikard-core/src/router.rs +249 -0
  102. data/vendor/spikard-core/src/schema_registry.rs +183 -0
  103. data/vendor/spikard-core/src/type_hints.rs +304 -0
  104. data/vendor/spikard-core/src/validation.rs +699 -0
  105. data/vendor/spikard-http/Cargo.toml +58 -0
  106. data/vendor/spikard-http/src/auth.rs +247 -0
  107. data/vendor/spikard-http/src/background.rs +249 -0
  108. data/vendor/spikard-http/src/bindings/mod.rs +3 -0
  109. data/vendor/spikard-http/src/bindings/response.rs +1 -0
  110. data/vendor/spikard-http/src/body_metadata.rs +8 -0
  111. data/vendor/spikard-http/src/cors.rs +490 -0
  112. data/vendor/spikard-http/src/debug.rs +63 -0
  113. data/vendor/spikard-http/src/di_handler.rs +423 -0
  114. data/vendor/spikard-http/src/handler_response.rs +190 -0
  115. data/vendor/spikard-http/src/handler_trait.rs +228 -0
  116. data/vendor/spikard-http/src/handler_trait_tests.rs +284 -0
  117. data/vendor/spikard-http/src/lib.rs +529 -0
  118. data/vendor/spikard-http/src/lifecycle/adapter.rs +149 -0
  119. data/vendor/spikard-http/src/lifecycle.rs +428 -0
  120. data/vendor/spikard-http/src/middleware/mod.rs +285 -0
  121. data/vendor/spikard-http/src/middleware/multipart.rs +86 -0
  122. data/vendor/spikard-http/src/middleware/urlencoded.rs +147 -0
  123. data/vendor/spikard-http/src/middleware/validation.rs +287 -0
  124. data/vendor/spikard-http/src/openapi/mod.rs +309 -0
  125. data/vendor/spikard-http/src/openapi/parameter_extraction.rs +190 -0
  126. data/vendor/spikard-http/src/openapi/schema_conversion.rs +308 -0
  127. data/vendor/spikard-http/src/openapi/spec_generation.rs +195 -0
  128. data/vendor/spikard-http/src/parameters.rs +1 -0
  129. data/vendor/spikard-http/src/problem.rs +1 -0
  130. data/vendor/spikard-http/src/query_parser.rs +369 -0
  131. data/vendor/spikard-http/src/response.rs +399 -0
  132. data/vendor/spikard-http/src/router.rs +1 -0
  133. data/vendor/spikard-http/src/schema_registry.rs +1 -0
  134. data/vendor/spikard-http/src/server/handler.rs +80 -0
  135. data/vendor/spikard-http/src/server/lifecycle_execution.rs +98 -0
  136. data/vendor/spikard-http/src/server/mod.rs +805 -0
  137. data/vendor/spikard-http/src/server/request_extraction.rs +119 -0
  138. data/vendor/spikard-http/src/sse.rs +447 -0
  139. data/vendor/spikard-http/src/testing/form.rs +14 -0
  140. data/vendor/spikard-http/src/testing/multipart.rs +60 -0
  141. data/vendor/spikard-http/src/testing/test_client.rs +285 -0
  142. data/vendor/spikard-http/src/testing.rs +377 -0
  143. data/vendor/spikard-http/src/type_hints.rs +1 -0
  144. data/vendor/spikard-http/src/validation.rs +1 -0
  145. data/vendor/spikard-http/src/websocket.rs +324 -0
  146. data/vendor/spikard-rb/Cargo.toml +42 -0
  147. data/vendor/spikard-rb/build.rs +8 -0
  148. data/vendor/spikard-rb/src/background.rs +63 -0
  149. data/vendor/spikard-rb/src/config.rs +294 -0
  150. data/vendor/spikard-rb/src/conversion.rs +392 -0
  151. data/vendor/spikard-rb/src/di.rs +409 -0
  152. data/vendor/spikard-rb/src/handler.rs +534 -0
  153. data/vendor/spikard-rb/src/lib.rs +2020 -0
  154. data/vendor/spikard-rb/src/lifecycle.rs +267 -0
  155. data/vendor/spikard-rb/src/server.rs +283 -0
  156. data/vendor/spikard-rb/src/sse.rs +231 -0
  157. data/vendor/spikard-rb/src/test_client.rs +404 -0
  158. data/vendor/spikard-rb/src/test_sse.rs +143 -0
  159. data/vendor/spikard-rb/src/test_websocket.rs +221 -0
  160. data/vendor/spikard-rb/src/websocket.rs +233 -0
  161. metadata +158 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95a6f0573c8f2a27f5f0785917f248475478eee2c28d3907299793797a6ebf40
4
- data.tar.gz: e739699670d6ac5cafff00703667c32e69461138e173e0ea8c129836eb4a7efb
3
+ metadata.gz: 5616d268b7eae56dd65ab9b6256316edf4c33bde32fc3b0cf5c833f3475c3a55
4
+ data.tar.gz: 31a189bd88e7d884f49ce4524c675c64328059d8edd67c601faff58346024059
5
5
  SHA512:
6
- metadata.gz: d6c1fd8c324f247b6179d90e31e1d687e004029a4ac53fa09c785098146f3ea9e1dd0083be57890ec9456e57bbb5bae07b267203f9ca9bdf612ab32c17616ea0
7
- data.tar.gz: 41df95e9a4bd12603d9d6401c480a0760e93e101c8ed6d59253bfc19a3192696c346a7c0bb3b5cdf290d558a1bfce4e55bdf5a9f83d7228ac57dc8866f1b1ce1
6
+ metadata.gz: 79837decbb2632f4c7face9ab1eb5304f50a519d534a11c252c481d81d0b657f1dec087e7523bb86511c0238fd1a127c2c4354a1ba18fca0b416f643023cf433
7
+ data.tar.gz: 94ae43695e6c19e8c265670836993bb0264834fcd0440622dc3b43ae74bb54973e74e3b1ec0c9d15808a11acf5f88bc470f088a978cc7a1ae29ed8015b8437ae
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "spikard-rb-ext"
3
- version = "0.3.1"
3
+ version = "0.3.2"
4
4
  edition = "2024"
5
5
  license = "MIT"
6
6
  authors = ["Na'aman Hirschfeld <nhirschfeld@gmail.com>"]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Spikard
4
- VERSION = '0.3.1'
4
+ VERSION = '0.3.2'
5
5
  end
@@ -0,0 +1,40 @@
1
+ [package]
2
+ name = "spikard-core"
3
+ version.workspace = true
4
+ edition.workspace = true
5
+ authors.workspace = true
6
+ license.workspace = true
7
+ repository.workspace = true
8
+ homepage.workspace = true
9
+ description = "Shared transport-agnostic primitives for Spikard runtimes"
10
+ keywords = ["http", "web", "framework", "validation", "middleware"]
11
+ categories = ["web-programming::http-server", "web-programming", "development-tools"]
12
+ documentation = "https://docs.rs/spikard-core"
13
+ readme = "README.md"
14
+
15
+ [dependencies]
16
+ serde.workspace = true
17
+ serde_json.workspace = true
18
+ tracing.workspace = true
19
+ anyhow = "1.0"
20
+ jsonschema.workspace = true
21
+ regex = "1"
22
+ flate2 = "1.1"
23
+ brotli = "8.0"
24
+ http.workspace = true
25
+ base64 = "0.22"
26
+ serde_qs = "0.15"
27
+ url = "2.5"
28
+ jiff = "0.2"
29
+ uuid = "1.18"
30
+ indexmap = "2.12"
31
+ tokio = { workspace = true, optional = true }
32
+ bytes = { version = "1.11", optional = true }
33
+ thiserror = { workspace = true, optional = true }
34
+
35
+ [features]
36
+ default = []
37
+ di = ["dep:tokio", "dep:bytes", "dep:thiserror"]
38
+
39
+ [dev-dependencies]
40
+ tokio-test = "0.4"
@@ -0,0 +1,3 @@
1
+ pub mod response;
2
+
3
+ pub use response::{RawResponse, StaticAsset};
@@ -0,0 +1,133 @@
1
+ use crate::CompressionConfig;
2
+ use brotli::CompressorWriter;
3
+ use flate2::Compression;
4
+ use flate2::write::GzEncoder;
5
+ use std::collections::HashMap;
6
+ use std::io::Write;
7
+
8
+ /// Minimal response container shared by bindings.
9
+ #[derive(Clone, Debug)]
10
+ pub struct RawResponse {
11
+ pub status: u16,
12
+ pub headers: HashMap<String, String>,
13
+ pub body: Vec<u8>,
14
+ }
15
+
16
+ impl RawResponse {
17
+ /// Construct a new response.
18
+ pub fn new(status: u16, headers: HashMap<String, String>, body: Vec<u8>) -> Self {
19
+ Self { status, headers, body }
20
+ }
21
+
22
+ /// Apply compression filters if the response qualifies.
23
+ pub fn apply_compression(&mut self, request_headers: &HashMap<String, String>, compression: &CompressionConfig) {
24
+ if self.body.is_empty() || self.status == 206 {
25
+ return;
26
+ }
27
+ if self
28
+ .headers
29
+ .keys()
30
+ .any(|key| key.eq_ignore_ascii_case("content-encoding"))
31
+ {
32
+ return;
33
+ }
34
+ if self.body.len() < compression.min_size {
35
+ return;
36
+ }
37
+
38
+ let accept_encoding = header_value(request_headers, "Accept-Encoding").map(|value| value.to_ascii_lowercase());
39
+ let accepts_brotli = accept_encoding
40
+ .as_ref()
41
+ .map(|value| value.contains("br"))
42
+ .unwrap_or(false);
43
+ if compression.brotli && accepts_brotli && self.try_compress_brotli(compression) {
44
+ return;
45
+ }
46
+
47
+ let accepts_gzip = accept_encoding
48
+ .as_ref()
49
+ .map(|value| value.contains("gzip"))
50
+ .unwrap_or(false);
51
+ if compression.gzip && accepts_gzip {
52
+ self.try_compress_gzip(compression);
53
+ }
54
+ }
55
+
56
+ fn try_compress_brotli(&mut self, compression: &CompressionConfig) -> bool {
57
+ let quality = compression.quality.min(11);
58
+ let mut writer = CompressorWriter::new(Vec::new(), 4096, quality, 22);
59
+ if writer.write_all(&self.body).is_err() || writer.flush().is_err() {
60
+ return false;
61
+ }
62
+ let compressed = writer.into_inner();
63
+ if compressed.is_empty() {
64
+ return false;
65
+ }
66
+ self.finalize_encoded_body("br", compressed);
67
+ true
68
+ }
69
+
70
+ fn try_compress_gzip(&mut self, compression: &CompressionConfig) -> bool {
71
+ let mut encoder = GzEncoder::new(Vec::new(), Compression::new(compression.quality));
72
+ if encoder.write_all(&self.body).is_err() {
73
+ return false;
74
+ }
75
+ let compressed = encoder.finish().unwrap_or_else(|_| Vec::new());
76
+ if compressed.is_empty() {
77
+ return false;
78
+ }
79
+ self.finalize_encoded_body("gzip", compressed);
80
+ true
81
+ }
82
+
83
+ fn finalize_encoded_body(&mut self, encoding: &str, compressed: Vec<u8>) {
84
+ self.body = compressed;
85
+ self.headers
86
+ .insert("content-encoding".to_string(), encoding.to_string());
87
+ self.headers.insert("vary".to_string(), "Accept-Encoding".to_string());
88
+ self.headers
89
+ .insert("content-length".to_string(), self.body.len().to_string());
90
+ }
91
+ }
92
+
93
+ fn header_value<'a>(headers: &'a HashMap<String, String>, name: &str) -> Option<&'a str> {
94
+ headers.iter().find_map(|(key, value)| {
95
+ if key.eq_ignore_ascii_case(name) {
96
+ Some(value.as_str())
97
+ } else {
98
+ None
99
+ }
100
+ })
101
+ }
102
+
103
+ /// Pre-rendered static asset produced by the CLI bundler.
104
+ #[derive(Clone, Debug)]
105
+ pub struct StaticAsset {
106
+ pub route: String,
107
+ pub headers: HashMap<String, String>,
108
+ pub body: Vec<u8>,
109
+ }
110
+
111
+ impl StaticAsset {
112
+ /// Build a response snapshot if the incoming request targets this asset.
113
+ pub fn serve(&self, method: &str, normalized_path: &str) -> Option<RawResponse> {
114
+ if !method.eq_ignore_ascii_case("GET") && !method.eq_ignore_ascii_case("HEAD") {
115
+ return None;
116
+ }
117
+ if self.route != normalized_path {
118
+ return None;
119
+ }
120
+
121
+ let mut headers = self.headers.clone();
122
+ headers
123
+ .entry("content-length".to_string())
124
+ .or_insert_with(|| self.body.len().to_string());
125
+ let body = if method.eq_ignore_ascii_case("HEAD") {
126
+ Vec::new()
127
+ } else {
128
+ self.body.clone()
129
+ };
130
+
131
+ Some(RawResponse::new(200, headers, body))
132
+ }
133
+ }
@@ -0,0 +1,63 @@
1
+ //! Debug logging utilities for spikard-http
2
+ //!
3
+ //! This module provides debug logging that can be enabled via:
4
+ //! - Building in debug mode (cfg(debug_assertions))
5
+ //! - Setting SPIKARD_DEBUG=1 environment variable
6
+
7
+ use std::sync::atomic::{AtomicBool, Ordering};
8
+
9
+ static DEBUG_ENABLED: AtomicBool = AtomicBool::new(false);
10
+
11
+ /// Initialize debug logging based on environment and build mode
12
+ pub fn init() {
13
+ let enabled = cfg!(debug_assertions) || std::env::var("SPIKARD_DEBUG").is_ok() || std::env::var("DEBUG").is_ok();
14
+
15
+ eprintln!(
16
+ "[spikard-http::debug] init() called, cfg!(debug_assertions)={}, DEBUG={}, enabled={}",
17
+ cfg!(debug_assertions),
18
+ std::env::var("DEBUG").is_ok(),
19
+ enabled
20
+ );
21
+
22
+ DEBUG_ENABLED.store(enabled, Ordering::Relaxed);
23
+
24
+ if enabled {
25
+ eprintln!("[spikard-http] Debug logging enabled");
26
+ }
27
+ }
28
+
29
+ /// Check if debug logging is enabled
30
+ #[inline]
31
+ pub fn is_enabled() -> bool {
32
+ DEBUG_ENABLED.load(Ordering::Relaxed)
33
+ }
34
+
35
+ /// Log a debug message if debugging is enabled
36
+ #[macro_export]
37
+ macro_rules! debug_log {
38
+ ($($arg:tt)*) => {
39
+ if $crate::debug::is_enabled() {
40
+ eprintln!("[spikard-http] {}", format!($($arg)*));
41
+ }
42
+ };
43
+ }
44
+
45
+ /// Log a debug message with a specific module/component name
46
+ #[macro_export]
47
+ macro_rules! debug_log_module {
48
+ ($module:expr, $($arg:tt)*) => {
49
+ if $crate::debug::is_enabled() {
50
+ eprintln!("[spikard-http::{}] {}", $module, format!($($arg)*));
51
+ }
52
+ };
53
+ }
54
+
55
+ /// Log a debug value with pretty-printing
56
+ #[macro_export]
57
+ macro_rules! debug_log_value {
58
+ ($name:expr, $value:expr) => {
59
+ if $crate::debug::is_enabled() {
60
+ eprintln!("[spikard-http] {} = {:?}", $name, $value);
61
+ }
62
+ };
63
+ }