jbr 3.2.0 → 3.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1028c7784920b94426d3c9d52a29232cdb4b8426baf5abe11cbcfe64d9f854f
4
- data.tar.gz: d27d31e838ea1fd1c2c3035abf3e21635955039febc8a481bb514a8bd8e9fb9d
3
+ metadata.gz: 074fba6db0300fd967935b1996f1791016e216aa49ef829e771f56340400af1f
4
+ data.tar.gz: c8433c006174ab91d76db6a331268c325a90ff4f049f179c5adf46acd9716487
5
5
  SHA512:
6
- metadata.gz: 74d582435245e0aebf5975748e2ba86e5e53f1190a4f4007d1b50e514df47816082f82a8cdf41b8bd9529e63fe25219035005335ed56708b857ba6aabfdbcb4e
7
- data.tar.gz: 6977198a4d12a410b0c2b8ef2aa0cda829a43ec5fda670ce7d9dbcd13301ac2ef3da55b605d4a6ab7e3017839a115c9f757a6a4ae6d86522f4fa584151cb4f12
6
+ metadata.gz: 1d3e116c317b973a9600af44e3fd02466e360321f08b4e1c696c2e214854b91b8318c45a8ffdb7c50f6f880bf07e6388bf060d33f54ad58b60b2ead27aab535d
7
+ data.tar.gz: 28ee328df69a90a166cfaa4ed6ee0b22fad572c7bca8defb501afba0b3054c652b17741df883f4be32b0bd33ca7253a4a7e5872564b2f636f02d459323a7693c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [3.3.0] - 2026-08-13
2
+
3
+ - [Fix] Credentials are given up only when Jobber says the grant itself is no good. Any
4
+ refusal at all used to set `invalid_at` -- a 500, a rate limit, an unreadable body -- so
5
+ a moment of trouble at Jobber's end read as a dead token, and an app acting on that could
6
+ revoke one that still worked. Only an `invalid_grant` Jobber names counts now; everything
7
+ else raises `Jbr::Error` for the caller to retry, which is what trouble deserves
8
+ - [New] `Jbr::Refused`, a `Jbr::Error` for the grant being no good rather than for the
9
+ answer failing to arrive. Rescue it to tell the two apart
10
+ - [Change] The token endpoint moved to `Jbr::Token`. `Jbr::OAuth.post` still answers it
11
+ unchanged, and so do `Jbr::OAuth.client_id` and `Jbr::OAuth.client_secret`
12
+
1
13
  ## [3.2.0] - 2026-08-13
2
14
 
3
15
  - [New] Wait rather than be refused. Jobber holds an app to two limits at once -- 2,500
data/README.md CHANGED
@@ -41,6 +41,16 @@ Revoke credentials:
41
41
  oauth.delete
