shipeasy-sdk 3.3.0 → 3.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/docs/skill/SKILL.md +6 -1
- data/lib/shipeasy/config.rb +11 -0
- data/lib/shipeasy/sdk/rack_middleware.rb +4 -1
- data/lib/shipeasy/sdk/see.rb +104 -8
- 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: c1b1f478bea3279f979e85e04476381f719d3db27aa29ffb23447768ceefc560
|
|
4
|
+
data.tar.gz: c0d4f8f1ca49a6a1b34ac3b1198a3788dc115f640eb5845fb388a66175e1384c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 94790b0a88b1524f35faf706245339db83908565b5adec3a7f8b9f5775d476cb703ce00ac55a697d79a343a1abe0c94145c2fd693538c1aecbdab81385525148
|
|
7
|
+
data.tar.gz: f35b460dd560167674a1a278c1e76600fd59040016ad06b3129ee77c5dd95d68d57d0c7695ca06dee7f7870f15489655ee20ca644b6d1a24d416fdf280c2daf7
|
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
|
|
data/lib/shipeasy/config.rb
CHANGED
|
@@ -326,6 +326,17 @@ module Shipeasy
|
|
|
326
326
|
Shipeasy::SDK.control_flow_exception(err)
|
|
327
327
|
end
|
|
328
328
|
|
|
329
|
+
# Ambient per-request see() extras — attach context from anywhere that
|
|
330
|
+
# merges into every see() report firing later in the same request, so you
|
|
331
|
+
# never thread it into the rescue block. See Shipeasy::SDK.add_extras.
|
|
332
|
+
def add_extras(extras = nil, **kwargs)
|
|
333
|
+
Shipeasy::SDK.add_extras(extras, **kwargs)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def clear_extras
|
|
337
|
+
Shipeasy::SDK.clear_extras
|
|
338
|
+
end
|
|
339
|
+
|
|
329
340
|
# Replace the registered global engine + attributes transform (used by the
|
|
330
341
|
# configure_for_* siblings — unlike configure, they replace so a test suite
|
|
331
342
|
# can reconfigure between cases). Returns the engine.
|
|
@@ -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
|
|
|
@@ -211,27 +222,65 @@ module Shipeasy
|
|
|
211
222
|
end
|
|
212
223
|
alias causesThe causes_the
|
|
213
224
|
|
|
225
|
+
# Attach debugging metadata. Chainable — call repeatedly (keys merge,
|
|
226
|
+
# later wins) *before* `.to`. Called after `.to` it is a no-op with a
|
|
227
|
+
# warning: the report already shipped, so there is nothing to amend and,
|
|
228
|
+
# crucially, it must not raise into the caller's rescue block. Use
|
|
229
|
+
# `.to(outcome, extras)` or `Shipeasy.add_extras` for late/scattered
|
|
230
|
+
# context instead.
|
|
214
231
|
def extras(extras)
|
|
215
|
-
if
|
|
216
|
-
|
|
232
|
+
if @done
|
|
233
|
+
Shipeasy::Logging.warn(
|
|
234
|
+
"[shipeasy] see() .extras(...) called after .to(...) is ignored — " \
|
|
235
|
+
"pass extras to .to(outcome, extras) or call .extras before .to"
|
|
236
|
+
)
|
|
237
|
+
return self
|
|
217
238
|
end
|
|
239
|
+
merge_extras(extras)
|
|
218
240
|
self
|
|
219
241
|
end
|
|
220
242
|
|
|
221
243
|
# Terminal: build the event and fire-and-forget the report. Idempotent.
|
|
222
|
-
|
|
223
|
-
|
|
244
|
+
# `extras` may be passed inline here as the trailing form
|
|
245
|
+
# `.to(outcome, { order_id: oid })` — merged like a final `.extras` call.
|
|
246
|
+
# Returns self so a stray trailing `.extras` chains harmlessly.
|
|
247
|
+
def to(outcome, extras = nil)
|
|
248
|
+
return self if @done
|
|
224
249
|
|
|
250
|
+
merge_extras(extras) unless extras.nil?
|
|
225
251
|
@done = true
|
|
226
252
|
@outcome = outcome.to_s
|
|
227
253
|
begin
|
|
228
254
|
@dispatch.call(
|
|
229
|
-
Built.new(@problem, @subject || DEFAULT_SUBJECT, @outcome.empty? ? DEFAULT_OUTCOME : @outcome,
|
|
255
|
+
Built.new(@problem, @subject || DEFAULT_SUBJECT, @outcome.empty? ? DEFAULT_OUTCOME : @outcome, resolved_extras)
|
|
230
256
|
)
|
|
231
257
|
rescue StandardError
|
|
232
258
|
# Reporting must never raise into caller code.
|
|
233
259
|
nil
|
|
234
260
|
end
|
|
261
|
+
self
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
private
|
|
265
|
+
|
|
266
|
+
def merge_extras(extras)
|
|
267
|
+
return unless extras.is_a?(Hash) && !extras.empty?
|
|
268
|
+
|
|
269
|
+
@extras = (@extras || {}).merge(extras)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# The chain's own extras merged OVER the ambient per-request buffer, so a
|
|
273
|
+
# chained key of the same name wins over an ambient one. Keys normalized
|
|
274
|
+
# to strings only when a merge actually happens; sanitize_extras
|
|
275
|
+
# stringifies the rest at build time.
|
|
276
|
+
def resolved_extras
|
|
277
|
+
ambient = Context.current
|
|
278
|
+
return @extras if ambient.empty?
|
|
279
|
+
return ambient if @extras.nil? || @extras.empty?
|
|
280
|
+
|
|
281
|
+
out = ambient.dup
|
|
282
|
+
@extras.each { |k, v| out[k.to_s] = v }
|
|
283
|
+
out
|
|
235
284
|
end
|
|
236
285
|
end
|
|
237
286
|
|
|
@@ -265,6 +314,8 @@ module Shipeasy
|
|
|
265
314
|
end
|
|
266
315
|
|
|
267
316
|
# A no-op chain returned by the module-level see() when no client exists.
|
|
317
|
+
# Every method returns self so the full grammar — including a trailing
|
|
318
|
+
# `.extras` after `.to` — chains without ever raising.
|
|
268
319
|
class NullChain
|
|
269
320
|
def causes_the(_subject)
|
|
270
321
|
self
|
|
@@ -275,9 +326,54 @@ module Shipeasy
|
|
|
275
326
|
self
|
|
276
327
|
end
|
|
277
328
|
|
|
278
|
-
def to(_outcome)
|
|
329
|
+
def to(_outcome, _extras = nil)
|
|
330
|
+
self
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# ---- Ambient per-request extras -------------------------------------
|
|
335
|
+
|
|
336
|
+
# A per-request buffer of extras that merge into EVERY see() report firing
|
|
337
|
+
# later in the same execution context. Lets a request attach context
|
|
338
|
+
# (order id, route, tenant) from anywhere without threading it into the
|
|
339
|
+
# rescue block: `Shipeasy.add_extras(order_id: oid)` here, and any
|
|
340
|
+
# subsequent `see()` in this request carries it.
|
|
341
|
+
#
|
|
342
|
+
# Fiber-local (like AnonId), so concurrent requests never bleed into each
|
|
343
|
+
# other. The Rack middleware clears it in an `ensure` at the end of each
|
|
344
|
+
# request; outside a Rack request (jobs, scripts) call
|
|
345
|
+
# `Shipeasy.clear_extras` yourself when a logical unit of work ends.
|
|
346
|
+
#
|
|
347
|
+
# Values are stored raw and sanitized (scalar-only, truncated, 20-key cap,
|
|
348
|
+
# private-attribute stripped) at build time, exactly like chained extras.
|
|
349
|
+
module Context
|
|
350
|
+
THREAD_KEY = :shipeasy_see_ambient_extras
|
|
351
|
+
|
|
352
|
+
module_function
|
|
353
|
+
|
|
354
|
+
# Merge fields into the current context's buffer (string keys, later
|
|
355
|
+
# wins). Non-hash / empty input is ignored. Never raises.
|
|
356
|
+
def add(extras)
|
|
357
|
+
return unless extras.is_a?(Hash) && !extras.empty?
|
|
358
|
+
|
|
359
|
+
buf = (Thread.current[THREAD_KEY] ||= {})
|
|
360
|
+
extras.each { |k, v| buf[k.to_s] = v }
|
|
361
|
+
nil
|
|
362
|
+
rescue StandardError
|
|
279
363
|
nil
|
|
280
364
|
end
|
|
365
|
+
|
|
366
|
+
# A copy of the current context's buffer, or {} when empty.
|
|
367
|
+
def current
|
|
368
|
+
buf = Thread.current[THREAD_KEY]
|
|
369
|
+
buf.nil? || buf.empty? ? {} : buf.dup
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# Drop the current context's buffer so extras never leak to the next
|
|
373
|
+
# request handled by this thread/fiber.
|
|
374
|
+
def clear
|
|
375
|
+
Thread.current[THREAD_KEY] = nil
|
|
376
|
+
end
|
|
281
377
|
end
|
|
282
378
|
end
|
|
283
379
|
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.4.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-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|