trycourier 6.5.0 → 6.7.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/README.md +1 -1
  4. data/lib/courier/models/create_journey_request.rb +16 -1
  5. data/lib/courier/models/digest_day_of_week.rb +21 -0
  6. data/lib/courier/models/digest_frequency.rb +21 -0
  7. data/lib/courier/models/journey_conditions_field.rb +11 -1
  8. data/lib/courier/models/journey_node.rb +17 -2
  9. data/lib/courier/models/journey_response.rb +14 -1
  10. data/lib/courier/models/topic_digest_category.rb +71 -0
  11. data/lib/courier/models/topic_digest_release_request.rb +35 -0
  12. data/lib/courier/models/topic_digest_request.rb +75 -0
  13. data/lib/courier/models/topic_digest_response.rb +66 -0
  14. data/lib/courier/models/topic_digest_schedule_request.rb +99 -0
  15. data/lib/courier/models/topic_digest_schedule_response.rb +111 -0
  16. data/lib/courier/models/users/preference_update_or_create_topic_params.rb +13 -1
  17. data/lib/courier/models/users/topic_preference.rb +17 -1
  18. data/lib/courier/models/workspace_preference_topic_create_request.rb +97 -1
  19. data/lib/courier/models/workspace_preference_topic_get_response.rb +9 -1
  20. data/lib/courier/models/workspace_preference_topic_replace_request.rb +15 -1
  21. data/lib/courier/models/workspace_preferences/topic_delete_digest_params.rb +28 -0
  22. data/lib/courier/models/workspace_preferences/topic_release_digest_params.rb +28 -0
  23. data/lib/courier/models.rb +16 -0
  24. data/lib/courier/resources/digests/schedules.rb +1 -1
  25. data/lib/courier/resources/journeys.rb +9 -2
  26. data/lib/courier/resources/workspace_preferences/topics.rb +77 -4
  27. data/lib/courier/resources/workspace_preferences.rb +0 -2
  28. data/lib/courier/version.rb +1 -1
  29. data/lib/courier.rb +10 -0
  30. data/rbi/courier/models/create_journey_request.rbi +19 -0
  31. data/rbi/courier/models/digest_day_of_week.rbi +25 -0
  32. data/rbi/courier/models/digest_frequency.rbi +25 -0
  33. data/rbi/courier/models/journey_node.rbi +12 -1
  34. data/rbi/courier/models/journey_response.rbi +12 -0
  35. data/rbi/courier/models/topic_digest_category.rbi +116 -0
  36. data/rbi/courier/models/topic_digest_release_request.rbi +51 -0
  37. data/rbi/courier/models/topic_digest_request.rbi +126 -0
  38. data/rbi/courier/models/topic_digest_response.rbi +98 -0
  39. data/rbi/courier/models/topic_digest_schedule_request.rbi +147 -0
  40. data/rbi/courier/models/topic_digest_schedule_response.rbi +175 -0
  41. data/rbi/courier/models/users/preference_update_or_create_topic_params.rbi +16 -0
  42. data/rbi/courier/models/users/topic_preference.rbi +27 -0
  43. data/rbi/courier/models/workspace_preference_topic_create_request.rbi +172 -0
  44. data/rbi/courier/models/workspace_preference_topic_get_response.rbi +13 -0
  45. data/rbi/courier/models/workspace_preference_topic_replace_request.rbi +25 -0
  46. data/rbi/courier/models/workspace_preferences/topic_delete_digest_params.rbi +48 -0
  47. data/rbi/courier/models/workspace_preferences/topic_release_digest_params.rbi +48 -0
  48. data/rbi/courier/models.rbi +16 -0
  49. data/rbi/courier/resources/digests/schedules.rbi +5 -2
  50. data/rbi/courier/resources/journeys.rbi +14 -0
  51. data/rbi/courier/resources/workspace_preferences/topics.rbi +80 -2
  52. data/rbi/courier/resources/workspace_preferences.rbi +0 -2
  53. data/sig/courier/models/create_journey_request.rbs +7 -0
  54. data/sig/courier/models/digest_day_of_week.rbs +26 -0
  55. data/sig/courier/models/digest_frequency.rbs +19 -0
  56. data/sig/courier/models/journey_response.rbs +5 -0
  57. data/sig/courier/models/topic_digest_category.rbs +57 -0
  58. data/sig/courier/models/topic_digest_release_request.rbs +17 -0
  59. data/sig/courier/models/topic_digest_request.rbs +52 -0
  60. data/sig/courier/models/topic_digest_response.rbs +58 -0
  61. data/sig/courier/models/topic_digest_schedule_request.rbs +80 -0
  62. data/sig/courier/models/topic_digest_schedule_response.rbs +96 -0
  63. data/sig/courier/models/users/preference_update_or_create_topic_params.rbs +5 -0
  64. data/sig/courier/models/users/topic_preference.rbs +7 -0
  65. data/sig/courier/models/workspace_preference_topic_create_request.rbs +50 -0
  66. data/sig/courier/models/workspace_preference_topic_get_response.rbs +5 -0
  67. data/sig/courier/models/workspace_preference_topic_replace_request.rbs +5 -0
  68. data/sig/courier/models/workspace_preferences/topic_delete_digest_params.rbs +30 -0
  69. data/sig/courier/models/workspace_preferences/topic_release_digest_params.rbs +34 -0
  70. data/sig/courier/models.rbs +16 -0
  71. data/sig/courier/resources/journeys.rbs +2 -0
  72. data/sig/courier/resources/workspace_preferences/topics.rbs +16 -0
  73. metadata +32 -2
