spikard 0.4.0-arm64-darwin-23

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 (138) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -0
  3. data/README.md +659 -0
  4. data/ext/spikard_rb/Cargo.toml +17 -0
  5. data/ext/spikard_rb/extconf.rb +10 -0
  6. data/ext/spikard_rb/src/lib.rs +6 -0
  7. data/lib/spikard/app.rb +405 -0
  8. data/lib/spikard/background.rb +27 -0
  9. data/lib/spikard/config.rb +396 -0
  10. data/lib/spikard/converters.rb +13 -0
  11. data/lib/spikard/handler_wrapper.rb +113 -0
  12. data/lib/spikard/provide.rb +214 -0
  13. data/lib/spikard/response.rb +173 -0
  14. data/lib/spikard/schema.rb +243 -0
  15. data/lib/spikard/sse.rb +111 -0
  16. data/lib/spikard/streaming_response.rb +44 -0
  17. data/lib/spikard/testing.rb +221 -0
  18. data/lib/spikard/upload_file.rb +131 -0
  19. data/lib/spikard/version.rb +5 -0
  20. data/lib/spikard/websocket.rb +59 -0
  21. data/lib/spikard.rb +43 -0
  22. data/sig/spikard.rbs +366 -0
  23. data/vendor/bundle/ruby/3.4.0/gems/diff-lcs-1.6.2/mise.toml +5 -0
  24. data/vendor/bundle/ruby/3.4.0/gems/rake-compiler-dock-1.10.0/build/buildkitd.toml +2 -0
  25. data/vendor/crates/spikard-bindings-shared/Cargo.toml +63 -0
  26. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +139 -0
  27. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +561 -0
  28. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +194 -0
  29. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +246 -0
  30. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +403 -0
  31. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +274 -0
  32. data/vendor/crates/spikard-bindings-shared/src/lib.rs +25 -0
  33. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +298 -0
  34. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +637 -0
  35. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +309 -0
  36. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +248 -0
  37. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +355 -0
  38. data/vendor/crates/spikard-bindings-shared/tests/comprehensive_coverage.rs +502 -0
  39. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +389 -0
  40. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +413 -0
  41. data/vendor/crates/spikard-core/Cargo.toml +40 -0
  42. data/vendor/crates/spikard-core/src/bindings/mod.rs +3 -0
  43. data/vendor/crates/spikard-core/src/bindings/response.rs +133 -0
  44. data/vendor/crates/spikard-core/src/debug.rs +63 -0
  45. data/vendor/crates/spikard-core/src/di/container.rs +726 -0
  46. data/vendor/crates/spikard-core/src/di/dependency.rs +273 -0
  47. data/vendor/crates/spikard-core/src/di/error.rs +118 -0
  48. data/vendor/crates/spikard-core/src/di/factory.rs +538 -0
  49. data/vendor/crates/spikard-core/src/di/graph.rs +545 -0
  50. data/vendor/crates/spikard-core/src/di/mod.rs +192 -0
  51. data/vendor/crates/spikard-core/src/di/resolved.rs +411 -0
  52. data/vendor/crates/spikard-core/src/di/value.rs +283 -0
  53. data/vendor/crates/spikard-core/src/errors.rs +39 -0
  54. data/vendor/crates/spikard-core/src/http.rs +153 -0
  55. data/vendor/crates/spikard-core/src/lib.rs +29 -0
  56. data/vendor/crates/spikard-core/src/lifecycle.rs +422 -0
  57. data/vendor/crates/spikard-core/src/metadata.rs +397 -0
  58. data/vendor/crates/spikard-core/src/parameters.rs +723 -0
  59. data/vendor/crates/spikard-core/src/problem.rs +310 -0
  60. data/vendor/crates/spikard-core/src/request_data.rs +189 -0
  61. data/vendor/crates/spikard-core/src/router.rs +249 -0
  62. data/vendor/crates/spikard-core/src/schema_registry.rs +183 -0
  63. data/vendor/crates/spikard-core/src/type_hints.rs +304 -0
  64. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +689 -0
  65. data/vendor/crates/spikard-core/src/validation/mod.rs +459 -0
  66. data/vendor/crates/spikard-http/Cargo.toml +58 -0
  67. data/vendor/crates/spikard-http/examples/sse-notifications.rs +147 -0
  68. data/vendor/crates/spikard-http/examples/websocket-chat.rs +91 -0
  69. data/vendor/crates/spikard-http/src/auth.rs +247 -0
  70. data/vendor/crates/spikard-http/src/background.rs +1562 -0
  71. data/vendor/crates/spikard-http/src/bindings/mod.rs +3 -0
  72. data/vendor/crates/spikard-http/src/bindings/response.rs +1 -0
  73. data/vendor/crates/spikard-http/src/body_metadata.rs +8 -0
  74. data/vendor/crates/spikard-http/src/cors.rs +490 -0
  75. data/vendor/crates/spikard-http/src/debug.rs +63 -0
  76. data/vendor/crates/spikard-http/src/di_handler.rs +1878 -0
  77. data/vendor/crates/spikard-http/src/handler_response.rs +532 -0
  78. data/vendor/crates/spikard-http/src/handler_trait.rs +861 -0
  79. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +284 -0
  80. data/vendor/crates/spikard-http/src/lib.rs +524 -0
  81. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +149 -0
  82. data/vendor/crates/spikard-http/src/lifecycle.rs +428 -0
  83. data/vendor/crates/spikard-http/src/middleware/mod.rs +285 -0
  84. data/vendor/crates/spikard-http/src/middleware/multipart.rs +930 -0
  85. data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +541 -0
  86. data/vendor/crates/spikard-http/src/middleware/validation.rs +287 -0
  87. data/vendor/crates/spikard-http/src/openapi/mod.rs +309 -0
  88. data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +535 -0
  89. data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +867 -0
  90. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +678 -0
  91. data/vendor/crates/spikard-http/src/query_parser.rs +369 -0
  92. data/vendor/crates/spikard-http/src/response.rs +399 -0
  93. data/vendor/crates/spikard-http/src/server/handler.rs +1557 -0
  94. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +98 -0
  95. data/vendor/crates/spikard-http/src/server/mod.rs +806 -0
  96. data/vendor/crates/spikard-http/src/server/request_extraction.rs +630 -0
  97. data/vendor/crates/spikard-http/src/server/routing_factory.rs +497 -0
  98. data/vendor/crates/spikard-http/src/sse.rs +961 -0
  99. data/vendor/crates/spikard-http/src/testing/form.rs +14 -0
  100. data/vendor/crates/spikard-http/src/testing/multipart.rs +60 -0
  101. data/vendor/crates/spikard-http/src/testing/test_client.rs +285 -0
  102. data/vendor/crates/spikard-http/src/testing.rs +377 -0
  103. data/vendor/crates/spikard-http/src/websocket.rs +831 -0
  104. data/vendor/crates/spikard-http/tests/background_behavior.rs +918 -0
  105. data/vendor/crates/spikard-http/tests/common/handlers.rs +308 -0
  106. data/vendor/crates/spikard-http/tests/common/mod.rs +21 -0
  107. data/vendor/crates/spikard-http/tests/di_integration.rs +202 -0
  108. data/vendor/crates/spikard-http/tests/doc_snippets.rs +4 -0
  109. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +1135 -0
  110. data/vendor/crates/spikard-http/tests/multipart_behavior.rs +688 -0
  111. data/vendor/crates/spikard-http/tests/server_config_builder.rs +324 -0
  112. data/vendor/crates/spikard-http/tests/sse_behavior.rs +728 -0
  113. data/vendor/crates/spikard-http/tests/websocket_behavior.rs +724 -0
  114. data/vendor/crates/spikard-rb/Cargo.toml +43 -0
  115. data/vendor/crates/spikard-rb/build.rs +199 -0
  116. data/vendor/crates/spikard-rb/src/background.rs +63 -0
  117. data/vendor/crates/spikard-rb/src/config/mod.rs +5 -0
  118. data/vendor/crates/spikard-rb/src/config/server_config.rs +283 -0
  119. data/vendor/crates/spikard-rb/src/conversion.rs +459 -0
  120. data/vendor/crates/spikard-rb/src/di/builder.rs +105 -0
  121. data/vendor/crates/spikard-rb/src/di/mod.rs +413 -0
  122. data/vendor/crates/spikard-rb/src/handler.rs +612 -0
  123. data/vendor/crates/spikard-rb/src/integration/mod.rs +3 -0
  124. data/vendor/crates/spikard-rb/src/lib.rs +1857 -0
  125. data/vendor/crates/spikard-rb/src/lifecycle.rs +275 -0
  126. data/vendor/crates/spikard-rb/src/metadata/mod.rs +5 -0
  127. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +427 -0
  128. data/vendor/crates/spikard-rb/src/runtime/mod.rs +5 -0
  129. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +326 -0
  130. data/vendor/crates/spikard-rb/src/server.rs +283 -0
  131. data/vendor/crates/spikard-rb/src/sse.rs +231 -0
  132. data/vendor/crates/spikard-rb/src/testing/client.rs +404 -0
  133. data/vendor/crates/spikard-rb/src/testing/mod.rs +7 -0
  134. data/vendor/crates/spikard-rb/src/testing/sse.rs +143 -0
  135. data/vendor/crates/spikard-rb/src/testing/websocket.rs +221 -0
  136. data/vendor/crates/spikard-rb/src/websocket.rs +233 -0
  137. data/vendor/crates/spikard-rb/tests/magnus_ffi_tests.rs +14 -0
  138. metadata +213 -0
