tidewave 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/lib/tidewave/configuration.rb +3 -2
- data/lib/tidewave/database_adapter.rb +2 -2
- data/lib/tidewave/database_adapters/active_record.rb +2 -2
- data/lib/tidewave/database_adapters/sequel.rb +3 -2
- data/lib/tidewave/middleware.rb +26 -18
- data/lib/tidewave/railtie.rb +4 -2
- data/lib/tidewave/streamable_http_transport.rb +131 -0
- data/lib/tidewave/tools/execute_sql_query.rb +6 -0
- data/lib/tidewave/tools/get_logs.rb +55 -5
- data/lib/tidewave/tools/get_models.rb +4 -2
- data/lib/tidewave/tools/project_eval.rb +6 -0
- data/lib/tidewave/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 728311a2ea0525028ccf9209d06bc1079f9258e35d534409f4ac867ff5212d32
|
|
4
|
+
data.tar.gz: 11c1b092dc830897e59cb39f71de745b840acfd6f8845bf058c9010a06258e75
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9b49181b3f571b668de00287f0fec47088256ee335e31036385cedcb3b8c34274529d70a4f21d9c114279d9a1f5e52a56cab75b8465546863e0fd539fd1b390
|
|
7
|
+
data.tar.gz: 1201a00a28892246592c158bc0e90cb5a6ce5d69a6a3533ef81bb8c853d2124d3544d029e8346613fa4d099010869f83cae49bcad82d890d1e935ee9f54903f4
|
data/README.md
CHANGED
|
@@ -29,7 +29,7 @@ If you want to use Docker for development, you either need to enable the configu
|
|
|
29
29
|
|
|
30
30
|
### Content security policy
|
|
31
31
|
|
|
32
|
-
If you have enabled Content-Security-Policy, Tidewave will automatically enable "unsafe-eval" under `script-src` in order for contextual browser testing to work correctly.
|
|
32
|
+
If you have enabled Content-Security-Policy, Tidewave will automatically enable "unsafe-eval" under `script-src` in order for contextual browser testing to work correctly. It also disables the `frame-ancestors` directive.
|
|
33
33
|
|
|
34
34
|
### Web server requirements
|
|
35
35
|
|
|
@@ -55,9 +55,11 @@ The following config is available:
|
|
|
55
55
|
|
|
56
56
|
* `allow_remote_access` - Tidewave only allows requests from localhost by default, even if your server listens on other interfaces as well. If you trust your network and need to access Tidewave from a different machine, this configuration can be set to `true`
|
|
57
57
|
|
|
58
|
+
* `logger_middleware` - The logger middleware Tidewave should wrap to silence its own logs
|
|
59
|
+
|
|
58
60
|
* `preferred_orm` - which ORM to use, either `:active_record` (default) or `:sequel`
|
|
59
61
|
|
|
60
|
-
* `team` - set your
|
|
62
|
+
* `team` - set your Tidewave Team configuration, such as `config.tidewave.team = { id: "my-company" }`
|
|
61
63
|
|
|
62
64
|
## Acknowledgements
|
|
63
65
|
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module Tidewave
|
|
4
4
|
class Configuration
|
|
5
|
-
attr_accessor :logger, :allow_remote_access, :preferred_orm, :
|
|
5
|
+
attr_accessor :logger, :allow_remote_access, :preferred_orm, :dev, :client_url, :team, :logger_middleware
|
|
6
6
|
|
|
7
7
|
def initialize
|
|
8
8
|
@logger = nil
|
|
9
9
|
@allow_remote_access = true
|
|
10
10
|
@preferred_orm = :active_record
|
|
11
|
-
@
|
|
11
|
+
@dev = false
|
|
12
12
|
@client_url = "https://tidewave.ai"
|
|
13
13
|
@team = {}
|
|
14
|
+
@logger_middleware = nil
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -26,8 +26,8 @@ module Tidewave
|
|
|
26
26
|
raise NotImplementedError, "Subclasses must implement execute_query"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def
|
|
30
|
-
raise NotImplementedError, "Subclasses must implement
|
|
29
|
+
def get_models
|
|
30
|
+
raise NotImplementedError, "Subclasses must implement get_models"
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
end
|
|
@@ -29,8 +29,9 @@ module Tidewave
|
|
|
29
29
|
}
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def
|
|
33
|
-
|
|
32
|
+
def get_models
|
|
33
|
+
# Filter out anonymous Sequel models that can't be resolved as constants
|
|
34
|
+
::Sequel::Model.descendants.reject { |model| model.name&.start_with?("Sequel::_Model(") }
|
|
34
35
|
end
|
|
35
36
|
end
|
|
36
37
|
end
|
data/lib/tidewave/middleware.rb
CHANGED
|
@@ -8,13 +8,13 @@ require "active_support/core_ext/class"
|
|
|
8
8
|
require "active_support/core_ext/object/blank"
|
|
9
9
|
require "json"
|
|
10
10
|
require "erb"
|
|
11
|
+
require_relative "streamable_http_transport"
|
|
11
12
|
|
|
12
13
|
class Tidewave::Middleware
|
|
13
14
|
TIDEWAVE_ROUTE = "tidewave".freeze
|
|
14
|
-
|
|
15
|
-
SSE_ROUTE = "mcp".freeze
|
|
16
|
-
MESSAGES_ROUTE = "mcp/message".freeze
|
|
15
|
+
MCP_ROUTE = "mcp".freeze
|
|
17
16
|
SHELL_ROUTE = "shell".freeze
|
|
17
|
+
CONFIG_ROUTE = "config".freeze
|
|
18
18
|
|
|
19
19
|
INVALID_IP = <<~TEXT.freeze
|
|
20
20
|
For security reasons, Tidewave does not accept remote connections by default.
|
|
@@ -31,9 +31,8 @@ class Tidewave::Middleware
|
|
|
31
31
|
@app = FastMcp.rack_middleware(app,
|
|
32
32
|
name: "tidewave",
|
|
33
33
|
version: Tidewave::VERSION,
|
|
34
|
-
path_prefix: "/" + TIDEWAVE_ROUTE,
|
|
35
|
-
|
|
36
|
-
sse_route: SSE_ROUTE,
|
|
34
|
+
path_prefix: "/" + TIDEWAVE_ROUTE + "/" + MCP_ROUTE,
|
|
35
|
+
transport: Tidewave::StreamableHttpTransport,
|
|
37
36
|
logger: config.logger || Logger.new(Rails.root.join("log", "tidewave.log")),
|
|
38
37
|
# Rails runs the HostAuthorization in dev, so we skip this
|
|
39
38
|
allowed_origins: [],
|
|
@@ -63,25 +62,26 @@ class Tidewave::Middleware
|
|
|
63
62
|
case [ request.request_method, path ]
|
|
64
63
|
when [ "GET", [ TIDEWAVE_ROUTE ] ]
|
|
65
64
|
return home(request)
|
|
66
|
-
when [ "GET", [ TIDEWAVE_ROUTE,
|
|
67
|
-
return
|
|
65
|
+
when [ "GET", [ TIDEWAVE_ROUTE, CONFIG_ROUTE ] ]
|
|
66
|
+
return config_endpoint(request)
|
|
68
67
|
when [ "POST", [ TIDEWAVE_ROUTE, SHELL_ROUTE ] ]
|
|
69
68
|
return shell(request)
|
|
70
69
|
end
|
|
71
70
|
end
|
|
72
71
|
|
|
73
|
-
@app.call(env)
|
|
72
|
+
status, headers, body = @app.call(env)
|
|
73
|
+
|
|
74
|
+
# Remove X-Frame-Options headers for non-Tidewave routes to allow embedding.
|
|
75
|
+
# CSP headers are configured in the CSP application environment.
|
|
76
|
+
headers.delete("X-Frame-Options")
|
|
77
|
+
|
|
78
|
+
[ status, headers, body ]
|
|
74
79
|
end
|
|
75
80
|
|
|
76
81
|
private
|
|
77
82
|
|
|
78
83
|
def home(request)
|
|
79
|
-
config =
|
|
80
|
-
"project_name" => @project_name,
|
|
81
|
-
"framework_type" => "rails",
|
|
82
|
-
"tidewave_version" => Tidewave::VERSION,
|
|
83
|
-
"team" => @team
|
|
84
|
-
}
|
|
84
|
+
config = config_data
|
|
85
85
|
|
|
86
86
|
html = <<~HTML
|
|
87
87
|
<html>
|
|
@@ -98,9 +98,17 @@ class Tidewave::Middleware
|
|
|
98
98
|
[ 200, { "Content-Type" => "text/html" }, [ html ] ]
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
def
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
def config_endpoint(request)
|
|
102
|
+
[ 200, { "Content-Type" => "application/json" }, [ JSON.generate(config_data) ] ]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def config_data
|
|
106
|
+
{
|
|
107
|
+
"project_name" => @project_name,
|
|
108
|
+
"framework_type" => "rails",
|
|
109
|
+
"tidewave_version" => Tidewave::VERSION,
|
|
110
|
+
"team" => @team
|
|
111
|
+
}
|
|
104
112
|
end
|
|
105
113
|
|
|
106
114
|
def forbidden(message)
|
data/lib/tidewave/railtie.rb
CHANGED
|
@@ -32,6 +32,8 @@ module Tidewave
|
|
|
32
32
|
content_security_policy.directives["script-src"].try do |script_src|
|
|
33
33
|
script_src << "'unsafe-eval'" unless script_src.include?("'unsafe-eval'")
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
content_security_policy.directives.delete("frame-ancestors")
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
end
|
|
@@ -39,7 +41,6 @@ module Tidewave
|
|
|
39
41
|
initializer "tidewave.intercept_exceptions" do |app|
|
|
40
42
|
# We intercept exceptions from DebugExceptions, format the
|
|
41
43
|
# information as text and inject into the exception page html.
|
|
42
|
-
|
|
43
44
|
ActionDispatch::DebugExceptions.register_interceptor do |request, exception|
|
|
44
45
|
request.set_header("tidewave.exception", exception)
|
|
45
46
|
end
|
|
@@ -49,7 +50,8 @@ module Tidewave
|
|
|
49
50
|
|
|
50
51
|
initializer "tidewave.logging" do |app|
|
|
51
52
|
# Do not pollute user logs with tidewave requests.
|
|
52
|
-
app.
|
|
53
|
+
logger_middleware = app.config.tidewave.logger_middleware || Rails::Rack::Logger
|
|
54
|
+
app.middleware.insert_before(logger_middleware, Tidewave::QuietRequestsMiddleware)
|
|
53
55
|
end
|
|
54
56
|
end
|
|
55
57
|
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "rack"
|
|
5
|
+
require "fast_mcp"
|
|
6
|
+
|
|
7
|
+
module Tidewave
|
|
8
|
+
# Streamable HTTP transport for MCP (POST-only, no SSE)
|
|
9
|
+
# This transport implements a simplified version of the MCP Streamable HTTP protocol
|
|
10
|
+
# that only supports POST requests for JSON-RPC messages. Unlike the full protocol,
|
|
11
|
+
# it does not support Server-Sent Events (SSE) for streaming responses.
|
|
12
|
+
class StreamableHttpTransport < FastMcp::Transports::BaseTransport
|
|
13
|
+
attr_reader :app, :path
|
|
14
|
+
|
|
15
|
+
def initialize(app, server, options = {})
|
|
16
|
+
super(server, logger: options[:logger])
|
|
17
|
+
@app = app
|
|
18
|
+
@path = options[:path_prefix] || "/mcp"
|
|
19
|
+
@running = false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def start
|
|
23
|
+
@logger.debug("Starting Streamable HTTP transport (POST-only) at path: #{@path}")
|
|
24
|
+
@running = true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def stop
|
|
28
|
+
@logger.debug("Stopping Streamable HTTP transport")
|
|
29
|
+
@running = false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Send a message - capture response for synchronous HTTP
|
|
33
|
+
# Required by FastMCP::Transports::BaseTransport interface
|
|
34
|
+
def send_message(message)
|
|
35
|
+
@logger.debug("send_message called, capturing response: #{message.inspect}")
|
|
36
|
+
@captured_response = message
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def call(env)
|
|
40
|
+
request = Rack::Request.new(env)
|
|
41
|
+
|
|
42
|
+
if request.path == @path
|
|
43
|
+
@server.transport = self
|
|
44
|
+
handle_mcp_request(request, env)
|
|
45
|
+
else
|
|
46
|
+
@app.call(env)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def handle_mcp_request(request, env)
|
|
53
|
+
if request.post?
|
|
54
|
+
handle_post_request(request)
|
|
55
|
+
else
|
|
56
|
+
method_not_allowed_response
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def handle_post_request(request)
|
|
61
|
+
@logger.debug("Received POST request to MCP endpoint")
|
|
62
|
+
|
|
63
|
+
begin
|
|
64
|
+
body = request.body.read
|
|
65
|
+
message = JSON.parse(body)
|
|
66
|
+
|
|
67
|
+
@logger.debug("Processing message: #{message.inspect}")
|
|
68
|
+
|
|
69
|
+
unless valid_jsonrpc_message?(message)
|
|
70
|
+
return json_rpc_error_response(400, -32600, "Invalid Request", nil)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Capture the response that will be sent via send_message
|
|
74
|
+
@captured_response = nil
|
|
75
|
+
@server.handle_json_request(message)
|
|
76
|
+
|
|
77
|
+
@logger.debug("Sending response: #{@captured_response.inspect}")
|
|
78
|
+
|
|
79
|
+
[
|
|
80
|
+
200,
|
|
81
|
+
{ "Content-Type" => "application/json" },
|
|
82
|
+
[ JSON.generate(@captured_response) ]
|
|
83
|
+
]
|
|
84
|
+
rescue JSON::ParserError => e
|
|
85
|
+
@logger.error("Invalid JSON in request: #{e.message}")
|
|
86
|
+
json_rpc_error_response(400, -32700, "Parse error", nil)
|
|
87
|
+
rescue => e
|
|
88
|
+
@logger.error("Error processing message: #{e.message}")
|
|
89
|
+
@logger.error(e.backtrace.join("\n")) if e.backtrace
|
|
90
|
+
json_rpc_error_response(500, -32603, "Internal error", nil)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def valid_jsonrpc_message?(message)
|
|
95
|
+
return false unless message.is_a?(Hash)
|
|
96
|
+
return false unless message["jsonrpc"] == "2.0"
|
|
97
|
+
|
|
98
|
+
message.key?("method") || message.key?("result") || message.key?("error")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def method_not_allowed_response
|
|
102
|
+
[
|
|
103
|
+
405,
|
|
104
|
+
{ "Content-Type" => "application/json" },
|
|
105
|
+
[ JSON.generate({
|
|
106
|
+
jsonrpc: "2.0",
|
|
107
|
+
error: {
|
|
108
|
+
code: -32601,
|
|
109
|
+
message: "Method not allowed. This endpoint only supports POST requests."
|
|
110
|
+
},
|
|
111
|
+
id: nil
|
|
112
|
+
}) ]
|
|
113
|
+
]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def json_rpc_error_response(http_status, code, message, id)
|
|
117
|
+
[
|
|
118
|
+
http_status,
|
|
119
|
+
{ "Content-Type" => "application/json" },
|
|
120
|
+
[ JSON.generate({
|
|
121
|
+
jsonrpc: "2.0",
|
|
122
|
+
error: {
|
|
123
|
+
code: code,
|
|
124
|
+
message: message
|
|
125
|
+
},
|
|
126
|
+
id: id
|
|
127
|
+
}) ]
|
|
128
|
+
]
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -22,6 +22,12 @@ class Tidewave::Tools::ExecuteSqlQuery < Tidewave::Tools::Base
|
|
|
22
22
|
optional(:arguments).value(:array).description("The arguments to pass to the query. The query must contain corresponding parameter placeholders.")
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def @input_schema.json_schema
|
|
26
|
+
schema = super
|
|
27
|
+
schema[:properties][:arguments][:items] = {}
|
|
28
|
+
schema
|
|
29
|
+
end
|
|
30
|
+
|
|
25
31
|
RESULT_LIMIT = 50
|
|
26
32
|
|
|
27
33
|
def call(query:, arguments: [])
|
|
@@ -17,13 +17,63 @@ class Tidewave::Tools::GetLogs < Tidewave::Tools::Base
|
|
|
17
17
|
log_file = Rails.root.join("log", "#{Rails.env}.log")
|
|
18
18
|
return "Log file not found" unless File.exist?(log_file)
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
regex = Regexp.new(grep, Regexp::IGNORECASE) if grep
|
|
21
|
+
matching_lines = []
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
regex
|
|
24
|
-
|
|
23
|
+
tail_lines(log_file) do |line|
|
|
24
|
+
if regex.nil? || line.match?(regex)
|
|
25
|
+
matching_lines.unshift(line)
|
|
26
|
+
break if matching_lines.size >= tail
|
|
27
|
+
end
|
|
25
28
|
end
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
matching_lines.join
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def tail_lines(file_path)
|
|
36
|
+
File.open(file_path, "rb") do |file|
|
|
37
|
+
file.seek(0, IO::SEEK_END)
|
|
38
|
+
file_size = file.pos
|
|
39
|
+
return if file_size == 0
|
|
40
|
+
|
|
41
|
+
buffer_size = [ 4096, file_size ].min
|
|
42
|
+
pos = file_size
|
|
43
|
+
buffer = ""
|
|
44
|
+
|
|
45
|
+
while pos > 0 && buffer.count("\n") < 10000 # Safety limit
|
|
46
|
+
# Move back by buffer_size or to beginning of file
|
|
47
|
+
seek_pos = [ pos - buffer_size, 0 ].max
|
|
48
|
+
file.seek(seek_pos)
|
|
49
|
+
|
|
50
|
+
# Read chunk
|
|
51
|
+
chunk = file.read(pos - seek_pos)
|
|
52
|
+
buffer = chunk + buffer
|
|
53
|
+
pos = seek_pos
|
|
54
|
+
|
|
55
|
+
# Extract complete lines from buffer
|
|
56
|
+
lines = buffer.split("\n")
|
|
57
|
+
|
|
58
|
+
# Keep the first partial line (if any) for next iteration
|
|
59
|
+
if pos > 0 && !buffer.start_with?("\n")
|
|
60
|
+
buffer = lines.shift || ""
|
|
61
|
+
else
|
|
62
|
+
buffer = ""
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Yield lines in reverse order (last to first)
|
|
66
|
+
lines.reverse_each do |line|
|
|
67
|
+
yield line + "\n" unless line.empty?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
break if pos == 0
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Handle any remaining buffer content
|
|
74
|
+
unless buffer.empty?
|
|
75
|
+
yield buffer + "\n"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
28
78
|
end
|
|
29
79
|
end
|
|
@@ -10,8 +10,10 @@ class Tidewave::Tools::GetModels < Tidewave::Tools::Base
|
|
|
10
10
|
# Ensure all models are loaded
|
|
11
11
|
Rails.application.eager_load!
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
# Use adapter to get models (encapsulates ORM-specific logic)
|
|
14
|
+
models = Tidewave::DatabaseAdapter.current.get_models
|
|
15
|
+
|
|
16
|
+
models.map do |model|
|
|
15
17
|
if location = get_relative_source_location(model.name)
|
|
16
18
|
"* #{model.name} at #{location}"
|
|
17
19
|
else
|
|
@@ -23,6 +23,12 @@ class Tidewave::Tools::ProjectEval < Tidewave::Tools::Base
|
|
|
23
23
|
optional(:json).hidden().filled(:bool).description("Whether to return the result as JSON with structured output containing result, success, stdout, and stderr fields. Defaults to false.")
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def @input_schema.json_schema
|
|
27
|
+
schema = super
|
|
28
|
+
schema[:properties][:arguments][:items] = {}
|
|
29
|
+
schema
|
|
30
|
+
end
|
|
31
|
+
|
|
26
32
|
def call(code:, arguments: [], timeout: 30_000, json: false)
|
|
27
33
|
original_stdout = $stdout
|
|
28
34
|
original_stderr = $stderr
|
data/lib/tidewave/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tidewave
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yorick Jacquin
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2025-
|
|
12
|
+
date: 2025-10-17 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rails
|
|
@@ -31,14 +31,14 @@ dependencies:
|
|
|
31
31
|
requirements:
|
|
32
32
|
- - "~>"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: 1.
|
|
34
|
+
version: 1.6.0
|
|
35
35
|
type: :runtime
|
|
36
36
|
prerelease: false
|
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
|
38
38
|
requirements:
|
|
39
39
|
- - "~>"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: 1.
|
|
41
|
+
version: 1.6.0
|
|
42
42
|
- !ruby/object:Gem::Dependency
|
|
43
43
|
name: rack
|
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,6 +72,7 @@ files:
|
|
|
72
72
|
- lib/tidewave/middleware.rb
|
|
73
73
|
- lib/tidewave/quiet_requests_middleware.rb
|
|
74
74
|
- lib/tidewave/railtie.rb
|
|
75
|
+
- lib/tidewave/streamable_http_transport.rb
|
|
75
76
|
- lib/tidewave/tools/base.rb
|
|
76
77
|
- lib/tidewave/tools/execute_sql_query.rb
|
|
77
78
|
- lib/tidewave/tools/get_docs.rb
|