data/lib/courier.rb CHANGED
@@ -94,6 +94,7 @@ require_relative "courier/models/workspace_preference_create_request"
94
94
  require_relative "courier/models/publish_preferences_request"
95
95
  require_relative "courier/models/workspace_preference_replace_request"
96
96
  require_relative "courier/models/workspace_preference_topic_create_request"
97
+ require_relative "courier/models/topic_digest_release_request"
97
98
  require_relative "courier/models/workspace_preference_topic_replace_request"
98
99
  require_relative "courier/models/airship_profile"
99
100
  require_relative "courier/models/airship_profile_audience"
@@ -175,6 +176,8 @@ require_relative "courier/models/check"
175
176
  require_relative "courier/models/default_preferences"
176
177
  require_relative "courier/models/device_type"
177
178
  require_relative "courier/models/digest_category"
179
+ require_relative "courier/models/digest_day_of_week"
180
+ require_relative "courier/models/digest_frequency"
178
181
  require_relative "courier/models/digest_instance"
179
182
  require_relative "courier/models/digest_instance_list_response"
180
183
  require_relative "courier/models/digests/schedule_list_instances_params"
@@ -421,6 +424,11 @@ require_relative "courier/models/tenant_update_params"
421
424
  require_relative "courier/models/text_style"
422
425
  require_relative "courier/models/timeouts"
423
426
  require_relative "courier/models/token"
427
+ require_relative "courier/models/topic_digest_category"
428
+ require_relative "courier/models/topic_digest_request"
429
+ require_relative "courier/models/topic_digest_response"
430
+ require_relative "courier/models/topic_digest_schedule_request"
431
+ require_relative "courier/models/topic_digest_schedule_response"
424
432
  require_relative "courier/models/translation_retrieve_params"
425
433
  require_relative "courier/models/translation_retrieve_response"
426
434
  require_relative "courier/models/translation_update_params"
@@ -473,7 +481,9 @@ require_relative "courier/models/workspace_preference_replace_params"
473
481
  require_relative "courier/models/workspace_preference_retrieve_params"
474
482
  require_relative "courier/models/workspace_preferences/topic_archive_params"
475
483
  require_relative "courier/models/workspace_preferences/topic_create_params"
484
+ require_relative "courier/models/workspace_preferences/topic_delete_digest_params"
476
485
  require_relative "courier/models/workspace_preferences/topic_list_params"
486
+ require_relative "courier/models/workspace_preferences/topic_release_digest_params"
477
487
  require_relative "courier/models/workspace_preferences/topic_replace_params"
478
488
  require_relative "courier/models/workspace_preferences/topic_retrieve_params"
479
489
  require_relative "courier/models/workspace_preference_topic_get_response"
@@ -37,6 +37,17 @@ module Courier
37
37
  end
38
38
  attr_accessor :nodes
39
39
 
40
+ # Cancelation token stored on the journey definition. It tags every run the
41
+ # journey creates so that `POST /journeys/cancel` can later cancel those runs by
42
+ # token. Accepts a templated string such as `order-{{data.order_id}}`, which is
43
+ # resolved per run when the journey is invoked. On a replace, omitting this field
44
+ # preserves any existing token and sending a value replaces it.
45
+ sig { returns(T.nilable(String)) }
46
+ attr_reader :cancelation_token
47
+
48
+ sig { params(cancelation_token: String).void }
49
+ attr_writer :cancelation_token
50
+
40
51
  sig { returns(T.nilable(T::Boolean)) }
