spikard 0.12.0 → 0.15.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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/Steepfile +6 -0
  3. data/ext/spikard_rb/extconf.rb +1 -2
  4. data/ext/spikard_rb/{Cargo.lock → native/Cargo.lock} +897 -451
  5. data/ext/spikard_rb/native/Cargo.toml +24 -0
  6. data/ext/spikard_rb/src/lib.rs +5366 -3
  7. data/lib/spikard/native.rb +86 -0
  8. data/lib/spikard/version.rb +6 -1
  9. data/lib/spikard.rb +8 -45
  10. data/lib/spikard_rb.so +0 -0
  11. data/sig/types.rbs +427 -0
  12. metadata +14 -242
  13. data/LICENSE +0 -1
  14. data/README.md +0 -267
  15. data/ext/spikard_rb/Cargo.toml +0 -17
  16. data/lib/spikard/app.rb +0 -428
  17. data/lib/spikard/background.rb +0 -58
  18. data/lib/spikard/config.rb +0 -506
  19. data/lib/spikard/converters.rb +0 -13
  20. data/lib/spikard/grpc.rb +0 -182
  21. data/lib/spikard/handler_wrapper.rb +0 -113
  22. data/lib/spikard/provide.rb +0 -214
  23. data/lib/spikard/response.rb +0 -173
  24. data/lib/spikard/schema.rb +0 -243
  25. data/lib/spikard/sse.rb +0 -111
  26. data/lib/spikard/streaming_response.rb +0 -44
  27. data/lib/spikard/testing.rb +0 -432
  28. data/lib/spikard/upload_file.rb +0 -131
  29. data/lib/spikard/websocket.rb +0 -59
  30. data/sig/spikard.rbs +0 -719
  31. data/vendor/crates/spikard-bindings-shared/Cargo.toml +0 -80
  32. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +0 -132
  33. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +0 -905
  34. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +0 -210
  35. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +0 -252
  36. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +0 -404
  37. data/vendor/crates/spikard-bindings-shared/src/grpc_metadata.rs +0 -199
  38. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +0 -252
  39. data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +0 -829
  40. data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +0 -587
  41. data/vendor/crates/spikard-bindings-shared/src/lib.rs +0 -33
  42. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +0 -298
  43. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +0 -594
  44. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +0 -743
  45. data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +0 -944
  46. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +0 -260
  47. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +0 -369
  48. data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +0 -192
  49. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +0 -383
  50. data/vendor/crates/spikard-bindings-shared/tests/full_coverage.rs +0 -459
  51. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +0 -280
  52. data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +0 -669
  53. data/vendor/crates/spikard-core/Cargo.toml +0 -60
  54. data/vendor/crates/spikard-core/src/bindings/mod.rs +0 -3
  55. data/vendor/crates/spikard-core/src/bindings/response.rs +0 -130
  56. data/vendor/crates/spikard-core/src/debug.rs +0 -127
  57. data/vendor/crates/spikard-core/src/di/container.rs +0 -702
  58. data/vendor/crates/spikard-core/src/di/dependency.rs +0 -273
  59. data/vendor/crates/spikard-core/src/di/error.rs +0 -118
  60. data/vendor/crates/spikard-core/src/di/factory.rs +0 -538
  61. data/vendor/crates/spikard-core/src/di/graph.rs +0 -507
  62. data/vendor/crates/spikard-core/src/di/mod.rs +0 -192
  63. data/vendor/crates/spikard-core/src/di/resolved.rs +0 -428
  64. data/vendor/crates/spikard-core/src/di/value.rs +0 -282
  65. data/vendor/crates/spikard-core/src/errors.rs +0 -72
  66. data/vendor/crates/spikard-core/src/http.rs +0 -492
  67. data/vendor/crates/spikard-core/src/lib.rs +0 -29
  68. data/vendor/crates/spikard-core/src/lifecycle.rs +0 -1273
  69. data/vendor/crates/spikard-core/src/metadata.rs +0 -378
  70. data/vendor/crates/spikard-core/src/parameters.rs +0 -2546
  71. data/vendor/crates/spikard-core/src/problem.rs +0 -358
  72. data/vendor/crates/spikard-core/src/request_data.rs +0 -1146
  73. data/vendor/crates/spikard-core/src/router.rs +0 -530
  74. data/vendor/crates/spikard-core/src/schema_registry.rs +0 -197
  75. data/vendor/crates/spikard-core/src/type_hints.rs +0 -311
  76. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +0 -710
  77. data/vendor/crates/spikard-core/src/validation/mod.rs +0 -470
  78. data/vendor/crates/spikard-core/tests/bindings_response_tests.rs +0 -136
  79. data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +0 -37
  80. data/vendor/crates/spikard-core/tests/error_mapper.rs +0 -761
  81. data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +0 -106
  82. data/vendor/crates/spikard-core/tests/parameters_full.rs +0 -701
  83. data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +0 -301
  84. data/vendor/crates/spikard-core/tests/request_data_roundtrip.rs +0 -67
  85. data/vendor/crates/spikard-core/tests/validation_coverage.rs +0 -250
  86. data/vendor/crates/spikard-core/tests/validation_error_paths.rs +0 -45
  87. data/vendor/crates/spikard-http/Cargo.toml +0 -87
  88. data/vendor/crates/spikard-http/examples/sse-notifications.rs +0 -148
  89. data/vendor/crates/spikard-http/examples/websocket-chat.rs +0 -92
  90. data/vendor/crates/spikard-http/src/auth.rs +0 -301
  91. data/vendor/crates/spikard-http/src/background.rs +0 -1860
  92. data/vendor/crates/spikard-http/src/bindings/mod.rs +0 -3
  93. data/vendor/crates/spikard-http/src/bindings/response.rs +0 -1
  94. data/vendor/crates/spikard-http/src/body_metadata.rs +0 -8
  95. data/vendor/crates/spikard-http/src/cors.rs +0 -1026
  96. data/vendor/crates/spikard-http/src/debug.rs +0 -128
  97. data/vendor/crates/spikard-http/src/di_handler.rs +0 -1672
  98. data/vendor/crates/spikard-http/src/grpc/framing.rs +0 -469
  99. data/vendor/crates/spikard-http/src/grpc/handler.rs +0 -1122
  100. data/vendor/crates/spikard-http/src/grpc/mod.rs +0 -434
  101. data/vendor/crates/spikard-http/src/grpc/service.rs +0 -622
  102. data/vendor/crates/spikard-http/src/grpc/streaming.rs +0 -319
  103. data/vendor/crates/spikard-http/src/handler_response.rs +0 -901
  104. data/vendor/crates/spikard-http/src/handler_trait.rs +0 -1015
  105. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +0 -290
  106. data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +0 -502
  107. data/vendor/crates/spikard-http/src/jsonrpc/method_registry.rs +0 -648
  108. data/vendor/crates/spikard-http/src/jsonrpc/mod.rs +0 -58
  109. data/vendor/crates/spikard-http/src/jsonrpc/protocol.rs +0 -1207
  110. data/vendor/crates/spikard-http/src/jsonrpc/router.rs +0 -2262
  111. data/vendor/crates/spikard-http/src/lib.rs +0 -548
  112. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +0 -230
  113. data/vendor/crates/spikard-http/src/lifecycle.rs +0 -1193
  114. data/vendor/crates/spikard-http/src/middleware/mod.rs +0 -560
  115. data/vendor/crates/spikard-http/src/middleware/multipart.rs +0 -912
  116. data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +0 -513
  117. data/vendor/crates/spikard-http/src/middleware/validation.rs +0 -768
  118. data/vendor/crates/spikard-http/src/openapi/mod.rs +0 -309
  119. data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +0 -535
  120. data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +0 -1363
  121. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +0 -667
  122. data/vendor/crates/spikard-http/src/query_parser.rs +0 -793
  123. data/vendor/crates/spikard-http/src/response.rs +0 -720
  124. data/vendor/crates/spikard-http/src/server/fast_router.rs +0 -186
  125. data/vendor/crates/spikard-http/src/server/grpc_routing.rs +0 -858
  126. data/vendor/crates/spikard-http/src/server/handler.rs +0 -1661
  127. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +0 -253
  128. data/vendor/crates/spikard-http/src/server/mod.rs +0 -1649
  129. data/vendor/crates/spikard-http/src/server/request_extraction.rs +0 -871
  130. data/vendor/crates/spikard-http/src/server/routing_factory.rs +0 -618
  131. data/vendor/crates/spikard-http/src/sse.rs +0 -1409
  132. data/vendor/crates/spikard-http/src/testing/form.rs +0 -52
  133. data/vendor/crates/spikard-http/src/testing/multipart.rs +0 -64
  134. data/vendor/crates/spikard-http/src/testing/test_client.rs +0 -787
  135. data/vendor/crates/spikard-http/src/testing.rs +0 -617
  136. data/vendor/crates/spikard-http/src/websocket.rs +0 -1477
  137. data/vendor/crates/spikard-http/tests/auth_integration.rs +0 -645
  138. data/vendor/crates/spikard-http/tests/background_behavior.rs +0 -832
  139. data/vendor/crates/spikard-http/tests/common/grpc_helpers.rs +0 -1012
  140. data/vendor/crates/spikard-http/tests/common/handlers.rs +0 -309
  141. data/vendor/crates/spikard-http/tests/common/mod.rs +0 -33
  142. data/vendor/crates/spikard-http/tests/common/test_builders.rs +0 -628
  143. data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +0 -162
  144. data/vendor/crates/spikard-http/tests/di_integration.rs +0 -192
  145. data/vendor/crates/spikard-http/tests/doc_snippets.rs +0 -5
  146. data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +0 -430
  147. data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +0 -738
  148. data/vendor/crates/spikard-http/tests/grpc_error_handling_test.rs +0 -652
  149. data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +0 -334
  150. data/vendor/crates/spikard-http/tests/grpc_metadata_test.rs +0 -532
  151. data/vendor/crates/spikard-http/tests/grpc_server_integration.rs +0 -495
  152. data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +0 -974
  153. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +0 -1093
  154. data/vendor/crates/spikard-http/tests/middleware_stack_integration.rs +0 -389
  155. data/vendor/crates/spikard-http/tests/multipart_behavior.rs +0 -656
  156. data/vendor/crates/spikard-http/tests/request_extraction_full.rs +0 -513
  157. data/vendor/crates/spikard-http/tests/server_auth_middleware_behavior.rs +0 -328
  158. data/vendor/crates/spikard-http/tests/server_config_builder.rs +0 -314
  159. data/vendor/crates/spikard-http/tests/server_configured_router_behavior.rs +0 -200
  160. data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +0 -83
  161. data/vendor/crates/spikard-http/tests/server_handler_wrappers.rs +0 -464
  162. data/vendor/crates/spikard-http/tests/server_method_router_additional_behavior.rs +0 -286
  163. data/vendor/crates/spikard-http/tests/server_method_router_coverage.rs +0 -118
  164. data/vendor/crates/spikard-http/tests/server_middleware_behavior.rs +0 -99
  165. data/vendor/crates/spikard-http/tests/server_middleware_branches.rs +0 -204
  166. data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +0 -421
  167. data/vendor/crates/spikard-http/tests/server_router_behavior.rs +0 -121
  168. data/vendor/crates/spikard-http/tests/sse_behavior.rs +0 -620
  169. data/vendor/crates/spikard-http/tests/sse_full_behavior.rs +0 -584
  170. data/vendor/crates/spikard-http/tests/sse_handler_behavior.rs +0 -130
  171. data/vendor/crates/spikard-http/tests/test_client_requests.rs +0 -167
  172. data/vendor/crates/spikard-http/tests/testing_helpers.rs +0 -87
  173. data/vendor/crates/spikard-http/tests/testing_module_coverage.rs +0 -155
  174. data/vendor/crates/spikard-http/tests/urlencoded_content_type.rs +0 -82
  175. data/vendor/crates/spikard-http/tests/websocket_behavior.rs +0 -663
  176. data/vendor/crates/spikard-http/tests/websocket_full_behavior.rs +0 -440
  177. data/vendor/crates/spikard-http/tests/websocket_integration.rs +0 -150
  178. data/vendor/crates/spikard-rb/Cargo.toml +0 -68
  179. data/vendor/crates/spikard-rb/build.rs +0 -200
  180. data/vendor/crates/spikard-rb/src/background.rs +0 -63
  181. data/vendor/crates/spikard-rb/src/config/mod.rs +0 -5
  182. data/vendor/crates/spikard-rb/src/config/server_config.rs +0 -401
  183. data/vendor/crates/spikard-rb/src/conversion.rs +0 -688
  184. data/vendor/crates/spikard-rb/src/di/builder.rs +0 -100
  185. data/vendor/crates/spikard-rb/src/di/mod.rs +0 -375
  186. data/vendor/crates/spikard-rb/src/grpc/handler.rs +0 -834
  187. data/vendor/crates/spikard-rb/src/grpc/mod.rs +0 -13
  188. data/vendor/crates/spikard-rb/src/gvl.rs +0 -80
  189. data/vendor/crates/spikard-rb/src/handler.rs +0 -699
  190. data/vendor/crates/spikard-rb/src/integration/mod.rs +0 -3
  191. data/vendor/crates/spikard-rb/src/lib.rs +0 -2264
  192. data/vendor/crates/spikard-rb/src/lifecycle.rs +0 -303
  193. data/vendor/crates/spikard-rb/src/metadata/mod.rs +0 -5
  194. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +0 -507
  195. data/vendor/crates/spikard-rb/src/request.rs +0 -439
  196. data/vendor/crates/spikard-rb/src/runtime/mod.rs +0 -5
  197. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +0 -344
  198. data/vendor/crates/spikard-rb/src/server.rs +0 -307
  199. data/vendor/crates/spikard-rb/src/sse.rs +0 -231
  200. data/vendor/crates/spikard-rb/src/testing/client.rs +0 -698
  201. data/vendor/crates/spikard-rb/src/testing/mod.rs +0 -7
  202. data/vendor/crates/spikard-rb/src/testing/sse.rs +0 -108
  203. data/vendor/crates/spikard-rb/src/testing/websocket.rs +0 -573
  204. data/vendor/crates/spikard-rb/src/websocket.rs +0 -475
  205. data/vendor/crates/spikard-rb-macros/Cargo.toml +0 -25
  206. data/vendor/crates/spikard-rb-macros/src/lib.rs +0 -51
