shipeasy-sdk 3.3.0 → 3.5.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/docs/skill/SKILL.md +7 -1
- data/lib/shipeasy/config.rb +19 -1
- data/lib/shipeasy/engine.rb +29 -1
- data/lib/shipeasy/sdk/rack_middleware.rb +4 -1
- data/lib/shipeasy/sdk/see.rb +129 -10
- data/lib/shipeasy/sdk/version.rb +1 -1
- data/lib/shipeasy-sdk.rb +29 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0453ca27510264bd268b40868bb5c55a942835b7a20076b11e19305b4eeb27a7
|
|
4
|
+
data.tar.gz: c9c0b1ee3c80cf28abac5af4ec8bdaec1613f8b3235708b79b27223e38d2d463
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d92ea1c2016d7e81791a7d7b8d6a0cd631da001893227685297e570c86372dc905da89cf54641d85ef7715e6ffd5ae0498a8781714326352fc139cf5adae0320
|
|
7
|
+
data.tar.gz: bfd396eeac063d46053f15fc865f8444f8284dae480cee7f064809a43bb288cd48ebd7cf559d08d5d3f0f68c3252a360800a8a2f787c5b63e2a3c25601e8d555
|
data/docs/skill/SKILL.md
CHANGED
|
@@ -126,12 +126,17 @@ rescue => e
|
|
|
126
126
|
end
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
Attach context with `.extras({...})` before `.to`, or inline as
|
|
130
|
+
`.to(outcome, {...})`. To attach it from anywhere without threading it into the
|
|
131
|
+
rescue, buffer it earlier with `Shipeasy.add_extras(order_id: id)` — it merges
|
|
132
|
+
into every see() report later in the same (fiber-local, per-request) scope.
|
|
133
|
+
|
|
129
134
|
`Shipeasy.see_violation(name)` for non-exception problems;
|
|
130
135
|
`Shipeasy.control_flow_exception(e).because(...)` marks expected control flow
|
|
131
136
|
(reports nothing).
|
|
132
137
|
|
|
133
138
|
→ More: `pages/error-reporting.md` · snippets `snippets/ops/see.md`
|
|
134
|
-
(`.extras`, violations, control-flow exceptions).
|
|
139
|
+
(`.extras`, `add_extras`, violations, control-flow exceptions).
|
|
135
140
|
|
|
136
141
|
## i18n (Rails)
|
|
137
142
|
|
|
@@ -150,6 +155,7 @@ the loader tag (public client key).
|
|
|
150
155
|
- Anon bucketing: `Shipeasy::SDK::RackMiddleware` mints the shared `__se_anon_id`
|
|
151
156
|
cookie (Rails Railtie auto-mounts it); anonymous `get_flag` then just works.
|
|
152
157
|
- `c.private_attributes = ["email"]` strips keys from outbound events.
|
|
158
|
+
- `c.clean_backtrace` (default on) filters `see()` stacks to app frames via `Rails.backtrace_cleaner`; set `false` for raw backtraces.
|
|
153
159
|
- `c.sticky_store = Shipeasy::SDK::InMemoryStickyStore.new` pins experiment assignment.
|
|
154
160
|
- SSR: `Shipeasy.bootstrap_script_tag(user)` + `Shipeasy.i18n_script_tag(client_key, "en:prod")`.
|
|
155
161
|
- `Shipeasy.on_change { ... }` (requires `c.poll = true`) fires after a poll fetches new data.
|
data/lib/shipeasy/config.rb
CHANGED
|
@@ -46,9 +46,14 @@ module Shipeasy
|
|
|
46
46
|
# swallows one of its OWN internal errors it normally ships a structured
|
|
47
47
|
# see event to Shipeasy's own project (NOT yours) so the SDK team can
|
|
48
48
|
# track SDK bugs; set true to disable that entirely.
|
|
49
|
+
# - clean_backtrace (default true): pass see() error backtraces through the
|
|
50
|
+
# host framework's own backtrace cleaner so reports carry only your
|
|
51
|
+
# application frames (gem/framework noise stripped). We do not invent the
|
|
52
|
+
# filtering rules — this leverages `Rails.backtrace_cleaner` and is a
|
|
53
|
+
# no-op outside Rails. Set false to always report the raw backtrace.
|
|
49
54
|
attr_accessor :env, :is_network_enabled, :disable_telemetry, :telemetry_url,
|
|
50
55
|
:private_attributes, :sticky_store,
|
|
51
|
-
:disable_internal_error_reporting
|
|
56
|
+
:disable_internal_error_reporting, :clean_backtrace
|
|
52
57
|
|
|
53
58
|
# SDK-wide diagnostic verbosity for the leveled logger (Shipeasy::Logging).
|
|
54
59
|
# One of :silent, :error, :warn (default), :info, :debug (strings accepted
|
|
@@ -103,6 +108,7 @@ module Shipeasy
|
|
|
103
108
|
@is_network_enabled = nil
|
|
104
109
|
@disable_telemetry = nil
|
|
105
110
|
@disable_internal_error_reporting = false
|
|
111
|
+
@clean_backtrace = true
|
|
106
112
|
@telemetry_url = nil
|
|
107
113
|
@private_attributes = nil
|
|
108
114
|
@sticky_store = nil
|
|
@@ -197,6 +203,7 @@ module Shipeasy
|
|
|
197
203
|
sticky_store: cfg.sticky_store,
|
|
198
204
|
log_level: cfg.log_level,
|
|
199
205
|
disable_internal_error_reporting: cfg.disable_internal_error_reporting,
|
|
206
|
+
clean_backtrace: cfg.clean_backtrace,
|
|
200
207
|
)
|
|
201
208
|
@engine = engine
|
|
202
209
|
# Capture +engine+ in the closure (not the @engine ivar, which a concurrent
|
|
@@ -326,6 +333,17 @@ module Shipeasy
|
|
|
326
333
|
Shipeasy::SDK.control_flow_exception(err)
|
|
327
334
|
end
|
|
328
335
|
|
|
336
|
+
# Ambient per-request see() extras — attach context from anywhere that
|
|
337
|
+
# merges into every see() report firing later in the same request, so you
|
|
338
|
+
# never thread it into the rescue block. See Shipeasy::SDK.add_extras.
|
|
339
|
+
def add_extras(extras = nil, **kwargs)
|
|
340
|
+
Shipeasy::SDK.add_extras(extras, **kwargs)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def clear_extras
|
|
344
|
+
Shipeasy::SDK.clear_extras
|
|
345
|
+
end
|
|
346
|
+
|
|
329
347
|
# Replace the registered global engine + attributes transform (used by the
|
|
330
348
|
# configure_for_* siblings — unlike configure, they replace so a test suite
|
|
331
349
|
# can reconfigure between cases). Returns the engine.
|
data/lib/shipeasy/engine.rb
CHANGED
|
@@ -36,7 +36,7 @@ module Shipeasy
|
|
|
36
36
|
# /sdk/i18n/loader.js) — distinct from the edge API the blobs are fetched from.
|
|
37
37
|
DEFAULT_CDN_BASE = "https://cdn.shipeasy.ai"
|
|
38
38
|
|
|
39
|
-
def initialize(api_key:, base_url: nil, env: "prod", is_network_enabled: nil, disable_telemetry: nil, telemetry_url: nil, test_mode: false, private_attributes: nil, sticky_store: nil, log_level: nil, disable_internal_error_reporting: false)
|
|
39
|
+
def initialize(api_key:, base_url: nil, env: "prod", is_network_enabled: nil, disable_telemetry: nil, telemetry_url: nil, test_mode: false, private_attributes: nil, sticky_store: nil, log_level: nil, disable_internal_error_reporting: false, clean_backtrace: true)
|
|
40
40
|
# SDK-wide diagnostic verbosity. Set the leveled logger from the passed
|
|
41
41
|
# level (default :warn; unknown falls back to :warn). The logger is
|
|
42
42
|
# module-scoped, so the last-built engine wins — mirrors the TS SDK,
|
|
@@ -52,6 +52,13 @@ module Shipeasy
|
|
|
52
52
|
# locally so private attrs never leave for evaluation; the only egress is
|
|
53
53
|
# track(), where the listed keys are dropped from the props bag.
|
|
54
54
|
@private_attributes = (private_attributes || []).map(&:to_s)
|
|
55
|
+
# When true (default), see() error stacks are passed through the host
|
|
56
|
+
# framework's own backtrace cleaner so a report carries only application
|
|
57
|
+
# frames (gem/framework noise stripped). We never invent the filtering —
|
|
58
|
+
# today this leverages Rails.backtrace_cleaner and is a no-op outside
|
|
59
|
+
# Rails. Set false to always send the raw backtrace. See
|
|
60
|
+
# see_backtrace_cleaner.
|
|
61
|
+
@clean_backtrace = clean_backtrace != false
|
|
55
62
|
# Pluggable sticky-bucketing store (doc 20 §2). Absent ⇒ deterministic.
|
|
56
63
|
# Threaded into experiment eval so an enrolled unit locks to its first
|
|
57
64
|
# assigned variant. Built-in: InMemoryStickyStore.
|
|
@@ -645,6 +652,7 @@ module Shipeasy
|
|
|
645
652
|
strip_private(built.extras),
|
|
646
653
|
sdk_version: Shipeasy::SDK::VERSION,
|
|
647
654
|
env: @env,
|
|
655
|
+
backtrace_cleaner: see_backtrace_cleaner,
|
|
648
656
|
)
|
|
649
657
|
return unless @see_limiter.should_send?(ev)
|
|
650
658
|
|
|
@@ -658,6 +666,26 @@ module Shipeasy
|
|
|
658
666
|
Shipeasy::Logging.error "[shipeasy] see() failed: #{e.message}"
|
|
659
667
|
end
|
|
660
668
|
|
|
669
|
+
# The framework-provided backtrace cleaner used to strip gem/framework
|
|
670
|
+
# frames from see() stacks, or nil to send the raw backtrace. Resolved
|
|
671
|
+
# lazily (not memoized) because Rails installs its cleaner during boot,
|
|
672
|
+
# which can finish after Shipeasy.configure runs. Today the only supported
|
|
673
|
+
# cleaner is Rails' own `ActiveSupport::BacktraceCleaner` — we leverage it
|
|
674
|
+
# rather than reimplementing the app-vs-gem frame rules ourselves. Returns
|
|
675
|
+
# nil when disabled or when not running under Rails.
|
|
676
|
+
def see_backtrace_cleaner
|
|
677
|
+
return nil unless @clean_backtrace
|
|
678
|
+
return nil unless defined?(::Rails) && ::Rails.respond_to?(:backtrace_cleaner)
|
|
679
|
+
|
|
680
|
+
cleaner = ::Rails.backtrace_cleaner
|
|
681
|
+
return nil unless cleaner.respond_to?(:clean)
|
|
682
|
+
|
|
683
|
+
->(bt) { cleaner.clean(bt) }
|
|
684
|
+
rescue StandardError
|
|
685
|
+
# Rails present but the cleaner blew up while resolving: fall back to raw.
|
|
686
|
+
nil
|
|
687
|
+
end
|
|
688
|
+
|
|
661
689
|
# Drop caller-marked private attributes from an outbound props bag. Handles
|
|
662
690
|
# both string and symbol keys against the stringified private list.
|
|
663
691
|
def strip_private(props)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require_relative "anon_id"
|
|
2
|
+
require_relative "see"
|
|
2
3
|
|
|
3
4
|
module Shipeasy
|
|
4
5
|
module SDK
|
|
@@ -32,8 +33,10 @@ module Shipeasy
|
|
|
32
33
|
begin
|
|
33
34
|
status, headers, body = @app.call(env)
|
|
34
35
|
ensure
|
|
35
|
-
# Don't leak the id
|
|
36
|
+
# Don't leak the id — or any ambient see() extras — onto the next
|
|
37
|
+
# request handled by this thread.
|
|
36
38
|
AnonId.current = nil
|
|
39
|
+
See::Context.clear
|
|
37
40
|
end
|
|
38
41
|
set_cookie!(headers, id, env) if minted
|
|
39
42
|
[status, headers, body]
|
data/lib/shipeasy/sdk/see.rb
CHANGED
|
@@ -12,11 +12,22 @@
|
|
|
12
12
|
#
|
|
13
13
|
# Dispatch model (differs from TS, which uses a microtask): `.to(outcome)` is
|
|
14
14
|
# the terminal — it builds the wire event and fire-and-forgets the POST to
|
|
15
|
-
# /collect. `causes_the` and `extras` are chainable setters
|
|
16
|
-
#
|
|
15
|
+
# /collect. `causes_the` and `extras` are chainable setters called *before*
|
|
16
|
+
# `.to`; `.to` also accepts the extras inline as a second arg, so there is no
|
|
17
|
+
# ordering trap to remember:
|
|
17
18
|
#
|
|
18
19
|
# client.see(e).causes_the("checkout").to("use cached prices")
|
|
19
20
|
# client.see(e).causes_the("checkout").extras({ order_id: oid }).to("use cached prices")
|
|
21
|
+
# client.see(e).causes_the("checkout").to("use cached prices", { order_id: oid })
|
|
22
|
+
#
|
|
23
|
+
# `.extras` chained AFTER `.to` is ignored with a warning (the report already
|
|
24
|
+
# went out) — it never raises into the rescue block.
|
|
25
|
+
#
|
|
26
|
+
# To attach context from anywhere in a request without threading it into the
|
|
27
|
+
# rescue block, use the ambient buffer (see `Context` below):
|
|
28
|
+
# `Shipeasy.add_extras(order_id: oid)` merges into EVERY see() report that fires
|
|
29
|
+
# later in the same request. It is fiber-local (concurrent requests never bleed)
|
|
30
|
+
# and the Rack middleware clears it at the end of each request.
|
|
20
31
|
#
|
|
21
32
|
# If you don't know the consequence of an exception, don't catch it.
|
|
22
33
|
|
|
@@ -110,7 +121,15 @@ module Shipeasy
|
|
|
110
121
|
# ---- Wire event construction ----
|
|
111
122
|
|
|
112
123
|
# Build the type:"error" event accepted by POST /collect.
|
|
113
|
-
|
|
124
|
+
#
|
|
125
|
+
# `backtrace_cleaner` (optional) is a callable that takes the raw backtrace
|
|
126
|
+
# array and returns an application-only subset (framework/gem frames
|
|
127
|
+
# stripped) — e.g. `->(bt) { Rails.backtrace_cleaner.clean(bt) }`. It is
|
|
128
|
+
# applied before the stack is joined; if it strips every frame (a stack
|
|
129
|
+
# that is purely framework/gem code) we fall back to the raw backtrace so
|
|
130
|
+
# an error is never left with an empty stack. We never invent the filtering
|
|
131
|
+
# rules — the callable is supplied by the framework's own cleaner.
|
|
132
|
+
def build_event(problem, subject, outcome, extras, sdk_version:, env:, backtrace_cleaner: nil)
|
|
114
133
|
stack = nil
|
|
115
134
|
|
|
116
135
|
if problem.is_a?(Violation)
|
|
@@ -120,7 +139,7 @@ module Shipeasy
|
|
|
120
139
|
elsif problem.is_a?(Exception)
|
|
121
140
|
error_type = problem.class.name || "Error"
|
|
122
141
|
message = (problem.message.to_s.empty? ? error_type : problem.message)
|
|
123
|
-
bt = problem.backtrace
|
|
142
|
+
bt = clean_backtrace(problem.backtrace, backtrace_cleaner)
|
|
124
143
|
stack = bt.join("\n") if bt && !bt.empty?
|
|
125
144
|
kind = "caught"
|
|
126
145
|
else
|
|
@@ -147,6 +166,21 @@ module Shipeasy
|
|
|
147
166
|
ev
|
|
148
167
|
end
|
|
149
168
|
|
|
169
|
+
# Apply the framework-provided backtrace cleaner to a raw backtrace,
|
|
170
|
+
# returning an application-only frame array. No cleaner (or no backtrace)
|
|
171
|
+
# ⇒ the input is returned untouched. If the cleaner raises, or strips every
|
|
172
|
+
# frame, fall back to the raw backtrace — a cleaned-to-empty stack would
|
|
173
|
+
# lose all debugging signal for an error that lives entirely in framework
|
|
174
|
+
# code. Never raises.
|
|
175
|
+
def clean_backtrace(bt, cleaner)
|
|
176
|
+
return bt if cleaner.nil? || bt.nil? || bt.empty?
|
|
177
|
+
|
|
178
|
+
cleaned = cleaner.call(bt)
|
|
179
|
+
cleaned && !cleaned.empty? ? cleaned : bt
|
|
180
|
+
rescue StandardError
|
|
181
|
+
bt
|
|
182
|
+
end
|
|
183
|
+
|
|
150
184
|
# ---- Spam limiter (mirror SeeLimiter) ----
|
|
151
185
|
|
|
152
186
|
# Per-process spam guard: identical events within 30s collapse to one
|
|
@@ -211,27 +245,65 @@ module Shipeasy
|
|
|
211
245
|
end
|
|
212
246
|
alias causesThe causes_the
|
|
213
247
|
|
|
248
|
+
# Attach debugging metadata. Chainable — call repeatedly (keys merge,
|
|
249
|
+
# later wins) *before* `.to`. Called after `.to` it is a no-op with a
|
|
250
|
+
# warning: the report already shipped, so there is nothing to amend and,
|
|
251
|
+
# crucially, it must not raise into the caller's rescue block. Use
|
|
252
|
+
# `.to(outcome, extras)` or `Shipeasy.add_extras` for late/scattered
|
|
253
|
+
# context instead.
|
|
214
254
|
def extras(extras)
|
|
215
|
-
if
|
|
216
|
-
|
|
255
|
+
if @done
|
|
256
|
+
Shipeasy::Logging.warn(
|
|
257
|
+
"[shipeasy] see() .extras(...) called after .to(...) is ignored — " \
|
|
258
|
+
"pass extras to .to(outcome, extras) or call .extras before .to"
|
|
259
|
+
)
|
|
260
|
+
return self
|
|
217
261
|
end
|
|
262
|
+
merge_extras(extras)
|
|
218
263
|
self
|
|
219
264
|
end
|
|
220
265
|
|
|
221
266
|
# Terminal: build the event and fire-and-forget the report. Idempotent.
|
|
222
|
-
|
|
223
|
-
|
|
267
|
+
# `extras` may be passed inline here as the trailing form
|
|
268
|
+
# `.to(outcome, { order_id: oid })` — merged like a final `.extras` call.
|
|
269
|
+
# Returns self so a stray trailing `.extras` chains harmlessly.
|
|
270
|
+
def to(outcome, extras = nil)
|
|
271
|
+
return self if @done
|
|
224
272
|
|
|
273
|
+
merge_extras(extras) unless extras.nil?
|
|
225
274
|
@done = true
|
|
226
275
|
@outcome = outcome.to_s
|
|
227
276
|
begin
|
|
228
277
|
@dispatch.call(
|
|
229
|
-
Built.new(@problem, @subject || DEFAULT_SUBJECT, @outcome.empty? ? DEFAULT_OUTCOME : @outcome,
|
|
278
|
+
Built.new(@problem, @subject || DEFAULT_SUBJECT, @outcome.empty? ? DEFAULT_OUTCOME : @outcome, resolved_extras)
|
|
230
279
|
)
|
|
231
280
|
rescue StandardError
|
|
232
281
|
# Reporting must never raise into caller code.
|
|
233
282
|
nil
|
|
234
283
|
end
|
|
284
|
+
self
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
private
|
|
288
|
+
|
|
289
|
+
def merge_extras(extras)
|
|
290
|
+
return unless extras.is_a?(Hash) && !extras.empty?
|
|
291
|
+
|
|
292
|
+
@extras = (@extras || {}).merge(extras)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# The chain's own extras merged OVER the ambient per-request buffer, so a
|
|
296
|
+
# chained key of the same name wins over an ambient one. Keys normalized
|
|
297
|
+
# to strings only when a merge actually happens; sanitize_extras
|
|
298
|
+
# stringifies the rest at build time.
|
|
299
|
+
def resolved_extras
|
|
300
|
+
ambient = Context.current
|
|
301
|
+
return @extras if ambient.empty?
|
|
302
|
+
return ambient if @extras.nil? || @extras.empty?
|
|
303
|
+
|
|
304
|
+
out = ambient.dup
|
|
305
|
+
@extras.each { |k, v| out[k.to_s] = v }
|
|
306
|
+
out
|
|
235
307
|
end
|
|
236
308
|
end
|
|
237
309
|
|
|
@@ -265,6 +337,8 @@ module Shipeasy
|
|
|
265
337
|
end
|
|
266
338
|
|
|
267
339
|
# A no-op chain returned by the module-level see() when no client exists.
|
|
340
|
+
# Every method returns self so the full grammar — including a trailing
|
|
341
|
+
# `.extras` after `.to` — chains without ever raising.
|
|
268
342
|
class NullChain
|
|
269
343
|
def causes_the(_subject)
|
|
270
344
|
self
|
|
@@ -275,8 +349,53 @@ module Shipeasy
|
|
|
275
349
|
self
|
|
276
350
|
end
|
|
277
351
|
|
|
278
|
-
def to(_outcome)
|
|
352
|
+
def to(_outcome, _extras = nil)
|
|
353
|
+
self
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# ---- Ambient per-request extras -------------------------------------
|
|
358
|
+
|
|
359
|
+
# A per-request buffer of extras that merge into EVERY see() report firing
|
|
360
|
+
# later in the same execution context. Lets a request attach context
|
|
361
|
+
# (order id, route, tenant) from anywhere without threading it into the
|
|
362
|
+
# rescue block: `Shipeasy.add_extras(order_id: oid)` here, and any
|
|
363
|
+
# subsequent `see()` in this request carries it.
|
|
364
|
+
#
|
|
365
|
+
# Fiber-local (like AnonId), so concurrent requests never bleed into each
|
|
366
|
+
# other. The Rack middleware clears it in an `ensure` at the end of each
|
|
367
|
+
# request; outside a Rack request (jobs, scripts) call
|
|
368
|
+
# `Shipeasy.clear_extras` yourself when a logical unit of work ends.
|
|
369
|
+
#
|
|
370
|
+
# Values are stored raw and sanitized (scalar-only, truncated, 20-key cap,
|
|
371
|
+
# private-attribute stripped) at build time, exactly like chained extras.
|
|
372
|
+
module Context
|
|
373
|
+
THREAD_KEY = :shipeasy_see_ambient_extras
|
|
374
|
+
|
|
375
|
+
module_function
|
|
376
|
+
|
|
377
|
+
# Merge fields into the current context's buffer (string keys, later
|
|
378
|
+
# wins). Non-hash / empty input is ignored. Never raises.
|
|
379
|
+
def add(extras)
|
|
380
|
+
return unless extras.is_a?(Hash) && !extras.empty?
|
|
381
|
+
|
|
382
|
+
buf = (Thread.current[THREAD_KEY] ||= {})
|
|
383
|
+
extras.each { |k, v| buf[k.to_s] = v }
|
|
279
384
|
nil
|
|
385
|
+
rescue StandardError
|
|
386
|
+
nil
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# A copy of the current context's buffer, or {} when empty.
|
|
390
|
+
def current
|
|
391
|
+
buf = Thread.current[THREAD_KEY]
|
|
392
|
+
buf.nil? || buf.empty? ? {} : buf.dup
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Drop the current context's buffer so extras never leak to the next
|
|
396
|
+
# request handled by this thread/fiber.
|
|
397
|
+
def clear
|
|
398
|
+
Thread.current[THREAD_KEY] = nil
|
|
280
399
|
end
|
|
281
400
|
end
|
|
282
401
|
end
|
data/lib/shipeasy/sdk/version.rb
CHANGED
data/lib/shipeasy-sdk.rb
CHANGED
|
@@ -76,5 +76,34 @@ module Shipeasy
|
|
|
76
76
|
def self.control_flow_exception(err)
|
|
77
77
|
See::ControlFlowChain.new(err)
|
|
78
78
|
end
|
|
79
|
+
|
|
80
|
+
# ---- ambient per-request see() extras -------------------------------
|
|
81
|
+
#
|
|
82
|
+
# Attach context that merges into every see() report firing later in this
|
|
83
|
+
# request, from anywhere — no need to thread it into the rescue block:
|
|
84
|
+
#
|
|
85
|
+
# Shipeasy::SDK.add_extras(order_id: order.id, tenant: tenant.slug)
|
|
86
|
+
# # ...later, somewhere else in the same request...
|
|
87
|
+
# rescue => e
|
|
88
|
+
# Shipeasy::SDK.see(e).causes_the("checkout").to("use cached prices")
|
|
89
|
+
# # ^ report carries order_id + tenant automatically
|
|
90
|
+
#
|
|
91
|
+
# Fiber-local, so concurrent requests never bleed. The Rack middleware
|
|
92
|
+
# clears the buffer per request (Rails auto-mounts it); outside Rack, call
|
|
93
|
+
# `clear_extras` when a unit of work ends. Accepts a hash and/or keywords.
|
|
94
|
+
# Works with no client configured (it only writes the buffer); never raises.
|
|
95
|
+
def self.add_extras(extras = nil, **kwargs)
|
|
96
|
+
merged = {}
|
|
97
|
+
merged.merge!(extras) if extras.is_a?(Hash)
|
|
98
|
+
merged.merge!(kwargs) unless kwargs.empty?
|
|
99
|
+
See::Context.add(merged)
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Drop the ambient extras buffer for the current request/context.
|
|
104
|
+
def self.clear_extras
|
|
105
|
+
See::Context.clear
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
79
108
|
end
|
|
80
109
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shipeasy-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shipeasy, Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|