@@ -0,0 +1,25 @@
1
+ //! Shared utilities for language bindings
2
+ //!
3
+ //! This crate provides common functionality used across all language bindings
4
+ //! (Python, Node.js, Ruby, PHP, WASM) to eliminate code duplication and ensure
5
+ //! consistent behavior.
6
+
7
+ pub mod config_extractor;
8
+ pub mod conversion_traits;
9
+ pub mod di_traits;
10
+ pub mod error_response;
11
+ pub mod handler_base;
12
+ pub mod lifecycle_base;
13
+ pub mod lifecycle_executor;
14
+ pub mod response_builder;
15
+ pub mod test_client_base;
16
+ pub mod validation_helpers;
17
+
18
+ // Re-export commonly used types
19
+ pub use config_extractor::{ConfigExtractor, ConfigSource};
20
+ pub use di_traits::{FactoryDependencyAdapter, ValueDependencyAdapter};
21
+ pub use error_response::ErrorResponseBuilder;
22
+ pub use handler_base::{HandlerError, HandlerExecutor, LanguageHandler};
23
+ pub use lifecycle_executor::{
24
+ HookResultData, LanguageLifecycleHook, LifecycleExecutor, RequestModifications, extract_body,
25
+ };
@@ -0,0 +1,298 @@
1
+ //! Lifecycle hook base implementations
2
+
3
+ use std::sync::Arc;
4
+
5
+ /// Lifecycle hook types supported across all bindings
6
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7
+ pub enum LifecycleHookType {
8
+ /// Called at the start of request processing
9
+ OnRequest,
10
+ /// Called before validation
11
+ PreValidation,
12
+ /// Called before handler execution
13
+ PreHandler,
14
+ /// Called after handler execution
15
+ OnResponse,
16
+ /// Called when an error occurs
17
+ OnError,
18
+ }
19
+
20
+ /// Result type for lifecycle hooks
21
+ #[derive(Clone)]
22
+ pub enum HookResult {
23
+ /// Continue with normal processing
24
+ Continue,
25
+ /// Short-circuit and return this response
26
+ ShortCircuit(serde_json::Value),
27
+ }
28
+
29
+ /// Trait for implementing lifecycle hooks in language bindings
30
+ pub trait LifecycleHook: Send + Sync {
31
+ /// Execute the lifecycle hook
32
+ fn execute(&self, context: serde_json::Value) -> Result<HookResult, String>;
33
+
34
+ /// Get the hook type
35
+ fn hook_type(&self) -> LifecycleHookType;
36
+ }
37
+
38
+ /// Base configuration for lifecycle hooks
39
+ pub struct LifecycleConfig {
40
+ /// Registered hooks by type
41
+ hooks: std::collections::HashMap<LifecycleHookType, Vec<Arc<dyn LifecycleHook>>>,
42
+ }
43
+
44
+ impl LifecycleConfig {
45
+ /// Create a new lifecycle configuration
46
+ pub fn new() -> Self {
47
+ Self {
48
+ hooks: std::collections::HashMap::new(),
49
+ }
50
+ }
51
+
52
+ /// Register a lifecycle hook
53
+ pub fn register(&mut self, hook: Arc<dyn LifecycleHook>) {
54
+ self.hooks.entry(hook.hook_type()).or_default().push(hook);
55
+ }
56
+
57
+ /// Get hooks for a specific type
58
+ pub fn get_hooks(&self, hook_type: LifecycleHookType) -> Vec<Arc<dyn LifecycleHook>> {
59
+ self.hooks.get(&hook_type).cloned().unwrap_or_default()
60
+ }
61
+ }
62
+
63
+ impl Default for LifecycleConfig {
64
+ fn default() -> Self {
65
+ Self::new()
66
+ }
67
+ }
68
+
69
+ #[cfg(test)]
70
+ mod tests {
71
+ use super::*;
72
+ use serde_json::json;
73
+
74
+ struct TestHook {
75
+ hook_type: LifecycleHookType,
76
+ result: HookResult,
77
+ }
78
+
79
+ impl LifecycleHook for TestHook {
80
+ fn execute(&self, _context: serde_json::Value) -> Result<HookResult, String> {
81
+ Ok(self.result.clone())
82
+ }
83
+
84
+ fn hook_type(&self) -> LifecycleHookType {
85
+ self.hook_type
86
+ }
87
+ }
88
+
89
+ #[test]
90
+ fn test_lifecycle_hook_type_equality() {
91
+ assert_eq!(LifecycleHookType::OnRequest, LifecycleHookType::OnRequest);
92
+ assert_ne!(LifecycleHookType::OnRequest, LifecycleHookType::OnResponse);
93
+ }
94
+
95
+ #[test]
96
+ fn test_lifecycle_hook_type_hash() {
97
+ use std::collections::HashSet;
98
+
99
+ let mut set = HashSet::new();
100
+ set.insert(LifecycleHookType::OnRequest);
101
+ set.insert(LifecycleHookType::PreHandler);
102
+ set.insert(LifecycleHookType::OnRequest);
103
+
104
+ assert_eq!(set.len(), 2); // OnRequest should only be added once
105
+ }
106
+
107
+ #[test]
108
+ fn test_hook_result_continue() {
109
+ let result = HookResult::Continue;
110
+ match result {
111
+ HookResult::Continue => {
112
+ // Expected
113
+ }
114
+ HookResult::ShortCircuit(_) => panic!("Expected Continue"),
115
+ }
116
+ }
117
+
118
+ #[test]
119
+ fn test_hook_result_short_circuit() {
120
+ let response = json!({ "status": "error" });
121
+ let result = HookResult::ShortCircuit(response.clone());
122
+ match result {
123
+ HookResult::Continue => panic!("Expected ShortCircuit"),
124
+ HookResult::ShortCircuit(r) => {
125
+ assert_eq!(r, response);
126
+ }
127
+ }
128
+ }
129
+
130
+ #[test]
131
+ fn test_lifecycle_config_new() {
132
+ let config = LifecycleConfig::new();
133
+ assert_eq!(config.get_hooks(LifecycleHookType::OnRequest).len(), 0);
134
+ }
135
+
136
+ #[test]
137
+ fn test_lifecycle_config_default() {
138
+ let config = LifecycleConfig::default();
139
+ assert_eq!(config.get_hooks(LifecycleHookType::OnRequest).len(), 0);
140
+ }
141
+
142
+ #[test]
143
+ fn test_register_single_hook() {
144
+ let mut config = LifecycleConfig::new();
145
+ let hook = Arc::new(TestHook {
146
+ hook_type: LifecycleHookType::OnRequest,
147
+ result: HookResult::Continue,
148
+ });
149
+
150
+ config.register(hook);
151
+
152
+ let hooks = config.get_hooks(LifecycleHookType::OnRequest);
153
+ assert_eq!(hooks.len(), 1);
154
+ }
155
+
156
+ #[test]
157
+ fn test_register_multiple_hooks_same_type() {
158
+ let mut config = LifecycleConfig::new();
159
+
160
+ for i in 0..3 {
161
+ let hook = Arc::new(TestHook {
162
+ hook_type: LifecycleHookType::OnRequest,
163
+ result: if i == 0 {
164
+ HookResult::Continue
165
+ } else {
166
+ HookResult::ShortCircuit(json!({ "index": i }))
167
+ },
168
+ });
169
+ config.register(hook);
170
+ }
171
+
172
+ let hooks = config.get_hooks(LifecycleHookType::OnRequest);
173
+ assert_eq!(hooks.len(), 3);
174
+ }
175
+
176
+ #[test]
177
+ fn test_register_hooks_different_types() {
178
+ let mut config = LifecycleConfig::new();
179
+
180
+ let hook_on_request = Arc::new(TestHook {
181
+ hook_type: LifecycleHookType::OnRequest,
182
+ result: HookResult::Continue,
183
+ });
184
+
185
+ let hook_on_error = Arc::new(TestHook {
186
+ hook_type: LifecycleHookType::OnError,
187
+ result: HookResult::Continue,
188
+ });
189
+
190
+ config.register(hook_on_request);
191
+ config.register(hook_on_error);
192
+
193
+ assert_eq!(config.get_hooks(LifecycleHookType::OnRequest).len(), 1);
194
+ assert_eq!(config.get_hooks(LifecycleHookType::OnError).len(), 1);
195
+ assert_eq!(config.get_hooks(LifecycleHookType::PreHandler).len(), 0);
196
+ }
197
+
198
+ #[test]
199
+ fn test_get_hooks_empty() {
200
+ let config = LifecycleConfig::new();
201
+ let hooks = config.get_hooks(LifecycleHookType::PreValidation);
202
+ assert!(hooks.is_empty());
203
+ }
204
+
205
+ #[test]
206
+ fn test_get_hooks_multiple_calls() {
207
+ let mut config = LifecycleConfig::new();
208
+
209
+ let hook1 = Arc::new(TestHook {
210
+ hook_type: LifecycleHookType::OnResponse,
211
+ result: HookResult::Continue,
212
+ });
213
+
214
+ let hook2 = Arc::new(TestHook {
215
+ hook_type: LifecycleHookType::OnResponse,
216
+ result: HookResult::Continue,
217
+ });
218
+
219
+ config.register(hook1);
220
+ config.register(hook2);
221
+
222
+ // Multiple calls should return independent clones
223
+ let hooks1 = config.get_hooks(LifecycleHookType::OnResponse);
224
+ let hooks2 = config.get_hooks(LifecycleHookType::OnResponse);
225
+
226
+ assert_eq!(hooks1.len(), 2);
227
+ assert_eq!(hooks2.len(), 2);
228
+ }
229
+
230
+ #[test]
231
+ fn test_hook_execute() {
232
+ let hook = TestHook {
233
+ hook_type: LifecycleHookType::OnRequest,
234
+ result: HookResult::Continue,
235
+ };
236
+
237
+ let context = json!({ "test": "data" });
238
+ let result = hook.execute(context);
239
+
240
+ assert!(result.is_ok());
241
+ match result.unwrap() {
242
+ HookResult::Continue => {
243
+ // Expected
244
+ }
245
+ HookResult::ShortCircuit(_) => panic!("Expected Continue"),
246
+ }
247
+ }
248
+
249
+ #[test]
250
+ fn test_hook_type_retrieval() {
251
+ let hook = TestHook {
252
+ hook_type: LifecycleHookType::PreValidation,
253
+ result: HookResult::Continue,
254
+ };
255
+
256
+ assert_eq!(hook.hook_type(), LifecycleHookType::PreValidation);
257
+ }
258
+
259
+ #[test]
260
+ fn test_all_hook_types() {
261
+ let hook_types = vec![
262
+ LifecycleHookType::OnRequest,
263
+ LifecycleHookType::PreValidation,
264
+ LifecycleHookType::PreHandler,
265
+ LifecycleHookType::OnResponse,
266
+ LifecycleHookType::OnError,
267
+ ];
268
+
269
+ let mut config = LifecycleConfig::new();
270
+
271
+ for hook_type in hook_types.iter() {
272
+ let hook = Arc::new(TestHook {
273
+ hook_type: *hook_type,
274
+ result: HookResult::Continue,
275
+ });
276
+ config.register(hook);
277
+ }
278
+
279
+ // Verify all types are registered
280
+ for hook_type in hook_types {
281
+ let hooks = config.get_hooks(hook_type);
282
+ assert_eq!(hooks.len(), 1);
283
+ }
284
+ }
285
+
286
+ #[test]
287
+ fn test_hook_result_clone() {
288
+ let original = HookResult::ShortCircuit(json!({ "key": "value" }));
289
+ let cloned = original.clone();
290
+
291
+ match cloned {
292
+ HookResult::ShortCircuit(response) => {
293
+ assert_eq!(response["key"], "value");
294
+ }
295
+ _ => panic!("Expected ShortCircuit"),
296
+ }
297
+ }
298
+ }