42
42
  ```
43
43
 
44
+ Credentials go bad only when Jobber says so. A refused refresh — the `invalid_grant` Jobber
45
+ names — sets `invalid_at` and answers queries with nothing. Anything else that goes wrong,
46
+ including a 500 or a rate limit, raises `Jbr::Error` instead, because a token that may still
47
+ work is worth more than a tidy failure:
48
+
49
+ ```ruby
50
+ oauth.invalid_at # => 2026-08-13 11:02:41, or nil while the credentials are good
51
+ oauth.query '{ ok }' # => {} once they are refused, raises Jbr::Error where Jobber had trouble
52
+ ```
53
+
44
54
  ### Requests
45
55
 
46
56
  Create a Jobber request, finding or creating a Client with a matching phone number:
data/lib/jbr/oauth.rb CHANGED
@@ -66,14 +66,7 @@ module Jbr
66
66
 
67
67
  # Exchange a code or a refresh token for credentials.
68
68
  def self.post(params = {})
69
- uri = URI 'https://api.getjobber.com/api/oauth/token'
70
- response = Net::HTTP.post_form uri,
71
- params.merge(client_id: client_id, client_secret: client_secret)
72
- raise Error, response.body unless response.is_a? Net::HTTPSuccess
73
- output = JSON.parse(response.body)
74
- { access_token: output['access_token'], refresh_token: output['refresh_token'],
75
- expires_at: (Time.now + output.fetch('expires_in', 3600).to_i),
76
- }
69
+ Token.post params.merge(client_id: client_id, client_secret: client_secret)
77
70
  end
78
71
 
79
72
  private
@@ -85,7 +78,7 @@ module Jbr
85
78
  @access_token = output[:access_token]
86
79
  @refresh_token = output[:refresh_token]
87
80
  @expires_at = output[:expires_at]
88
- rescue Error => e
81
+ rescue Refused
89
82
  @invalid_at = Time.now
90
83
  false
91
84
  end
@@ -0,0 +1,5 @@
1
+ module Jbr
2
+ # Jobber refusing the grant itself, rather than failing to answer about it. The first is a
3
+ # token that will never work again; the second may be a moment of trouble at their end.
4
+ Refused = Class.new Error
5
+ end
data/lib/jbr/token.rb ADDED
@@ -0,0 +1,35 @@
1
+ module Jbr
2
+ # The endpoint that trades an authorization code or a refresh token for credentials.
3
+ class Token
4
+ # Where a grant is exchanged.
5
+ URL = 'https://api.getjobber.com/api/oauth/token'
6
+
7
+ # What Jobber calls a grant that is no good, in the OAuth 2 word for it.
8
+ REFUSAL = 'invalid_grant'
9
+
10
+ # Trade a grant for credentials.
11
+ # @param params [Hash] the grant, and the app making the exchange.
12
+ # @raise [Refused] where Jobber says the grant itself is no good.
13
+ # @raise [Error] where Jobber could not answer about it.
14
+ # @return [Hash] the tokens, and the moment the access one expires.
15
+ def self.post(params = {})
16
+ response = Net::HTTP.post_form URI(URL), params
17
+ raise Refused, response.body if refused? response
18
+ raise Error, response.body unless response.is_a? Net::HTTPSuccess
19
+
20
+ output = JSON.parse response.body
21
+ { access_token: output['access_token'], refresh_token: output['refresh_token'],
22
+ expires_at: (Time.now + output.fetch('expires_in', 3600).to_i),
23
+ }
24
+ end
25
+
26
+ def self.refused?(response)
27
+ return false if response.is_a? Net::HTTPSuccess
28
+
29
+ JSON.parse(response.body)['error'] == REFUSAL
30
+ rescue JSON::ParserError
31
+ false
32
+ end
33
+ private_class_method :refused?
34
+ end
35
+ end
data/lib/jbr/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # A Ruby client for the Jobber API.
2
2
  module Jbr
3
3
  # The version of this gem.
4
- VERSION = '3.2.0'
4
+ VERSION = '3.3.0'
5
5
  end
data/lib/jbr.rb CHANGED
@@ -15,6 +15,8 @@ require 'jbr/mock'
15
15
 
16
16
  require 'jbr/url'
17
17
  require 'jbr/error'
18
+ require 'jbr/refused'
19
+ require 'jbr/token'
18
20
  # Phone before Cliental, and Cliental before the records that include it: what each asks
19
21
  # Jobber for about a client is built as they load.
20
22
  require 'jbr/phone'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jbr
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo
@@ -137,9 +137,11 @@ files:
137
137
  - lib/jbr/properted.rb
138
138
  - lib/jbr/property.rb
139
139
  - lib/jbr/quote.rb
140
+ - lib/jbr/refused.rb
140
141
  - lib/jbr/request.rb
141
142
  - lib/jbr/resource.rb
142
143
  - lib/jbr/throttle.rb
144
+ - lib/jbr/token.rb
143
145
  - lib/jbr/url.rb
144
146
  - lib/jbr/version.rb
145
147
  - lib/jbr/visit.rb