mailkube 1.2.1 → 1.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 +4 -4
- data/README.md +31 -2
- data/lib/mailkube/client.rb +3 -0
- data/lib/mailkube/resources/credential.rb +32 -0
- data/lib/mailkube/transport.rb +7 -3
- data/lib/mailkube/types/api_key.rb +102 -0
- data/lib/mailkube/version.rb +1 -1
- data/lib/mailkube.rb +2 -0
- data/sig/mailkube/client.rbs +1 -0
- data/sig/mailkube/resources/credential.rbs +8 -0
- data/sig/mailkube/types/api_key.rbs +57 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c5efd02b82c63ffe38f919d2fa9a5141aa5c7e10a893ddc33ecdf6227d0eb379
|
|
4
|
+
data.tar.gz: 6cafb691b11923b959de7be667353c0f410183fa72dcb91fa538a40f5ad2eda9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2b0bfab25b6a83378b6a943c1493af5ad98fd7046eb4baec3428bb93b4fbf536c376c737058baed3d0cf9a56c722e74809e79c306ee4dcf67d0b774d9b54640
|
|
7
|
+
data.tar.gz: c3d57c7e69b2ed05e6ab5472242d5309df53a4e0a33d83f0a473f0bf1f9164abca2c83e9fc4ed6eee936bf3440667adb373a8c8948b766c99ff81b4df9b227eb
|
data/README.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
The official Ruby SDK for [mailkube](https://mailkube.com).
|
|
9
9
|
|
|
10
|
+
Full product and API documentation: [docs.mailkube.com/sdks/ruby](https://docs.mailkube.com/sdks/ruby).
|
|
11
|
+
|
|
10
12
|
Requires Ruby 3.4 or newer.
|
|
11
13
|
|
|
12
14
|
## Install
|
|
@@ -149,6 +151,28 @@ client.scheduled_emails.batches.cancel("welcome-2026-08")
|
|
|
149
151
|
An unknown batch is a no-op reporting `canceled_count: 0` rather than a 404, so a count of zero is
|
|
150
152
|
not a failure.
|
|
151
153
|
|
|
154
|
+
## Your API key
|
|
155
|
+
|
|
156
|
+
`client.credential.info` describes the key the client authenticates with: its domain,
|
|
157
|
+
organization, source-IP allowlist, plan and send-quota usage.
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
key = client.credential.info
|
|
161
|
+
puts key.key_id, key.domain.name, key.organization.alias
|
|
162
|
+
|
|
163
|
+
key.plan&.quotas&.each do |quota|
|
|
164
|
+
puts "#{quota.name}: #{quota.used} of #{quota.limit} in #{quota.period}"
|
|
165
|
+
end
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The key is checked exactly as a send checks it, so a key that cannot send raises
|
|
169
|
+
`Mailkube::AuthenticationError` (`invalid_api_key`): calling `info` is how to verify a key. The call
|
|
170
|
+
counts as a use of the key, and plan and quota figures can be up to 30 seconds old. `plan` is nil
|
|
171
|
+
when the organization has no subscription, and a plan without a daily limit lists
|
|
172
|
+
`emails_per_month` only. `remaining` counts recipients, not messages.
|
|
173
|
+
|
|
174
|
+
The client keeps the key it was constructed with. To use another key, construct another client.
|
|
175
|
+
|
|
152
176
|
## Errors
|
|
153
177
|
|
|
154
178
|
Every error descends from `Mailkube::Error`, so rescue the category you care about:
|
|
@@ -171,7 +195,8 @@ on the response line, which is what makes a failure traceable from your own logs
|
|
|
171
195
|
Categories: `BadRequestError` (400), `AuthenticationError` (403), `NotFoundError` (404),
|
|
172
196
|
`ConflictError` (409), `InvalidRequestError` (422), `RateLimitError` (429), `ServerError` (5xx),
|
|
173
197
|
and `APIError` for anything else, which is also the parent of all of them. A transport failure
|
|
174
|
-
raises `ConnectionError` and is deliberately **not** an API error.
|
|
198
|
+
raises `ConnectionError` and is deliberately **not** an API error. Neither is a 2xx response whose
|
|
199
|
+
body is not the shape the call expects: that raises the base `Mailkube::Error`.
|
|
175
200
|
|
|
176
201
|
`Mailkube::ErrorName` lists the documented `name` values for discoverability. It is **not** a
|
|
177
202
|
closed set: `error_name` stays a plain String, so a value this release has never heard of is
|
|
@@ -295,7 +320,7 @@ response body. If you want pooling, inject an adapter that pools — and make it
|
|
|
295
320
|
These are covered by semantic versioning:
|
|
296
321
|
|
|
297
322
|
- `Mailkube.new`, `Mailkube.enable_logging`
|
|
298
|
-
- `client.emails`, `client.scheduled_emails` and their verbs
|
|
323
|
+
- `client.emails`, `client.scheduled_emails`, `client.credential` and their verbs
|
|
299
324
|
- the response models and `Mailkube::Attachment` / `Mailkube::Tag`
|
|
300
325
|
- the error hierarchy and `Mailkube::ErrorName`
|
|
301
326
|
- `Mailkube::Webhooks` and everything under `Mailkube::Events`
|
|
@@ -319,10 +344,14 @@ Runnable scripts in [`examples/`](examples/):
|
|
|
319
344
|
- [`send_with_tags.rb`](examples/send_with_tags.rb) — tag a send for filtering and reporting
|
|
320
345
|
- [`send_with_template.rb`](examples/send_with_template.rb) — send from a saved template
|
|
321
346
|
- [`schedule_send.rb`](examples/schedule_send.rb) — schedule a send, then inspect the ack
|
|
347
|
+
- [`list_scheduled_emails.rb`](examples/list_scheduled_emails.rb) — one page for the metadata,
|
|
348
|
+
then the lazy walk, read-only
|
|
322
349
|
- [`manage_scheduled_emails.rb`](examples/manage_scheduled_emails.rb) — list, paginate, retrieve,
|
|
323
350
|
reschedule and cancel
|
|
324
351
|
- [`schedule_batch.rb`](examples/schedule_batch.rb) — schedule a batch, then move or cancel it as
|
|
325
352
|
a unit
|
|
353
|
+
- [`credential_info.rb`](examples/credential_info.rb) — describe the calling key, its plan and quota
|
|
354
|
+
usage
|
|
326
355
|
- [`webhook_receiver_sinatra.rb`](examples/webhook_receiver_sinatra.rb) — verify and dispatch
|
|
327
356
|
webhooks in Sinatra
|
|
328
357
|
- [`webhook_receiver_rails.rb`](examples/webhook_receiver_rails.rb) — the same in Rails, including
|
data/lib/mailkube/client.rb
CHANGED
|
@@ -26,6 +26,8 @@ module Mailkube
|
|
|
26
26
|
attr_reader :emails
|
|
27
27
|
# @return [Resources::ScheduledEmails] the scheduled-emails namespace.
|
|
28
28
|
attr_reader :scheduled_emails
|
|
29
|
+
# @return [Resources::Credential] the namespace for the API key this client authenticates with.
|
|
30
|
+
attr_reader :credential
|
|
29
31
|
|
|
30
32
|
# Create a client, resolving configuration from the arguments then the environment.
|
|
31
33
|
#
|
|
@@ -49,6 +51,7 @@ module Mailkube
|
|
|
49
51
|
@config = config
|
|
50
52
|
@emails = Resources::Emails.new(transport)
|
|
51
53
|
@scheduled_emails = Resources::ScheduledEmails.new(transport)
|
|
54
|
+
@credential = Resources::Credential.new(transport)
|
|
52
55
|
freeze
|
|
53
56
|
end
|
|
54
57
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mailkube
|
|
4
|
+
module Resources
|
|
5
|
+
# The client's own credential, reached as `client.credential`.
|
|
6
|
+
#
|
|
7
|
+
# It describes the API key the client was constructed with and holds no setter: a client takes
|
|
8
|
+
# its key at construction and keeps it, which is what makes one instance safe to share across
|
|
9
|
+
# threads. A second key is a second client.
|
|
10
|
+
class Credential
|
|
11
|
+
# @param transport [#request_json] the transport performing this resource's requests.
|
|
12
|
+
def initialize(transport)
|
|
13
|
+
@transport = transport
|
|
14
|
+
freeze
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Describe the API key this client authenticates with: its domain, organization, source-IP
|
|
18
|
+
# allowlist, plan and send-quota usage.
|
|
19
|
+
#
|
|
20
|
+
# The key is checked exactly as a send checks it, so a key that cannot send raises
|
|
21
|
+
# {AuthenticationError} (`invalid_api_key`), which also makes this the way to verify a key.
|
|
22
|
+
# The call counts as a use of the key. Plan and quota figures can be up to 30 seconds old.
|
|
23
|
+
#
|
|
24
|
+
# @return [APIKey] the calling API key.
|
|
25
|
+
# @raise [APIError] on any non-2xx response.
|
|
26
|
+
# @raise [ConnectionError] on a transport failure or timeout.
|
|
27
|
+
def info
|
|
28
|
+
APIKey.from(@transport.request_json(RequestSpec.new(path: "api-keys/me", method: "GET")))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/mailkube/transport.rb
CHANGED
|
@@ -80,12 +80,14 @@ module Mailkube
|
|
|
80
80
|
# @param spec [RequestSpec] the request to perform.
|
|
81
81
|
# @return [Email] the accepted-send result.
|
|
82
82
|
# @raise [APIError] on any non-2xx response.
|
|
83
|
+
# @raise [Error] on a 2xx body without an `id`: a body of the wrong shape is an SDK-level
|
|
84
|
+
# failure, not an API error.
|
|
83
85
|
# @raise [ConnectionError] on a transport failure or timeout.
|
|
84
86
|
def send_email(spec)
|
|
85
87
|
response = perform(spec)
|
|
86
88
|
payload = decode(response.body)
|
|
87
89
|
id = payload["id"]
|
|
88
|
-
raise
|
|
90
|
+
raise Error, "expected a JSON body with an 'id' from a #{response.status} response" unless id.is_a?(String)
|
|
89
91
|
|
|
90
92
|
Email.new(
|
|
91
93
|
id: id,
|
|
@@ -111,12 +113,14 @@ module Mailkube
|
|
|
111
113
|
#
|
|
112
114
|
# @param spec [RequestSpec] the request to perform.
|
|
113
115
|
# @return [Hash{String => Object}] the decoded 2xx body.
|
|
114
|
-
# @raise [APIError] on any non-2xx response
|
|
116
|
+
# @raise [APIError] on any non-2xx response.
|
|
117
|
+
# @raise [Error] on a 2xx body that is not a JSON object: a body of the wrong shape is an
|
|
118
|
+
# SDK-level failure, not an API error.
|
|
115
119
|
# @raise [ConnectionError] on a transport failure or timeout.
|
|
116
120
|
def request_json(spec)
|
|
117
121
|
response = perform(spec)
|
|
118
122
|
payload = decode_object(response.body)
|
|
119
|
-
raise
|
|
123
|
+
raise Error, "expected a JSON object body from a #{response.status} response" if payload.nil?
|
|
120
124
|
|
|
121
125
|
payload
|
|
122
126
|
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mailkube
|
|
4
|
+
# The API key the client authenticates with, as it describes itself.
|
|
5
|
+
#
|
|
6
|
+
# Returned by {Resources::Credential#info}. Timestamps stay the verbatim ISO-8601 strings the
|
|
7
|
+
# server sent; call `Time.iso8601` yourself if you want objects. Plan and quota figures can be up
|
|
8
|
+
# to 30 seconds old.
|
|
9
|
+
class APIKey < Data.define(:object, :key_id, :name, :description, :created_at, :last_auth_at,
|
|
10
|
+
:allowed_source_ips, :domain, :organization, :plan)
|
|
11
|
+
# @param object [String] the resource discriminator, always `api_key`.
|
|
12
|
+
# @param key_id [String] the key's public identifier.
|
|
13
|
+
# @param name [String] the key's name.
|
|
14
|
+
# @param description [String, nil] the key's description.
|
|
15
|
+
# @param created_at [String] when the key was created.
|
|
16
|
+
# @param last_auth_at [String, nil] the key's last successful authentication, this call included.
|
|
17
|
+
# @param allowed_source_ips [Array<String>] the CIDR networks the key may be used from; empty
|
|
18
|
+
# means any address.
|
|
19
|
+
# @param domain [APIKeyDomain] the sending domain the key belongs to.
|
|
20
|
+
# @param organization [APIKeyOrganization] the organization owning the domain.
|
|
21
|
+
# @param plan [APIKeyPlan, nil] the organization's plan, nil when it has no subscription.
|
|
22
|
+
def initialize(key_id:, object: "api_key", name: "", description: nil, created_at: "", last_auth_at: nil,
|
|
23
|
+
allowed_source_ips: [], domain: APIKeyDomain.new, organization: APIKeyOrganization.new,
|
|
24
|
+
plan: nil)
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# `plan` is the one field the API sends as null, meaning "no subscription", so it is decoded
|
|
29
|
+
# only when present: an empty plan built from defaults would look like a real one.
|
|
30
|
+
#
|
|
31
|
+
# @param payload [Hash{String => Object}] the decoded `api_key` object.
|
|
32
|
+
# @return [APIKey] the model.
|
|
33
|
+
def self.from(payload)
|
|
34
|
+
new(key_id: payload["key_id"], object: payload["object"] || "api_key", name: payload["name"] || "",
|
|
35
|
+
description: payload["description"], created_at: payload["created_at"] || "",
|
|
36
|
+
last_auth_at: payload["last_auth_at"], allowed_source_ips: payload["allowed_source_ips"] || [],
|
|
37
|
+
domain: APIKeyDomain.from(payload["domain"]), organization: APIKeyOrganization.from(payload["organization"]),
|
|
38
|
+
plan: payload["plan"] && APIKeyPlan.from(payload["plan"]))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# The sending domain an API key belongs to.
|
|
43
|
+
class APIKeyDomain < Data.define(:name)
|
|
44
|
+
# @param name [String] the domain name, e.g. `example.com`.
|
|
45
|
+
def initialize(name: "") = super
|
|
46
|
+
|
|
47
|
+
# @param payload [Hash{String => Object}, nil] the decoded `domain` block.
|
|
48
|
+
# @return [APIKeyDomain] the model.
|
|
49
|
+
def self.from(payload) = new(name: (payload || {})["name"] || "")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The organization owning an API key's domain.
|
|
53
|
+
class APIKeyOrganization < Data.define(:name, :alias)
|
|
54
|
+
# @param name [String] the organization's display name.
|
|
55
|
+
# @param alias [String] the organization's short alias.
|
|
56
|
+
def initialize(name: "", alias: "") = super
|
|
57
|
+
|
|
58
|
+
# @param payload [Hash{String => Object}, nil] the decoded `organization` block.
|
|
59
|
+
# @return [APIKeyOrganization] the model.
|
|
60
|
+
def self.from(payload)
|
|
61
|
+
block = payload || {}
|
|
62
|
+
new(name: block["name"] || "", alias: block["alias"] || "")
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The organization's plan, its status and its send quotas.
|
|
67
|
+
#
|
|
68
|
+
# `status` is a server-controlled string, deliberately not an enum. A plan without a daily limit
|
|
69
|
+
# lists the monthly quota only: an absent quota is a missing limit, never a limit of zero.
|
|
70
|
+
class APIKeyPlan < Data.define(:code, :name, :status, :quotas)
|
|
71
|
+
# @param code [String] the plan's UUID.
|
|
72
|
+
# @param name [String] the plan's name.
|
|
73
|
+
# @param status [String] the subscription status, e.g. `active`.
|
|
74
|
+
# @param quotas [Array<APIKeyQuota>] the send quotas the plan carries.
|
|
75
|
+
def initialize(code: "", name: "", status: "", quotas: []) = super
|
|
76
|
+
|
|
77
|
+
# @param payload [Hash{String => Object}] the decoded `plan` block.
|
|
78
|
+
# @return [APIKeyPlan] the model.
|
|
79
|
+
def self.from(payload)
|
|
80
|
+
new(code: payload["code"] || "", name: payload["name"] || "", status: payload["status"] || "",
|
|
81
|
+
quotas: (payload["quotas"] || []).map { |quota| APIKeyQuota.from(quota) })
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# One send quota of the plan: its limit and what the current period has used, in recipients.
|
|
86
|
+
class APIKeyQuota < Data.define(:name, :limit, :used, :remaining, :period)
|
|
87
|
+
# @param name [String] which quota, e.g. `emails_per_day` or `emails_per_month`; a
|
|
88
|
+
# server-controlled string, deliberately not an enum.
|
|
89
|
+
# @param limit [Integer] the plan's limit for the period.
|
|
90
|
+
# @param used [Integer] recipients sent to so far in the period.
|
|
91
|
+
# @param remaining [Integer] recipients left in the period.
|
|
92
|
+
# @param period [String] the UTC day (`2026-10-19`) or month (`2026-10`) the figures count.
|
|
93
|
+
def initialize(name: "", limit: 0, used: 0, remaining: 0, period: "") = super
|
|
94
|
+
|
|
95
|
+
# @param payload [Hash{String => Object}] one decoded quota.
|
|
96
|
+
# @return [APIKeyQuota] the model.
|
|
97
|
+
def self.from(payload)
|
|
98
|
+
new(name: payload["name"] || "", limit: payload["limit"] || 0, used: payload["used"] || 0,
|
|
99
|
+
remaining: payload["remaining"] || 0, period: payload["period"] || "")
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/mailkube/version.rb
CHANGED
|
@@ -11,5 +11,5 @@ module Mailkube
|
|
|
11
11
|
# semantic-release rewrites this line **in the release runner** just before the gem is built, and
|
|
12
12
|
# commits nothing back to `main` (see `.rules/RELEASE.md`). So a checkout reports `0.0.0` and an
|
|
13
13
|
# installed gem reports the real version: that is intended, not a bug to fix by hardcoding one.
|
|
14
|
-
VERSION = "1.
|
|
14
|
+
VERSION = "1.3.0"
|
|
15
15
|
end
|
data/lib/mailkube.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative "mailkube/logging"
|
|
|
6
6
|
require_relative "mailkube/types"
|
|
7
7
|
require_relative "mailkube/types/scheduled_emails"
|
|
8
8
|
require_relative "mailkube/types/scheduled_acks"
|
|
9
|
+
require_relative "mailkube/types/api_key"
|
|
9
10
|
require_relative "mailkube/serialization"
|
|
10
11
|
require_relative "mailkube/config"
|
|
11
12
|
require_relative "mailkube/transport"
|
|
@@ -13,6 +14,7 @@ require_relative "mailkube/net_http_adapter"
|
|
|
13
14
|
require_relative "mailkube/resources/emails"
|
|
14
15
|
require_relative "mailkube/resources/scheduled_email_requests"
|
|
15
16
|
require_relative "mailkube/resources/scheduled_emails"
|
|
17
|
+
require_relative "mailkube/resources/credential"
|
|
16
18
|
require_relative "mailkube/client"
|
|
17
19
|
require_relative "mailkube/events/node"
|
|
18
20
|
require_relative "mailkube/events/contexts"
|
data/sig/mailkube/client.rbs
CHANGED
|
@@ -2,6 +2,7 @@ module Mailkube
|
|
|
2
2
|
class Client
|
|
3
3
|
attr_reader emails: Resources::Emails
|
|
4
4
|
attr_reader scheduled_emails: Resources::ScheduledEmails
|
|
5
|
+
attr_reader credential: Resources::Credential
|
|
5
6
|
|
|
6
7
|
def initialize: (?api_key: String?, ?base_url: String?, ?timeout: Numeric, ?http: _HttpAdapter?,
|
|
7
8
|
?user_agent_suffix: String?) -> void
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Mailkube
|
|
2
|
+
# Declared the same way as every other model; see `sig/mailkube/types.rbs`.
|
|
3
|
+
class APIKey
|
|
4
|
+
attr_reader object: String
|
|
5
|
+
attr_reader key_id: String
|
|
6
|
+
attr_reader name: String
|
|
7
|
+
attr_reader description: String?
|
|
8
|
+
attr_reader created_at: String
|
|
9
|
+
attr_reader last_auth_at: String?
|
|
10
|
+
attr_reader allowed_source_ips: Array[String]
|
|
11
|
+
attr_reader domain: APIKeyDomain
|
|
12
|
+
attr_reader organization: APIKeyOrganization
|
|
13
|
+
attr_reader plan: APIKeyPlan?
|
|
14
|
+
|
|
15
|
+
def initialize: (key_id: String, ?object: String, ?name: String, ?description: String?,
|
|
16
|
+
?created_at: String, ?last_auth_at: String?, ?allowed_source_ips: Array[String],
|
|
17
|
+
?domain: APIKeyDomain, ?organization: APIKeyOrganization, ?plan: APIKeyPlan?) -> void
|
|
18
|
+
def self.from: (Hash[String, untyped]) -> APIKey
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class APIKeyDomain
|
|
22
|
+
attr_reader name: String
|
|
23
|
+
|
|
24
|
+
def initialize: (?name: String) -> void
|
|
25
|
+
def self.from: (Hash[String, untyped]?) -> APIKeyDomain
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class APIKeyOrganization
|
|
29
|
+
attr_reader name: String
|
|
30
|
+
# Declared as `def` because `alias` is a keyword, as `PageSteps#next` is.
|
|
31
|
+
def alias: () -> String
|
|
32
|
+
|
|
33
|
+
def initialize: (?name: String, ?alias: String) -> void
|
|
34
|
+
def self.from: (Hash[String, untyped]?) -> APIKeyOrganization
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class APIKeyPlan
|
|
38
|
+
attr_reader code: String
|
|
39
|
+
attr_reader name: String
|
|
40
|
+
attr_reader status: String
|
|
41
|
+
attr_reader quotas: Array[APIKeyQuota]
|
|
42
|
+
|
|
43
|
+
def initialize: (?code: String, ?name: String, ?status: String, ?quotas: Array[APIKeyQuota]) -> void
|
|
44
|
+
def self.from: (Hash[String, untyped]) -> APIKeyPlan
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class APIKeyQuota
|
|
48
|
+
attr_reader name: String
|
|
49
|
+
attr_reader limit: Integer
|
|
50
|
+
attr_reader used: Integer
|
|
51
|
+
attr_reader remaining: Integer
|
|
52
|
+
attr_reader period: String
|
|
53
|
+
|
|
54
|
+
def initialize: (?name: String, ?limit: Integer, ?used: Integer, ?remaining: Integer, ?period: String) -> void
|
|
55
|
+
def self.from: (Hash[String, untyped]) -> APIKeyQuota
|
|
56
|
+
end
|
|
57
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailkube
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mail Tactic Corporation
|
|
@@ -29,12 +29,14 @@ files:
|
|
|
29
29
|
- lib/mailkube/events/registry.rb
|
|
30
30
|
- lib/mailkube/logging.rb
|
|
31
31
|
- lib/mailkube/net_http_adapter.rb
|
|
32
|
+
- lib/mailkube/resources/credential.rb
|
|
32
33
|
- lib/mailkube/resources/emails.rb
|
|
33
34
|
- lib/mailkube/resources/scheduled_email_requests.rb
|
|
34
35
|
- lib/mailkube/resources/scheduled_emails.rb
|
|
35
36
|
- lib/mailkube/serialization.rb
|
|
36
37
|
- lib/mailkube/transport.rb
|
|
37
38
|
- lib/mailkube/types.rb
|
|
39
|
+
- lib/mailkube/types/api_key.rb
|
|
38
40
|
- lib/mailkube/types/scheduled_acks.rb
|
|
39
41
|
- lib/mailkube/types/scheduled_emails.rb
|
|
40
42
|
- lib/mailkube/version.rb
|
|
@@ -50,12 +52,14 @@ files:
|
|
|
50
52
|
- sig/mailkube/events/registry.rbs
|
|
51
53
|
- sig/mailkube/logging.rbs
|
|
52
54
|
- sig/mailkube/net_http_adapter.rbs
|
|
55
|
+
- sig/mailkube/resources/credential.rbs
|
|
53
56
|
- sig/mailkube/resources/emails.rbs
|
|
54
57
|
- sig/mailkube/resources/scheduled_email_requests.rbs
|
|
55
58
|
- sig/mailkube/resources/scheduled_emails.rbs
|
|
56
59
|
- sig/mailkube/serialization.rbs
|
|
57
60
|
- sig/mailkube/transport.rbs
|
|
58
61
|
- sig/mailkube/types.rbs
|
|
62
|
+
- sig/mailkube/types/api_key.rbs
|
|
59
63
|
- sig/mailkube/types/scheduled_acks.rbs
|
|
60
64
|
- sig/mailkube/types/scheduled_emails.rbs
|
|
61
65
|
- sig/mailkube/webhooks.rbs
|