41
52
  attr_reader :enabled
42
53
 
@@ -75,6 +86,7 @@ module Courier
75
86
  Courier::JourneyNode::JourneyBranchNode::OrHash
76
87
  )
77
88
  ],
89
+ cancelation_token: String,
78
90
  enabled: T::Boolean,
79
91
  state: Courier::JourneyState::OrSymbol
80
92
  ).returns(T.attached_class)
@@ -82,6 +94,12 @@ module Courier
82
94
  def self.new(
83
95
  name:,
84
96
  nodes:,
97
+ # Cancelation token stored on the journey definition. It tags every run the
98
+ # journey creates so that `POST /journeys/cancel` can later cancel those runs by
99
+ # token. Accepts a templated string such as `order-{{data.order_id}}`, which is
100
+ # resolved per run when the journey is invoked. On a replace, omitting this field
101
+ # preserves any existing token and sending a value replaces it.
102
+ cancelation_token: nil,
85
103
  enabled: nil,
86
104
  # Lifecycle state of a journey.
87
105
  state: nil
@@ -113,6 +131,7 @@ module Courier
113
131
  Courier::JourneyNode::JourneyBranchNode
114
132
  )
115
133
  ],
134
+ cancelation_token: String,
116
135
  enabled: T::Boolean,
117
136
  state: Courier::JourneyState::OrSymbol
118
137
  }
@@ -0,0 +1,25 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ # A day of the week. Accepted case-insensitively, returned lowercase.
6
+ module DigestDayOfWeek
7
+ extend Courier::Internal::Type::Enum
8
+
9
+ TaggedSymbol = T.type_alias { T.all(Symbol, Courier::DigestDayOfWeek) }
10
+ OrSymbol = T.type_alias { T.any(Symbol, String) }
11
+
12
+ SUNDAY = T.let(:sunday, Courier::DigestDayOfWeek::TaggedSymbol)
13
+ MONDAY = T.let(:monday, Courier::DigestDayOfWeek::TaggedSymbol)
14
+ TUESDAY = T.let(:tuesday, Courier::DigestDayOfWeek::TaggedSymbol)
15
+ WEDNESDAY = T.let(:wednesday, Courier::DigestDayOfWeek::TaggedSymbol)
16
+ THURSDAY = T.let(:thursday, Courier::DigestDayOfWeek::TaggedSymbol)
17
+ FRIDAY = T.let(:friday, Courier::DigestDayOfWeek::TaggedSymbol)
18
+ SATURDAY = T.let(:saturday, Courier::DigestDayOfWeek::TaggedSymbol)
19
+
20
+ sig { override.returns(T::Array[Courier::DigestDayOfWeek::TaggedSymbol]) }
21
+ def self.values
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ # How often a digest is delivered. `instant` delivers immediately without
6
+ # batching, and is the one value that takes no `time`.
7
+ module DigestFrequency
8
+ extend Courier::Internal::Type::Enum
9
+
10
+ TaggedSymbol = T.type_alias { T.all(Symbol, Courier::DigestFrequency) }
11
+ OrSymbol = T.type_alias { T.any(Symbol, String) }
12
+
13
+ INSTANT = T.let(:instant, Courier::DigestFrequency::TaggedSymbol)
14
+ DAILY = T.let(:daily, Courier::DigestFrequency::TaggedSymbol)
15
+ WEEKDAYS = T.let(:weekdays, Courier::DigestFrequency::TaggedSymbol)
16
+ WEEKLY = T.let(:weekly, Courier::DigestFrequency::TaggedSymbol)
17
+ CUSTOM_DAYS = T.let(:custom_days, Courier::DigestFrequency::TaggedSymbol)
18
+ MONTHLY = T.let(:monthly, Courier::DigestFrequency::TaggedSymbol)
19
+
20
+ sig { override.returns(T::Array[Courier::DigestFrequency::TaggedSymbol]) }
21
+ def self.values
22
+ end
23
+ end
24
+ end
25
+ end
@@ -398,7 +398,18 @@ module Courier
398
398
 
399
399
  # Add the current event to a digest keyed by the given subscription topic. The
400
400
  # digest accumulates events and releases them on the schedule configured for the
