aris 1.3.0

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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +342 -0
  4. data/lib/aris/adapters/base.rb +25 -0
  5. data/lib/aris/adapters/joys_integration.rb +94 -0
  6. data/lib/aris/adapters/mock/adapter.rb +141 -0
  7. data/lib/aris/adapters/mock/request.rb +81 -0
  8. data/lib/aris/adapters/mock/response.rb +17 -0
  9. data/lib/aris/adapters/rack/adapter.rb +117 -0
  10. data/lib/aris/adapters/rack/request.rb +66 -0
  11. data/lib/aris/adapters/rack/response.rb +16 -0
  12. data/lib/aris/core.rb +931 -0
  13. data/lib/aris/discovery.rb +312 -0
  14. data/lib/aris/locale_injector.rb +39 -0
  15. data/lib/aris/pipeline_runner.rb +100 -0
  16. data/lib/aris/plugins/api_key_auth.rb +61 -0
  17. data/lib/aris/plugins/basic_auth.rb +68 -0
  18. data/lib/aris/plugins/bearer_auth.rb +64 -0
  19. data/lib/aris/plugins/cache.rb +120 -0
  20. data/lib/aris/plugins/compression.rb +96 -0
  21. data/lib/aris/plugins/cookies.rb +46 -0
  22. data/lib/aris/plugins/cors.rb +81 -0
  23. data/lib/aris/plugins/csrf.rb +48 -0
  24. data/lib/aris/plugins/etag.rb +90 -0
  25. data/lib/aris/plugins/flash.rb +124 -0
  26. data/lib/aris/plugins/form_parser.rb +46 -0
  27. data/lib/aris/plugins/health_check.rb +62 -0
  28. data/lib/aris/plugins/json.rb +32 -0
  29. data/lib/aris/plugins/multipart.rb +160 -0
  30. data/lib/aris/plugins/rate_limiter.rb +60 -0
  31. data/lib/aris/plugins/request_id.rb +38 -0
  32. data/lib/aris/plugins/request_logger.rb +43 -0
  33. data/lib/aris/plugins/security_headers.rb +99 -0
  34. data/lib/aris/plugins/session.rb +175 -0
  35. data/lib/aris/plugins.rb +23 -0
  36. data/lib/aris/response_helpers.rb +156 -0
  37. data/lib/aris/route_helpers.rb +141 -0
  38. data/lib/aris/utils/redirects.rb +44 -0
  39. data/lib/aris/utils/sitemap.rb +84 -0
  40. data/lib/aris/version.rb +3 -0
  41. data/lib/aris.rb +35 -0
  42. metadata +151 -0
