expo_notifier 0.1.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 (113) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +3 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +172 -0
  6. data/Rakefile +17 -0
  7. data/lib/expo_notifier/mapper/base.rb +30 -0
  8. data/lib/expo_notifier/mapper/error.rb +24 -0
  9. data/lib/expo_notifier/mapper/push_message.rb +132 -0
  10. data/lib/expo_notifier/mapper/push_messages.rb +15 -0
  11. data/lib/expo_notifier/mapper/push_receipt.rb +23 -0
  12. data/lib/expo_notifier/mapper/push_receipt_error_details.rb +23 -0
  13. data/lib/expo_notifier/mapper/push_receipt_ids.rb +16 -0
  14. data/lib/expo_notifier/mapper/push_receipts.rb +38 -0
  15. data/lib/expo_notifier/mapper/push_ticket.rb +30 -0
  16. data/lib/expo_notifier/mapper/push_ticket_error_details.rb +19 -0
  17. data/lib/expo_notifier/mapper/push_tickets.rb +26 -0
  18. data/lib/expo_notifier/mapper/rich_content.rb +17 -0
  19. data/lib/expo_notifier/request/base.rb +162 -0
  20. data/lib/expo_notifier/request/get_push_notification_receipts.rb +18 -0
  21. data/lib/expo_notifier/request/send_push_notifications.rb +26 -0
  22. data/lib/expo_notifier/response.rb +93 -0
  23. data/lib/expo_notifier/sorbet_shim.rb +18 -0
  24. data/lib/expo_notifier/version.rb +6 -0
  25. data/lib/expo_notifier.rb +19 -0
  26. data/sorbet/config +6 -0
  27. data/sorbet/rbi/annotations/.gitattributes +1 -0
  28. data/sorbet/rbi/annotations/activesupport.rbi +495 -0
  29. data/sorbet/rbi/annotations/faraday.rbi +17 -0
  30. data/sorbet/rbi/annotations/minitest.rbi +119 -0
  31. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  32. data/sorbet/rbi/annotations/webmock.rbi +9 -0
  33. data/sorbet/rbi/dsl/.gitattributes +1 -0
  34. data/sorbet/rbi/dsl/active_support/callbacks.rbi +21 -0
  35. data/sorbet/rbi/dsl/expo_notifier/mapper/base.rbi +12 -0
  36. data/sorbet/rbi/dsl/expo_notifier/mapper/error.rbi +42 -0
  37. data/sorbet/rbi/dsl/expo_notifier/mapper/push_message.rbi +263 -0
  38. data/sorbet/rbi/dsl/expo_notifier/mapper/push_messages.rbi +29 -0
  39. data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipt.rbi +45 -0
  40. data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipt_error_details.rbi +38 -0
  41. data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipt_ids.rbi +20 -0
  42. data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipts.rbi +25 -0
  43. data/sorbet/rbi/dsl/expo_notifier/mapper/push_ticket.rbi +59 -0
  44. data/sorbet/rbi/dsl/expo_notifier/mapper/push_ticket_error_details.rbi +32 -0
  45. data/sorbet/rbi/dsl/expo_notifier/mapper/push_tickets.rbi +54 -0
  46. data/sorbet/rbi/dsl/expo_notifier/mapper/rich_content.rbi +26 -0
  47. data/sorbet/rbi/dsl/time.rbi +13 -0
  48. data/sorbet/rbi/gems/.gitattributes +1 -0
  49. data/sorbet/rbi/gems/activesupport@8.1.1.rbi +22456 -0
  50. data/sorbet/rbi/gems/addressable@2.8.8.rbi +2005 -0
  51. data/sorbet/rbi/gems/ast@2.4.3.rbi +586 -0
  52. data/sorbet/rbi/gems/base64@0.3.0.rbi +545 -0
  53. data/sorbet/rbi/gems/benchmark@0.5.0.rbi +637 -0
  54. data/sorbet/rbi/gems/bigdecimal@4.0.1.rbi +409 -0
  55. data/sorbet/rbi/gems/booleans@0.1.3.rbi +31 -0
  56. data/sorbet/rbi/gems/concurrent-ruby@1.3.6.rbi +11729 -0
  57. data/sorbet/rbi/gems/connection_pool@3.0.2.rbi +9 -0
  58. data/sorbet/rbi/gems/crack@1.0.1.rbi +145 -0
  59. data/sorbet/rbi/gems/date@3.5.1.rbi +403 -0
  60. data/sorbet/rbi/gems/drb@2.2.3.rbi +1661 -0
  61. data/sorbet/rbi/gems/erb@6.0.1.rbi +815 -0
  62. data/sorbet/rbi/gems/erubi@1.13.1.rbi +157 -0
  63. data/sorbet/rbi/gems/faraday-net_http@3.4.2.rbi +72 -0
  64. data/sorbet/rbi/gems/faraday@2.14.0.rbi +3301 -0
  65. data/sorbet/rbi/gems/hashdiff@1.2.1.rbi +355 -0
  66. data/sorbet/rbi/gems/i18n@1.14.8.rbi +2383 -0
  67. data/sorbet/rbi/gems/io-console@0.8.2.rbi +9 -0
  68. data/sorbet/rbi/gems/json@2.18.0.rbi +2278 -0
  69. data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +323 -0
  70. data/sorbet/rbi/gems/logger@1.7.0.rbi +963 -0
  71. data/sorbet/rbi/gems/minitest@6.0.1.rbi +1524 -0
  72. data/sorbet/rbi/gems/net-http@0.9.1.rbi +4304 -0
  73. data/sorbet/rbi/gems/netrc@0.11.0.rbi +177 -0
  74. data/sorbet/rbi/gems/parallel@1.27.0.rbi +291 -0
  75. data/sorbet/rbi/gems/parser@3.3.10.0.rbi +5537 -0
  76. data/sorbet/rbi/gems/pp@0.6.3.rbi +390 -0
  77. data/sorbet/rbi/gems/prettyprint@0.2.0.rbi +477 -0
  78. data/sorbet/rbi/gems/prism@1.6.0.rbi +42126 -0
  79. data/sorbet/rbi/gems/psych@5.3.1.rbi +2556 -0
  80. data/sorbet/rbi/gems/public_suffix@7.0.2.rbi +957 -0
  81. data/sorbet/rbi/gems/racc@1.8.1.rbi +168 -0
  82. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +404 -0
  83. data/sorbet/rbi/gems/rake@13.3.1.rbi +3038 -0
  84. data/sorbet/rbi/gems/rbi@0.3.8.rbi +5238 -0
  85. data/sorbet/rbi/gems/rbs@4.0.0.dev.4.rbi +7805 -0
  86. data/sorbet/rbi/gems/regexp_parser@2.11.3.rbi +3849 -0
  87. data/sorbet/rbi/gems/reline@0.6.3.rbi +2995 -0
  88. data/sorbet/rbi/gems/require-hooks@0.2.2.rbi +110 -0
  89. data/sorbet/rbi/gems/rexml@3.4.4.rbi +5258 -0
  90. data/sorbet/rbi/gems/rubocop-espago@1.2.0.rbi +9 -0
  91. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1318 -0
  92. data/sorbet/rbi/gems/securerandom@0.4.1.rbi +75 -0
  93. data/sorbet/rbi/gems/shale-builder@0.8.5.rbi +267 -0
  94. data/sorbet/rbi/gems/shale@1.2.2.rbi +2323 -0
  95. data/sorbet/rbi/gems/shoulda-context@2.0.0.rbi +563 -0
  96. data/sorbet/rbi/gems/spoom@1.7.11.rbi +5878 -0
  97. data/sorbet/rbi/gems/stringio@3.2.0.rbi +9 -0
  98. data/sorbet/rbi/gems/tapioca@0.17.4.rbi +3507 -0
  99. data/sorbet/rbi/gems/thor@1.4.0.rbi +4399 -0
  100. data/sorbet/rbi/gems/tsort@0.2.0.rbi +393 -0
  101. data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +5919 -0
  102. data/sorbet/rbi/gems/unicode-display_width@3.2.0.rbi +132 -0
  103. data/sorbet/rbi/gems/unicode-emoji@4.2.0.rbi +254 -0
  104. data/sorbet/rbi/gems/uri@1.1.1.rbi +2407 -0
  105. data/sorbet/rbi/gems/vcr@6.4.0.rbi +3055 -0
  106. data/sorbet/rbi/gems/webmock@3.26.1.rbi +1816 -0
  107. data/sorbet/rbi/shims/gems/set.rbi +2 -0
  108. data/sorbet/rbi/shims/gems/shale.rbi +27 -0
  109. data/sorbet/rbi/shims/gems/shoulda-context.rbi +20 -0
  110. data/sorbet/tapioca/config.yml +21 -0
  111. data/sorbet/tapioca/extensions/load_gem.rb +1 -0
  112. data/sorbet/tapioca/require.rb +15 -0
  113. metadata +228 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2d86c0f277972155ddcf39b833745bfdaef1a94173ba61e90f92c8b1715b5920
