Class: Browserctl::WorkflowContext
- Inherits:
-
Object
- Object
- Browserctl::WorkflowContext
show all
- Defined in:
- lib/browserctl/workflow.rb
Constant Summary
collapse
- DEPRECATED_LOAD_SESSION_FALLBACK =
<<~MSG
[browserctl] DEPRECATION: `load_session(name, fallback:, expired_if:)` is superseded by
`load_state(name)` with a flow-bound bundle (`save_state(name, flow: :name)`).
`load_session` will be removed in v0.12. See docs/concepts/state.md.
MSG
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#ask(prompt) ⇒ Object
-
#assert(condition, msg = "assertion failed") ⇒ Object
-
#assert_snapshot_stable(page_name, expected_digest:) ⇒ Object
Snapshots the named page and compares its digest against ‘expected_digest`.
-
#close_page(page_name) ⇒ Object
-
#compose ⇒ Object
-
#fetch(key) ⇒ Object
-
#initialize(params, client, replay_context: nil) ⇒ WorkflowContext
constructor
A new instance of WorkflowContext.
-
#invoke(target_name, page: nil, **override_params) ⇒ Object
-
#list_sessions ⇒ Object
-
#load_session(session_name, fallback: nil, expired_if: nil) ⇒ Object
-
#load_state(name, on_auth_required: nil) ⇒ Object
-
#method_missing(name, *args) ⇒ Object
-
#open_page(page_name, url: nil) ⇒ Object
-
#page(name) ⇒ Object
-
#respond_to_missing?(name, include_private = false) ⇒ Boolean
-
#save_session(session_name, encrypt: false) ⇒ Object
-
#save_state(name, flow: nil, origins: nil, encrypt: false) ⇒ Object
Persists the daemon’s current cookies + storage as a .bctl bundle.
-
#store(key, value) ⇒ Object
Constructor Details
#initialize(params, client, replay_context: nil) ⇒ WorkflowContext
Returns a new instance of WorkflowContext.
76
77
78
79
80
|
# File 'lib/browserctl/workflow.rb', line 76
def initialize(params, client, replay_context: nil)
@params = params
@client = client
@replay_context = replay_context
end
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
96
97
98
99
100
|
# File 'lib/browserctl/workflow.rb', line 96
def method_missing(name, *args)
return @params[name] if @params.key?(name)
super
end
|
Instance Attribute Details
#client ⇒ Object
Returns the value of attribute client.
74
75
76
|
# File 'lib/browserctl/workflow.rb', line 74
def client
@client
end
|
#params ⇒ Object
Returns the value of attribute params.
74
75
76
|
# File 'lib/browserctl/workflow.rb', line 74
def params
@params
end
|
#replay_context ⇒ Object
Returns the value of attribute replay_context.
74
75
76
|
# File 'lib/browserctl/workflow.rb', line 74
def replay_context
@replay_context
end
|
Instance Method Details
#ask(prompt) ⇒ Object
184
185
186
187
|
# File 'lib/browserctl/workflow.rb', line 184
def ask(prompt)
$stderr.print("[browserctl] #{prompt} ")
$stdin.gets.chomp
end
|
#assert(condition, msg = "assertion failed") ⇒ Object
201
202
203
|
# File 'lib/browserctl/workflow.rb', line 201
def assert(condition, msg = "assertion failed")
raise WorkflowError, msg unless condition
end
|
#assert_snapshot_stable(page_name, expected_digest:) ⇒ Object
Snapshots the named page and compares its digest against ‘expected_digest`. Under `workflow run –check` (a replay context is attached), a mismatch is recorded as a drift event with reason “post-snapshot mismatch” and the step still passes. Outside –check, mismatch raises WorkflowError so the workflow fails fast.
210
211
212
213
214
215
216
217
218
219
220
221
222
|
# File 'lib/browserctl/workflow.rb', line 210
def assert_snapshot_stable(page_name, expected_digest:)
res = @client.snapshot(page_name.to_s, format: "elements")
snapshot = res[:snapshot]
actual = Replay::SnapshotDiff.digest(snapshot)
return if actual == expected_digest
msg = "post-snapshot mismatch on :#{page_name} — expected #{expected_digest}, got #{actual}"
raise WorkflowError, msg unless @replay_context
@replay_context.record(command: :assert_snapshot_stable, selector: page_name.to_s,
matched_ref: nil, score: nil, reason: "post-snapshot mismatch")
warn "[browserctl replay] #{msg}"
end
|
#close_page(page_name) ⇒ Object
117
118
119
120
121
122
|
# File 'lib/browserctl/workflow.rb', line 117
def close_page(page_name)
res = @client.page_close(page_name.to_s)
raise WorkflowError, res[:error] if res[:error]
res
end
|
#compose ⇒ Object
224
225
226
227
228
|
# File 'lib/browserctl/workflow.rb', line 224
def compose(*)
raise WorkflowError,
"`compose` must be called at the workflow definition level, not inside a step block. " \
"Did you mean `invoke`?"
end
|
#fetch(key) ⇒ Object
89
90
91
92
93
94
|
# File 'lib/browserctl/workflow.rb', line 89
def fetch(key)
res = @client.fetch(key.to_s)
raise WorkflowError, res[:error] if res[:error]
res[:value]
end
|
#invoke(target_name, page: nil, **override_params) ⇒ Object
189
190
191
192
193
194
195
196
197
198
199
|
# File 'lib/browserctl/workflow.rb', line 189
def invoke(target_name, page: nil, **override_params)
name = target_name.to_s
guard_circular!(name)
flow = lookup_flow_target(name)
if flow
track_invoke(name) { run_invoked_flow(flow, page_name: page, **override_params) }
else
track_invoke(name) { run_nested(target_name, **override_params) }
end
end
|
#list_sessions ⇒ Object
180
181
182
|
# File 'lib/browserctl/workflow.rb', line 180
def list_sessions
@client.session_list[:sessions]
end
|
#load_session(session_name, fallback: nil, expired_if: nil) ⇒ Object
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
# File 'lib/browserctl/workflow.rb', line 162
def load_session(session_name, fallback: nil, expired_if: nil)
warn DEPRECATED_LOAD_SESSION_FALLBACK if fallback || expired_if
validate_expired_if!(expired_if)
fallback_name = fallback&.to_s
res = @client.session_load(session_name)
if res[:error]
raise WorkflowError, res[:error] unless fallback_name
invoke(fallback_name)
return load_after_fallback(session_name, fallback_name)
end
return res if expired_if.nil? || !call_expired_if(expired_if, session_name)
recover_expired_session(session_name, fallback_name, expired_if)
end
|
#load_state(name, on_auth_required: nil) ⇒ Object
Restores a .bctl bundle. When the daemon detects AUTH_REQUIRED before applying (e.g. expired cookies in the payload), this rotates the bound flow and retries — no caller code change required.
150
151
152
153
154
155
|
# File 'lib/browserctl/workflow.rb', line 150
def load_state(name, on_auth_required: nil)
res = @client.state_load(name.to_s)
return res unless auth_required_response?(res)
recover_auth_required_state(name.to_s, res, on_auth_required)
end
|
#open_page(page_name, url: nil) ⇒ Object
110
111
112
113
114
115
|
# File 'lib/browserctl/workflow.rb', line 110
def open_page(page_name, url: nil)
res = @client.page_open(page_name.to_s, url: url)
raise WorkflowError, res[:error] if res[:error]
res
end
|
#page(name) ⇒ Object
106
107
108
|
# File 'lib/browserctl/workflow.rb', line 106
def page(name)
PageProxy.new(name.to_s, @client, replay_context: @replay_context)
end
|
#respond_to_missing?(name, include_private = false) ⇒ Boolean
102
103
104
|
# File 'lib/browserctl/workflow.rb', line 102
def respond_to_missing?(name, include_private = false)
@params.key?(name) || super
end
|
#save_session(session_name, encrypt: false) ⇒ Object
124
125
126
127
128
129
|
# File 'lib/browserctl/workflow.rb', line 124
def save_session(session_name, encrypt: false)
res = @client.session_save(session_name, encrypt: encrypt)
raise WorkflowError, res[:error] if res[:error]
res
end
|
#save_state(name, flow: nil, origins: nil, encrypt: false) ⇒ Object
Persists the daemon’s current cookies + storage as a .bctl bundle. Optional flow binding lets ‘load_state` auto-rotate when the bundle is detected as needing authentication.
134
135
136
137
138
139
140
141
|
# File 'lib/browserctl/workflow.rb', line 134
def save_state(name, flow: nil, origins: nil, encrypt: false)
passphrase = encrypt ? ENV.fetch("BROWSERCTL_STATE_PASSPHRASE", nil) : nil
res = @client.state_save(name.to_s,
flow: flow&.to_s, origins: origins, passphrase: passphrase)
raise WorkflowError, res[:error] if res[:error]
res
end
|
#store(key, value) ⇒ Object
82
83
84
85
86
87
|
# File 'lib/browserctl/workflow.rb', line 82
def store(key, value)
res = @client.store(key.to_s, value)
raise WorkflowError, res[:error] if res[:error]
value
end
|