stagehand 0.0.3 → 3.5.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 (145) hide show
  1. checksums.yaml +7 -0
  2. data/.ignore +2 -0
  3. data/CHANGELOG.md +185 -0
  4. data/README.md +394 -31
  5. data/SECURITY.md +23 -0
  6. data/lib/stagehand/client.rb +126 -0
  7. data/lib/stagehand/errors.rb +228 -0
  8. data/lib/stagehand/file_part.rb +58 -0
  9. data/lib/stagehand/internal/stream.rb +56 -0
  10. data/lib/stagehand/internal/transport/base_client.rb +575 -0
  11. data/lib/stagehand/internal/transport/pooled_net_requester.rb +210 -0
  12. data/lib/stagehand/internal/type/array_of.rb +168 -0
  13. data/lib/stagehand/internal/type/base_model.rb +531 -0
  14. data/lib/stagehand/internal/type/base_page.rb +55 -0
  15. data/lib/stagehand/internal/type/base_stream.rb +83 -0
  16. data/lib/stagehand/internal/type/boolean.rb +77 -0
  17. data/lib/stagehand/internal/type/converter.rb +327 -0
  18. data/lib/stagehand/internal/type/enum.rb +131 -0
  19. data/lib/stagehand/internal/type/file_input.rb +111 -0
  20. data/lib/stagehand/internal/type/hash_of.rb +188 -0
  21. data/lib/stagehand/internal/type/request_parameters.rb +42 -0
  22. data/lib/stagehand/internal/type/union.rb +237 -0
  23. data/lib/stagehand/internal/type/unknown.rb +81 -0
  24. data/lib/stagehand/internal/util.rb +920 -0
  25. data/lib/stagehand/internal.rb +20 -0
  26. data/lib/stagehand/local.rb +439 -0
  27. data/lib/stagehand/models/action.rb +50 -0
  28. data/lib/stagehand/models/model_config.rb +55 -0
  29. data/lib/stagehand/models/session_act_params.rb +112 -0
  30. data/lib/stagehand/models/session_act_response.rb +127 -0
  31. data/lib/stagehand/models/session_end_params.rb +33 -0
  32. data/lib/stagehand/models/session_end_response.rb +17 -0
  33. data/lib/stagehand/models/session_execute_params.rb +212 -0
  34. data/lib/stagehand/models/session_execute_response.rb +212 -0
  35. data/lib/stagehand/models/session_extract_params.rb +107 -0
  36. data/lib/stagehand/models/session_extract_response.rb +46 -0
  37. data/lib/stagehand/models/session_navigate_params.rb +107 -0
  38. data/lib/stagehand/models/session_navigate_response.rb +44 -0
  39. data/lib/stagehand/models/session_observe_params.rb +99 -0
  40. data/lib/stagehand/models/session_observe_response.rb +91 -0
  41. data/lib/stagehand/models/session_replay_params.rb +33 -0
  42. data/lib/stagehand/models/session_replay_response.rb +100 -0
  43. data/lib/stagehand/models/session_start_params.rb +762 -0
  44. data/lib/stagehand/models/session_start_response.rb +55 -0
  45. data/lib/stagehand/models/stream_event.rb +120 -0
  46. data/lib/stagehand/models.rb +63 -0
  47. data/lib/stagehand/request_options.rb +77 -0
  48. data/lib/stagehand/resources/sessions.rb +488 -0
  49. data/lib/stagehand/version.rb +3 -1
  50. data/lib/stagehand.rb +74 -21
  51. data/manifest.yaml +17 -0
  52. data/rbi/stagehand/client.rbi +89 -0
  53. data/rbi/stagehand/errors.rbi +205 -0
  54. data/rbi/stagehand/file_part.rbi +37 -0
  55. data/rbi/stagehand/internal/stream.rbi +20 -0
  56. data/rbi/stagehand/internal/transport/base_client.rbi +314 -0
  57. data/rbi/stagehand/internal/transport/pooled_net_requester.rbi +83 -0
  58. data/rbi/stagehand/internal/type/array_of.rbi +104 -0
  59. data/rbi/stagehand/internal/type/base_model.rbi +308 -0
  60. data/rbi/stagehand/internal/type/base_page.rbi +42 -0
  61. data/rbi/stagehand/internal/type/base_stream.rbi +75 -0
  62. data/rbi/stagehand/internal/type/boolean.rbi +58 -0
  63. data/rbi/stagehand/internal/type/converter.rbi +216 -0
  64. data/rbi/stagehand/internal/type/enum.rbi +82 -0
  65. data/rbi/stagehand/internal/type/file_input.rbi +59 -0
  66. data/rbi/stagehand/internal/type/hash_of.rbi +104 -0
  67. data/rbi/stagehand/internal/type/request_parameters.rbi +29 -0
  68. data/rbi/stagehand/internal/type/union.rbi +128 -0
  69. data/rbi/stagehand/internal/type/unknown.rbi +58 -0
  70. data/rbi/stagehand/internal/util.rbi +487 -0
  71. data/rbi/stagehand/internal.rbi +18 -0
  72. data/rbi/stagehand/models/action.rbi +77 -0
  73. data/rbi/stagehand/models/model_config.rbi +94 -0
  74. data/rbi/stagehand/models/session_act_params.rbi +204 -0
  75. data/rbi/stagehand/models/session_act_response.rbi +250 -0
  76. data/rbi/stagehand/models/session_end_params.rbi +87 -0
  77. data/rbi/stagehand/models/session_end_response.rbi +30 -0
  78. data/rbi/stagehand/models/session_execute_params.rbi +440 -0
  79. data/rbi/stagehand/models/session_execute_response.rbi +414 -0
  80. data/rbi/stagehand/models/session_extract_params.rbi +209 -0
  81. data/rbi/stagehand/models/session_extract_response.rbi +91 -0
  82. data/rbi/stagehand/models/session_navigate_params.rbi +240 -0
  83. data/rbi/stagehand/models/session_navigate_response.rbi +91 -0
  84. data/rbi/stagehand/models/session_observe_params.rbi +198 -0
  85. data/rbi/stagehand/models/session_observe_response.rbi +184 -0
  86. data/rbi/stagehand/models/session_replay_params.rbi +89 -0
  87. data/rbi/stagehand/models/session_replay_response.rbi +286 -0
  88. data/rbi/stagehand/models/session_start_params.rbi +1703 -0
  89. data/rbi/stagehand/models/session_start_response.rbi +102 -0
  90. data/rbi/stagehand/models/stream_event.rbi +237 -0
  91. data/rbi/stagehand/models.rbi +25 -0
  92. data/rbi/stagehand/request_options.rbi +59 -0
  93. data/rbi/stagehand/resources/sessions.rbi +421 -0
  94. data/rbi/stagehand/version.rbi +5 -0
  95. data/sig/stagehand/client.rbs +41 -0
  96. data/sig/stagehand/errors.rbs +117 -0
  97. data/sig/stagehand/file_part.rbs +21 -0
  98. data/sig/stagehand/internal/stream.rbs +9 -0
  99. data/sig/stagehand/internal/transport/base_client.rbs +133 -0
  100. data/sig/stagehand/internal/transport/pooled_net_requester.rbs +48 -0
  101. data/sig/stagehand/internal/type/array_of.rbs +48 -0
  102. data/sig/stagehand/internal/type/base_model.rbs +102 -0
  103. data/sig/stagehand/internal/type/base_page.rbs +24 -0
  104. data/sig/stagehand/internal/type/base_stream.rbs +38 -0
  105. data/sig/stagehand/internal/type/boolean.rbs +26 -0
  106. data/sig/stagehand/internal/type/converter.rbs +79 -0
  107. data/sig/stagehand/internal/type/enum.rbs +32 -0
  108. data/sig/stagehand/internal/type/file_input.rbs +25 -0
  109. data/sig/stagehand/internal/type/hash_of.rbs +48 -0
  110. data/sig/stagehand/internal/type/request_parameters.rbs +19 -0
  111. data/sig/stagehand/internal/type/union.rbs +52 -0
  112. data/sig/stagehand/internal/type/unknown.rbs +26 -0
  113. data/sig/stagehand/internal/util.rbs +185 -0
  114. data/sig/stagehand/internal.rbs +9 -0
  115. data/sig/stagehand/models/action.rbs +46 -0
  116. data/sig/stagehand/models/model_config.rbs +56 -0
  117. data/sig/stagehand/models/session_act_params.rbs +111 -0
  118. data/sig/stagehand/models/session_act_response.rbs +121 -0
  119. data/sig/stagehand/models/session_end_params.rbs +41 -0
  120. data/sig/stagehand/models/session_end_response.rbs +13 -0
  121. data/sig/stagehand/models/session_execute_params.rbs +193 -0
  122. data/sig/stagehand/models/session_execute_response.rbs +215 -0
  123. data/sig/stagehand/models/session_extract_params.rbs +112 -0
  124. data/sig/stagehand/models/session_extract_response.rbs +36 -0
  125. data/sig/stagehand/models/session_navigate_params.rbs +114 -0
  126. data/sig/stagehand/models/session_navigate_response.rbs +36 -0
  127. data/sig/stagehand/models/session_observe_params.rbs +105 -0
  128. data/sig/stagehand/models/session_observe_response.rbs +89 -0
  129. data/sig/stagehand/models/session_replay_params.rbs +41 -0
  130. data/sig/stagehand/models/session_replay_response.rbs +137 -0
  131. data/sig/stagehand/models/session_start_params.rbs +866 -0
  132. data/sig/stagehand/models/session_start_response.rbs +44 -0
  133. data/sig/stagehand/models/stream_event.rbs +109 -0
  134. data/sig/stagehand/models.rbs +23 -0
  135. data/sig/stagehand/request_options.rbs +34 -0
  136. data/sig/stagehand/resources/sessions.rbs +121 -0
  137. data/sig/stagehand/version.rbs +3 -0
  138. metadata +173 -42
  139. data/.gitignore +0 -16
  140. data/Gemfile +0 -4
  141. data/Rakefile +0 -10
  142. data/lib/stagehand/railtie.rb +0 -14
  143. data/spec/spec_helper.rb +0 -7
  144. data/spec/stagehand_spec.rb +0 -15
  145. data/stagehand.gemspec +0 -24
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stagehand
4
+ class Client < Stagehand::Internal::Transport::BaseClient
5
+ # Default max number of retries to attempt after a failed retryable request.
6
+ DEFAULT_MAX_RETRIES = 2
7
+
8
+ # Default per-request timeout.
9
+ DEFAULT_TIMEOUT_IN_SECONDS = 60.0
10
+
11
+ # Default initial retry delay in seconds.
12
+ # Overall delay is calculated using exponential backoff + jitter.
13
+ DEFAULT_INITIAL_RETRY_DELAY = 0.5
14
+
15
+ # Default max retry delay in seconds.
16
+ DEFAULT_MAX_RETRY_DELAY = 8.0
17
+
18
+ # Your [Browserbase API Key](https://www.browserbase.com/settings)
19
+ # @return [String]
20
+ attr_reader :browserbase_api_key
21
+
22
+ # Your [Browserbase Project ID](https://www.browserbase.com/settings)
23
+ # @return [String]
24
+ attr_reader :browserbase_project_id
25
+
26
+ # Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
27
+ # @return [String]
28
+ attr_reader :model_api_key
29
+
30
+ # @return [Stagehand::Resources::Sessions]
31
+ attr_reader :sessions
32
+
33
+ # @api private
34
+ #
35
+ # @return [Hash{String=>String}]
36
+ private def auth_headers
37
+ {**bb_api_key_auth, **bb_project_id_auth, **llm_model_api_key_auth}
38
+ end
39
+
40
+ # @api private
41
+ #
42
+ # @return [Hash{String=>String}]
43
+ private def bb_api_key_auth
44
+ {"x-bb-api-key" => @browserbase_api_key}
45
+ end
46
+
47
+ # @api private
48
+ #
49
+ # @return [Hash{String=>String}]
50
+ private def bb_project_id_auth
51
+ {"x-bb-project-id" => @browserbase_project_id}
52
+ end
53
+
54
+ # @api private
55
+ #
56
+ # @return [Hash{String=>String}]
57
+ private def llm_model_api_key_auth
58
+ {"x-model-api-key" => @model_api_key}
59
+ end
60
+
61
+ # Creates and returns a new client for interacting with the API.
62
+ #
63
+ # @param browserbase_api_key [String, nil] Your [Browserbase API Key](https://www.browserbase.com/settings) Defaults to
64
+ # `ENV["BROWSERBASE_API_KEY"]`
65
+ #
66
+ # @param browserbase_project_id [String, nil] Your [Browserbase Project ID](https://www.browserbase.com/settings) Defaults to
67
+ # `ENV["BROWSERBASE_PROJECT_ID"]`
68
+ #
69
+ # @param model_api_key [String, nil] Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
70
+ # Defaults to `ENV["MODEL_API_KEY"]`
71
+ #
72
+ # @param server [String] Server mode to use ("remote" or "local"). Defaults to "remote"
73
+ #
74
+ # @param base_url [String, nil] Override the default base URL for the API, e.g.,
75
+ # `"https://api.example.com/v2/"`. Defaults to `ENV["STAGEHAND_BASE_URL"]`
76
+ #
77
+ # @param max_retries [Integer] Max number of retries to attempt after a failed retryable request.
78
+ #
79
+ # @param timeout [Float]
80
+ #
81
+ # @param initial_retry_delay [Float]
82
+ #
83
+ # @param max_retry_delay [Float]
84
+ def initialize(
85
+ browserbase_api_key: ENV["BROWSERBASE_API_KEY"],
86
+ browserbase_project_id: ENV["BROWSERBASE_PROJECT_ID"],
87
+ model_api_key: ENV["MODEL_API_KEY"],
88
+ server: "remote",
89
+ base_url: ENV["STAGEHAND_BASE_URL"],
90
+ max_retries: self.class::DEFAULT_MAX_RETRIES,
91
+ timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
92
+ initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
93
+ max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
94
+ )
95
+ @server = server
96
+ base_url ||= "https://api.stagehand.browserbase.com"
97
+
98
+ if browserbase_api_key.nil?
99
+ raise ArgumentError,
100
+ "browserbase_api_key is required, and can be set via environ: \"BROWSERBASE_API_KEY\""
101
+ end
102
+ if browserbase_project_id.nil?
103
+ raise ArgumentError,
104
+ "browserbase_project_id is required, and can be set via environ: \"BROWSERBASE_PROJECT_ID\""
105
+ end
106
+ if model_api_key.nil?
107
+ raise ArgumentError,
108
+ "model_api_key is required, and can be set via environ: \"MODEL_API_KEY\""
109
+ end
110
+
111
+ @browserbase_api_key = browserbase_api_key.to_s
112
+ @browserbase_project_id = browserbase_project_id.to_s
113
+ @model_api_key = model_api_key.to_s
114
+
115
+ super(
116
+ base_url: base_url,
117
+ timeout: timeout,
118
+ max_retries: max_retries,
119
+ initial_retry_delay: initial_retry_delay,
120
+ max_retry_delay: max_retry_delay
121
+ )
122
+
123
+ @sessions = Stagehand::Resources::Sessions.new(client: self)
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stagehand
4
+ module Errors
5
+ class Error < StandardError
6
+ # @!attribute cause
7
+ #
8
+ # @return [StandardError, nil]
9
+ end
10
+
11
+ class ConversionError < Stagehand::Errors::Error
12
+ # @return [StandardError, nil]
13
+ def cause = @cause.nil? ? super : @cause
14
+
15
+ # @api private
16
+ #
17
+ # @param on [Class<StandardError>]
18
+ # @param method [Symbol]
19
+ # @param target [Object]
20
+ # @param value [Object]
21
+ # @param cause [StandardError, nil]
22
+ def initialize(on:, method:, target:, value:, cause: nil)
23
+ cls = on.name.split("::").last
24
+
25
+ message = [
26
+ "Failed to parse #{cls}.#{method} from #{value.class} to #{target.inspect}.",
27
+ "To get the unparsed API response, use #{cls}[#{method.inspect}].",
28
+ cause && "Cause: #{cause.message}"
29
+ ].filter(&:itself).join(" ")
30
+
31
+ @cause = cause
32
+ super(message)
33
+ end
34
+ end
35
+
36
+ class APIError < Stagehand::Errors::Error
37
+ # @return [URI::Generic]
38
+ attr_accessor :url
39
+
40
+ # @return [Integer, nil]
41
+ attr_accessor :status
42
+
43
+ # @return [Hash{String=>String}, nil]
44
+ attr_accessor :headers
45
+
46
+ # @return [Object, nil]
47
+ attr_accessor :body
48
+
49
+ # @api private
50
+ #
51
+ # @param url [URI::Generic]
52
+ # @param status [Integer, nil]
53
+ # @param headers [Hash{String=>String}, nil]
54
+ # @param body [Object, nil]
55
+ # @param request [nil]
56
+ # @param response [nil]
57
+ # @param message [String, nil]
58
+ def initialize(url:, status: nil, headers: nil, body: nil, request: nil, response: nil, message: nil)
59
+ @url = url
60
+ @status = status
61
+ @headers = headers
62
+ @body = body
63
+ @request = request
64
+ @response = response
65
+ super(message)
66
+ end
67
+ end
68
+
69
+ class APIConnectionError < Stagehand::Errors::APIError
70
+ # @!attribute status
71
+ #
72
+ # @return [nil]
73
+
74
+ # @!attribute body
75
+ #
76
+ # @return [nil]
77
+
78
+ # @api private
79
+ #
80
+ # @param url [URI::Generic]
81
+ # @param status [nil]
82
+ # @param headers [Hash{String=>String}, nil]
83
+ # @param body [nil]
84
+ # @param request [nil]
85
+ # @param response [nil]
86
+ # @param message [String, nil]
87
+ def initialize(
88
+ url:,
89
+ status: nil,
90
+ headers: nil,
91
+ body: nil,
92
+ request: nil,
93
+ response: nil,
94
+ message: "Connection error."
95
+ )
96
+ super
97
+ end
98
+ end
99
+
100
+ class APITimeoutError < Stagehand::Errors::APIConnectionError
101
+ # @api private
102
+ #
103
+ # @param url [URI::Generic]
104
+ # @param status [nil]
105
+ # @param headers [Hash{String=>String}, nil]
106
+ # @param body [nil]
107
+ # @param request [nil]
108
+ # @param response [nil]
109
+ # @param message [String, nil]
110
+ def initialize(
111
+ url:,
112
+ status: nil,
113
+ headers: nil,
114
+ body: nil,
115
+ request: nil,
116
+ response: nil,
117
+ message: "Request timed out."
118
+ )
119
+ super
120
+ end
121
+ end
122
+
123
+ class APIStatusError < Stagehand::Errors::APIError
124
+ # @api private
125
+ #
126
+ # @param url [URI::Generic]
127
+ # @param status [Integer]
128
+ # @param headers [Hash{String=>String}, nil]
129
+ # @param body [Object, nil]
130
+ # @param request [nil]
131
+ # @param response [nil]
132
+ # @param message [String, nil]
133
+ #
134
+ # @return [self]
135
+ def self.for(url:, status:, headers:, body:, request:, response:, message: nil)
136
+ kwargs =
137
+ {
138
+ url: url,
139
+ status: status,
140
+ headers: headers,
141
+ body: body,
142
+ request: request,
143
+ response: response,
144
+ message: message
145
+ }
146
+
147
+ case status
148
+ in 400
149
+ Stagehand::Errors::BadRequestError.new(**kwargs)
150
+ in 401
151
+ Stagehand::Errors::AuthenticationError.new(**kwargs)
152
+ in 403
153
+ Stagehand::Errors::PermissionDeniedError.new(**kwargs)
154
+ in 404
155
+ Stagehand::Errors::NotFoundError.new(**kwargs)
156
+ in 409
157
+ Stagehand::Errors::ConflictError.new(**kwargs)
158
+ in 422
159
+ Stagehand::Errors::UnprocessableEntityError.new(**kwargs)
160
+ in 429
161
+ Stagehand::Errors::RateLimitError.new(**kwargs)
162
+ in (500..)
163
+ Stagehand::Errors::InternalServerError.new(**kwargs)
164
+ else
165
+ Stagehand::Errors::APIStatusError.new(**kwargs)
166
+ end
167
+ end
168
+
169
+ # @!parse
170
+ # # @return [Integer]
171
+ # attr_accessor :status
172
+
173
+ # @api private
174
+ #
175
+ # @param url [URI::Generic]
176
+ # @param status [Integer]
177
+ # @param headers [Hash{String=>String}, nil]
178
+ # @param body [Object, nil]
179
+ # @param request [nil]
180
+ # @param response [nil]
181
+ # @param message [String, nil]
182
+ def initialize(url:, status:, headers:, body:, request:, response:, message: nil)
183
+ message ||= {url: url.to_s, status: status, body: body}
184
+ super(
185
+ url: url,
186
+ status: status,
187
+ headers: headers,
188
+ body: body,
189
+ request: request,
190
+ response: response,
191
+ message: message&.to_s
192
+ )
193
+ end
194
+ end
195
+
196
+ class BadRequestError < Stagehand::Errors::APIStatusError
197
+ HTTP_STATUS = 400
198
+ end
199
+
200
+ class AuthenticationError < Stagehand::Errors::APIStatusError
201
+ HTTP_STATUS = 401
202
+ end
203
+
204
+ class PermissionDeniedError < Stagehand::Errors::APIStatusError
205
+ HTTP_STATUS = 403
206
+ end
207
+
208
+ class NotFoundError < Stagehand::Errors::APIStatusError
209
+ HTTP_STATUS = 404
210
+ end
211
+
212
+ class ConflictError < Stagehand::Errors::APIStatusError
213
+ HTTP_STATUS = 409
214
+ end
215
+
216
+ class UnprocessableEntityError < Stagehand::Errors::APIStatusError
217
+ HTTP_STATUS = 422
218
+ end
219
+
220
+ class RateLimitError < Stagehand::Errors::APIStatusError
221
+ HTTP_STATUS = 429
222
+ end
223
+
224
+ class InternalServerError < Stagehand::Errors::APIStatusError
225
+ HTTP_STATUS = (500..)
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stagehand
4
+ class FilePart
5
+ # @return [Pathname, StringIO, IO, String]
6
+ attr_reader :content
7
+
8
+ # @return [String, nil]
9
+ attr_reader :content_type
10
+
11
+ # @return [String, nil]
12
+ attr_reader :filename
13
+
14
+ # @api private
15
+ #
16
+ # @return [String]
17
+ private def read
18
+ case content
19
+ in Pathname
20
+ content.read(binmode: true)
21
+ in StringIO
22
+ content.string
23
+ in IO
24
+ content.read
25
+ in String
26
+ content
27
+ end
28
+ end
29
+
30
+ # @param a [Object]
31
+ #
32
+ # @return [String]
33
+ def to_json(*a) = read.to_json(*a)
34
+
35
+ # @param a [Object]
36
+ #
37
+ # @return [String]
38
+ def to_yaml(*a) = read.to_yaml(*a)
39
+
40
+ # @param content [Pathname, StringIO, IO, String]
41
+ # @param filename [Pathname, String, nil]
42
+ # @param content_type [String, nil]
43
+ def initialize(content, filename: nil, content_type: nil)
44
+ @content_type = content_type
45
+ @filename =
46
+ case [filename, (@content = content)]
47
+ in [String | Pathname, _]
48
+ ::File.basename(filename)
49
+ in [nil, Pathname]
50
+ content.basename.to_path
51
+ in [nil, IO]
52
+ content.to_path
53
+ else
54
+ filename
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stagehand
4
+ module Internal
5
+ # @generic Elem
6
+ #
7
+ # @example
8
+ # stream.each do |event|
9
+ # puts(event)
10
+ # end
11
+ class Stream
12
+ include Stagehand::Internal::Type::BaseStream
13
+
14
+ # @api private
15
+ #
16
+ # @return [Enumerable<generic<Elem>>]
17
+ private def iterator
18
+ # rubocop:disable Metrics/BlockLength
19
+ @iterator ||= Stagehand::Internal::Util.chain_fused(@stream) do |y|
20
+ consume = false
21
+
22
+ @stream.each do |msg|
23
+ next if consume
24
+
25
+ case msg
26
+ in {data: String => data} if data.start_with?("{\"data\":{\"status\":\"finished\"")
27
+ consume = true
28
+ next
29
+ in {data: String => data} if data.start_with?("error")
30
+ decoded = Kernel.then do
31
+ JSON.parse(data, symbolize_names: true)
32
+ rescue JSON::ParserError
33
+ data
34
+ end
35
+ err = Stagehand::Errors::APIStatusError.for(
36
+ url: @url,
37
+ status: @status,
38
+ headers: @headers,
39
+ body: decoded,
40
+ request: nil,
41
+ response: @response
42
+ )
43
+ raise err
44
+ in {event: nil, data: String => data}
45
+ decoded = JSON.parse(data, symbolize_names: true)
46
+ unwrapped = Stagehand::Internal::Util.dig(decoded, @unwrap)
47
+ y << Stagehand::Internal::Type::Converter.coerce(@model, unwrapped)
48
+ else
49
+ end
50
+ end
51
+ end
52
+ # rubocop:enable Metrics/BlockLength
53
+ end
54
+ end
55
+ end
56
+ end