kit-rb 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa9f06f61a89d938cb719fcbd0cad578e8dd6d6ffc35fcf9b17d356f6a9160b3
4
- data.tar.gz: 6279b4801b2cd8738b11bcc43babad6b8654739683ace8ff86389e040b8a994b
3
+ metadata.gz: 5c627d63853645447ea42de84d81c8e30141478644e74c844a318af8962e53d2
4
+ data.tar.gz: 1c54a33e809f7d1e66a2342ed361551e8ec6c365e991bd56b1b6e93c5c2a06bd
5
5
  SHA512:
6
- metadata.gz: 3cc4008cae00b1fe78391e5816b3e19040103c86b5d4feedbc8a03fdce856325e969840f4d568c583f2f5a1bd579f69ffd403c7e515cfca611a3ea0eca24b636
7
- data.tar.gz: 279c04700c82548a16c64637d72269d1ad36a06419228e5ba738e603f98f23983f60183078a79c5a166dee45bc40d5f36a50c4b841a969d020acdaa6bdebf8b7
6
+ metadata.gz: 455b8b55b3a263194e59c7567f9ec46e8388eaed94db902f13fdd213e19a2898b3a4d7657adf8862c6edfa8bfdcc32680b395dac4a1edd09cbc3741f9a40e565
7
+ data.tar.gz: 96f26f83e33a0a6d95b573d59a29afd78cb612eef9a6ccba76c5e355f5cb3b6693345c245646fd27d5bb9aeb720ef264f99c5bc9fcd6cea4bdcfa00d5bbc6c44
data/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres
5
5
  to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.2.0] - 2026-09-04
8
+
9
+ ### Changed
10
+ - **Breaking:** the stats and analytics endpoints now return typed value objects
11
+ instead of raw hashes, matching every other resource:
12
+ `broadcasts.stats`/`stats_list` → `Objects::BroadcastStats` (the nested metrics
13
+ flattened), `broadcasts.clicks` → `Collection[Objects::BroadcastClick]`,
14
+ `subscribers.stats` → `Objects::SubscriberStats`, `account.email_stats` →
15
+ `Objects::EmailStats`, and `account.growth_stats` → `Objects::GrowthStats`.
16
+
17
+ ### Removed
18
+ - `Objects::Raw` (the identity used by the old raw-hash stats returns).
19
+
7
20
  ## [0.1.0] - 2026-09-04
8
21
 
