kit-rb 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cd1696be6db17ef8f8d6a5c010d7e827bb914f7ea32e1b8e0e68a55f4a548cfc
4
+ data.tar.gz: f68f531db1eaa19bd17f46f4a764f994419fbf01cf2349d141686f00c33ccc7f
5
+ SHA512:
6
+ metadata.gz: fea1917e81a6eef748518e0609b9d0b4e6c5f347b5527d12ba5575dbf02a210ea3db32037163d98e30e83cb6d35a258a0a5a712a969306960ca9ffaedbafe612
7
+ data.tar.gz: '058e607d279ad4c3f462a50495874c5d4ce8792dc73961ca193488c7e44e5442fc2cb057b3563fc295b382d2184e4c467f4742d1b4478ac4fb1ea7c4a3493d86'
data/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres
5
+ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.0.0] - 2026-09-04
8
+
9
+ Name-reservation release: the P0 foundation and a working `GET /v4/account`
10
+ vertical slice. Not yet feature-complete — resources land in 0.1.0 per docs/DESIGN.md.
11
+
12
+ ### Added
13
+ - P0 foundations: gem skeleton on the clean `Kit` namespace, with rspec +
14
+ rubocop + steep gates green on CI (Ruby 3.2–3.4).
15
+ - `Kit::Client` with API-key (`X-Kit-Api-Key`) and OAuth 2.0 bearer auth.
16
+ - `http.rb`-backed `Kit::Connection` with JSON handling and a typed error
17
+ hierarchy (`Kit::AuthenticationError`, `NotFoundError`, `RateLimitError`, …).
18
+ - `GET /v4/account` vertical slice returning immutable `Data` value objects.
19
+ - RBS signatures for the public surface.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Lawrence Lin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # kit-rb
2
+
3
+ A modern, fully-typed Ruby client for the **Kit** (formerly ConvertKit) **API v4**.
4
+
5
+ The gem is named `kit-rb`; the public namespace is the clean `Kit`.
6
+
7
+ > Status: early. P0 (foundations + the `GET /v4/account` vertical slice) is in
8
+ > place; resources are landing per [`docs/DESIGN.md`](docs/DESIGN.md).
9
+
10
+ ## Install
11
+
12
+ ```ruby
13
+ gem "kit-rb"
14
+ ```
15
+
16
+ Requires Ruby >= 3.2.
17
+
18
+ ## Usage
19
+
20
+ ```ruby
21
+ require "kit-rb"
22
+
23
+ # API key — simplest, for your own account (120 req / 60s):
24
+ client = Kit::Client.new(api_key: ENV.fetch("KIT_API_KEY"))
25
+
26
+ # or OAuth 2.0 (600 req / 60s; required for bulk & purchase endpoints):
27
+ client = Kit::Client.new(access_token: oauth_access_token)
28
+
29
+ info = client.account.get # => Kit::Objects::AccountInfo
30
+ info.account.plan_type # => "creator_pro"
31
+ info.user.email # => "you@example.com"
32
+ ```
33
+
34
+ Responses are immutable `Data` value objects. Errors are typed:
35
+
36
+ ```ruby
37
+ begin
38
+ client.account.get
39
+ rescue Kit::AuthenticationError => e # 401
40
+ warn e.status # => 401
41
+ rescue Kit::RateLimitError => e # 429
42
+ sleep e.retry_after
43
+ rescue Kit::APIError => e # any other non-2xx
44
+ warn e.errors # => ["..."] from Kit's body
45
+ end
46
+ ```
47
+
48
+ ## Development
49
+
50
+ ```sh
51
+ bin/setup
52
+ bundle exec rake # spec + rubocop + steep
53
+ ```
54
+
55
+ ## License
56
+
57
+ MIT.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
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
+
10
+ RuboCop::RakeTask.new
11
+
12
+ desc "Type-check with Steep"
13
+ task :steep do
14
+ sh "bundle exec steep check"
15
+ end
16
+
17
+ task default: %i[spec rubocop steep]
data/Steepfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :lib do
4
+ signature "sig"
5
+ check "lib"
6
+
7
+ # http.rb and json ship without RBS here; treat their calls as untyped.
8
+ library "json"
9
+ configure_code_diagnostics(Steep::Diagnostic::Ruby.lenient)
10
+ end
data/docs/DESIGN.md ADDED
@@ -0,0 +1,50 @@
1
+ # kit-rb — design
2
+
3
+ A modern, fully-typed Ruby client for the **Kit** (formerly ConvertKit) **API v4**.
4
+ The existing Ruby gems all stop at API v3/v2; kit-rb targets v4 to a high bar.
5
+
6
+ ## Locked decisions
7
+
8
+ | area | choice | why |
9
+ |---|---|---|
10
+ | HTTP | **http.rb** (`~> 5.2`) | one modern dependency; cleaner than Net::HTTP boilerplate, lighter than Faraday |
11
+ | Auth | **API key + OAuth 2.0 from day one** | Kit's bulk & purchase-creation endpoints require OAuth |
12
+ | Types | **RBS + steep**, response = **`Data` value objects** | Ruby-native, immutable, zero runtime type dep |
13
+ | Ruby floor | **3.2** | `Data.define` |
14
+ | Build process | P1 by hand; **P2 resources via local models + `forge`** | dogfood the reliable-edit workflow; Ruby verified across the fleet benchmarks |
15
+
16
+ ## Architecture
17
+
18
+ ```
19
+ Kit::Client # entry: picks an auth strategy, holds one Connection
20
+ ├─ Kit::Configuration # immutable; validates exactly-one-credential
21
+ ├─ Kit::Auth::ApiKey # X-Kit-Api-Key header
22
+ ├─ Kit::Auth::OAuth # Bearer; authorize/refresh/PKCE land in P1
23
+ ├─ Kit::Connection # http.rb transport, JSON, auth injection, error mapping
24
+ ├─ Kit::Error (tree) # typed exceptions mapped from HTTP status
25
+ ├─ Kit::Objects::* # Data value objects, `.from(hash)` constructors
26
+ └─ Kit::Resources::* # one class per resource group; client.account.get
27
+ ```
28
+
29
+ Facts pinned from the OpenAPI spec (`developers.kit.com/api-reference/v4.json`,
30
+ OpenAPI 3.0.3, "Kit API 4.0", host `https://api.kit.com`, 52 paths): API-key
31
+ header `X-Kit-Api-Key`; OAuth authorize/token at `/v4/oauth/*`, scopes read/write;
32
+ rate limits 120/60s (key) and 600/60s (OAuth); cursor pagination (`after`/`before`
33
+ + `per_page`, response carries a `pagination` object).
34
+
35
+ ## Phases
36
+
37
+ - **P0 — foundations (this).** Gem skeleton on the clean `Kit` namespace, gates
38
+ (rspec + rubocop + steep) green in CI (Ruby 3.2–3.4), and a walking-skeleton
39
+ vertical slice: `GET /v4/account` end to end (auth → request → typed error →
40
+ `Data` object) with full spec coverage.
41
+ - **P1 — core, by hand.** Flesh out the transport: cursor auto-pagination
42
+ (lazy Enumerator), 429 rate-limit-aware retry with backoff, the full OAuth
43
+ authorization-code grant + refresh + PKCE, and instrumentation hooks.
44
+ - **P2 — resources, spec-driven + local models.** One class + objects + specs per
45
+ resource group (subscribers, tags, custom fields, forms, sequences, broadcasts,
46
+ purchases, webhooks, email templates, segments, snippets), generated against
47
+ the OpenAPI spec via `forge`, gated by `rspec`/`steep`.
48
+ - **P3 — quality.** Contract tests against the OpenAPI spec, edge cases
49
+ (pagination tail, nulls, large payloads), coverage floor.
50
+ - **P4 — DX & release.** YARD docs, examples, signed gem, release automation.
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Auth
5
+ # API-key authentication: sends the key in the `X-Kit-Api-Key` header.
6
+ #
7
+ # Simplest way to reach your own account. Rate limit is 120 requests / 60s.
8
+ # Note: Kit's bulk and purchase-creation endpoints require OAuth, not a key.
9
+ class ApiKey
10
+ HEADER = "X-Kit-Api-Key"
11
+
12
+ def initialize(key)
13
+ raise ConfigurationError, "API key cannot be blank" if key.nil? || key.empty?
14
+
15
+ @key = key
16
+ end
17
+
18
+ # Adds the auth header to an outgoing request's header hash.
19
+ def headers
20
+ { HEADER => @key }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Auth
5
+ # OAuth 2.0 bearer-token authentication: sends `Authorization: Bearer <token>`.
6
+ #
7
+ # Rate limit is 600 requests / 60s, and OAuth is required for the bulk and
8
+ # purchase-creation endpoints.
9
+ #
10
+ # P0 scope: carry an already-obtained access token. The authorization-code
11
+ # grant (authorize/token URLs at /v4/oauth/*), refresh, and PKCE helper land
12
+ # in P1 — this class is the seam they plug into.
13
+ class OAuth
14
+ AUTHORIZE_URL = "https://api.kit.com/v4/oauth/authorize"
15
+ TOKEN_URL = "https://api.kit.com/v4/oauth/token"
16
+
17
+ def initialize(access_token)
18
+ raise ConfigurationError, "OAuth access token cannot be blank" if access_token.nil? || access_token.empty?
19
+
20
+ @access_token = access_token
21
+ end
22
+
23
+ def headers
24
+ { "Authorization" => "Bearer #{@access_token}" }
25
+ end
26
+ end
27
+ end
28
+ end
data/lib/kit/client.rb ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ # The entry point. Construct with one credential, then reach resources:
5
+ #
6
+ # client = Kit::Client.new(api_key: ENV.fetch("KIT_API_KEY"))
7
+ # client.account.get.account.plan_type
8
+ #
9
+ # client = Kit::Client.new(access_token: oauth_token) # OAuth
10
+ #
11
+ # A client is thread-safe to share: it holds immutable config and a stateless
12
+ # connection, and resource accessors are memoized per client.
13
+ class Client
14
+ attr_reader :config
15
+
16
+ def initialize(api_key: nil, access_token: nil, **options)
17
+ @config = Configuration.new(api_key: api_key, access_token: access_token, **options)
18
+ @connection = Connection.new(@config)
19
+ end
20
+
21
+ def account
22
+ @account ||= Resources::Account.new(@connection)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ # Immutable per-client configuration. Exactly one credential (api_key or
5
+ # access_token) must be supplied; the matching auth strategy is selected here.
6
+ class Configuration
7
+ attr_reader :auth, :base_url, :open_timeout, :read_timeout
8
+
9
+ def initialize(api_key: nil, access_token: nil, base_url: DEFAULT_BASE_URL,
10
+ open_timeout: 10, read_timeout: 30)
11
+ @auth = build_auth(api_key, access_token)
12
+ @base_url = base_url
13
+ @open_timeout = open_timeout
14
+ @read_timeout = read_timeout
15
+ end
16
+
17
+ private
18
+
19
+ def build_auth(api_key, access_token)
20
+ raise ConfigurationError, "supply either api_key or access_token, not both" if api_key && access_token
21
+
22
+ return Auth::ApiKey.new(api_key) if api_key
23
+ return Auth::OAuth.new(access_token) if access_token
24
+
25
+ raise ConfigurationError, "an api_key or access_token is required"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "http"
4
+ require "json"
5
+
6
+ module Kit
7
+ # The transport layer: builds requests with http.rb, injects auth and JSON
8
+ # headers, parses responses, and maps non-2xx statuses onto the typed error
9
+ # hierarchy. Resources talk to the API only through this.
10
+ class Connection
11
+ JSON_TYPE = "application/json"
12
+
13
+ def initialize(config)
14
+ @config = config
15
+ end
16
+
17
+ # Issues a request and returns the parsed JSON body (a Hash) on success.
18
+ #
19
+ # @param method [Symbol] :get, :post, :put, :delete
20
+ # @param path [String] e.g. "/v4/account" (leading slash, no host)
21
+ # @param params [Hash] query string params
22
+ # @param body [Hash, nil] JSON request body
23
+ def request(method, path, params: {}, body: nil)
24
+ response = client.request(
25
+ method,
26
+ "#{@config.base_url}#{path}",
27
+ params: params,
28
+ json: body
29
+ )
30
+ handle(response)
31
+ rescue HTTP::Error => e
32
+ raise Error, "HTTP transport error: #{e.message}"
33
+ end
34
+
35
+ private
36
+
37
+ def client
38
+ HTTP
39
+ .headers(default_headers)
40
+ .timeout(connect: @config.open_timeout, read: @config.read_timeout)
41
+ end
42
+
43
+ def default_headers
44
+ {
45
+ "Accept" => JSON_TYPE,
46
+ "Content-Type" => JSON_TYPE,
47
+ "User-Agent" => "kit-rb/#{Kit::VERSION}"
48
+ }.merge(@config.auth.headers)
49
+ end
50
+
51
+ def handle(response)
52
+ status = response.status.to_i
53
+ parsed = parse(response)
54
+ return parsed if (200..299).cover?(status)
55
+
56
+ raise error_for(status, parsed, response)
57
+ end
58
+
59
+ def parse(response)
60
+ raw = response.body.to_s
61
+ return nil if raw.empty?
62
+
63
+ JSON.parse(raw)
64
+ rescue JSON::ParserError
65
+ raw
66
+ end
67
+
68
+ def error_for(status, body, response)
69
+ klass = Error.class_for(status)
70
+ if klass == RateLimitError
71
+ klass.new(status: status, body: body, response: response,
72
+ retry_after: response.headers["Retry-After"]&.to_i)
73
+ else
74
+ klass.new(status: status, body: body, response: response)
75
+ end
76
+ end
77
+ end
78
+ end
data/lib/kit/errors.rb ADDED
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ # Base class for every error the gem raises. Rescue `Kit::Error` to catch all.
5
+ class Error < StandardError; end
6
+
7
+ # Raised for configuration problems detected before any request is made
8
+ # (e.g. no credentials supplied).
9
+ class ConfigurationError < Error; end
10
+
11
+ # Base for every error that carries an HTTP response. `status` is the code,
12
+ # `body` the parsed JSON body (or the raw string when it wasn't JSON), and
13
+ # `errors` the `errors` array Kit returns on validation failures.
14
+ class APIError < Error
15
+ attr_reader :status, :body, :errors, :response
16
+
17
+ def initialize(message = nil, status:, body: nil, response: nil)
18
+ @status = status
19
+ @body = body
20
+ @response = response
21
+ @errors = body.is_a?(Hash) ? Array(body["errors"]) : []
22
+ super(message || default_message)
23
+ end
24
+
25
+ private
26
+
27
+ def default_message
28
+ base = "Kit API request failed with status #{status}"
29
+ @errors.empty? ? base : "#{base}: #{@errors.join(", ")}"
30
+ end
31
+ end
32
+
33
+ # 401 — missing or invalid credentials.
34
+ class AuthenticationError < APIError; end
35
+ # 403 — authenticated but not permitted (e.g. an API-key-only call needing OAuth).
36
+ class AuthorizationError < APIError; end
37
+ # 404 — no such resource.
38
+ class NotFoundError < APIError; end
39
+ # 422 — the request was well-formed but semantically invalid.
40
+ class UnprocessableEntityError < APIError; end
41
+
42
+ # 429 — rate limited. `retry_after` is the seconds to wait, when Kit sends it.
43
+ class RateLimitError < APIError
44
+ attr_reader :retry_after
45
+
46
+ def initialize(message = nil, status:, body: nil, response: nil, retry_after: nil)
47
+ @retry_after = retry_after
48
+ super(message, status: status, body: body, response: response)
49
+ end
50
+ end
51
+
52
+ # 5xx — a Kit-side failure.
53
+ class ServerError < APIError; end
54
+
55
+ # Maps an HTTP status to the most specific error class above.
56
+ class Error
57
+ def self.class_for(status)
58
+ case status
59
+ when 401 then AuthenticationError
60
+ when 403 then AuthorizationError
61
+ when 404 then NotFoundError
62
+ when 422 then UnprocessableEntityError
63
+ when 429 then RateLimitError
64
+ when 500..599 then ServerError
65
+ else APIError
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Objects
5
+ # The user half of GET /v4/account.
6
+ User = Data.define(:email, :id) do
7
+ def self.from(hash)
8
+ new(email: hash["email"], id: hash["id"])
9
+ end
10
+ end
11
+
12
+ # The account half of GET /v4/account. Extra fields Kit adds later are
13
+ # ignored rather than crashing the client (forward-compatible).
14
+ Account = Data.define(:id, :name, :plan_type, :primary_email_address, :created_at) do
15
+ def self.from(hash)
16
+ new(
17
+ id: hash["id"],
18
+ name: hash["name"],
19
+ plan_type: hash["plan_type"],
20
+ primary_email_address: hash["primary_email_address"],
21
+ created_at: hash["created_at"]
22
+ )
23
+ end
24
+ end
25
+
26
+ # The whole GET /v4/account response: { user:, account: }.
27
+ AccountInfo = Data.define(:user, :account) do
28
+ def self.from(hash)
29
+ new(
30
+ user: User.from(hash.fetch("user", {})),
31
+ account: Account.from(hash.fetch("account", {}))
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Resources
5
+ # The /v4/account endpoints. P0 covers the current-account read; colors,
6
+ # creator_profile, email_stats, and growth_stats follow in P1/P2.
7
+ class Account < Base
8
+ # GET /v4/account — current account and user info.
9
+ #
10
+ # @return [Kit::Objects::AccountInfo]
11
+ def get
12
+ Objects::AccountInfo.from(super("/v4/account"))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Resources
5
+ # Shared base for every resource group. Holds the connection and exposes
6
+ # thin verb helpers so resource classes read as `get("/v4/account")`.
7
+ class Base
8
+ def initialize(connection)
9
+ @connection = connection
10
+ end
11
+
12
+ private
13
+
14
+ def get(path, params: {})
15
+ @connection.request(:get, path, params: params)
16
+ end
17
+
18
+ def post(path, body: nil, params: {})
19
+ @connection.request(:post, path, params: params, body: body)
20
+ end
21
+
22
+ def put(path, body: nil, params: {})
23
+ @connection.request(:put, path, params: params, body: body)
24
+ end
25
+
26
+ def delete(path, params: {})
27
+ @connection.request(:delete, path, params: params)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ VERSION = "0.0.0"
5
+ end
data/lib/kit-rb.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # kit-rb — a Ruby client for the Kit (formerly ConvertKit) API v4.
4
+ #
5
+ # The gem is named `kit-rb`; the public namespace is the clean `Kit`
6
+ # (like redis-rb → Redis). Require it and talk to the API through a client:
7
+ #
8
+ # client = Kit::Client.new(api_key: ENV.fetch("KIT_API_KEY"))
9
+ # client.account.get.plan_type # => "creator_pro"
10
+ module Kit
11
+ # Base URL for the v4 REST API. Overridable per-client for tests/mocks.
12
+ DEFAULT_BASE_URL = "https://api.kit.com"
13
+ end
14
+
15
+ require "kit/version"
16
+ require "kit/errors"
17
+ require "kit/configuration"
18
+ require "kit/auth/api_key"
19
+ require "kit/auth/oauth"
20
+ require "kit/connection"
21
+ require "kit/objects/account"
22
+ require "kit/resources/base"
23
+ require "kit/resources/account"
24
+ require "kit/client"
data/sig/kit-rb.rbs ADDED
@@ -0,0 +1,100 @@
1
+ # RBS type signatures for the public surface of kit-rb (P0: account slice).
2
+ # Expanded per-resource as coverage grows in P1/P2.
3
+
4
+ module Kit
5
+ VERSION: String
6
+ DEFAULT_BASE_URL: String
7
+
8
+ class Error < StandardError
9
+ def self.class_for: (Integer status) -> singleton(APIError)
10
+ end
11
+ class ConfigurationError < Error
12
+ end
13
+
14
+ class APIError < Error
15
+ attr_reader status: Integer
16
+ attr_reader body: untyped
17
+ attr_reader errors: Array[untyped]
18
+ attr_reader response: untyped
19
+ def initialize: (?String? message, status: Integer, ?body: untyped, ?response: untyped) -> void
20
+ end
21
+ class AuthenticationError < APIError
22
+ end
23
+ class AuthorizationError < APIError
24
+ end
25
+ class NotFoundError < APIError
26
+ end
27
+ class UnprocessableEntityError < APIError
28
+ end
29
+ class RateLimitError < APIError
30
+ attr_reader retry_after: Integer?
31
+ def initialize: (?String? message, status: Integer, ?body: untyped, ?response: untyped, ?retry_after: Integer?) -> void
32
+ end
33
+ class ServerError < APIError
34
+ end
35
+
36
+ module Auth
37
+ class ApiKey
38
+ HEADER: String
39
+ def initialize: (String key) -> void
40
+ def headers: () -> Hash[String, String]
41
+ end
42
+
43
+ class OAuth
44
+ AUTHORIZE_URL: String
45
+ TOKEN_URL: String
46
+ def initialize: (String access_token) -> void
47
+ def headers: () -> Hash[String, String]
48
+ end
49
+ end
50
+
51
+ class Configuration
52
+ attr_reader auth: (Auth::ApiKey | Auth::OAuth)
53
+ attr_reader base_url: String
54
+ attr_reader open_timeout: Integer
55
+ attr_reader read_timeout: Integer
56
+ def initialize: (?api_key: String?, ?access_token: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer) -> void
57
+ end
58
+
59
+ class Connection
60
+ JSON_TYPE: String
61
+ def initialize: (Configuration config) -> void
62
+ def request: (Symbol method, String path, ?params: Hash[untyped, untyped], ?body: Hash[untyped, untyped]?) -> untyped
63
+ end
64
+
65
+ module Objects
66
+ class User
67
+ attr_reader email: String?
68
+ attr_reader id: Integer?
69
+ def self.from: (Hash[String, untyped] hash) -> User
70
+ end
71
+ class Account
72
+ attr_reader id: Integer?
73
+ attr_reader name: String?
74
+ attr_reader plan_type: String?
75
+ attr_reader primary_email_address: String?
76
+ attr_reader created_at: String?
77
+ def self.from: (Hash[String, untyped] hash) -> Account
78
+ end
79
+ class AccountInfo
80
+ attr_reader user: User
81
+ attr_reader account: Account
82
+ def self.from: (Hash[String, untyped] hash) -> AccountInfo
83
+ end
84
+ end
85
+
86
+ module Resources
87
+ class Base
88
+ def initialize: (Connection connection) -> void
89
+ end
90
+ class Account < Base
91
+ def get: () -> Objects::AccountInfo
92
+ end
93
+ end
94
+
95
+ class Client
96
+ attr_reader config: Configuration
97
+ def initialize: (?api_key: String?, ?access_token: String?, **untyped options) -> void
98
+ def account: () -> Resources::Account
99
+ end
100
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kit-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Lawrence Lin
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: http
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '5.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '5.2'
26
+ description: kit-rb wraps the Kit v4 REST API with API-key and OAuth 2.0 auth, cursor
27
+ pagination, typed errors, and immutable value objects.
28
+ email:
29
+ - deduce@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - CHANGELOG.md
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - Steepfile
39
+ - docs/DESIGN.md
40
+ - lib/kit-rb.rb
41
+ - lib/kit/auth/api_key.rb
42
+ - lib/kit/auth/oauth.rb
43
+ - lib/kit/client.rb
44
+ - lib/kit/configuration.rb
45
+ - lib/kit/connection.rb
46
+ - lib/kit/errors.rb
47
+ - lib/kit/objects/account.rb
48
+ - lib/kit/resources/account.rb
49
+ - lib/kit/resources/base.rb
50
+ - lib/kit/version.rb
51
+ - sig/kit-rb.rbs
52
+ homepage: https://github.com/solcreek/kit-rb
53
+ licenses:
54
+ - MIT
55
+ metadata:
56
+ homepage_uri: https://github.com/solcreek/kit-rb
57
+ source_code_uri: https://github.com/solcreek/kit-rb
58
+ changelog_uri: https://github.com/solcreek/kit-rb/blob/main/CHANGELOG.md
59
+ rubygems_mfa_required: 'true'
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 3.2.0
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.6.9
75
+ specification_version: 4
76
+ summary: A modern, fully-typed Ruby client for the Kit (ConvertKit) API v4.
77
+ test_files: []