momento 0.5.1 → 0.6.4

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: da6c7b43f3c86bd649bb9142ce480a47cc9bb5170b19574faad12702882d9a71
4
- data.tar.gz: 316ca34d216b1aad4e3cb3c09f71ed09ce1bdaf27244c5087f2606a8dd266843
3
+ metadata.gz: d710dce969543a0ceca5d48787b0caa8900068d41897d1f58bb5e376f0ef6fc5
4
+ data.tar.gz: 20667320d3f97f74e1e4b4620f9f0e9922a76cbecde617c5da06129187444bc8
5
5
  SHA512:
6
- metadata.gz: 957cd146d883a440d6d7b6b11a40b385a8f828641dc4d44f19be3886962ebbcd1a72e8502455f3e538708b840f2d49cef4e6b985129bd9d15bd6ce82fb2bdcb7
7
- data.tar.gz: c63138d8888a4a4f75c94e5f791a8eb47cc445a046c62c26649dd025e8c1f17b998492db1151075cf0b8695200cb806fa50b2f729259ef88462c88cfc29b46b9
6
+ metadata.gz: 8a947860bed1a3e0f7ebab1e3740bcbb73d55d69f476988a42226fc20cd6203d0c8eb6987ce089c4d6949d5d3340ed4c311b314fb78bf1d22c41d0251b5872a2
7
+ data.tar.gz: 59fbc4168cc931a1e6d4672610b1402b044e59ee78c9b51439eec66634f86c39aab50f437490f4b21ebc074f9e29e7cacd3e7e82335618f80c8ff50475a7b672
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.5.1"
2
+ ".": "0.6.4"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,59 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.4](https://github.com/momentohq/client-sdk-ruby/compare/momento/v0.6.3...momento/v0.6.4) (2026-01-08)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * run bundle install and use bundle exec to call rake build ([28615a7](https://github.com/momentohq/client-sdk-ruby/commit/28615a7834cabef92215661eb8833d468c7fd4d9))
9
+ * run bundle install and use bundle exec to call rake build ([#206](https://github.com/momentohq/client-sdk-ruby/issues/206)) ([16256d2](https://github.com/momentohq/client-sdk-ruby/commit/16256d273ea48c61395bd1bf12fba4d8a31066af))
10
+
11
+ ## [0.6.3](https://github.com/momentohq/client-sdk-ruby/compare/momento/v0.6.2...momento/v0.6.3) (2026-01-08)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * use rake build to package gem for publishing ([c6c8ac3](https://github.com/momentohq/client-sdk-ruby/commit/c6c8ac3e9dd293b3aa3fd3bdeaeb870870f0cf35))
17
+ * use rake build to package gem for publishing ([#204](https://github.com/momentohq/client-sdk-ruby/issues/204)) ([a6a7105](https://github.com/momentohq/client-sdk-ruby/commit/a6a71051f99fc1805c6dcd2ed9c79770b2d5a6fc))
18
+
19
+ ## [0.6.2](https://github.com/momentohq/client-sdk-ruby/compare/momento/v0.6.1...momento/v0.6.2) (2026-01-08)
20
+
21
+
22
+ ### Miscellaneous Chores
23
+
24
+ * release 0.6.2 ([e435dde](https://github.com/momentohq/client-sdk-ruby/commit/e435dde85def1dea661169a92f3ecc5dec477523))
25
+ * release 0.6.2 ([#202](https://github.com/momentohq/client-sdk-ruby/issues/202)) ([210dbf1](https://github.com/momentohq/client-sdk-ruby/commit/210dbf10ad3056e9f142620c6d4726a3e1a8e856))
26
+
27
+ ## [0.6.1](https://github.com/momentohq/client-sdk-ruby/compare/momento/v0.6.0...momento/v0.6.1) (2025-12-17)
28
+
29
+
30
+ ### Miscellaneous Chores
31
+
32
+ * release 0.6.1 ([d857669](https://github.com/momentohq/client-sdk-ruby/commit/d857669abf0934391e61580832f713142c187a17))
33
+ * release 0.6.1 ([#198](https://github.com/momentohq/client-sdk-ruby/issues/198)) ([ed8998e](https://github.com/momentohq/client-sdk-ruby/commit/ed8998e361068ce2100fc5b54c65c13c483a4990))
34
+
35
+ ## [0.6.0](https://github.com/momentohq/client-sdk-ruby/compare/momento/v0.5.2...momento/v0.6.0) (2025-12-15)
36
+
37
+
38
+ ### Features
39
+
40
+ * new credential provider methods for accepting global api keys ([eb4737f](https://github.com/momentohq/client-sdk-ruby/commit/eb4737ff608e15dad77064e40157da3b4691b2da))
41
+ * new credential provider methods for accepting v2 api keys ([#195](https://github.com/momentohq/client-sdk-ruby/issues/195)) ([79e3777](https://github.com/momentohq/client-sdk-ruby/commit/79e37776ef9c7a8703bddc3dfbe569af8e42e888))
42
+
43
+
44
+ ### Bug Fixes
45
+
46
+ * disable dynamic DNS service config ([#194](https://github.com/momentohq/client-sdk-ruby/issues/194)) ([d9a0976](https://github.com/momentohq/client-sdk-ruby/commit/d9a0976dec3c8ab68e8ed4a83d50ee97963fb4b1))
47
+ * only configure git in release please if the repo was checked out ([#192](https://github.com/momentohq/client-sdk-ruby/issues/192)) ([d202329](https://github.com/momentohq/client-sdk-ruby/commit/d2023298b388e36616e766157d2a7ad017f07917))
48
+
49
+ ## [0.5.2](https://github.com/momentohq/client-sdk-ruby/compare/momento/v0.5.1...momento/v0.5.2) (2024-11-25)
50
+
51
+
52
+ ### Bug Fixes
53
+
54
+ * copyright info ([87d44d5](https://github.com/momentohq/client-sdk-ruby/commit/87d44d525041c4cd2e060fd63765ebb35904badb))
55
+ * copyright info ([#190](https://github.com/momentohq/client-sdk-ruby/issues/190)) ([47f3904](https://github.com/momentohq/client-sdk-ruby/commit/47f3904d39451957313f3306323e2c636945d971))
56
+
3
57
  ## [0.5.1](https://github.com/momentohq/client-sdk-ruby/compare/momento/v0.5.0...momento/v0.5.1) (2024-06-18)
4
58
 
5
59
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- momento (0.5.1)
4
+ momento (0.6.4)
5
5
  grpc (~> 1.62)
6
6
 
7
7
  GEM
data/LICENSE.txt CHANGED
@@ -186,7 +186,7 @@ file or class name and description of purpose be included on the
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright [yyyy] [name of copyright owner]
189
+ Copyright 2024 Momento Inc.
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -1,22 +1,22 @@
1
1
  <head>
2
- <meta name="Momento Ruby Client Library Documentation" content="Ruby client software development kit for Momento Cache">
2
+ <meta name="Momento Client Library Documentation for Ruby" content="Momento client software development kit for Ruby">
3
3
  </head>
4
4
  <img src="https://docs.momentohq.com/img/momento-logo-forest.svg" alt="logo" width="400"/>
5
5
 
6
6
  [![project status](https://momentohq.github.io/standards-and-practices/badges/project-status-official.svg)](https://github.com/momentohq/standards-and-practices/blob/main/docs/momento-on-github.md)
7
7
  [![project stability](https://momentohq.github.io/standards-and-practices/badges/project-stability-stable.svg)](https://github.com/momentohq/standards-and-practices/blob/main/docs/momento-on-github.md)
8
8
 
9
- # Momento Ruby Client Library
9
+ # Momento Client Library for Ruby
10
10
 
11
11
  Momento Cache is a fast, simple, pay-as-you-go caching solution without any of the operational overhead
12
- required by traditional caching solutions. This repo contains the source code for the Momento Ruby client library.
12
+ required by traditional caching solutions. This repo contains the source code for the Momento client library for Ruby.
13
13
 
14
14
  To get started with Momento you will need a Momento Auth Token. You can get one from the [Momento Console](https://console.gomomento.com).
15
15
 
16
16
  * Website: [https://www.gomomento.com/](https://www.gomomento.com/)
17
17
  * Momento Documentation: [https://docs.momentohq.com/](https://docs.momentohq.com/)
18
18
  * Getting Started: [https://docs.momentohq.com/getting-started](https://docs.momentohq.com/getting-started)
19
- * Ruby SDK Documentation: [https://docs.momentohq.com/sdks/ruby](https://docs.momentohq.com/sdks/ruby)
19
+ * Momento SDK Documentation for Ruby: [https://docs.momentohq.com/sdks/ruby](https://docs.momentohq.com/sdks/ruby)
20
20
  * Discuss: [Momento Discord](https://discord.gg/3HkAKjUZGq)
21
21
 
22
22
  # Momento Ruby SDK
@@ -74,7 +74,7 @@ credential_provider = Momento::CredentialProvider.from_env_var('MOMENTO_API_KEY'
74
74
  # This is a reasonable configuration for dev work on a laptop.
75
75
  configuration = Momento::Cache::Configurations::Laptop.latest
76
76
  # This configuration might be better for a production where you want more aggressive timeouts
77
- # configuration = Momento::Cache::Configuration::InRegion.latest
77
+ # configuration = Momento::Cache::Configurations::InRegion.latest
78
78
  # To set a custom timeout, you can use the with_timeout method.
79
79
  # configuration = configuration.with_timeout(10_000)
80
80
  # To increase the number of TCP connections for a client where you expect a high volume of traffic,
data/examples/Gemfile CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem 'momento', '~> 0.4.9'
5
+ gem 'momento', '~> 0.5.2'
data/examples/example.rb CHANGED
@@ -15,7 +15,7 @@ credential_provider = Momento::CredentialProvider.from_env_var('MOMENTO_API_KEY'
15
15
  # This is a reasonable configuration for dev work on a laptop.
16
16
  configuration = Momento::Cache::Configurations::Laptop.latest
17
17
  # This configuration might be better for a production where you want more aggressive timeouts
18
- # configuration = Momento::Cache::Configuration::InRegion.latest
18
+ # configuration = Momento::Cache::Configurations::InRegion.latest
19
19
  # To set a custom timeout, you can use the with_timeout method.
20
20
  # configuration = configuration.with_timeout(10_000)
21
21
  # To increase the number of TCP connections for a client where you expect a high volume of traffic,
@@ -10,6 +10,7 @@ module Momento
10
10
  # @param env_var_name [String] the environment variable containing the API key
11
11
  # @return [Momento::CredentialProvider]
12
12
  # @raise [Momento::Error::InvalidArgumentError] if the API key is invalid
13
+ # @deprecated Please use {#from_env_var_v2} instead.
13
14
  def self.from_env_var(env_var_name)
14
15
  api_key = ENV.fetch(env_var_name) {
15
16
  raise Momento::Error::InvalidArgumentError, "Env var #{env_var_name} must be set"
@@ -21,15 +22,84 @@ module Momento
21
22
  # @param api_key [String] the Momento API key
22
23
  # @return [Momento::CredentialProvider]
23
24
  # @raise [Momento::Error::InvalidArgumentError] if the API key is invalid
25
+ # @deprecated Please use {#from_api_key_v2} or {#from_disposable_token} instead.
24
26
  def self.from_string(api_key)
25
27
  raise Momento::Error::InvalidArgumentError, 'Auth token string cannot be empty' if api_key.empty?
26
28
 
27
29
  new(api_key)
28
30
  end
29
31
 
32
+ # Creates a CredentialProvider from a Momento disposable token
33
+ # @param token [String] the Momento disposable token
34
+ # @return [Momento::CredentialProvider]
35
+ # @raise [Momento::Error::InvalidArgumentError] if the token is invalid
36
+ def self.from_disposable_token(token)
37
+ raise Momento::Error::InvalidArgumentError, 'Auth token string cannot be empty' if token.empty?
38
+
39
+ new(token)
40
+ end
41
+
42
+ # Creates a CredentialProvider from a v2 API key string and endpoint.
43
+ # @param api_key [String] the v2 API key
44
+ # @param endpoint [String] the Momento service endpoint
45
+ # @return [Momento::CredentialProvider]
46
+ # @raise [Momento::Error::InvalidArgumentError] if parameters are invalid
47
+ def self.from_api_key_v2(api_key:, endpoint:)
48
+ raise Momento::Error::InvalidArgumentError, 'API key cannot be empty' if api_key.nil? || api_key.empty?
49
+ raise Momento::Error::InvalidArgumentError, 'Endpoint cannot be empty' if endpoint.nil? || endpoint.empty?
50
+
51
+ unless v2_api_key?(api_key)
52
+ raise Momento::Error::InvalidArgumentError,
53
+ 'Received an invalid v2 API key. Are you using the correct key? \
54
+ Or did you mean to use `from_string()` with a legacy key instead?'
55
+ end
56
+
57
+ allocate.tap do |instance|
58
+ instance.send(:initialize_from_v2, api_key, endpoint)
59
+ end
60
+ end
61
+
62
+ # Creates a CredentialProvider from a v2 API key and endpoint loaded from environment variables
63
+ # MOMENTO_API_KEY and MOMENTO_ENDPOINT by default.
64
+ # @param api_key_env_var [String] optionally provide alternate environment variable containing the v2 API key
65
+ # @param endpoint_env_var [String] optionally provide alternate environment variable containing the endpoint
66
+ # @return [Momento::CredentialProvider]
67
+ # @raise [Momento::Error::InvalidArgumentError] if parameters are invalid
68
+ def self.from_env_var_v2(api_key_env_var: "MOMENTO_API_KEY", endpoint_env_var: "MOMENTO_ENDPOINT")
69
+ api_key = ENV.fetch(api_key_env_var) {
70
+ raise Momento::Error::InvalidArgumentError, "Env var #{api_key_env_var} must be set"
71
+ }
72
+ endpoint = ENV.fetch(endpoint_env_var) {
73
+ raise Momento::Error::InvalidArgumentError, "Env var #{endpoint_env_var} must be set"
74
+ }
75
+ unless v2_api_key?(api_key)
76
+ raise Momento::Error::InvalidArgumentError,
77
+ 'Received an invalid v2 API key. Are you using the correct key? \
78
+ Or did you mean to use `from_env_var()` with a legacy key instead?'
79
+ end
80
+ allocate.tap do |instance|
81
+ instance.send(:initialize_from_v2, api_key, endpoint)
82
+ end
83
+ end
84
+
30
85
  private
31
86
 
87
+ def initialize_from_v2(api_key, endpoint)
88
+ raise Momento::Error::InvalidArgumentError, 'API key cannot be empty' if api_key.nil? || api_key.empty?
89
+ raise Momento::Error::InvalidArgumentError, 'Endpoint cannot be empty' if endpoint.nil? || endpoint.empty?
90
+
91
+ @api_key = api_key
92
+ @control_endpoint = "control.#{endpoint}"
93
+ @cache_endpoint = "cache.#{endpoint}"
94
+ end
95
+
32
96
  def initialize(api_key)
97
+ if v2_api_key?(api_key)
98
+ raise Momento::Error::InvalidArgumentError,
99
+ 'Received a v2 API key. Are you using the correct key? Or did you mean to use\
100
+ `from_api_key_v2()` or `from_env_var_v2()` instead?'
101
+ end
102
+
33
103
  decoded_token = decode_api_key(api_key)
34
104
  @api_key = decoded_token.api_key
35
105
  @control_endpoint = decoded_token.control_endpoint
@@ -76,3 +146,25 @@ module Momento
76
146
  end
77
147
  end
78
148
  end
149
+
150
+ def base64?(string)
151
+ return false if string.nil? || string.empty?
152
+
153
+ Base64.strict_decode64(string)
154
+ true
155
+ rescue ArgumentError
156
+ false
157
+ end
158
+
159
+ def v2_api_key?(api_key)
160
+ false if base64?(api_key)
161
+
162
+ key_parts = api_key.split('.')
163
+ raise Momento::Error::InvalidArgumentError, 'Malformed legacy API key' if key_parts.size != 3
164
+
165
+ decoded_key = Base64.decode64(key_parts[1])
166
+ key_json = JSON.parse(decoded_key, symbolize_names: true)
167
+ key_json[:t] == 'g'
168
+ rescue ArgumentError, JSON::ParserError
169
+ false
170
+ end
@@ -345,7 +345,9 @@ module Momento
345
345
  @cache_stubs ||= (1..@num_cache_stubs).map {
346
346
  CACHE_CLIENT_STUB_CLASS.new(@cache_endpoint, combined_credentials,
347
347
  timeout: @configuration.transport_strategy.grpc_configuration.deadline,
348
- channel_args: { 'grpc.use_local_subchannel_pool' => 1 }
348
+ channel_args: { 'grpc.use_local_subchannel_pool' => 1,
349
+ # Disable service config resolution to avoid DNS TXT record lookups
350
+ 'grpc.service_config_disable_resolution' => 1 }
349
351
  )
350
352
  }
351
353
  @next_cache_stub_index = (@next_cache_stub_index + 1) % @num_cache_stubs
@@ -353,7 +355,10 @@ module Momento
353
355
  end
354
356
 
355
357
  def control_stub
356
- @control_stub ||= CONTROL_CLIENT_STUB_CLASS.new(@control_endpoint, combined_credentials)
358
+ @control_stub ||= CONTROL_CLIENT_STUB_CLASS.new(@control_endpoint, combined_credentials,
359
+ # Disable service config resolution to avoid DNS TXT record lookups
360
+ channel_args: { 'grpc.service_config_disable_resolution' => 1 }
361
+ )
357
362
  end
358
363
 
359
364
  def combined_credentials
@@ -146,16 +146,69 @@ module Momento
146
146
 
147
147
  # Request rate exceeded the limits for this account.
148
148
  class LimitExceededError < RuntimeError
149
- include Momento::Error
149
+ attr_reader :details, :transport_details
150
+
151
+ def initialize(details = '', transport_details = nil)
152
+ super()
153
+ @details = details.to_s
154
+ @transport_details = transport_details
155
+ end
156
+
157
+ # Extract the error cause from metadata
158
+ def error_cause
159
+ metadata = transport_details&.grpc&.metadata || {}
160
+ metadata[:err] || 'unknown_error'
161
+ end
150
162
 
151
163
  # (see Momento::Error#error_code)
152
164
  def error_code
153
165
  :LIMIT_EXCEEDED_ERROR
154
166
  end
155
167
 
156
- # (see Momento::Error#message)
168
+ class ErrorMessages
169
+ TOPIC_SUBSCRIPTIONS_LIMIT_EXCEEDED = 'Topic subscriptions limit exceeded.'.freeze
170
+ OPERATIONS_RATE_LIMIT_EXCEEDED = 'Operations rate limit exceeded.'.freeze
171
+ THROUGHPUT_RATE_LIMIT_EXCEEDED = 'Throughput rate limit exceeded.'.freeze
172
+ REQUEST_SIZE_LIMIT_EXCEEDED = 'Request size limit exceeded.'.freeze
173
+ ITEM_SIZE_LIMIT_EXCEEDED = 'Item size limit exceeded.'.freeze
174
+ ELEMENT_SIZE_LIMIT_EXCEEDED = 'Element size limit exceeded.'.freeze
175
+ UNKNOWN_LIMIT_EXCEEDED = 'Limit exceeded for this account.'.freeze
176
+
177
+ # Map error causes to the corresponding message
178
+ ERROR_CAUSES = {
179
+ 'topic_subscriptions_limit_exceeded' => TOPIC_SUBSCRIPTIONS_LIMIT_EXCEEDED,
180
+ 'operations_rate_limit_exceeded' => OPERATIONS_RATE_LIMIT_EXCEEDED,
181
+ 'throughput_rate_limit_exceeded' => THROUGHPUT_RATE_LIMIT_EXCEEDED,
182
+ 'request_size_limit_exceeded' => REQUEST_SIZE_LIMIT_EXCEEDED,
183
+ 'item_size_limit_exceeded' => ITEM_SIZE_LIMIT_EXCEEDED,
184
+ 'element_size_limit_exceeded' => ELEMENT_SIZE_LIMIT_EXCEEDED
185
+ }.freeze
186
+
187
+ # Map substrings to the corresponding message
188
+ ERROR_SUBSTRINGS = {
189
+ 'subscribers' => TOPIC_SUBSCRIPTIONS_LIMIT_EXCEEDED,
190
+ 'operations' => OPERATIONS_RATE_LIMIT_EXCEEDED,
191
+ 'throughput' => THROUGHPUT_RATE_LIMIT_EXCEEDED,
192
+ 'request limit' => REQUEST_SIZE_LIMIT_EXCEEDED,
193
+ 'item size' => ITEM_SIZE_LIMIT_EXCEEDED,
194
+ 'element size' => ELEMENT_SIZE_LIMIT_EXCEEDED
195
+ }.freeze
196
+ end
197
+
198
+ # Generate the appropriate message based on the error cause or details
157
199
  def message
158
- "Request rate exceeded the limits for this account. To resolve this error, reduce your request rate, or contact Momento to request a limit increase."
200
+ # First, check for a direct match in the ERROR_CAUSES for the error cause
201
+ message = ErrorMessages::ERROR_CAUSES[error_cause]
202
+
203
+ # If no direct match for error cause, then check if any substring in details matches
204
+ if message.nil?
205
+ ErrorMessages::ERROR_SUBSTRINGS.each do |key, msg|
206
+ return msg if details.include?(key)
207
+ end
208
+ end
209
+
210
+ # Return the default message if no match is found
211
+ message || ErrorMessages::UNKNOWN_LIMIT_EXCEEDED
159
212
  end
160
213
  end
161
214
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Momento
4
4
  # This gem's version.
5
- VERSION = "0.5.1"
5
+ VERSION = "0.6.4"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: momento
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Momento
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-18 00:00:00.000000000 Z
11
+ date: 2026-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -321,7 +321,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
321
321
  - !ruby/object:Gem::Version
322
322
  version: '0'
323
323
  requirements: []
324
- rubygems_version: 3.5.11
324
+ rubygems_version: 3.4.10
325
325
  signing_key:
326
326
  specification_version: 4
327
327
  summary: Client for Momento Serverless Cache