operto 0.3.0 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31bc34a291dadd87aded5937654fc9824be5cc365e94010724ef763b75169b49
4
- data.tar.gz: 46b42729bb8e8590b02452b56c83fe4387638e5db2bee5b290f6f98040196d63
3
+ metadata.gz: 560a7613ec23670aa8c3e8f14eae1047aa3aa56b11e918b436aea5a0650fea19
4
+ data.tar.gz: ade003d02974835e84663c7d9bdb745bb420d6d076daed0452cab20f8a55f35d
5
5
  SHA512:
6
- metadata.gz: 0cc0aa3b12cb92f0d521dfa5f46e6a834a69ddb047a881f9eb125a12a829bc5ff4ca2b9210a8c18b48f9df761abc81ad7374133fd2bac236dac55d6199cae374
7
- data.tar.gz: 8579d576182fc7598faf1bc8a4fa5e7e166a995def47059412a00a74ab23f5854225ea702468611f4116a76a29db45ab6469a73182437b1e02b5222c449a27fb
6
+ metadata.gz: 898ef137d8c04c1aa72ee37783c1b731cd4789bbe297355c5605fad46551f1bdd9f5af45140778e3c02d561801590e23263d7ad90f6ae2769c18b8039059d06d
7
+ data.tar.gz: 98691df6518db77646c2e26d9310746bf0c71c686714b615cc6d224f780ba8fa50ea61491d97daae8dbe463d6e4f6744110cc3e81046e43abb4681baa82c8a94
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0 - 2026-10-12
4
+
5
+ - When Operto rejects the access token (a `401` or an `auth_token_expired` response), the client clears the token store, renews the token and replays the request once.
6
+ - A host token store's `clear` must retire the token so the next `active` returns `nil`.
7
+ - Retry only idempotent requests, and only on `502`, `503` and `504`. `POST` and `PATCH` requests and `429` responses are no longer retried.
8
+ - `Homes::Index` and `Staff::Index` keep an unparseable create date as the raw value instead of failing with `Date::Error`.
9
+
3
10
  ## 0.3.0 - 2026-09-27
4
11
 
5
12
  - `Tasks::Index` returns the whole task: rule, booking, name, description, start and due times, and the active and completion flags.
data/README.md CHANGED
@@ -9,7 +9,7 @@ framework dependency.
9
9
 
10
10
  ```ruby
11
11
  # Gemfile
12
- gem 'operto', '~> 0.3.0'
12
+ gem 'operto', '~> 0.4.0'
13
13
  ```
14
14
 
15
15
  ```sh
@@ -43,7 +43,7 @@ login/refresh and delegates persistence to it via four methods:
43
43
  | `active` | the current non-expired token, or `nil` |
44
44
  | `refreshable` | a token whose refresh token is still valid, or `nil` |
45
45
  | `save(access_token:, expires_at:, refresh_token: nil, refresh_expires_at: nil)` | persist and return the token |
46
- | `clear` | drop the cached token (called after a `401`) |
46
+ | `clear` | retire the token so the next `active` returns `nil` (called when Operto rejects it, before the renewal) |
47
47
 
48
48
  A token responds to `access_token`, `refresh_token`, `refresh_expires_at`, and
49
49
  `expired?`.
@@ -0,0 +1,30 @@
1
+ module Operto
2
+ # Faraday middleware that signs each request with the stored access token.
3
+ # When Operto rejects the token (a 401 or an auth_token_expired envelope), it
4
+ # clears the store, renews the token and replays the request once.
5
+ class Authorization < Faraday::Middleware
6
+ HEADER = 'Authorization'.freeze
7
+ EXPIRED_REASON = 'auth_token_expired'.freeze
8
+
9
+ def call(env)
10
+ request_body = env.body
11
+ response = @app.call(sign(env))
12
+ return response unless rejected?(response)
13
+
14
+ Operto.config.token_store.clear
15
+ env.body = request_body
16
+ @app.call(sign(env))
17
+ end
18
+
19
+ private
20
+
21
+ def sign(env)
22
+ env.request_headers[HEADER] = "VRS #{Operto::Client.auth_token}"
23
+ env
24
+ end
25
+
26
+ def rejected?(response)
27
+ response.status == 401 || Operto::Client.response_body(response)[:ReasonText].to_s.include?(EXPIRED_REASON)
28
+ end
29
+ end
30
+ end
data/lib/operto/client.rb CHANGED
@@ -10,15 +10,14 @@ module Operto
10
10
  interval: 1.0,
11
11
  interval_randomness: 0.5,
12
12
  backoff_factor: 2,
13
- retry_statuses: [401, 429, 502, 503, 504],
13
+ retry_statuses: [502, 503, 504],
14
14
  exceptions: [*Faraday::Retry::Middleware::DEFAULT_EXCEPTIONS, Faraday::ConnectionFailed],
15
- methods: [*Faraday::Retry::Middleware::IDEMPOTENT_METHODS, :patch, :post],
16
- retry_block: ->(env:, **) { Operto.config.token_store.clear if env.status == 401 }
15
+ methods: Faraday::Retry::Middleware::IDEMPOTENT_METHODS
17
16
  }.freeze
18
17
 
19
18
  def connection(url: Operto.config.base_url, skip_auth: false)
20
19
  Faraday.new(url:) do |builder|
21
- builder.request :authorization, 'VRS', -> { auth_token } unless skip_auth
20
+ builder.use Operto::Authorization unless skip_auth
22
21
 
23
22
  builder.request :json
24
23
  builder.request :retry, RETRY_OPTIONS
@@ -1,3 +1,3 @@
1
1
  module Operto
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
data/lib/operto.rb CHANGED
@@ -10,6 +10,7 @@ require_relative 'operto/error'
10
10
  require_relative 'operto/memory_token_store'
11
11
  require_relative 'operto/config'
12
12
  require_relative 'operto/operation'
13
+ require_relative 'operto/authorization'
13
14
  require_relative 'operto/client'
14
15
  require_relative 'operto/issue_types'
15
16
  require_relative 'operto/filtered_pagination'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: operto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guestit
@@ -90,6 +90,7 @@ files:
90
90
  - README.md
91
91
  - lib/operto.rb
92
92
  - lib/operto/access_tokens/upsert.rb
93
+ - lib/operto/authorization.rb
93
94
  - lib/operto/client.rb
94
95
  - lib/operto/config.rb
95
96
  - lib/operto/error.rb
@@ -133,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
134
  - !ruby/object:Gem::Version
134
135
  version: '0'
135
136
  requirements: []
136
- rubygems_version: 4.0.20
137
+ rubygems_version: 4.0.21
137
138
  specification_version: 4
138
139
  summary: Client for the Operto Teams API
139
140
  test_files: []