@@ -1,243 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # rubocop:disable Metrics/ModuleLength
4
- module Spikard
5
- # Schema extraction helpers for Ruby type systems
6
- #
7
- # Supports:
8
- # - Plain JSON Schema (Hash)
9
- # - Dry::Schema with :json_schema extension
10
- # - Dry::Struct (Dry-Types)
11
- #
12
- # @example With Dry::Schema
13
- # require 'dry-schema'
14
- # Dry::Schema.load_extensions(:json_schema)
15
- #
16
- # UserSchema = Dry::Schema.JSON do
17
- # required(:email).filled(:str?)
18
- # required(:age).filled(:int?)
19
- # end
20
- #
21
- # schema = Spikard::Schema.extract_json_schema(UserSchema)
22
- #
23
- # @example With Dry::Struct
24
- # require 'dry-struct'
25
- #
26
- # class User < Dry::Struct
27
- # attribute :email, Types::String
28
- # attribute :age, Types::Integer
29
- # end
30
- #
31
- # schema = Spikard::Schema.extract_json_schema(User)
32
- #
33
- # @example With plain JSON Schema
34
- # schema_hash = {
35
- # "type" => "object",
36
- # "properties" => {
37
- # "email" => { "type" => "string" },
38
- # "age" => { "type" => "integer" }
39
- # },
40
- # "required" => ["email", "age"]
41
- # }
42
- #
43
- # schema = Spikard::Schema.extract_json_schema(schema_hash)
44
- module Schema
45
- # rubocop:disable Metrics/ClassLength
46
- class << self
47
- # Extract JSON Schema from various Ruby schema sources
48
- #
49
- # @param schema_source [Object] The schema source (Hash, Dry::Schema, Dry::Struct class)
50
- # @return [Hash, nil] JSON Schema hash or nil if extraction fails
51
- def extract_json_schema(schema_source)
52
- return nil if schema_source.nil?
53
-
54
- # 1. Check if plain JSON Schema hash
55
- return schema_source if schema_source.is_a?(Hash) && json_schema_hash?(schema_source)
56
-
57
- # 2. Check for Dry::Schema with json_schema extension
58
- return extract_from_dry_schema(schema_source) if dry_schema?(schema_source)
59
-
60
- # 3. Check for Dry::Struct (Dry-Types)
61
- return extract_from_dry_struct(schema_source) if dry_struct_class?(schema_source)
62
-
63
- # 4. Unknown type
64
- warn "Spikard: Unable to extract JSON Schema from #{schema_source.class}. " \
65
- 'Supported types: Hash, Dry::Schema, Dry::Struct'
66
- nil
67
- end
68
-
69
- private
70
-
71
- # Check if object is a plain JSON Schema hash
72
- def json_schema_hash?(obj)
73
- return false unless obj.is_a?(Hash)
74
-
75
- # Must have 'type' key or '$schema' key
76
- obj.key?('type') || obj.key?('$schema') || obj.key?(:type) || obj.key?(:$schema)
77
- end
78
-
79
- # Check if object is a Dry::Schema
80
- def dry_schema?(obj)
81
- defined?(Dry::Schema::Processor) && obj.is_a?(Dry::Schema::Processor)
82
- end
83
-
84
- # Check if object is a Dry::Struct class
85
- def dry_struct_class?(obj)
86
- return false unless obj.is_a?(Class)
87
-
88
- defined?(Dry::Struct) && obj < Dry::Struct
89
- end
90
-
91
- # Extract JSON Schema from Dry::Schema
92
- def extract_from_dry_schema(schema)
93
- unless schema.respond_to?(:json_schema)
94
- warn 'Spikard: Dry::Schema instance does not have json_schema method. ' \
95
- 'Did you load the :json_schema extension? ' \
96
- 'Add: Dry::Schema.load_extensions(:json_schema)'
97
- return nil
98
- end
99
-
100
- begin
101
- schema.json_schema
102
- rescue StandardError => e
103
- warn "Spikard: Failed to extract JSON Schema from Dry::Schema: #{e.message}"
104
- nil
105
- end
106
- end
107
-
108
- # Extract JSON Schema from Dry::Struct class
109
- # rubocop:disable Metrics/MethodLength
110
- def extract_from_dry_struct(struct_class)
111
- # Dry::Struct doesn't have built-in JSON Schema export
112
- # We need to manually build it from the attribute schema
113
-
114
- properties = {}
115
- required = []
116
-
117
- struct_class.schema.each do |key, type_definition|
118
- # Extract attribute name
119
- attr_name = key.to_s
120
-
121
- # Determine if required (non-optional)
122
- is_required = !type_definition.optional?
123
- required << attr_name if is_required
124
-
125
- # Convert Dry::Types to JSON Schema type
126
- json_type = dry_type_to_json_schema(type_definition)
127
- properties[attr_name] = json_type if json_type
128
- end
129
-
130
- {
131
- 'type' => 'object',
132
- 'properties' => properties,
133
- 'required' => required
134
- }
135
- rescue StandardError => e
136
- warn "Spikard: Failed to extract JSON Schema from Dry::Struct: #{e.message}"
137
- nil
138
- end
139
- # rubocop:enable Metrics/MethodLength
140
-
141
- # Convert Dry::Types type to JSON Schema type
142
- def dry_type_to_json_schema(type_def)
143
- schema = base_schema_for(type_def)
144
- apply_metadata_constraints(schema, type_def)
145
- rescue StandardError
146
- { 'type' => 'object' }
147
- end
148
-
149
- # rubocop:disable Metrics/MethodLength
150
- def base_schema_for(type_def)
151
- type_class = type_def.primitive.to_s
152
- case type_class
153
- when 'String' then { 'type' => 'string' }
154
- when 'Integer' then { 'type' => 'integer' }
155
- when 'Float', 'BigDecimal' then { 'type' => 'number' }
156
- when 'TrueClass', 'FalseClass' then { 'type' => 'boolean' }
157
- when 'Array'
158
- {
159
- 'type' => 'array',
160
- 'items' => infer_array_items_schema(type_def)
161
- }
162
- when 'Hash'
163
- { 'type' => 'object', 'additionalProperties' => true }
164
- when 'NilClass' then { 'type' => 'null' }
165
- else
166
- { 'type' => 'object' }
167
- end
168
- end
169
- # rubocop:enable Metrics/MethodLength
170
-
171
- def infer_array_items_schema(type_def)
172
- if type_def.respond_to?(:member) && type_def.member
173
- dry_type_to_json_schema(type_def.member)
174
- else
175
- {}
176
- end
177
- rescue StandardError
178
- {}
179
- end
180
-
181
- def apply_metadata_constraints(schema, type_def)
182
- metadata = extract_metadata(type_def)
183
- return schema if metadata.empty?
184
-
185
- schema = apply_enum_and_format(schema, metadata)
186
- apply_numeric_constraints(schema, metadata)
187
- end
188
-
189
- def apply_enum_and_format(schema, metadata)
190
- enum_values = metadata[:enum] || metadata['enum']
191
- schema['enum'] = Array(enum_values) if enum_values
192
-
193
- format_value = metadata[:format] || metadata['format']
194
- schema['format'] = format_value.to_s if format_value
195
-
196
- description = metadata[:description] || metadata['description']
197
- schema['description'] = description.to_s if description
198
- schema
199
- end
200
-
201
- # rubocop:disable Metrics/MethodLength
202
- def apply_numeric_constraints(schema, metadata)
203
- mapping = {
204
- min_size: 'minLength',
205
- max_size: 'maxLength',
206
- min_items: 'minItems',
207
- max_items: 'maxItems',
208
- min: 'minimum',
209
- max: 'maximum',
210
- gte: 'minimum',
211
- lte: 'maximum',
212
- gt: 'exclusiveMinimum',
213
- lt: 'exclusiveMaximum'
214
- }
215
-
216
- mapping.each do |meta_key, json_key|
217
- value = metadata[meta_key] || metadata[meta_key.to_s]
218
- next unless value
219
-
220
- schema[json_key] = value
221
- end
222
- schema
223
- end
224
- # rubocop:enable Metrics/MethodLength
225
-
226
- def extract_metadata(type_def)
227
- return {} unless type_def.respond_to?(:meta) || type_def.respond_to?(:options)
228
-
229
- if type_def.respond_to?(:meta) && type_def.meta
230
- type_def.meta
231
- elsif type_def.respond_to?(:options) && type_def.options.is_a?(Hash)
232
- type_def.options
233
- else
234
- {}
235
- end
236
- rescue StandardError
237
- {}
238
- end
239
- end
240
- # rubocop:enable Metrics/ClassLength
241
- end
242
- end
243
- # rubocop:enable Metrics/ModuleLength
data/lib/spikard/sse.rb DELETED
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spikard
4
- # Represents a Server-Sent Event.
5
- #
6
- # @!attribute [rw] data
7
- # @return [Hash] Event data (will be JSON serialized)
8
- # @!attribute [rw] event_type
9
- # @return [String, nil] Optional event type
10
- # @!attribute [rw] id
11
- # @return [String, nil] Optional event ID for client reconnection support
12
- # @!attribute [rw] retry_ms
13
- # @return [Integer, nil] Optional retry timeout in milliseconds
14
- class SseEvent
15
- attr_accessor :data, :event_type, :id, :retry_ms
16
-
17
- # Create a new SSE event.
18
- #
19
- # @param data [Hash] Event data (will be JSON serialized)
20
- # @param event_type [String, nil] Optional event type
21
- # @param id [String, nil] Optional event ID for client reconnection support
22
- # @param retry_ms [Integer, nil] Optional retry timeout in milliseconds
23
- def initialize(data:, event_type: nil, id: nil, retry_ms: nil)
24
- @data = data
25
- @event_type = event_type
26
- @id = id
27
- @retry_ms = retry_ms
28
- end
29
-
30
- # Convert to hash for JSON serialization.
31
- #
32
- # @return [Hash] Hash representation of the event
33
- def to_h
34
- {
35
- data: @data,
36
- event_type: @event_type,
37
- id: @id,
38
- retry: @retry_ms
39
- }.compact
40
- end
41
- end
42
-
43
- # Base class for SSE event producers.
44
- #
45
- # Implement this class to generate Server-Sent Events.
46
- #
47
- # @example
48
- # class NotificationProducer < Spikard::SseEventProducer
49
- # def initialize
50
- # @count = 0
51
- # end
52
- #
53
- # def next_event
54
- # sleep 1 # Wait 1 second between events
55
- #
56
- # return nil if @count >= 10 # End stream after 10 events
57
- #
58
- # event = Spikard::SseEvent.new(
59
- # data: { message: "Notification #{@count}" },
60
- # event_type: 'notification',
61
- # id: @count.to_s
62
- # )
63
- # @count += 1
64
- # event
65
- # end
66
- #
67
- # def on_connect
68
- # puts "Client connected to SSE stream"
69
- # end
70
- #
71
- # def on_disconnect
72
- # puts "Client disconnected from SSE stream"
73
- # end
74
- # end
75
- #
76
- # app = Spikard::App.new
77
- #
78
- # app.sse('/notifications') do
79
- # NotificationProducer.new
80
- # end
81
- #
82
- # app.run
83
- class SseEventProducer
84
- # Generate the next event.
85
- #
86
- # This method is called repeatedly to produce the event stream.
87
- #
88
- # @return [SseEvent, nil] SseEvent when an event is ready, or nil to end the stream.
89
- def next_event
90
- raise NotImplementedError, "#{self.class.name} must implement #next_event"
91
- end
92
-
93
- # Called when a client connects to the SSE endpoint.
94
- #
95
- # Override this method to perform initialization when a client connects.
96
- #
97
- # @return [void]
98
- def on_connect
99
- # Optional hook - default implementation does nothing
100
- end
101
-
102
- # Called when a client disconnects from the SSE endpoint.
103
- #
104
- # Override this method to perform cleanup when a client disconnects.
105
- #
106
- # @return [void]
107
- def on_disconnect
108
- # Optional hook - default implementation does nothing
109
- end
110
- end
111
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spikard
4
- # Represents a streaming HTTP response made of chunks produced lazily.
5
- class StreamingResponse
6
- attr_reader :stream, :status_code, :headers, :native_response
7
-
8
- def initialize(stream, status_code: 200, headers: nil)
9
- unless stream.respond_to?(:next) || stream.respond_to?(:each)
10
- raise ArgumentError, 'StreamingResponse requires an object responding to #next or #each'
11
- end
12
-
13
- @stream = stream.respond_to?(:to_enum) ? stream.to_enum : stream
14
- @status_code = Integer(status_code || 200)
15
- header_hash = headers || {}
16
- @headers = header_hash.each_with_object({}) do |(key, value), memo|
17
- memo[String(key)] = String(value)
18
- end
19
-
20
- rebuild_native!
21
- end
22
-
23
- def to_native_response
24
- @native_response
25
- end
26
-
27
- private
28
-
29
- def rebuild_native!
30
- ensure_native!
31
- @native_response = Spikard::Native.build_streaming_response(@stream, @status_code, @headers)
32
- return unless @native_response
33
-
34
- @status_code = @native_response.status_code
35
- @headers = @native_response.headers
36
- end
37
-
38
- def ensure_native!
39
- return if defined?(Spikard::Native) && Spikard::Native.respond_to?(:build_streaming_response)
40
-
41
- raise 'Spikard native extension is not loaded'
42
- end
43
- end
44
- end