@@ -0,0 +1,81 @@
1
+ # lib/aris/adapters/mock/request.rb
2
+ module Aris
3
+ module Adapters
4
+ module Mock
5
+ class Request
6
+ attr_reader :raw_request, :cookies # Add cookies
7
+ attr_accessor :json_body
8
+
9
+ def initialize(method:, path:, domain:, headers: {}, body: '', query: '', cookies: {}) # Add cookies parameter
10
+ @raw_request = {
11
+ method: method.to_s.upcase,
12
+ path: path,
13
+ domain: domain,
14
+ headers: headers,
15
+ body: body,
16
+ query: query
17
+ }
18
+ @cookies = cookies || {} # Initialize cookies
19
+ end
20
+
21
+ # Add env method for plugin compatibility
22
+ def env
23
+ @raw_request[:headers]
24
+ end
25
+
26
+ def host
27
+ @raw_request[:domain]
28
+ end
29
+
30
+ alias_method :domain, :host
31
+
32
+ def request_method
33
+ @raw_request[:method]
34
+ end
35
+
36
+ def method
37
+ @raw_request[:method]
38
+ end
39
+
40
+ def path_info
41
+ @raw_request[:path]
42
+ end
43
+
44
+ alias_method :path, :path_info
45
+
46
+ def query
47
+ @raw_request[:query]
48
+ end
49
+
50
+ def headers
51
+ @raw_request[:headers]
52
+ end
53
+
54
+ def body
55
+ @raw_request[:body]
56
+ end
57
+
58
+ def params
59
+ # Simple query string parser (no external dependencies)
60
+ return @params if @params
61
+ @params = {}
62
+ query.split('&').each do |pair|
63
+ key, value = pair.split('=')
64
+ @params[key] = value if key
65
+ end
66
+ @params
67
+ end
68
+
69
+ def [](key)
70
+ case key
71
+ when :method then method
72
+ when :domain then domain
73
+ when :path then path
74
+ when :host then host
75
+ else @raw_request[key]
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,17 @@
1
+ # lib/aris/adapters/mock/response.rb
2
+ module Aris
3
+ module Adapters
4
+ module Mock
5
+ class Response
6
+ include Aris::ResponseHelpers
7
+ attr_accessor :status, :headers, :body
8
+
9
+ def initialize
10
+ @status = 200
11
+ @headers = {'content-type' => 'text/html'}
12
+ @body = []
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,117 @@
1
+ # lib/aris/adapters/rack/adapter.rb
2
+ require_relative '../../core'
3
+ require_relative '../../pipeline_runner'
4
+ require_relative '../base'
5
+ require_relative 'request'
6
+ require_relative 'response'
7
+ require 'json'
8
+
9
+ module Aris
10
+ module Adapters
11
+ class RackApp < Base
12
+ def initialize(app = nil)
13
+ @app = app
14
+ end
15
+
16
+ # lib/aris/adapters/rack/adapter.rb
17
+
18
+ # lib/aris/adapters/rack/adapter.rb
19
+
20
+ def call(env)
21
+ request = Rack::Request.new(env)
22
+ return res if res = handle_sitemap(request)
23
+ return res if res = handle_redirect(request)
24
+ redirect_res, normalized_path = Aris.handle_trailing_slash(request.path_info)
25
+ return redirect_res if redirect_res
26
+
27
+ path_for_matching = normalized_path || request.path_info
28
+
29
+ request_domain = request.host
30
+ Thread.current[:aris_current_domain] = request_domain
31
+
32
+ response = Rack::Response.new
33
+ request.instance_variable_set(:@response, response)
34
+ request.define_singleton_method(:response) { @response }
35
+
36
+ begin
37
+ domain_config = Aris::Router.domain_config(request_domain)
38
+ route = Aris::Router.match(
39
+ domain: request_domain,
40
+ method: request.request_method.downcase.to_sym,
41
+ path: path_for_matching
42
+ )
43
+ if route
44
+ inject_locale_methods(request, route, domain_config)
45
+ result = PipelineRunner.call(request: request, route: route, response: response)
46
+ format_response(result, response)
47
+ else
48
+ format_response(Aris.not_found(request, response), response)
49
+ end
50
+
51
+ rescue Aris::Router::RouteNotFoundError
52
+ format_response(Aris.not_found(request, response), response)
53
+ rescue Exception => e
54
+ # Error Path: 500
55
+ format_response(Aris.error(request, e), response)
56
+
57
+ ensure
58
+ Thread.current[:aris_current_domain] = nil
59
+ end
60
+ end
61
+
62
+ def subdomain
63
+ @subdomain || extract_subdomain_from_domain
64
+ end
65
+
66
+ private
67
+
68
+ def extract_subdomain_from_domain
69
+ return nil unless @env[:subdomain] || @env['SUBDOMAIN']
70
+
71
+ @env[:subdomain] || @env['SUBDOMAIN']
72
+ end
73
+
74
+
75
+ def inject_locale_methods(request, route, domain_config)
76
+ return unless route[:locale]
77
+
78
+ # Inject the locale helper
79
+ request.define_singleton_method(:locale) { route[:locale] }
80
+
81
+ # Inject domain-specific locale configuration if it exists
82
+ if domain_config
83
+ request.define_singleton_method(:available_locales) { domain_config[:locales] }
84
+ request.define_singleton_method(:default_locale) { domain_config[:default_locale] }
85
+ end
86
+ end
87
+
88
+ def format_response(result, response = nil)
89
+ # 1. Identify the 'active' response source
90
+ # We check the passed object (response) and the returned object (result)
91
+ active_res = if result.respond_to?(:body) && !Array(result.body).empty?
92
+ result
93
+ elsif response.respond_to?(:body) && !Array(response.body).empty?
94
+ response
95
+ else
96
+ nil
97
+ end
98
+
99
+ # 2. If we found a response with content, send it to the Rack server
100
+ if active_res
101
+ # Standardize the body as an Array of Strings for Rack 3 compatibility
102
+ body = active_res.body
103
+ body = [body] if body.is_a?(String)
104
+
105
+ return [active_res.status, active_res.headers, body]
106
+ end
107
+
108
+ # 3. Final Fallback (If Joys rendered nothing)
109
+ case result
110
+ when Array then result
111
+ when Hash then [200, {'content-type' => 'application/json'}, [result.to_json]]
112
+ else [200, {'content-type' => 'text/plain'}, [result.to_s]]
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,66 @@
1
+ # lib/aris/adapters/rack/request.rb
2
+ module Aris
3
+ module Adapters
4
+ module Rack
5
+ class Request
6
+ attr_reader :env
7
+ attr_accessor :json_body
8
+
9
+ def initialize(env)
10
+ @env = env
11
+ end
12
+
13
+ # Add cookies method to match Mock adapter interface
14
+ def cookies
15
+ @env['rack.request.cookie_hash'] || {}
16
+ end
17
+
18
+ def host
19
+ @env['HTTP_HOST'] || @env['SERVER_NAME']
20
+ end
21
+
22
+ alias_method :domain, :host
23
+
24
+ def request_method
25
+ @env['REQUEST_METHOD']
26
+ end
27
+
28
+ def method
29
+ @env['REQUEST_METHOD']
30
+ end
31
+
32
+ def path_info
33
+ @env['PATH_INFO']
34
+ end
35
+
36
+ alias_method :path, :path_info
37
+
38
+ def query
39
+ @env['QUERY_STRING']
40
+ end
41
+
42
+ def headers
43
+ @env.select { |k, v| k.start_with?('HTTP_') }
44
+ end
45
+
46
+ def body
47
+ @env['rack.input']&.read
48
+ end
49
+
50
+ def params
51
+ @params ||= ::Rack::Utils.parse_nested_query(@env['QUERY_STRING'] || '')
52
+ end
53
+
54
+ def [](key)
55
+ case key
56
+ when :method then method
57
+ when :domain then domain
58
+ when :path then path
59
+ when :host then host
60
+ else @env[key.to_s]
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,16 @@
1
+ # lib/aris/adapters/rack/response.rb
2
+ module Aris
3
+ module Adapters
4
+ module Rack
5
+ class Response
6
+ include Aris::ResponseHelpers
7
+ attr_accessor :status, :headers, :body
8
+ def initialize
9
+ @status = 200
10
+ @headers = {'content-type' => 'text/html'}
11
+ @body = []
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end