lightrate-client 1.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c63b6519eeb427af97e5de527bc710be417a302dedde208d0915b259c9ef1ed7
4
+ data.tar.gz: 62a4447c9e7f57358552a447aa06553a51a40a116c09d376e9a3e6d4c18ddcfe
5
+ SHA512:
6
+ metadata.gz: 47024b5debeb8cbfef45d0cbdb7263bd43a7d4959acf37bf506541a12af07149dc27869775e73468793baddb0dc60d73ffa50fc4868f14fc99098b949ef42189
7
+ data.tar.gz: d89180c3cb9399316b73903ec63078d9bd02a522a157781916f09c154658a82024ef87064752996a77144f7ac370e97176975bf409817c7960a5820e918a003f
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,32 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.7
4
+ Exclude:
5
+ - 'spec/fixtures/**/*'
6
+ - 'vendor/**/*'
7
+
8
+ Layout/LineLength:
9
+ Max: 120
10
+
11
+ Style/Documentation:
12
+ Enabled: false
13
+
14
+ Style/FrozenStringLiteralComment:
15
+ Enabled: true
16
+
17
+ Style/StringLiterals:
18
+ EnforcedStyle: single_quotes
19
+
20
+ Style/ClassAndModuleChildren:
21
+ Enabled: false
22
+
23
+ Metrics/BlockLength:
24
+ Exclude:
25
+ - 'spec/**/*'
26
+ - 'Rakefile'
27
+
28
+ Metrics/MethodLength:
29
+ Max: 20
30
+
31
+ Metrics/AbcSize:
32
+ Max: 20
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in lightrate-client.gemspec
6
+ gemspec
7
+
8
+ group :development, :test do
9
+ gem "pry", "~> 0.14"
10
+ gem "pry-byebug", "~> 3.10"
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,133 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lightrate-client (1.0.0)
5
+ faraday (~> 2.0)
6
+ faraday-retry (~> 2.0)
7
+ json (~> 2.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.8.7)
13
+ public_suffix (>= 2.0.2, < 7.0)
14
+ ast (2.4.3)
15
+ base64 (0.3.0)
16
+ bigdecimal (3.2.3)
17
+ byebug (12.0.0)
18
+ coderay (1.1.3)
19
+ crack (1.0.0)
20
+ bigdecimal
21
+ rexml
22
+ diff-lcs (1.6.2)
23
+ docile (1.4.1)
24
+ faraday (2.13.4)
25
+ faraday-net_http (>= 2.0, < 3.5)
26
+ json
27
+ logger
28
+ faraday-net_http (3.4.1)
29
+ net-http (>= 0.5.0)
30
+ faraday-retry (2.3.2)
31
+ faraday (~> 2.0)
32
+ hashdiff (1.2.1)
33
+ json (2.15.0)
34
+ language_server-protocol (3.17.0.5)
35
+ lint_roller (1.1.0)
36
+ logger (1.7.0)
37
+ method_source (1.1.0)
38
+ net-http (0.6.0)
39
+ uri
40
+ parallel (1.27.0)
41
+ parser (3.3.9.0)
42
+ ast (~> 2.4.1)
43
+ racc
44
+ prism (1.5.1)
45
+ pry (0.15.2)
46
+ coderay (~> 1.1)
47
+ method_source (~> 1.0)
48
+ pry-byebug (3.11.0)
49
+ byebug (~> 12.0)
50
+ pry (>= 0.13, < 0.16)
51
+ public_suffix (6.0.2)
52
+ racc (1.8.1)
53
+ rainbow (3.1.1)
54
+ rake (13.3.0)
55
+ regexp_parser (2.11.3)
56
+ rexml (3.4.4)
57
+ rspec (3.13.1)
58
+ rspec-core (~> 3.13.0)
59
+ rspec-expectations (~> 3.13.0)
60
+ rspec-mocks (~> 3.13.0)
61
+ rspec-core (3.13.5)
62
+ rspec-support (~> 3.13.0)
63
+ rspec-expectations (3.13.5)
64
+ diff-lcs (>= 1.2.0, < 2.0)
65
+ rspec-support (~> 3.13.0)
66
+ rspec-mocks (3.13.5)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.13.0)
69
+ rspec-support (3.13.6)
70
+ rubocop (1.81.1)
71
+ json (~> 2.3)
72
+ language_server-protocol (~> 3.17.0.2)
73
+ lint_roller (~> 1.1.0)
74
+ parallel (~> 1.10)
75
+ parser (>= 3.3.0.2)
76
+ rainbow (>= 2.2.2, < 4.0)
77
+ regexp_parser (>= 2.9.3, < 3.0)
78
+ rubocop-ast (>= 1.47.1, < 2.0)
79
+ ruby-progressbar (~> 1.7)
80
+ unicode-display_width (>= 2.4.0, < 4.0)
81
+ rubocop-ast (1.47.1)
82
+ parser (>= 3.3.7.2)
83
+ prism (~> 1.4)
84
+ rubocop-capybara (2.22.1)
85
+ lint_roller (~> 1.1)
86
+ rubocop (~> 1.72, >= 1.72.1)
87
+ rubocop-factory_bot (2.27.1)
88
+ lint_roller (~> 1.1)
89
+ rubocop (~> 1.72, >= 1.72.1)
90
+ rubocop-rspec (2.31.0)
91
+ rubocop (~> 1.40)
92
+ rubocop-capybara (~> 2.17)
93
+ rubocop-factory_bot (~> 2.22)
94
+ rubocop-rspec_rails (~> 2.28)
95
+ rubocop-rspec_rails (2.29.1)
96
+ rubocop (~> 1.61)
97
+ ruby-progressbar (1.13.0)
98
+ simplecov (0.22.0)
99
+ docile (~> 1.1)
100
+ simplecov-html (~> 0.11)
101
+ simplecov_json_formatter (~> 0.1)
102
+ simplecov-html (0.13.2)
103
+ simplecov_json_formatter (0.1.4)
104
+ unicode-display_width (3.2.0)
105
+ unicode-emoji (~> 4.1)
106
+ unicode-emoji (4.1.0)
107
+ uri (1.0.3)
108
+ vcr (6.3.1)
109
+ base64
110
+ webmock (3.25.1)
111
+ addressable (>= 2.8.0)
112
+ crack (>= 0.3.2)
113
+ hashdiff (>= 0.4.0, < 2.0.0)
114
+
115
+ PLATFORMS
116
+ ruby
117
+ x86_64-darwin-22
118
+
119
+ DEPENDENCIES
120
+ bundler (~> 2.0)
121
+ lightrate-client!
122
+ pry (~> 0.14)
123
+ pry-byebug (~> 3.10)
124
+ rake (~> 13.0)
125
+ rspec (~> 3.0)
126
+ rubocop (~> 1.0)
127
+ rubocop-rspec (~> 2.0)
128
+ simplecov (~> 0.21)
129
+ vcr (~> 6.0)
130
+ webmock (~> 3.0)
131
+
132
+ BUNDLED WITH
133
+ 2.5.21
data/README.md ADDED
@@ -0,0 +1,289 @@
1
+ # Lightrate Client Ruby
2
+
3
+ A Ruby gem for interacting with the Lightrate token management API, providing easy-to-use methods for consuming tokens.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'lightrate-client'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ $ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ $ gem install lightrate-client
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Configuration
28
+
29
+ Configure the client with your API credentials:
30
+
31
+ ```ruby
32
+ require 'lightrate_client'
33
+
34
+ LightrateClient.configure do |config|
35
+ config.api_key = 'your_api_key'
36
+ config.application_id = 'your_application_id' # required
37
+ config.timeout = 30 # optional, defaults to 30 seconds
38
+ config.retry_attempts = 3 # optional, defaults to 3
39
+ config.logger = Logger.new(STDOUT) # optional, for request logging
40
+ end
41
+ ```
42
+
43
+ ### Basic Usage
44
+
45
+ ```ruby
46
+ # Simple usage - pass your API key and application ID
47
+ client = LightrateClient::Client.new('your_api_key', 'your_application_id')
48
+
49
+ # Or use the convenience method
50
+ client = LightrateClient.new_client('your_api_key', 'your_application_id')
51
+
52
+ # With additional options
53
+ client = LightrateClient::Client.new('your_api_key', 'your_application_id',
54
+ timeout: 60
55
+ )
56
+
57
+ # Or configure globally and use the default client
58
+ LightrateClient.configure do |config|
59
+ config.api_key = 'your_api_key'
60
+ config.application_id = 'your_application_id'
61
+ end
62
+ client = LightrateClient.client
63
+ ```
64
+
65
+ ### Token Consumption Methods
66
+
67
+ The Lightrate Client provides two methods for consuming tokens, each with different performance characteristics:
68
+
69
+ #### 🚀 Recommended: Local Token Buckets (`consume_local_bucket_token`)
70
+
71
+ **Use this method for high-frequency token consumption.** It maintains local token buckets that are refilled in batches from the API, dramatically reducing the number of HTTP requests.
72
+
73
+ ```ruby
74
+ # Configure client with default bucket size
75
+ client = LightrateClient::Client.new(
76
+ 'your_api_key',
77
+ 'your_application_id',
78
+ default_local_bucket_size: 20 # Default bucket size for all operations
79
+ )
80
+
81
+ # Consume tokens using local buckets (fast, reduces API calls)
82
+ response = client.consume_local_bucket_token(
83
+ operation: 'send_email',
84
+ user_identifier: 'user123'
85
+ )
86
+
87
+ puts "Success: #{response.success}"
88
+ puts "Used local token: #{response.used_local_token}"
89
+ puts "Bucket status: #{response.bucket_status}"
90
+
91
+ # Or consume by path
92
+ response = client.consume_local_bucket_token(
93
+ path: '/api/v1/emails/send',
94
+ http_method: 'POST',
95
+ user_identifier: 'user123'
96
+ )
97
+ ```
98
+
99
+ **Benefits of Local Buckets:**
100
+ - ⚡ **Fast**: Most token consumption happens locally without HTTP requests
101
+ - 🔄 **Efficient**: Batches token requests to reduce API calls by 95%+
102
+ - 🛡️ **Resilient**: Continues working even with temporary API outages
103
+ - 🎯 **Configurable**: Customizable bucket sizes for your application needs
104
+
105
+ #### 🌐 Direct API Calls (`consume_tokens`)
106
+
107
+ **Use this method for occasional token consumption or when you need immediate API feedback.**
108
+
109
+ ```ruby
110
+ # Direct API call - makes HTTP request every time
111
+ response = client.consume_tokens(
112
+ operation: 'send_email',
113
+ user_identifier: 'user123',
114
+ tokens_requested: 1
115
+ )
116
+
117
+ puts "Tokens consumed: #{response.tokens_consumed}"
118
+ puts "Tokens remaining: #{response.tokens_remaining}"
119
+ puts "Throttles: #{response.throttles}"
120
+ puts "Rule: #{response.rule.name} (ID: #{response.rule.id})"
121
+ ```
122
+
123
+ **When to use Direct API Calls:**
124
+ - 🔍 **Debugging**: When you need immediate API feedback
125
+ - 📊 **Monitoring**: For applications that rarely consume tokens
126
+ - 🎛️ **Control**: When you need precise control over token requests
127
+ - 🔄 **Legacy**: For compatibility with existing code
128
+
129
+ ### Method Comparison
130
+
131
+ | Feature | Local Buckets | Direct API |
132
+ |---------|---------------|------------|
133
+ | **Speed** | ⚡ Very Fast | 🐌 Network dependent |
134
+ | **API Calls** | 📉 Minimal (95%+ reduction) | 📈 Every request |
135
+ | **Resilience** | 🛡️ High (works offline briefly) | 🔗 Requires network |
136
+ | **Feedback** | 📊 Bucket status only | 📋 Full API response |
137
+ | **Best For** | High-frequency usage | Occasional usage |
138
+
139
+ ### Performance Benefits
140
+
141
+ **Local Token Buckets dramatically improve performance:**
142
+
143
+ - **95%+ reduction in API calls** - Instead of making an HTTP request for every token consumption, tokens are fetched in batches
144
+ - **Sub-millisecond response times** - Local token consumption is nearly instant
145
+ - **Better reliability** - Continues working even during brief API outages
146
+ - **Reduced bandwidth costs** - Fewer HTTP requests mean lower network usage
147
+
148
+ **Example Performance Comparison:**
149
+ ```ruby
150
+ # ❌ Slow: Direct API calls
151
+ 1000.times do
152
+ client.consume_tokens(operation: 'send_email', user_identifier: 'user123', tokens_requested: 1)
153
+ # Each call: ~100-200ms network latency
154
+ end
155
+ # Total: 1000 API calls, ~100-200 seconds
156
+
157
+ # ✅ Fast: Local buckets
158
+ 1000.times do
159
+ client.consume_local_bucket_token(operation: 'send_email', user_identifier: 'user123')
160
+ # Each call: ~0.1ms local operation
161
+ end
162
+ # Total: ~1 API call, ~0.1 seconds
163
+ ```
164
+
165
+ ### When to Use Each Method
166
+
167
+ **Use Local Buckets when:**
168
+ - 🚀 Building high-performance applications
169
+ - 📧 Sending bulk emails, SMS, or notifications
170
+ - 🔄 Processing webhooks or background jobs
171
+ - 📊 Handling user-facing requests that need fast response times
172
+ - 🏭 Running production applications with high token usage
173
+
174
+ **Use Direct API when:**
175
+ - 🔍 Debugging or testing rate limiting
176
+ - 📊 Building monitoring dashboards
177
+ - 🎛️ Need immediate feedback on token consumption
178
+ - 🔄 Migrating from existing implementations
179
+ - 📱 Building low-frequency applications (fewer than 10 requests/minute)
180
+
181
+
182
+
183
+ ### Complete Example: High-Performance Token Consumption
184
+
185
+ ```ruby
186
+ require 'lightrate_client'
187
+
188
+ # Create a client with default bucket size
189
+ client = LightrateClient::Client.new(
190
+ ENV['LIGHTRATE_API_KEY'] || 'your_api_key',
191
+ ENV['LIGHTRATE_APPLICATION_ID'] || 'your_application_id',
192
+ default_local_bucket_size: 50 # All operations use this bucket size
193
+ )
194
+
195
+ begin
196
+ # First call: Fetches 50 tokens from API and consumes 1 locally
197
+ response1 = client.consume_local_bucket_token(
198
+ operation: 'send_email',
199
+ user_identifier: 'user123'
200
+ )
201
+
202
+ puts "First call - Success: #{response1.success}"
203
+ puts "Used local token: #{response1.used_local_token}"
204
+ puts "Bucket status: #{response1.bucket_status}"
205
+
206
+ # Second call: Consumes from local bucket (no API call!)
207
+ response2 = client.consume_local_bucket_token(
208
+ operation: 'send_email',
209
+ user_identifier: 'user123'
210
+ )
211
+
212
+ puts "Second call - Success: #{response2.success}"
213
+ puts "Used local token: #{response2.used_local_token}"
214
+ puts "Bucket status: #{response2.bucket_status}"
215
+
216
+ # Example with path-based consumption
217
+ response3 = client.consume_local_bucket_token(
218
+ path: '/api/v1/emails/send',
219
+ http_method: 'POST',
220
+ user_identifier: 'user123'
221
+ )
222
+
223
+ puts "Path-based call - Success: #{response3.success}"
224
+ puts "Bucket status: #{response3.bucket_status}"
225
+
226
+ # Proceed with your operations...
227
+
228
+ rescue LightrateClient::UnauthorizedError => e
229
+ puts "❌ Authentication failed: #{e.message}"
230
+ rescue LightrateClient::TooManyRequestsError => e
231
+ puts "⚠️ Rate limited: #{e.message}"
232
+ rescue LightrateClient::APIError => e
233
+ puts "❌ API Error (#{e.status_code}): #{e.message}"
234
+ rescue LightrateClient::NetworkError => e
235
+ puts "❌ Network error: #{e.message}"
236
+ end
237
+ ```
238
+
239
+ ### Advanced Configuration
240
+
241
+ ```ruby
242
+ # For applications with very high token consumption
243
+ client = LightrateClient::Client.new(
244
+ 'your_api_key',
245
+ 'your_application_id',
246
+ default_local_bucket_size: 500, # Large default bucket for all operations
247
+ timeout: 60, # Longer timeout for large bucket requests
248
+ retry_attempts: 5, # More retries for reliability
249
+ logger: Logger.new(STDOUT) # Enable request logging
250
+ )
251
+ ```
252
+
253
+ ## Error Handling
254
+
255
+ The gem provides comprehensive error handling with specific exception types:
256
+
257
+ ```ruby
258
+ begin
259
+ client.users
260
+ rescue LightrateClient::UnauthorizedError => e
261
+ puts "Authentication failed: #{e.message}"
262
+ rescue LightrateClient::NotFoundError => e
263
+ puts "Resource not found: #{e.message}"
264
+ rescue LightrateClient::APIError => e
265
+ puts "API Error (#{e.status_code}): #{e.message}"
266
+ rescue LightrateClient::NetworkError => e
267
+ puts "Network error: #{e.message}"
268
+ rescue LightrateClient::TimeoutError => e
269
+ puts "Request timed out: #{e.message}"
270
+ end
271
+ ```
272
+
273
+ ## Development
274
+
275
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
276
+
277
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
278
+
279
+ ## Contributing
280
+
281
+ Bug reports and pull requests are welcome on GitHub at https://github.com/lightbourne-technologies/lightrate-client-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/lightbourne-technologies/lightrate-client-ruby/blob/main/CODE_OF_CONDUCT.md).
282
+
283
+ ## License
284
+
285
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
286
+
287
+ ## Code of Conduct
288
+
289
+ Everyone interacting in the Lightrate Client Ruby project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/lightbourne-technologies/lightrate-client-ruby/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+ RuboCop::RakeTask.new
10
+
11
+ task default: :spec
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'lightrate_client'
5
+
6
+ # This example demonstrates the Lightrate Client with the new API response structure.
7
+ # The consume_tokens API now returns:
8
+ # - tokensRemaining: Number of tokens left in the bucket
9
+ # - tokensConsumed: Number of tokens consumed in this request
10
+ # - throttles: Number of throttles applied (usually 0)
11
+ # - rule: Object containing rule information (id, name, refillRate, burstRate, isDefault)
12
+
13
+ # Create a client with default bucket size
14
+ # Note: Both API key and application ID are required for all requests
15
+ client = LightrateClient::Client.new(
16
+ ENV['LIGHTRATE_API_KEY'] || 'your_api_key_here',
17
+ ENV['LIGHTRATE_APPLICATION_ID'] || 'your_application_id_here',
18
+ default_local_bucket_size: 20, # Default bucket size for all operations
19
+ logger: ENV['DEBUG'] ? Logger.new(STDOUT) : nil
20
+ )
21
+
22
+ puts "=== Lightrate Client with Local Token Buckets ==="
23
+ puts
24
+
25
+ begin
26
+ # Example 1: Email operation (uses default bucket size)
27
+ puts "1. Email operation (bucket size: 20):"
28
+ result1 = client.consume_local_bucket_token(
29
+ operation: 'operation.one',
30
+ user_identifier: 'user123'
31
+ )
32
+
33
+ puts " Success: #{result1.success}"
34
+ puts " Used local token: #{result1.used_local_token}"
35
+ puts " Bucket status: #{result1.bucket_status}"
36
+ puts
37
+
38
+ # Example 2: SMS operation (uses default bucket size)
39
+ puts "2. SMS operation (bucket size: 20):"
40
+ result2 = client.consume_local_bucket_token(
41
+ operation: 'operation.two',
42
+ user_identifier: 'user123'
43
+ )
44
+
45
+ puts " Success: #{result2.success}"
46
+ puts " Used local token: #{result2.used_local_token}"
47
+ puts " Bucket status: #{result2.bucket_status}"
48
+ puts
49
+
50
+ # Example 3: Notification operation (uses default bucket size)
51
+ puts "3. Notification operation (bucket size: 20):"
52
+ result3 = client.consume_local_bucket_token(
53
+ operation: 'operation.one',
54
+ user_identifier: 'user123'
55
+ )
56
+
57
+ puts " Success: #{result3.success}"
58
+ puts " Used local token: #{result3.used_local_token}"
59
+ puts " Bucket status: #{result3.bucket_status}"
60
+ puts
61
+
62
+ # Example 4: Path-based operation (uses default bucket size)
63
+ puts "4. Path-based operation (bucket size: 20):"
64
+ result4 = client.consume_local_bucket_token(
65
+ path: '/api/v1/emails/send',
66
+ http_method: 'POST',
67
+ user_identifier: 'user456'
68
+ )
69
+
70
+ puts " Success: #{result4.success}"
71
+ puts " Used local token: #{result4.used_local_token}"
72
+ puts " Bucket status: #{result4.bucket_status}"
73
+ puts
74
+
75
+ # Example 5: Admin path operation (uses default bucket size)
76
+ puts "5. Admin path operation (bucket size: 20):"
77
+ result5 = client.consume_local_bucket_token(
78
+ path: '/api/v1/admin/users/123/notify',
79
+ http_method: 'POST',
80
+ user_identifier: 'admin_user'
81
+ )
82
+
83
+ puts " Success: #{result5.success}"
84
+ puts " Used local token: #{result5.used_local_token}"
85
+ puts " Bucket status: #{result5.bucket_status}"
86
+ puts
87
+
88
+ # Example 6: Different HTTP methods for same path
89
+ puts "6. Different HTTP methods for same path:"
90
+ result6a = client.consume_local_bucket_token(
91
+ path: '/api/v1/users',
92
+ http_method: 'GET',
93
+ user_identifier: 'user123'
94
+ )
95
+ result6b = client.consume_local_bucket_token(
96
+ path: '/api/v1/users',
97
+ http_method: 'POST',
98
+ user_identifier: 'user123'
99
+ )
100
+
101
+ puts " GET /api/v1/users - Success: #{result6a.success}"
102
+ puts " POST /api/v1/users - Success: #{result6b.success}"
103
+ puts " (These create separate buckets due to different HTTP methods)"
104
+ puts
105
+
106
+ # Example 7: Direct API call using consume_tokens
107
+ puts "7. Direct API call using consume_tokens:"
108
+ api_response = client.consume_tokens(
109
+ operation: 'send_notification',
110
+ user_identifier: 'user789',
111
+ tokens_requested: 3
112
+ )
113
+
114
+ puts " Tokens consumed: #{api_response.tokens_consumed}"
115
+ puts " Tokens remaining: #{api_response.tokens_remaining}"
116
+ puts " Throttles: #{api_response.throttles}"
117
+ puts " Rule: #{api_response.rule.name} (ID: #{api_response.rule.id})"
118
+ puts " Is default rule: #{api_response.rule.is_default}"
119
+ puts
120
+
121
+ rescue LightrateClient::UnauthorizedError => e
122
+ puts "❌ Authentication failed: #{e.message}"
123
+ puts " Please check your API key"
124
+ rescue LightrateClient::ForbiddenError => e
125
+ puts "❌ Access denied: #{e.message}"
126
+ puts " Please check your subscription status"
127
+ rescue LightrateClient::TooManyRequestsError => e
128
+ puts "⚠️ Rate limited: #{e.message}"
129
+ puts " Please wait before making more requests"
130
+ rescue LightrateClient::NotFoundError => e
131
+ puts "❌ Rule not found: #{e.message}"
132
+ puts " Please check your operation/path configuration"
133
+ rescue LightrateClient::APIError => e
134
+ puts "❌ API Error (#{e.status_code}): #{e.message}"
135
+ rescue LightrateClient::NetworkError => e
136
+ puts "❌ Network error: #{e.message}"
137
+ puts " Please check your internet connection"
138
+ rescue LightrateClient::TimeoutError => e
139
+ puts "❌ Request timed out: #{e.message}"
140
+ rescue => e
141
+ puts "❌ Unexpected error: #{e.class}: #{e.message}"
142
+ puts e.backtrace.first(5).join("\n")
143
+ end
144
+
145
+ puts
146
+ puts "=== Example Complete ==="