atlas_rb 1.8.0 → 1.8.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 (5) hide show
  1. checksums.yaml +4 -4
  2. data/.version +1 -1
  3. data/Gemfile.lock +1 -1
  4. data/lib/atlas_rb/blob.rb +68 -14
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3d2bc949790f66ee7081de2e94d427f69869fcb301c45d4b9399c072f466820
4
- data.tar.gz: 466abe63f27507e1845bc1126b739d2bfa396f7c79c447b1bf57e5be42352f4c
3
+ metadata.gz: 0a0fac04427bc3f23f92da8a5241a263111f45b28fa01cc8829da0de3b6b48f9
4
+ data.tar.gz: 8e95150d0f2ecd0a33c52179e384f8462546b422dcd6997c69886163215811c8
5
5
  SHA512:
6
- metadata.gz: 87494a7060c9b9f192edb404ecffd98ea5b8f4859f4b507e25e7a8d66717d34af7c240f3d99df13163f5e822163d5d3f146df4e9898937a5cb0687b80d12cae1
7
- data.tar.gz: 04b3221d9ae88ff6bd1b4586321dbd4eda20a4f6753cedfbf465ad4ad2d27214f5252a6e7dd4259e10a24b813eda4a966a7a39fd243244ad295b9c9a749cd5a6
6
+ metadata.gz: 4ced2b3f0f3fee473712f38ae3161ea8f678d9468abaf1250c9577e13261b5688be16ea687a69f6b28931a6e8920ad737d7a2057059c14751cceb683e463c2ef
7
+ data.tar.gz: 017e1004f59a5529184e3f07f93c815a463da07937863ff72b2063b3e1986f624e5e8ea83c0b5750b57885e7942ef981b32e66f7d3e5931ea6545108c643162d
data/.version CHANGED
@@ -1 +1 @@
1
- 1.8.0
1
+ 1.8.2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- atlas_rb (1.8.0)
4
+ atlas_rb (1.8.2)
5
5
  faraday (~> 2.7)
6
6
  faraday-follow_redirects (~> 0.3.0)
7
7
  faraday-multipart (~> 1)
data/lib/atlas_rb/blob.rb CHANGED
@@ -39,14 +39,65 @@ module AtlasRb
39
39
  ))['blob']
40
40
  end
41
41
 
42
+ # Resolve a content Blob to its parent FileSet and containing Work noids.
43
+ #
44
+ # Wraps `GET /files/<id>/ancestry`. The download path is keyed only by the
45
+ # blob id, so a consumer recording a download/stream impression against the
46
+ # containing Work resolves it here — instead of threading the work noid
47
+ # through the download URL. Reads on the Blob floor (no admin gate). An
48
+ # unknown id yields a `404` (raw Faraday response); either value is `nil`
49
+ # when unresolvable (e.g. an orphan blob with no FileSet parent).
50
+ #
51
+ # @param id [String] the Blob ID.
52
+ # @param nuid [String, nil] optional acting user's NUID. On the relay-signing
53
+ # path it is signed into the assertion `sub`; on the BYO-JWT (`ATLAS_JWT`)
54
+ # path it is ignored (identity lives in the token).
55
+ # @param on_behalf_of [String, nil] optional NUID for the `On-Behalf-Of`
56
+ # header. Falls through to {AtlasRb.config}.default_on_behalf_of when
57
+ # omitted.
58
+ # @return [AtlasRb::Mash] `{ "file_set" => "<noid>", "work" => "<noid>" }`
59
+ # (either value `nil` when unresolvable).
60
+ #
61
+ # @example
62
+ # AtlasRb::Blob.ancestry("b-321")
63
+ # # => { "file_set" => "fs-654", "work" => "w-789" }
64
+ def self.ancestry(id, nuid: nil, on_behalf_of: nil)
65
+ AtlasRb::Mash.new(JSON.parse(
66
+ connection({}, nuid, on_behalf_of: on_behalf_of).get("#{ROUTE}#{id}/ancestry")&.body
67
+ ))
68
+ end
69
+
70
+ # Convenience over {.ancestry}: the containing Work's noid for a content
71
+ # Blob (or `nil` when unresolvable). The shape Cerberus's impression-capture
72
+ # job wants — roll a download up to its Work from the blob id alone.
73
+ #
74
+ # @param id [String] the Blob ID.
75
+ # @param nuid [String, nil] optional acting user's NUID (see {.ancestry}).
76
+ # @param on_behalf_of [String, nil] optional `On-Behalf-Of` NUID (see {.ancestry}).
77
+ # @return [String, nil] the containing Work's noid, or `nil` when unresolvable.
78
+ #
79
+ # @example
80
+ # AtlasRb::Blob.work("b-321") # => "w-789"
81
+ def self.work(id, nuid: nil, on_behalf_of: nil)
82
+ ancestry(id, nuid: nuid, on_behalf_of: on_behalf_of)['work']
83
+ end
84
+
42
85
  # Stream the Blob's binary content through a caller-supplied block.