4
+ data.tar.gz: a86943ba071821f9432efe3855abab57d1ba89f3424af4dd22619bfec1ef2322
5
+ SHA512:
6
+ metadata.gz: 0c0f39964de4d9d00228e002048eba5ebffc34c2c51d56703bef71d5539e5751a38cb1766a28e7d04d0fc8789f7cc644a00ffe8a8b370ddf89f55cee116b53aa
7
+ data.tar.gz: d962ac34f292bda4f07956dd084884a6fb49f883671a271944e7493e2798a1e800dbfbb0f1932b9e3db21bf4a0c50b8f0ce12e3ffdfc07f9918af29dd507c955
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 4.0.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## [0.1.0] - 2026-01-06
2
+
3
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Michał Zaporski
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,172 @@
1
+ [![Ruby](https://github.com/MichalZaporski/expo_notifier/actions/workflows/main.yml/badge.svg)](https://github.com/MichalZaporski/expo_notifier/actions/workflows/main.yml)
2
+
3
+ # ExpoNotifier
4
+
5
+ A Ruby client for the Expo Push Notifications API, providing typed request/response objects, automatic payload mapping, error classification, and configurable HTTP behavior. It is built on Faraday for HTTP communication.
6
+
7
+ The library currently supports:
8
+
9
+ - Sending push notifications
10
+
11
+ - Fetching push notification receipts
12
+
13
+ - Validating Expo push tokens
14
+
15
+ More information about the Expo API you can [find here.](https://docs.expo.dev/push-notifications/sending-notifications/)
16
+
17
+ ## Installation
18
+
19
+ Install the gem and add to the application's Gemfile by executing:
20
+
21
+ ```bash
22
+ bundle add expo_notifier
23
+ ```
24
+
25
+ If bundler is not being used to manage dependencies, install the gem by executing:
26
+
27
+ ```bash
28
+ gem install expo_notifier
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ ### SendPushNotifications
34
+
35
+ #### Example
36
+
37
+ ```ruby
38
+ params = ExpoNotifier::Mapper::PushMessages.build do |msgs|
39
+ msgs.push_message do |msg|
40
+ msg.to = ['ExponentPushToken[xxxxxxxx]']
41
+ msg.title = 'Title'
42
+ msg.body = 'Body'
43
+ msg.data = { order_id: 123 }
44
+ end
45
+ msgs.push_message do |msg|
46
+ msg.to = ['ExponentPushToken[xxxxxxxx]']
47
+ msg.title = 'Title'
48
+ msg.body = 'Second msg'
49
+ end
50
+ end
51
+
52
+ request = ExpoNotifier::Request::SendPushNotifications.new(params)
53
+ response = request.execute
54
+ if response.success?
55
+ response.body.data.each do |ticket|
56
+ puts "Notification status: #{ticket.status}, id: #{ticket.id}"
57
+ end
58
+ end
59
+ ```
60
+
61
+ #### Available message parameters
62
+
63
+ | Parameter | Type |
64
+ | -------------------- | --------------- |
65
+ | `to` | `Array[String]` |
66
+ | `title` | `String` |
67
+ | `body` | `String` |
68
+ | `data` | `Hash` |
69
+ | `content_available` | `Boolean` |
70
+ | `ttl` | `Integer` |
71
+ | `expiration` | `Integer` |
72
+ | `priority` | `String` |
73
+ | `subtitle` | `String` |
74
+ | `sound` | `String` |
75
+ | `badge` | `Integer` |
76
+ | `interruption_level` | `String` |
77
+ | `channel_id` | `String` |
78
+ | `icon` | `String` |
79
+ | `category_id` | `String` |
80
+ | `mutable_content` | `Boolean` |
81
+ | `rich_content.image` | `String` |
82
+
83
+
84
+ ### GetPushNotificationReceipts
85
+
86
+ #### Example
87
+
88
+ ``` ruby
89
+ params = ExpoNotifier::Mapper::PushReceiptIds.new(
90
+ ids: ['receipt-id-1', 'receipt-id-2'],
91
+ )
92
+
93
+ request = ExpoNotifier::Request::GetPushNotificationReceipts.new(params)
94
+ response = request.execute
95
+ if response.success?
96
+ response.body.data.each do |receipt_id, receipt|
97
+ puts "Receipt #{receipt_id}: status=#{receipt.status}, message=#{receipt.message}"
98
+ end
99
+ end
100
+ ```
101
+
102
+ ### Request configuration
103
+
104
+ Each request accepts optional configuration parameters that control HTTP behavior.
105
+
106
+ #### Available options
107
+
108
+ ```ruby
109
+ access_token: String # Adds Authorization: Bearer <token>
110
+ faraday_adapter: Symbol # Default: your default Faraday adapter
111
+ base_url: String # API base URL, default: https://exp.host
112
+ write_timeout: Integer # Write timeout in seconds, default: 5
113
+ open_timeout: Integer # Open timeout in seconds, default: 5
114
+ read_timeout: Integer # Read timeout in seconds, default: 30
115
+ gzip: Boolean # Enable gzip compression, default: true
116
+ gzip_min_size: Integer # Minimum request body size to enable gzip, default: 1024 bytes
117
+ additional_headers: Hash # Your additional headers
118
+ ```
119
+
120
+ #### Example
121
+
122
+ ```ruby
123
+ request = ExpoNotifier::Request::SendPushNotifications.new(
124
+ params,
125
+ access_token: 'secret-token',
126
+ base_url: 'https://example.test',
127
+ gzip_min_size: 512,
128
+ additional_headers: {
129
+ 'X-Custom-Header' => 'custom',
130
+ },
131
+ )
132
+ ```
133
+
134
+ ### Response Handling
135
+
136
+ All requests return a Response object exposing:
137
+
138
+ ```ruby
139
+ response.status_code
140
+ response.duration
141
+ response.headers
142
+ response.body
143
+
144
+ response.success? # 200
145
+ response.malformed_request_error? # 400
146
+ response.too_many_requests_error? # 429
147
+ response.server_error? # 5xx
148
+ response.communication_error? # HTTP communication error
149
+ response.communication_error_message
150
+ ```
151
+
152
+ ### Expo push token validation
153
+
154
+ The library provides a helper for validating Expo push tokens before sending requests. Usage:
155
+
156
+ ```ruby
157
+ ExpoNotifier.expo_push_token?('ExponentPushToken[abcdef123456]')
158
+ ```
159
+
160
+ ## Development
161
+
162
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
163
+
164
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
165
+
166
+ ## Contributing
167
+
168
+ Bug reports and pull requests are welcome on GitHub at https://github.com/MichalZaporski/expo_notifier.
169
+
170
+ ## License
171
+
172
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'minitest/test_task'
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ desc 'Run Sorbet type checking'
13
+ task :typecheck do
14
+ sh 'bundle exec srb tc'
15
+ end
16
+
17
+ task default: %i[test rubocop typecheck]
@@ -0,0 +1,30 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require 'active_support/core_ext/string'
5
+ require 'shale'
6
+ require 'shale/builder'
7
+
8
+ module ExpoNotifier
9
+ module Mapper
10
+ # An abstract mapper class.
11
+ # @abstract
12
+ class Base < Shale::Mapper
13
+ include Shale::Builder
14
+
15
+ class << self
16
+ alias orig_attribute attribute
17
+
18
+ #: (Symbol, *Object, ?as: String?, **Object) ?{ -> void } -> void
19
+ def attribute(name, *args, as: nil, **kwargs, &block)
20
+ json_mapping.finalize! unless json_mapping.finalized?
21
+ T.unsafe(self).orig_attribute(name, *args, **kwargs, &block) # rubocop:disable Sorbet/ForbidTUnsafe
22
+ as ||= name.to_s.camelize(:lower)
23
+
24
+ json_mapping.map(as, to: name)
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+
6
+ module ExpoNotifier
7
+ module Mapper
8
+ class Error < Base
9
+ attribute :code, Shale::Type::String, doc: <<~DOC
10
+ Available values:
11
+
12
+ - TOO_MANY_REQUESTS: You are exceeding the request limit of 600 notifications per second per project.
13
+
14
+ - PUSH_TOO_MANY_EXPERIENCE_IDS: You are trying to send push notifications to different Expo experiences.
15
+
16
+ - PUSH_TOO_MANY_NOTIFICATIONS: You are trying to send more than 100 push notifications in one request.
17
+
18
+ - PUSH_TOO_MANY_RECEIPTS: You are trying to get more than 1000 push receipts in one request.
19
+ DOC
20
+
21
+ attribute :message, Shale::Type::String
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,132 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+ require_relative 'rich_content'
6
+
7
+ module ExpoNotifier
8
+ module Mapper
9
+ class PushMessage < Base
10
+ attribute :to, Shale::Type::String, collection: true, doc: <<~DOC
11
+ Android and iOS
12
+
13
+ An array of Expo push tokens specifying the recipient(s) of this message.
14
+ DOC
15
+
16
+ attribute :content_available, Shale::Type::Boolean, as: '_contentAvailable', doc: <<~DOC
17
+ iOS Only
18
+
19
+ When this is set to true, the notification will cause the iOS app to start in the background to
20
+ run a background task. Your app needs to be configured to support this.
21
+ DOC
22
+
23
+ attribute :data, Shale::Type::Value, doc: <<~DOC
24
+ Android and iOS
25
+
26
+ A JSON object delivered to your app.It may be up to about 4KiB; the total notification payload
27
+ sent to Apple and Google must be at most 4KiB or else you will get a "Message Too Big" error.
28
+ DOC
29
+
30
+ attribute :title, Shale::Type::String, doc: <<~DOC
31
+ Android and iOS
32
+
33
+ The title to display in the notification. Often displayed above the notification body.
34
+ Maps to `AndroidNotification.title` and `aps.alert.title`.
35
+ DOC
36
+
37
+ attribute :body, Shale::Type::String, doc: <<~DOC
38
+ Android and iOS
39
+
40
+ The message to display in the notification. Maps to `AndroidNotification.body` and `aps.alert.body`.
41
+ DOC
42
+
43
+ attribute :ttl, Shale::Type::Integer, doc: <<~DOC
44
+ Android and iOS
45
+
46
+ Time to Live: the number of seconds for which the message may be kept around for redelivery if
47
+ it hasn't been delivered yet. Defaults to undefined to use the respective defaults of each
48
+ provider (1 month for Android/FCM as well as iOS/APNs).
49
+ DOC
50
+
51
+ attribute :expiration, Shale::Type::Integer, doc: <<~DOC
52
+ Android and iOS
53
+
54
+ Timestamp since the Unix epoch specifying when the message expires.
55
+ Same effect as `ttl` (`ttl` takes precedence over `expiration`).
56
+ DOC
57
+
58
+ attribute :priority, Shale::Type::String, doc: <<~DOC
59
+ Android and iOS
60
+
61
+ Accepted values: 'default' | 'normal' | 'high'
62
+
63
+ The delivery priority of the message. Specify default or omit this field to use the default priority
64
+ on each platform ("normal" on Android and "high" on iOS).
65
+ DOC
66
+
67
+ attribute :subtitle, Shale::Type::String, doc: <<~DOC
68
+ iOS Only
69
+
70
+ The subtitle to display in the notification below the title. Maps to `aps.alert.subtitle`.
71
+ DOC
72
+
73
+ attribute :sound, Shale::Type::String, doc: <<~DOC
74
+ iOS Only
75
+
76
+ Play a sound when the recipient receives this notification. Specify default to play the device's
77
+ default notification sound, or omit this field to play no sound. Custom sounds need to be configured
78
+ via the config plugin and then specified including the file extension. Example: bells_sound.wav.
79
+ DOC
80
+
81
+ attribute :badge, Shale::Type::Integer, doc: <<~DOC
82
+ iOS Only
83
+
84
+ Number to display in the badge on the app icon. Specify zero to clear the badge.
85
+ DOC
86
+
87
+ attribute :interruption_level, Shale::Type::String, doc: <<~DOC
88
+ iOS Only
89
+
90
+ Accepted values: 'active' | 'critical' | 'passive' | 'time-sensitive'
91
+
92
+ The importance and delivery timing of a notification. The string values correspond to the
93
+ `UNNotificationInterruptionLevel` enumeration cases.
94
+ DOC
95
+
96
+ attribute :channel_id, Shale::Type::String, doc: <<~DOC
97
+ Android Only
98
+
99
+ ID of the Notification Channel through which to display this notification. If an ID is specified but
100
+ the corresponding channel does not exist on the device (that has not yet been created by your app),
101
+ the notification will not be displayed to the user.
102
+ DOC
103
+
104
+ attribute :icon, Shale::Type::String, doc: <<~DOC
105
+ Android Only
106
+
107
+ The notification's icon. Name of an Android drawable resource (example: my_icon).
108
+ Defaults to the icon specified in the config plugin.
109
+ DOC
110
+
111
+ attribute :rich_content, RichContent, doc: <<~DOC
112
+ Android and iOS
113
+
114
+ Currently supports setting a notification image. Provide an object with key image and value of
115
+ type string, which is the image URL. Android will show the image out of the box. On iOS, you need to add
116
+ a Notification Service Extension target to your app.
117
+ DOC
118
+
119
+ attribute :category_id, Shale::Type::String, doc: <<~DOC
120
+ Android and iOS
121
+
122
+ ID of the notification category that this notification is associated with.
123
+ DOC
124
+
125
+ attribute :mutable_content, Shale::Type::Boolean, doc: <<~DOC
126
+ iOS Only
127
+
128
+ Specifies whether this notification can be intercepted by the client app. Defaults to false.
129
+ DOC
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,15 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+ require_relative 'push_message'
6
+
7
+ module ExpoNotifier
8
+ module Mapper
9
+ class PushMessages < Base
10
+ attribute :push_message, PushMessage, collection: true, doc: <<~DOC
11
+ An array of push messages.
12
+ DOC
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+ require_relative 'push_receipt_error_details'
6
+
7
+ module ExpoNotifier
8
+ module Mapper
9
+ class PushReceipt < Base
10
+ attribute :status, Shale::Type::String, doc: <<~DOC
11
+ Available values: 'error' | 'ok'
12
+ DOC
13
+
14
+ attribute :message, Shale::Type::String, doc: <<~DOC
15
+ Error message. Only populated if `status` is equal to `error`.
16
+ DOC
17
+
18
+ attribute :details, PushReceiptErrorDetails, doc: <<~DOC
19
+ Error details. Only populated if `status` is equal to `error`.
20
+ DOC
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+
6
+ module ExpoNotifier
7
+ module Mapper
8
+ class PushReceiptErrorDetails < Base
9
+ attribute :error, Shale::Type::String, doc: <<~DOC
10
+ Available values:
11
+
12
+ - DeviceNotRegistered: The device cannot receive push notifications anymore and you should stop
13
+ sending messages to the corresponding Expo push token.
14
+
15
+ - MessageTooBig: The total notification payload was too large. On Android and iOS, the total payload must be at most 4096 bytes.
16
+
17
+ - MismatchSenderId: This indicates that there is an issue with your FCM push credentials.
18
+
19
+ - InvalidCredentials: Your push notification credentials for your standalone app are invalid.
20
+ DOC
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+ require_relative 'push_ticket'
6
+ require_relative 'error'
7
+
8
+ module ExpoNotifier
9
+ module Mapper
10
+ class PushReceiptIds < Base
11
+ attribute :ids, Shale::Type::String, collection: true, doc: <<~DOC
12
+ An array of Expo push receipt ids.
13
+ DOC
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+ require_relative 'push_receipt'
6
+ require_relative 'error'
7
+
8
+ module ExpoNotifier
9
+ module Mapper
10
+ class PushReceipts < Base
11
+
12
+ # Hash where keys are receipt IDs and values are push receipts
13
+ #: Hash[String, PushReceipt]
14
+ attr_accessor :data
15
+
16
+ attribute :errors, Error, collection: true, doc: <<~DOC
17
+ Errors — only populated if there was an error with the entire request.
18
+ DOC
19
+
20
+ json do
21
+ map 'data', using: {
22
+ from: :parse_push_receipts_from_json,
23
+ to: :undefined,
24
+ }
25
+
26
+ map 'errors', to: :errors
27
+ end
28
+
29
+ #: (ExpoNotifier::Mapper::PushReceipts, Hash[String, Object]) -> void
30
+ def parse_push_receipts_from_json(model, value)
31
+ model.data = value.transform_values do |receipt_hash|
32
+ PushReceipt.from_hash(receipt_hash)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+ require_relative 'push_ticket_error_details'
6
+
7
+ module ExpoNotifier
8
+ module Mapper
9
+ class PushTicket < Base
10
+ attribute :status, Shale::Type::String, doc: <<~DOC
11
+ Available values: 'error' | 'ok'
12
+
13
+ A status of ok along with a receipt ID means that the message was received by Expo's servers,
14
+ not that it was received by the user (for that you will need to check the push receipt).
15
+ DOC
16
+
17
+ attribute :id, Shale::Type::String, doc: <<~DOC
18
+ The Receipt ID.
19
+ DOC
20
+
21
+ attribute :message, Shale::Type::String, doc: <<~DOC
22
+ Error message. Only populated if `status` is equal to `error`.
23
+ DOC
24
+
25
+ attribute :details, PushTicketErrorDetails, doc: <<~DOC
26
+ Error details. Only populated if `status` is equal to `error`.
27
+ DOC
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+
6
+ module ExpoNotifier
7
+ module Mapper
8
+ class PushTicketErrorDetails < Base
9
+ attribute :error, Shale::Type::String, doc: <<~DOC
10
+ Available values:
11
+
12
+ - DeviceNotRegistered: The device cannot receive push notifications anymore and you should stop
13
+ sending messages to the corresponding Expo push token.
14
+ DOC
15
+
16
+ attribute :expo_push_token, Shale::Type::String
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+ require_relative 'push_ticket'
6
+ require_relative 'error'
7
+
8
+ module ExpoNotifier
9
+ module Mapper
10
+ class PushTickets < Base
11
+ attribute :data, PushTicket, collection: true, doc: <<~DOC
12
+ An array of Expo push tickets.
13
+
14
+ The Expo push notification service responds with push tickets upon successfully receiving notifications.
15
+ A push ticket indicates that Expo has received your notification payload but may still need to send it.
16
+ Each push ticket contains a ticket ID, which you later use to look up a push receipt.
17
+ A push receipt is available after Expo has tried to deliver the notification to FCM or APNs.
18
+ It tells you whether delivery to the push notification provider was successful.
19
+ DOC
20
+
21
+ attribute :errors, Error, collection: true, doc: <<~DOC
22
+ Errors — only populated if there was an error with the entire request.
23
+ DOC
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'base'
5
+
6
+ module ExpoNotifier
7
+ module Mapper
8
+ class RichContent < Base
9
+ attribute :image, Shale::Type::String, doc: <<~DOC
10
+ Android and iOS
11
+
12
+ The image URL. Android will show the image out of the box. On iOS, you need to add a Notification Service Extension
13
+ target to your app. See this example on how to do that.
14
+ DOC
15
+ end
16
+ end
17
+ end