401
- # topic.
401
+ # topic, using the notification template configured on that topic. This node's
402
+ # `type` value is `add-to-digest`.
403
+ #
404
+ # **The topic must have a template configured.** If the topic has no template when
405
+ # the first event reaches this node, the journey run fails immediately: the run is
406
+ # marked `ERROR`, no digest instance is created, and the journey does not continue
407
+ # past this node. Configure the topic's template before using the topic in a
408
+ # journey.
409
+ #
410
+ # If the journey run is scoped to a tenant, digests are kept separate per tenant:
411
+ # two runs for the same user under different tenants accumulate and release as
412
+ # separate digests, even on the same topic.
402
413
  sig do
403
414
  params(
404
415
  subscription_topic_id: String,
@@ -11,6 +11,12 @@ module Courier
11
11
  sig { returns(String) }
12
12
  attr_accessor :id
13
13
 
14
+ # The journey cancelation token, or null when none is set. A token authored in the
15
+ # dashboard is returned in its raw templated form, such as
16
+ # `order-{{data.order_id}}`, so it can be read back and asserted.
17
+ sig { returns(T.nilable(String)) }
18
+ attr_accessor :cancelation_token
19
+
14
20
  sig { returns(T.nilable(Integer)) }
15
21
  attr_accessor :created
16
22
 
@@ -43,6 +49,7 @@ module Courier
43
49
  sig do
44
50
  params(
45
51
  id: String,
52
+ cancelation_token: T.nilable(String),
46
53
  created: T.nilable(Integer),
47
54
  creator: T.nilable(String),
48
55
  enabled: T::Boolean,
@@ -76,6 +83,10 @@ module Courier
76
83
  end
77
84
  def self.new(
78
85
  id:,
86
+ # The journey cancelation token, or null when none is set. A token authored in the
87
+ # dashboard is returned in its raw templated form, such as
88
+ # `order-{{data.order_id}}`, so it can be read back and asserted.
89
+ cancelation_token:,
79
90
  created:,
80
91
  creator:,
81
92
  enabled:,
@@ -93,6 +104,7 @@ module Courier
93
104
  override.returns(
94
105
  {
95
106
  id: String,
107
+ cancelation_token: T.nilable(String),
96
108
  created: T.nilable(Integer),
97
109
  creator: T.nilable(String),
98
110
  enabled: T::Boolean,
@@ -0,0 +1,116 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ class TopicDigestCategory < Courier::Internal::Type::BaseModel
6
+ OrHash =
7
+ T.type_alias do
8
+ T.any(Courier::TopicDigestCategory, Courier::Internal::AnyHash)
9
+ end
10
+
11
+ # The key that identifies the category within the digest.
12
+ sig { returns(String) }
13
+ attr_accessor :category_key
14
+
15
+ # How many collected events are carried into the rendered digest. Defaults to 10.
16
+ #
17
+ # Events beyond the limit are discarded, not held back for the next digest: the
18
+ # release consumes everything collected so far and only `limit` of them appear.
19
+ # `retain` decides which ones those are.
20
+ sig { returns(T.nilable(Integer)) }
21
+ attr_reader :limit
22
+
23
+ sig { params(limit: Integer).void }
24
+ attr_writer :limit
25
+
26
+ # Which collected events survive the `limit`. `FIRST` and `LOWEST` keep the
27
+ # earliest or smallest; `LAST` and `HIGHEST` keep the latest or largest. Accepted
28
+ # case-insensitively, returned uppercase.
29
+ sig { returns(T.nilable(Courier::TopicDigestCategory::Retain::OrSymbol)) }
30
+ attr_reader :retain
31
+
32
+ sig do
33
+ params(retain: Courier::TopicDigestCategory::Retain::OrSymbol).void
34
+ end
35
+ attr_writer :retain
36
+
37
+ # The data key used to rank events. Required when `retain` is `HIGHEST` or
38
+ # `LOWEST`.
39
+ sig { returns(T.nilable(String)) }
40
+ attr_reader :sort_key
41
+
42
+ sig { params(sort_key: String).void }
43
+ attr_writer :sort_key
44
+
45
+ # How events collected under a category key are retained when a digest holds more
46
+ # than it will render.
47
+ sig do
48
+ params(
49
+ category_key: String,
50
+ limit: Integer,
51
+ retain: Courier::TopicDigestCategory::Retain::OrSymbol,
52
+ sort_key: String
53
+ ).returns(T.attached_class)
54
+ end
55
+ def self.new(
56
+ # The key that identifies the category within the digest.
57
+ category_key:,
58
+ # How many collected events are carried into the rendered digest. Defaults to 10.
59
+ #
60
+ # Events beyond the limit are discarded, not held back for the next digest: the
61
+ # release consumes everything collected so far and only `limit` of them appear.
62
+ # `retain` decides which ones those are.
63
+ limit: nil,
64
+ # Which collected events survive the `limit`. `FIRST` and `LOWEST` keep the
65
+ # earliest or smallest; `LAST` and `HIGHEST` keep the latest or largest. Accepted
66
+ # case-insensitively, returned uppercase.
67
+ retain: nil,
68
+ # The data key used to rank events. Required when `retain` is `HIGHEST` or
69
+ # `LOWEST`.
70
+ sort_key: nil
71
+ )
72
+ end
73
+
74
+ sig do
75
+ override.returns(
76
+ {
77
+ category_key: String,
78
+ limit: Integer,
79
+ retain: Courier::TopicDigestCategory::Retain::OrSymbol,
80
+ sort_key: String
81
+ }
82
+ )
83
+ end
84
+ def to_hash
85
+ end
86
+
87
+ # Which collected events survive the `limit`. `FIRST` and `LOWEST` keep the
88
+ # earliest or smallest; `LAST` and `HIGHEST` keep the latest or largest. Accepted
89
+ # case-insensitively, returned uppercase.
90
+ module Retain
91
+ extend Courier::Internal::Type::Enum
92
+
93
+ TaggedSymbol =
94
+ T.type_alias { T.all(Symbol, Courier::TopicDigestCategory::Retain) }
95
+ OrSymbol = T.type_alias { T.any(Symbol, String) }
96
+
97
+ FIRST =
98
+ T.let(:FIRST, Courier::TopicDigestCategory::Retain::TaggedSymbol)
99
+ LAST = T.let(:LAST, Courier::TopicDigestCategory::Retain::TaggedSymbol)
100
+ HIGHEST =
101
+ T.let(:HIGHEST, Courier::TopicDigestCategory::Retain::TaggedSymbol)
102
+ LOWEST =
103
+ T.let(:LOWEST, Courier::TopicDigestCategory::Retain::TaggedSymbol)
104
+ NONE = T.let(:NONE, Courier::TopicDigestCategory::Retain::TaggedSymbol)
105
+
106
+ sig do
107
+ override.returns(
108
+ T::Array[Courier::TopicDigestCategory::Retain::TaggedSymbol]
109
+ )
110
+ end
111
+ def self.values
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,51 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ class TopicDigestReleaseRequest < Courier::Internal::Type::BaseModel
6
+ OrHash =
7
+ T.type_alias do
8
+ T.any(Courier::TopicDigestReleaseRequest, Courier::Internal::AnyHash)
9
+ end
10
+
11
+ # The recipient whose digest to release. Required: there is no "release everyone
12
+ # on this topic" form, because a whole-schedule flush already has its own endpoint
13
+ # and a body-shaped difference between one recipient and all of them is too easy
14
+ # to get wrong.
15
+ sig { returns(String) }
16
+ attr_accessor :user_id
17
+
18
+ # The recipient's tenant, when they were sent to as part of one -- the same value
19
+ # returned as `tenant_id` on a digest instance and sent as
20
+ # `message.context.tenant_id`. It is part of the held digest's key, so a tenanted
21
+ # recipient cannot be found without it. Omit for an ordinary recipient.
22
+ sig { returns(T.nilable(String)) }
23
+ attr_reader :tenant_id
24
+
25
+ sig { params(tenant_id: String).void }
26
+ attr_writer :tenant_id
27
+
28
+ # Which recipient's held digest to release.
29
+ sig do
30
+ params(user_id: String, tenant_id: String).returns(T.attached_class)
31
+ end
32
+ def self.new(
33
+ # The recipient whose digest to release. Required: there is no "release everyone
34
+ # on this topic" form, because a whole-schedule flush already has its own endpoint
35
+ # and a body-shaped difference between one recipient and all of them is too easy
36
+ # to get wrong.
37
+ user_id:,
38
+ # The recipient's tenant, when they were sent to as part of one -- the same value
39
+ # returned as `tenant_id` on a digest instance and sent as
40
+ # `message.context.tenant_id`. It is part of the held digest's key, so a tenanted
41
+ # recipient cannot be found without it. Omit for an ordinary recipient.
42
+ tenant_id: nil
43
+ )
44
+ end
45
+
46
+ sig { override.returns({ user_id: String, tenant_id: String }) }
47
+ def to_hash
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,126 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ class TopicDigestRequest < Courier::Internal::Type::BaseModel
6
+ OrHash =
7
+ T.type_alias do
8
+ T.any(Courier::TopicDigestRequest, Courier::Internal::AnyHash)
9
+ end
10
+
11
+ # The notification template that renders the digest. A digest with no template
12
+ # collects nothing, so this is required.
13
+ sig { returns(String) }
14
+ attr_accessor :template_id
15
+
16
+ # Optional audience the digest is scoped to.
17
+ sig { returns(T.nilable(String)) }
18
+ attr_reader :audience_id
19
+
20
+ sig { params(audience_id: String).void }
21
+ attr_writer :audience_id
22
+
23
+ # Retention rules per category key. Defaults to a single `digest` category
24
+ # retaining `FIRST`.
25
+ sig { returns(T.nilable(T::Array[Courier::TopicDigestCategory])) }
26
+ attr_reader :categories
27
+
28
+ sig do
29
+ params(categories: T::Array[Courier::TopicDigestCategory::OrHash]).void
30
+ end
31
+ attr_writer :categories
32
+
33
+ # The cadences this digest delivers on.
34
+ #
35
+ # The array replaces the stored schedules wholesale, so a schedule you leave out
36
+ # of it is deleted along with its delivery rule. Omit the key entirely to leave
37
+ # the stored schedules untouched — useful for changing `template_id` or
38
+ # `categories` without restating every schedule.
39
+ #
40
+ # A digest must end up with at least one schedule, because one with none collects
41
+ # events into an instance that can never fire. So sending `[]` is always a `400`,
42
+ # and so is omitting the key on a topic that has no schedules stored yet.
43
+ #
44
+ # On **create** the key is required outright: a topic being created has nothing
45
+ # stored to leave alone, and the topic row is written before its digest, so
46
+ # rejecting it any later would leave the topic behind and let a retry duplicate
47
+ # it.
48
+ sig { returns(T.nilable(T::Array[Courier::TopicDigestScheduleRequest])) }
49
+ attr_reader :schedules
50
+
51
+ sig do
52
+ params(
53
+ schedules: T::Array[Courier::TopicDigestScheduleRequest::OrHash]
54
+ ).void
55
+ end
56
+ attr_writer :schedules
57
+
58
+ # Whether to deliver the digest even when nothing was collected.
59
+ sig { returns(T.nilable(T::Boolean)) }
60
+ attr_reader :trigger_empty
61
+
62
+ sig { params(trigger_empty: T::Boolean).void }
63
+ attr_writer :trigger_empty
64
+
65
+ # A topic's digest configuration: the template that renders it, the cadences it
66
+ # delivers on, and how collected events are retained.
67
+ #
68
+ # Send `null` for the whole object to turn a digest off, which unlinks the
69
+ # template and removes its schedules. There is no `enabled` flag, and
70
+ # `schedules: []` is rejected, because both states are un-deliverable rather than
71
+ # merely off.
72
+ sig do
73
+ params(
74
+ template_id: String,
75
+ audience_id: String,
76
+ categories: T::Array[Courier::TopicDigestCategory::OrHash],
77
+ schedules: T::Array[Courier::TopicDigestScheduleRequest::OrHash],
78
+ trigger_empty: T::Boolean
79
+ ).returns(T.attached_class)
80
+ end
81
+ def self.new(
82
+ # The notification template that renders the digest. A digest with no template
83
+ # collects nothing, so this is required.
84
+ template_id:,
85
+ # Optional audience the digest is scoped to.
86
+ audience_id: nil,
87
+ # Retention rules per category key. Defaults to a single `digest` category
88
+ # retaining `FIRST`.
89
+ categories: nil,
90
+ # The cadences this digest delivers on.
91
+ #
92
+ # The array replaces the stored schedules wholesale, so a schedule you leave out
93
+ # of it is deleted along with its delivery rule. Omit the key entirely to leave
94
+ # the stored schedules untouched — useful for changing `template_id` or
95
+ # `categories` without restating every schedule.
96
+ #
97
+ # A digest must end up with at least one schedule, because one with none collects
98
+ # events into an instance that can never fire. So sending `[]` is always a `400`,
99
+ # and so is omitting the key on a topic that has no schedules stored yet.
100
+ #
101
+ # On **create** the key is required outright: a topic being created has nothing
102
+ # stored to leave alone, and the topic row is written before its digest, so
103
+ # rejecting it any later would leave the topic behind and let a retry duplicate
104
+ # it.
105
+ schedules: nil,
106
+ # Whether to deliver the digest even when nothing was collected.
107
+ trigger_empty: nil
108
+ )
109
+ end
110
+
111
+ sig do
112
+ override.returns(
113
+ {
114
+ template_id: String,
115
+ audience_id: String,
116
+ categories: T::Array[Courier::TopicDigestCategory],
117
+ schedules: T::Array[Courier::TopicDigestScheduleRequest],
118
+ trigger_empty: T::Boolean
119
+ }
120
+ )
121
+ end
122
+ def to_hash
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,98 @@
1
+ # typed: strong
2
+
3
+ module Courier
4
+ module Models
5
+ class TopicDigestResponse < Courier::Internal::Type::BaseModel
6
+ OrHash =
7
+ T.type_alias do
8
+ T.any(Courier::TopicDigestResponse, Courier::Internal::AnyHash)
9
+ end
10
+
11
+ # Retention rules per category key.
12
+ sig { returns(T::Array[Courier::TopicDigestCategory]) }
13
+ attr_accessor :categories
14
+
15
+ # The digest's delivery cadences, each with its server-assigned `schedule_id`.
16
+ sig { returns(T::Array[Courier::TopicDigestScheduleResponse]) }
17
+ attr_accessor :schedules
18
+
19
+ # The notification template that renders the digest.
20
+ sig { returns(String) }
21
+ attr_accessor :template_id
22
+
23
+ # The audience the digest is scoped to, when set.
24
+ sig { returns(T.nilable(String)) }
25
+ attr_reader :audience_id
26
+
27
+ sig { params(audience_id: String).void }
28
+ attr_writer :audience_id
29
+
30
+ # ISO-8601 timestamp of when the digest was configured.
31
+ sig { returns(T.nilable(String)) }
32
+ attr_reader :created
33
+
34
+ sig { params(created: String).void }
35
+ attr_writer :created
36
+
37
+ # Whether the digest is delivered even when nothing was collected.
38
+ sig { returns(T.nilable(T::Boolean)) }
39
+ attr_reader :trigger_empty
40
+
41
+ sig { params(trigger_empty: T::Boolean).void }
42
+ attr_writer :trigger_empty
43
+
44
+ # ISO-8601 timestamp of the last update.
45
+ sig { returns(T.nilable(String)) }
46
+ attr_reader :updated
47
+
48
+ sig { params(updated: String).void }
49
+ attr_writer :updated
50
+
51
+ # A topic's digest configuration.
52
+ sig do
53
+ params(
54
+ categories: T::Array[Courier::TopicDigestCategory::OrHash],
55
+ schedules: T::Array[Courier::TopicDigestScheduleResponse::OrHash],
56
+ template_id: String,
57
+ audience_id: String,
58
+ created: String,
59
+ trigger_empty: T::Boolean,
60
+ updated: String
61
+ ).returns(T.attached_class)
62
+ end
63
+ def self.new(
64
+ # Retention rules per category key.
65
+ categories:,
66
+ # The digest's delivery cadences, each with its server-assigned `schedule_id`.
67
+ schedules:,
68
+ # The notification template that renders the digest.
69
+ template_id:,
70
+ # The audience the digest is scoped to, when set.
71
+ audience_id: nil,
72
+ # ISO-8601 timestamp of when the digest was configured.
73
+ created: nil,
74
+ # Whether the digest is delivered even when nothing was collected.
75
+ trigger_empty: nil,
76
+ # ISO-8601 timestamp of the last update.
77
+ updated: nil
78
+ )
79
+ end
80
+
81
+ sig do
82
+ override.returns(
83
+ {
84
+ categories: T::Array[Courier::TopicDigestCategory],
85
+ schedules: T::Array[Courier::TopicDigestScheduleResponse],
86
+ template_id: String,
87
+ audience_id: String,
88
+ created: String,
89
+ trigger_empty: T::Boolean,
90
+ updated: String
91
+ }
92
+ )
93
+ end
94
+ def to_hash
95
+ end
96
+ end
97
+ end
98
+ end