43
86
  #
44
87
  # The body is **not** buffered — each chunk Faraday receives is yielded
45
88
  # to `chunk_handler` immediately, making this safe for files larger than
46
- # available memory. The first chunk's response headers are captured and
47
- # returned so callers can inspect `Content-Type`, `Content-Length`, etc.
89
+ # available memory.
90
+ #
91
+ # Pass `range:` (e.g. `"bytes=0-1048575"`) to forward an HTTP `Range`
92
+ # header; Atlas answers `206 Partial Content` and the chunks yielded are
93
+ # just the requested slice. The returned hash exposes both the response
94
+ # **status** (200 vs 206) and the response **headers** — so a caller
95
+ # proxying to a browser media element can relay `Content-Range`,
96
+ # `Content-Length` and `Accept-Ranges` verbatim and reproduce the 206.
48
97
  #
49
98
  # @param id [String] the Blob ID.
99
+ # @param range [String, nil] optional HTTP byte range (`"bytes=START-END"`,
100
+ # `"bytes=START-"`, or `"bytes=-SUFFIX"`). Omitted ⇒ whole-body `200`.
50
101
  # @param nuid [String, nil] optional acting user's NUID. On the relay-signing
51
102
  # path it is signed into the assertion `sub`; on the BYO-JWT (`ATLAS_JWT`)
52
103
  # path it is ignored (identity lives in the token).
@@ -54,22 +105,25 @@ module AtlasRb
54
105
  # header. Falls through to {AtlasRb.config}.default_on_behalf_of when
55
106
  # omitted.
56
107
  # @yieldparam chunk [String] the next chunk of binary data.
57
- # @return [Hash] the response headers from `GET /files/<id>/content`.
108
+ # @return [Hash] `{ status: Integer, headers: Faraday::Utils::Headers }` for
109
+ # `GET /files/<id>/content` (`headers` is case-insensitive, hash-like).
58
110
  #
59
- # @example Stream to disk
111
+ # @example Stream the whole body to disk
60
112
  # File.open("/tmp/out.pdf", "wb") do |f|
61
- # headers = AtlasRb::Blob.content("b-321") { |chunk| f.write(chunk) }
62
- # puts headers["content-type"]
113
+ # res = AtlasRb::Blob.content("b-321") { |chunk| f.write(chunk) }
114
+ # puts res[:headers]["content-type"]
63
115
  # end
64
- def self.content(id, nuid: nil, on_behalf_of: nil, &chunk_handler)
65
- headers = {}
66
- connection({}, nuid, on_behalf_of: on_behalf_of).get("#{ROUTE}#{id}/content") do |req|
67
- req.options.on_data = proc do |chunk, _bytes_received, env|
68
- headers = env.response_headers if headers.empty? && env
69
- chunk_handler.call(chunk)
70
- end
116
+ #
117
+ # @example Relay a browser's Range request as a 206
118
+ # res = AtlasRb::Blob.content("b-321", range: "bytes=0-1048575") { |c| out << c }
119
+ # res[:status] # => 206
120
+ # res[:headers]["content-range"] # => "bytes 0-1048575/52428800"
121
+ def self.content(id, range: nil, nuid: nil, on_behalf_of: nil, &chunk_handler)
122
+ response = connection({}, nuid, on_behalf_of: on_behalf_of).get("#{ROUTE}#{id}/content") do |req|
123
+ req.headers["Range"] = range if range
124
+ req.options.on_data = proc { |chunk, _bytes_received, _env| chunk_handler.call(chunk) }
71
125
  end
72
- headers
126
+ { status: response.status, headers: response.headers }
73
127
  end
74
128
 
75
129
  # Upload a new Blob attached to a Work.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atlas_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cliff
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-24 00:00:00.000000000 Z
11
+ date: 2026-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday