clicksign-ruby-sdk 0.1.5 → 0.1.7

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: a45728b201a9703e1d70cb6de98056f85da9a524d9d0c122a1ed951d6f98ef5b
4
- data.tar.gz: 7a2aea99029254b4849b27090f40927d4cbf66d44cb516f121ea14c65544f141
3
+ metadata.gz: 5d76bec5fed9c775d1277ef1d0cd7158a87f7234d71fcd2fc8933a4421c8dba1
4
+ data.tar.gz: d18db7bdcf3825e7d266ff30609f9034c0a8e2fbb3d7f82352ae1e4a0c7ef0dd
5
5
  SHA512:
6
- metadata.gz: e9cb3bdaff221f8a8e58a9ef4ca47363962e19b7dcb4f22eb129cb1f5f3b60812550db76301ee8a36473be11490293932895d83c91ef60d10928206d090cd162
7
- data.tar.gz: 8c3cd41e15ba5c21136fc3ee4b53fcb96c231620735c17401acbd046a032262b31a9a1617f07ec704e9a9593dedb8023dd82019afe156cee782356c78c297199
6
+ metadata.gz: d1f36573b8720bb2d5548540cabcb1b9d995b8cc6afb877e6b02844cef69a73af2708901c2f50dd43ca540db7f098c61077bfc9647a5e880928c361707da9069
7
+ data.tar.gz: d7b63661a2702eaaecfd59d65508964110965ed32a4dd26f273199951c7353f9761a8f5269389e8aec83044c3bc54562e458fa885180817f17b0ad19fec59b67
data/README.md CHANGED
@@ -9,7 +9,7 @@ Cliente Ruby oficial para a [API v3 da Clicksign](https://developers.clicksign.c
9
9
 
10
10
  **Requisitos:** Ruby >= 3.0 · dependências de runtime: apenas biblioteca padrão (`net/http`, `json`).
11
11
 
12
- **Documentação:** [índice `docs/`](docs/) · [Workflow](docs/WORKFLOW.md) · [Cookbook](docs/cookbook/) · [Troubleshooting](docs/TROUBLESHOOTING.md) · [Arquitetura](docs/ARCHITECTURE.md) · [Observabilidade](docs/OBSERVABILITY.md) · [SPEC](docs/SPEC.md) · API: [Sandbox](https://sandbox.clicksign.com/api/v3) · [Produção](https://app.clicksign.com/api/v3)
12
+ **Documentação:** [índice `docs/`](docs/) · [Workflow](docs/WORKFLOW.md) · [Cookbook](docs/examples/) · [Troubleshooting](docs/TROUBLESHOOTING.md) · [Arquitetura](docs/ARCHITECTURE.md) · [Observabilidade](docs/OBSERVABILITY.md) · [SPEC](docs/SPEC.md) · API: [Sandbox](https://sandbox.clicksign.com/api/v3) · [Produção](https://app.clicksign.com/api/v3)
13
13
 
14
14
  ---
15
15
 
@@ -31,7 +31,7 @@ Cliente Ruby oficial para a [API v3 da Clicksign](https://developers.clicksign.c
31
31
 
32
32
  > **Exemplo passo a passo:** [`docs/WORKFLOW.md`](docs/WORKFLOW.md) — fluxo completo de envelope → documento → signatário → requisitos → ativação → notificação.
33
33
 
34
- > **Cookbook (receitas por cenário):** [`docs/cookbook/`](docs/cookbook/) — [retries](docs/cookbook/01-retries.md), [bulk requirements](docs/cookbook/02-bulk-requirements.md), [webhooks](docs/cookbook/03-webhooks.md), [vários clientes](docs/cookbook/04-multi-client.md), [list vs filter](docs/cookbook/07-list-and-filter.md), [limitações de produção](docs/cookbook/08-production-limitations.md).
34
+ > **Cookbook (receitas por cenário):** [`docs/examples/`](docs/examples/) — [retries](docs/examples/01-retries.md), [bulk requirements](docs/examples/02-bulk-requirements.md), [webhooks](docs/examples/03-webhooks.md), [vários clientes](docs/examples/04-multi-client.md), [list vs filter](docs/examples/07-list-and-filter.md), [limitações de produção](docs/examples/08-production-limitations.md).
35
35
 
36
36
  > **Troubleshooting:** [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) — sintoma → causa → correção (erros HTTP, multi-tenant, bulk parcial, webhooks).
37
37
 
@@ -507,7 +507,7 @@ Event.create(
507
507
 
508
508
  `list` **não** aceita argumentos. Para filtrar: `Envelope.filter(status: 'draft').to_a` (não `Envelope.list(status: 'draft')`).
509
509
 
510
- Guia completo: [`docs/cookbook/07-list-and-filter.md`](docs/cookbook/07-list-and-filter.md).
510
+ Guia completo: [`docs/examples/07-list-and-filter.md`](docs/examples/07-list-and-filter.md).
511
511
 
512
512
  ```ruby
513
513
  # Sem filtros — retorna Array imediatamente
@@ -720,7 +720,7 @@ Cada request abre e fecha uma conexão TCP (via `Net::HTTP.start`). Não há reu
720
720
  - **OK** para jobs sequenciais, integrações moderadas e a maioria dos apps Rails.
721
721
  - **Atenção** em Puma com muitas threads e várias chamadas Clicksign por request: overhead de handshake/TLS pode virar gargalo antes do rate limit da API.
722
722
 
723
- Mitigações: menos round-trips (`BulkRequirement`, batch na app), filas (Sidekiq), cache de leitura. Detalhes: [`docs/cookbook/08-production-limitations.md`](docs/cookbook/08-production-limitations.md).
723
+ Mitigações: menos round-trips (`BulkRequirement`, batch na app), filas (Sidekiq), cache de leitura. Detalhes: [`docs/examples/08-production-limitations.md`](docs/examples/08-production-limitations.md).
724
724
 
725
725
  ### `Thread.current` e Fibers
726
726
 
@@ -765,7 +765,7 @@ lib/clicksign/
765
765
  docs/SPEC.md # mapa completo de resources e rotas
766
766
  docs/WORKFLOW.md # fluxo notarial ponta a ponta
767
767
  docs/README.md # índice da documentação
768
- docs/cookbook/ # receitas: retries, bulk, webhooks, multi-cliente
768
+ docs/examples/ # receitas: retries, bulk, webhooks, multi-cliente
769
769
  docs/TROUBLESHOOTING.md # diagnóstico e erros comuns
770
770
  docs/ARCHITECTURE.md # diagramas e camadas
771
771
  docs/OBSERVABILITY.md # logs, métricas, OpenTelemetry
data/REVISION ADDED
@@ -0,0 +1 @@
1
+ 0.1.7
@@ -82,8 +82,9 @@ module Clicksign
82
82
  context = request_context(request, uri, attempt)
83
83
  response = http_request(request, uri)
84
84
  handle_response(response, context, start)
85
- rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNREFUSED => e
86
- handle_network_error(e, context, elapsed_ms(start))
85
+ rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout,
86
+ Errno::ECONNREFUSED => e
87
+ handle_network_error(e, context, start)
87
88
  end
88
89
 
89
90
  def http_request(request, uri)
@@ -37,7 +37,7 @@ module Clicksign
37
37
  end
38
38
 
39
39
  def build_requirement(data, envelope_id:)
40
- return nil if data.nil? || data.empty?
40
+ return nil if data.nil? || (!data['id'] && !data['type'])
41
41
 
42
42
  Resources::Notarial::Requirement.send(
43
43
  :build_instance,
@@ -64,8 +64,8 @@ module Clicksign
64
64
  end
65
65
 
66
66
  def handle_bulk_body(response, context, status, duration)
67
- parsed = parse_response_body(response) || {}
68
- return parsed if parsed.key?('atomic:results')
67
+ parsed = parse_response_body(response)
68
+ return parsed if parsed&.key?('atomic:results')
69
69
 
70
70
  begin
71
71
  ErrorHandler.call(response)
@@ -73,7 +73,7 @@ module Clicksign
73
73
  publish_http_error(context, e, status, duration)
74
74
  raise
75
75
  end
76
- parsed
76
+ parsed || {}
77
77
  end
78
78
 
79
79
  def http_post(request, uri)
@@ -4,6 +4,8 @@ module Clicksign
4
4
  module JsonApi
5
5
  module Parser
6
6
  def self.parse(raw)
7
+ return { data: [], included: [], links: nil } if raw.nil?
8
+
7
9
  raw_data = raw['data']
8
10
  data = case raw_data
9
11
  when Array then raw_data.map { |item| build(item) }
@@ -3,8 +3,8 @@
3
3
  module Clicksign
4
4
  module JsonApi
5
5
  module Serializer
6
- def self.dump(type:, attributes:, id: nil, relationships: {})
7
- data = { type: type, attributes: attributes }
6
+ def self.dump(type:, attributes: {}, id: nil, relationships: {})
7
+ data = { type: type, attributes: attributes || {} }
8
8
  data[:id] = id if id
9
9
  data[:relationships] = relationships unless relationships.empty?
10
10
  { data: data }
@@ -42,6 +42,10 @@ module Clicksign
42
42
  end
43
43
 
44
44
  def self.create(envelope_id:, &block)
45
+ if envelope_id.nil? || envelope_id.to_s.empty?
46
+ raise ArgumentError,
47
+ 'envelope_id is required'
48
+ end
45
49
  raise ArgumentError, 'block is required' unless block
46
50
 
47
51
  ops = JsonApi::Operations::BulkRequirement.new
@@ -28,7 +28,13 @@ module Clicksign
28
28
  end
29
29
 
30
30
  def base_path
31
- "/envelopes/#{@_parent_id || envelope_id}/documents"
31
+ eid = @_parent_id || envelope_id
32
+ if eid.nil?
33
+ raise Clicksign::Error,
34
+ 'envelope_id is required for Document operations'
35
+ end
36
+
37
+ "/envelopes/#{eid}/documents"
32
38
  end
33
39
 
34
40
  def envelope_id
@@ -6,6 +6,8 @@ module Clicksign
6
6
  class Event < Clicksign::Resource
7
7
  self.resource_type = 'events'
8
8
 
9
+ # Known custom event kinds. Override or append to extend without SDK update:
10
+ # Clicksign::Resources::Notarial::Event::CUSTOM_KINDS << 'new_kind'
9
11
  CUSTOM_KINDS = %w[token_email token_sms].freeze
10
12
 
11
13
  def self.create(envelope_id:, document_id:, **attributes)
@@ -43,7 +43,13 @@ module Clicksign
43
43
  private_class_method :list_related
44
44
 
45
45
  def base_path
46
- "/envelopes/#{@_parent_id || envelope_id}/requirements"
46
+ eid = @_parent_id || envelope_id
47
+ if eid.nil?
48
+ raise Clicksign::Error,
49
+ 'envelope_id is required for Requirement operations'
50
+ end
51
+
52
+ "/envelopes/#{eid}/requirements"
47
53
  end
48
54
 
49
55
  def envelope_id
@@ -22,7 +22,13 @@ module Clicksign
22
22
  end
23
23
 
24
24
  def base_path
25
- "/envelopes/#{@_parent_id || envelope_id}/signature_watchers"
25
+ eid = @_parent_id || envelope_id
26
+ if eid.nil?
27
+ raise Clicksign::Error,
28
+ 'envelope_id is required for SignatureWatcher operations'
29
+ end
30
+
31
+ "/envelopes/#{eid}/signature_watchers"
26
32
  end
27
33
 
28
34
  def update(**)
@@ -44,7 +44,13 @@ module Clicksign
44
44
  end
45
45
 
46
46
  def base_path
47
- "/envelopes/#{@_parent_id || envelope_id}/signers"
47
+ eid = @_parent_id || envelope_id
48
+ if eid.nil?
49
+ raise Clicksign::Error,
50
+ 'envelope_id is required for Signer operations'
51
+ end
52
+
53
+ "/envelopes/#{eid}/signers"
48
54
  end
49
55
 
50
56
  def envelope_id
@@ -25,18 +25,21 @@ module Clicksign
25
25
 
26
26
  # Computes the expected Content-HMAC value for a given payload and secret.
27
27
  def self.compute_signature(payload, secret:)
28
+ raise ArgumentError, 'secret must not be empty' if secret.nil? || secret.empty?
29
+
28
30
  "#{DIGEST}=#{OpenSSL::HMAC.hexdigest(DIGEST, secret, payload)}"
29
31
  end
30
32
 
31
33
  # Constant-time comparison to prevent timing attacks.
32
34
  def self.secure_compare?(expected, actual)
33
- return false if actual.nil? || actual.to_s.empty?
35
+ return false if actual.nil?
36
+
37
+ actual_str = actual.is_a?(String) ? actual : actual.to_s
38
+ return false if actual_str.empty?
34
39
 
35
- digest_a = OpenSSL::Digest::SHA256.hexdigest(expected)
36
- digest_b = OpenSSL::Digest::SHA256.hexdigest(actual.to_s)
37
- result = 0
38
- digest_a.bytes.zip(digest_b.bytes) { |x, y| result |= x ^ y }
39
- result.zero?
40
+ OpenSSL.fixed_length_secure_compare(expected, actual_str)
41
+ rescue ArgumentError
42
+ false
40
43
  end
41
44
  private_class_method :secure_compare?
42
45
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clicksign-ruby-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clicksign
@@ -17,6 +17,7 @@ extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
19
  - README.md
20
+ - REVISION
20
21
  - lib/clicksign.rb
21
22
  - lib/clicksign/client.rb
22
23
  - lib/clicksign/configuration.rb