9
22
  First feature-complete release: the entire Kit API v4 surface — all 81 documented
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Objects
5
+ # One clicked link in a broadcast's click report
6
+ # (/v4/broadcasts/:id/clicks), with its click totals and rates.
7
+ BroadcastClick = Data.define(
8
+ :id, :url, :unique_clicks, :click_to_delivery_rate, :click_to_open_rate
9
+ ) do
10
+ def self.from(hash)
11
+ new(id: hash["id"], url: hash["url"], unique_clicks: hash["unique_clicks"],
12
+ click_to_delivery_rate: hash["click_to_delivery_rate"],
13
+ click_to_open_rate: hash["click_to_open_rate"])
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Objects
5
+ # Performance stats for a broadcast, as returned by /v4/broadcasts/:id/stats
6
+ # and each row of /v4/broadcasts/stats. The API nests the metrics under a
7
+ # "stats" key alongside id/subject/send_at; this flattens them into one
8
+ # object (subject/send_at are absent on the single-broadcast endpoint).
9
+ BroadcastStats = Data.define(
10
+ :id, :subject, :send_at, :recipients, :open_rate, :emails_opened,
11
+ :click_rate, :unsubscribe_rate, :unsubscribes, :total_clicks,
12
+ :show_total_clicks, :status, :progress, :open_tracking_disabled,
13
+ :click_tracking_disabled
14
+ ) do
15
+ def self.from(hash)
16
+ stats = hash["stats"] || {}
17
+ new(
18
+ id: hash["id"], subject: hash["subject"], send_at: hash["send_at"],
19
+ recipients: stats["recipients"], open_rate: stats["open_rate"],
20
+ emails_opened: stats["emails_opened"], click_rate: stats["click_rate"],
21
+ unsubscribe_rate: stats["unsubscribe_rate"], unsubscribes: stats["unsubscribes"],
22
+ total_clicks: stats["total_clicks"], show_total_clicks: stats["show_total_clicks"],
23
+ status: stats["status"], progress: stats["progress"],
24
+ open_tracking_disabled: stats["open_tracking_disabled"],
25
+ click_tracking_disabled: stats["click_tracking_disabled"]
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Objects
5
+ # Account-wide email engagement stats (/v4/account/email_stats), covering the
6
+ # window [starting, ending].
7
+ EmailStats = Data.define(
8
+ :sent, :clicked, :opened, :email_stats_mode,
9
+ :open_tracking_enabled, :click_tracking_enabled,
10
+ :starting, :ending, :open_rate, :click_rate, :unsubscribe_rate, :bounce_rate
11
+ ) do
12
+ def self.from(hash)
13
+ new(
14
+ sent: hash["sent"], clicked: hash["clicked"], opened: hash["opened"],
15
+ email_stats_mode: hash["email_stats_mode"],
16
+ open_tracking_enabled: hash["open_tracking_enabled"],
17
+ click_tracking_enabled: hash["click_tracking_enabled"],
18
+ starting: hash["starting"], ending: hash["ending"],
19
+ open_rate: hash["open_rate"], click_rate: hash["click_rate"],
20
+ unsubscribe_rate: hash["unsubscribe_rate"], bounce_rate: hash["bounce_rate"]
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Objects
5
+ # Account subscriber-growth stats (/v4/account/growth_stats) over the window
6
+ # [starting, ending].
7
+ GrowthStats = Data.define(
8
+ :cancellations, :net_new_subscribers, :new_subscribers, :subscribers,
9
+ :starting, :ending
10
+ ) do
11
+ def self.from(hash)
12
+ new(
13
+ cancellations: hash["cancellations"], net_new_subscribers: hash["net_new_subscribers"],
14
+ new_subscribers: hash["new_subscribers"], subscribers: hash["subscribers"],
15
+ starting: hash["starting"], ending: hash["ending"]
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kit
4
+ module Objects
5
+ # Engagement stats for a subscriber (/v4/subscribers/:id/stats). The API
6
+ # nests the metrics under "stats" next to the id; this flattens them.
7
+ SubscriberStats = Data.define(
8
+ :id, :sent, :opened, :clicked, :bounced, :open_rate, :click_rate,
9
+ :last_sent, :last_opened, :last_clicked,
10
+ :sends_since_last_open, :sends_since_last_click
11
+ ) do
12
+ def self.from(hash)
13
+ stats = hash["stats"] || {}
14
+ new(
15
+ id: hash["id"], sent: stats["sent"], opened: stats["opened"],
16
+ clicked: stats["clicked"], bounced: stats["bounced"],
17
+ open_rate: stats["open_rate"], click_rate: stats["click_rate"],
18
+ last_sent: stats["last_sent"], last_opened: stats["last_opened"],
19
+ last_clicked: stats["last_clicked"],
20
+ sends_since_last_open: stats["sends_since_last_open"],
21
+ sends_since_last_click: stats["sends_since_last_click"]
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -27,14 +27,15 @@ module Kit
27
27
  one(:get, "/v4/account/creator_profile", "profile", Objects::CreatorProfile)
28
28
  end
29
29
 
30
- # GET /v4/account/email_stats — returns the raw stats hash.
30
+ # GET /v4/account/email_stats — account-wide email engagement stats.
31
31
  def email_stats
32
- http_get("/v4/account/email_stats").fetch("stats")
32
+ one(:get, "/v4/account/email_stats", "stats", Objects::EmailStats)
33
33
  end
34
34
 
35
- # GET /v4/account/growth_stats — raw stats hash; accepts starting/ending.
35
+ # GET /v4/account/growth_stats — subscriber-growth stats; accepts
36
+ # starting/ending to bound the window.
36
37
  def growth_stats(**params)
37
- http_get("/v4/account/growth_stats", params: params).fetch("stats")
38
+ one(:get, "/v4/account/growth_stats", "stats", Objects::GrowthStats, params: params)
38
39
  end
39
40
  end
40
41
  end
@@ -31,21 +31,25 @@ module Kit
31
31
  nil
32
32
  end
33
33
 
34
- # GET /v4/broadcasts/stats — a cursor-paginated list of per-broadcast stats
35
- # ({ "id", "stats", "subject", "send_at" } hashes), not full broadcasts.
34
+ # GET /v4/broadcasts/stats — a cursor-paginated list of per-broadcast stats.
36
35
  def stats_list(**params)
37
- collection("/v4/broadcasts/stats", "broadcasts", Objects::Raw, params)
36
+ collection("/v4/broadcasts/stats", "broadcasts", Objects::BroadcastStats, params)
38
37
  end
39
38
 
40
- # GET /v4/broadcasts/:id/stats — the raw stats hash for one broadcast.
39
+ # GET /v4/broadcasts/:id/stats — one broadcast's performance stats.
41
40
  def stats(id)
42
- http_get("/v4/broadcasts/#{id}/stats").fetch("broadcast")
41
+ one(:get, "/v4/broadcasts/#{id}/stats", "broadcast", Objects::BroadcastStats)
43
42
  end
44
43
 
45
- # GET /v4/broadcasts/:id/clicks — the raw link-click report ({ "id",
46
- # "clicks" => [...] }); accepts pagination params.
44
+ # GET /v4/broadcasts/:id/clicks — a cursor-paginated Collection of the
45
+ # broadcast's clicked links. The API nests the array under "broadcast", so
46
+ # this is built directly rather than through Base#collection.
47
47
  def clicks(id, **params)
48
- http_get("/v4/broadcasts/#{id}/clicks", params: params).fetch("broadcast")
48
+ body = http_get("/v4/broadcasts/#{id}/clicks", params: params)
49
+ rows = body.fetch("broadcast").fetch("clicks").map { |row| Objects::BroadcastClick.from(row) }
50
+ Collection.new(data: rows, pagination: Pagination.from(body.fetch("pagination"))) do |after|
51
+ clicks(id, **params, after: after)
52
+ end
49
53
  end
50
54
  end
51
55
  end
@@ -45,10 +45,9 @@ module Kit
45
45
  collection("/v4/subscribers/#{id}/tags", "tags", Objects::Tag, params)
46
46
  end
47
47
 
48
- # GET /v4/subscribers/:id/stats — engagement stats. Returns the raw
49
- # `subscriber` hash ({ "id" => ..., "stats" => { ... } }).
48
+ # GET /v4/subscribers/:id/stats — the subscriber's engagement stats.
50
49
  def stats(id)
51
- http_get("/v4/subscribers/#{id}/stats").fetch("subscriber")
50
+ one(:get, "/v4/subscribers/#{id}/stats", "subscriber", Objects::SubscriberStats)
52
51
  end
53
52
 
54
53
  # POST /v4/subscribers/:id/location — set the subscriber's location
data/lib/kit/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kit
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/kit-rb.rb CHANGED
@@ -22,7 +22,6 @@ require "kit/pagination"
22
22
  require "kit/oauth/pkce"
23
23
  require "kit/oauth/token"
24
24
  require "kit/oauth/client"
25
- require "kit/objects/raw"
26
25
  require "kit/objects/account"
27
26
  require "kit/objects/creator_profile"
28
27
  require "kit/objects/subscriber"
@@ -32,6 +31,11 @@ require "kit/objects/form"
32
31
  require "kit/objects/sequence"
33
32
  require "kit/objects/sequence_email"
34
33
  require "kit/objects/broadcast"
34
+ require "kit/objects/broadcast_stats"
35
+ require "kit/objects/broadcast_click"
36
+ require "kit/objects/subscriber_stats"
37
+ require "kit/objects/email_stats"
38
+ require "kit/objects/growth_stats"
35
39
  require "kit/objects/webhook"
36
40
  require "kit/objects/webhook_endpoint"
37
41
  require "kit/objects/email_template"
data/sig/kit-rb.rbs CHANGED
@@ -126,9 +126,6 @@ module Kit
126
126
  end
127
127
 
128
128
  module Objects
129
- module Raw
130
- def self.from: (Hash[String, untyped] hash) -> Hash[String, untyped]
131
- end
132
129
  class User
133
130
  attr_reader email: String?
134
131
  attr_reader id: Integer?
@@ -314,6 +311,71 @@ module Kit
314
311
  attr_reader stats: Hash[String, untyped]?
315
312
  def self.from: (Hash[String, untyped] hash) -> SequenceEmail
316
313
  end
314
+ class BroadcastStats
315
+ attr_reader id: Integer?
316
+ attr_reader subject: String?
317
+ attr_reader send_at: String?
318
+ attr_reader recipients: Integer?
319
+ attr_reader open_rate: Numeric?
320
+ attr_reader emails_opened: Integer?
321
+ attr_reader click_rate: Numeric?
322
+ attr_reader unsubscribe_rate: Numeric?
323
+ attr_reader unsubscribes: Integer?
324
+ attr_reader total_clicks: Integer?
325
+ attr_reader show_total_clicks: bool?
326
+ attr_reader status: String?
327
+ attr_reader progress: Numeric?
328
+ attr_reader open_tracking_disabled: bool?
329
+ attr_reader click_tracking_disabled: bool?
330
+ def self.from: (Hash[String, untyped] hash) -> BroadcastStats
331
+ end
332
+ class BroadcastClick
333
+ attr_reader id: Integer?
334
+ attr_reader url: String?
335
+ attr_reader unique_clicks: Integer?
336
+ attr_reader click_to_delivery_rate: Numeric?
337
+ attr_reader click_to_open_rate: Numeric?
338
+ def self.from: (Hash[String, untyped] hash) -> BroadcastClick
339
+ end
340
+ class SubscriberStats
341
+ attr_reader id: Integer?
342
+ attr_reader sent: Integer?
343
+ attr_reader opened: Integer?
344
+ attr_reader clicked: Integer?
345
+ attr_reader bounced: Integer?
346
+ attr_reader open_rate: Numeric?
347
+ attr_reader click_rate: Numeric?
348
+ attr_reader last_sent: String?
349
+ attr_reader last_opened: String?
350
+ attr_reader last_clicked: String?
351
+ attr_reader sends_since_last_open: Integer?
352
+ attr_reader sends_since_last_click: Integer?
353
+ def self.from: (Hash[String, untyped] hash) -> SubscriberStats
354
+ end
355
+ class EmailStats
356
+ attr_reader sent: Integer?
357
+ attr_reader clicked: Integer?
358
+ attr_reader opened: Integer?
359
+ attr_reader email_stats_mode: String?
360
+ attr_reader open_tracking_enabled: bool?
361
+ attr_reader click_tracking_enabled: bool?
362
+ attr_reader starting: String?
363
+ attr_reader ending: String?
364
+ attr_reader open_rate: Numeric?
365
+ attr_reader click_rate: Numeric?
366
+ attr_reader unsubscribe_rate: Numeric?
367
+ attr_reader bounce_rate: Numeric?
368
+ def self.from: (Hash[String, untyped] hash) -> EmailStats
369
+ end
370
+ class GrowthStats
371
+ attr_reader cancellations: Integer?
372
+ attr_reader net_new_subscribers: Integer?
373
+ attr_reader new_subscribers: Integer?
374
+ attr_reader subscribers: Integer?
375
+ attr_reader starting: String?
376
+ attr_reader ending: String?
377
+ def self.from: (Hash[String, untyped] hash) -> GrowthStats
378
+ end
317
379
  class Subscriber
318
380
  attr_reader id: Integer?
319
381
  attr_reader first_name: String?
@@ -336,8 +398,8 @@ module Kit
336
398
  def colors: () -> Array[String]
337
399
  def update_colors: (Array[String] colors) -> Array[String]
338
400
  def creator_profile: () -> Objects::CreatorProfile
339
- def email_stats: () -> Hash[String, untyped]
340
- def growth_stats: (**untyped params) -> Hash[String, untyped]
401
+ def email_stats: () -> Objects::EmailStats
402
+ def growth_stats: (**untyped params) -> Objects::GrowthStats
341
403
  end
342
404
  class Subscribers < Base
343
405
  def list: (**untyped params) -> Collection[Objects::Subscriber]
@@ -347,7 +409,7 @@ module Kit
347
409
  def unsubscribe: (Integer id) -> Objects::Subscriber
348
410
  def filter: (**untyped params) -> Collection[Objects::Subscriber]
349
411
  def tags: (Integer id, **untyped params) -> Collection[Objects::Tag]
350
- def stats: (Integer id) -> Hash[String, untyped]
412
+ def stats: (Integer id) -> Objects::SubscriberStats
351
413
  def set_location: (Integer id, location: Hash[untyped, untyped]) -> Objects::Subscriber
352
414
  def remove_location: (Integer id) -> void
353
415
  end
@@ -394,9 +456,9 @@ module Kit
394
456
  def create: (**untyped attributes) -> Objects::Broadcast
395
457
  def update: (Integer id, **untyped attributes) -> Objects::Broadcast
396
458
  def delete: (Integer id) -> void
397
- def stats_list: (**untyped params) -> Collection[Hash[String, untyped]]
398
- def stats: (Integer id) -> Hash[String, untyped]
399
- def clicks: (Integer id, **untyped params) -> Hash[String, untyped]
459
+ def stats_list: (**untyped params) -> Collection[Objects::BroadcastStats]
460
+ def stats: (Integer id) -> Objects::BroadcastStats
461
+ def clicks: (Integer id, **untyped params) -> Collection[Objects::BroadcastClick]
400
462
  end
401
463
  class EmailTemplates < Base
402
464
  def list: (**untyped params) -> Collection[Objects::EmailTemplate]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kit-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lawrence Lin
@@ -49,18 +49,22 @@ files:
49
49
  - lib/kit/oauth/token.rb
50
50
  - lib/kit/objects/account.rb
51
51
  - lib/kit/objects/broadcast.rb
52
+ - lib/kit/objects/broadcast_click.rb
53
+ - lib/kit/objects/broadcast_stats.rb
52
54
  - lib/kit/objects/creator_profile.rb
53
55
  - lib/kit/objects/custom_field.rb
56
+ - lib/kit/objects/email_stats.rb
54
57
  - lib/kit/objects/email_template.rb
55
58
  - lib/kit/objects/form.rb
59
+ - lib/kit/objects/growth_stats.rb
56
60
  - lib/kit/objects/post.rb
57
61
  - lib/kit/objects/purchase.rb
58
- - lib/kit/objects/raw.rb
59
62
  - lib/kit/objects/segment.rb
60
63
  - lib/kit/objects/sequence.rb
61
64
  - lib/kit/objects/sequence_email.rb
62
65
  - lib/kit/objects/snippet.rb
63
66
  - lib/kit/objects/subscriber.rb
67
+ - lib/kit/objects/subscriber_stats.rb
64
68
  - lib/kit/objects/tag.rb
65
69
  - lib/kit/objects/webhook.rb
66
70
  - lib/kit/objects/webhook_endpoint.rb
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kit
4
- module Objects
5
- # Identity "object" for endpoints that return plain analytics hashes rather
6
- # than a modelled resource (e.g. the broadcast-stats list). Lets those lists
7
- # flow through Base#collection unchanged while keeping .from uniform.
8
- module Raw
9
- def self.from(hash) = hash
10
- end
11
- end
12
- end