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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +172 -0
- data/Rakefile +17 -0
- data/lib/expo_notifier/mapper/base.rb +30 -0
- data/lib/expo_notifier/mapper/error.rb +24 -0
- data/lib/expo_notifier/mapper/push_message.rb +132 -0
- data/lib/expo_notifier/mapper/push_messages.rb +15 -0
- data/lib/expo_notifier/mapper/push_receipt.rb +23 -0
- data/lib/expo_notifier/mapper/push_receipt_error_details.rb +23 -0
- data/lib/expo_notifier/mapper/push_receipt_ids.rb +16 -0
- data/lib/expo_notifier/mapper/push_receipts.rb +38 -0
- data/lib/expo_notifier/mapper/push_ticket.rb +30 -0
- data/lib/expo_notifier/mapper/push_ticket_error_details.rb +19 -0
- data/lib/expo_notifier/mapper/push_tickets.rb +26 -0
- data/lib/expo_notifier/mapper/rich_content.rb +17 -0
- data/lib/expo_notifier/request/base.rb +162 -0
- data/lib/expo_notifier/request/get_push_notification_receipts.rb +18 -0
- data/lib/expo_notifier/request/send_push_notifications.rb +26 -0
- data/lib/expo_notifier/response.rb +93 -0
- data/lib/expo_notifier/sorbet_shim.rb +18 -0
- data/lib/expo_notifier/version.rb +6 -0
- data/lib/expo_notifier.rb +19 -0
- data/sorbet/config +6 -0
- data/sorbet/rbi/annotations/.gitattributes +1 -0
- data/sorbet/rbi/annotations/activesupport.rbi +495 -0
- data/sorbet/rbi/annotations/faraday.rbi +17 -0
- data/sorbet/rbi/annotations/minitest.rbi +119 -0
- data/sorbet/rbi/annotations/rainbow.rbi +269 -0
- data/sorbet/rbi/annotations/webmock.rbi +9 -0
- data/sorbet/rbi/dsl/.gitattributes +1 -0
- data/sorbet/rbi/dsl/active_support/callbacks.rbi +21 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/base.rbi +12 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/error.rbi +42 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_message.rbi +263 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_messages.rbi +29 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipt.rbi +45 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipt_error_details.rbi +38 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipt_ids.rbi +20 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_receipts.rbi +25 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_ticket.rbi +59 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_ticket_error_details.rbi +32 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/push_tickets.rbi +54 -0
- data/sorbet/rbi/dsl/expo_notifier/mapper/rich_content.rbi +26 -0
- data/sorbet/rbi/dsl/time.rbi +13 -0
- data/sorbet/rbi/gems/.gitattributes +1 -0
- data/sorbet/rbi/gems/activesupport@8.1.1.rbi +22456 -0
- data/sorbet/rbi/gems/addressable@2.8.8.rbi +2005 -0
- data/sorbet/rbi/gems/ast@2.4.3.rbi +586 -0
- data/sorbet/rbi/gems/base64@0.3.0.rbi +545 -0
- data/sorbet/rbi/gems/benchmark@0.5.0.rbi +637 -0
- data/sorbet/rbi/gems/bigdecimal@4.0.1.rbi +409 -0
- data/sorbet/rbi/gems/booleans@0.1.3.rbi +31 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.3.6.rbi +11729 -0
- data/sorbet/rbi/gems/connection_pool@3.0.2.rbi +9 -0
- data/sorbet/rbi/gems/crack@1.0.1.rbi +145 -0
- data/sorbet/rbi/gems/date@3.5.1.rbi +403 -0
- data/sorbet/rbi/gems/drb@2.2.3.rbi +1661 -0
- data/sorbet/rbi/gems/erb@6.0.1.rbi +815 -0
- data/sorbet/rbi/gems/erubi@1.13.1.rbi +157 -0
- data/sorbet/rbi/gems/faraday-net_http@3.4.2.rbi +72 -0
- data/sorbet/rbi/gems/faraday@2.14.0.rbi +3301 -0
- data/sorbet/rbi/gems/hashdiff@1.2.1.rbi +355 -0
- data/sorbet/rbi/gems/i18n@1.14.8.rbi +2383 -0
- data/sorbet/rbi/gems/io-console@0.8.2.rbi +9 -0
- data/sorbet/rbi/gems/json@2.18.0.rbi +2278 -0
- data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +323 -0
- data/sorbet/rbi/gems/logger@1.7.0.rbi +963 -0
- data/sorbet/rbi/gems/minitest@6.0.1.rbi +1524 -0
- data/sorbet/rbi/gems/net-http@0.9.1.rbi +4304 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +177 -0
- data/sorbet/rbi/gems/parallel@1.27.0.rbi +291 -0
- data/sorbet/rbi/gems/parser@3.3.10.0.rbi +5537 -0
- data/sorbet/rbi/gems/pp@0.6.3.rbi +390 -0
- data/sorbet/rbi/gems/prettyprint@0.2.0.rbi +477 -0
- data/sorbet/rbi/gems/prism@1.6.0.rbi +42126 -0
- data/sorbet/rbi/gems/psych@5.3.1.rbi +2556 -0
- data/sorbet/rbi/gems/public_suffix@7.0.2.rbi +957 -0
- data/sorbet/rbi/gems/racc@1.8.1.rbi +168 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +404 -0
- data/sorbet/rbi/gems/rake@13.3.1.rbi +3038 -0
- data/sorbet/rbi/gems/rbi@0.3.8.rbi +5238 -0
- data/sorbet/rbi/gems/rbs@4.0.0.dev.4.rbi +7805 -0
- data/sorbet/rbi/gems/regexp_parser@2.11.3.rbi +3849 -0
- data/sorbet/rbi/gems/reline@0.6.3.rbi +2995 -0
- data/sorbet/rbi/gems/require-hooks@0.2.2.rbi +110 -0
- data/sorbet/rbi/gems/rexml@3.4.4.rbi +5258 -0
- data/sorbet/rbi/gems/rubocop-espago@1.2.0.rbi +9 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1318 -0
- data/sorbet/rbi/gems/securerandom@0.4.1.rbi +75 -0
- data/sorbet/rbi/gems/shale-builder@0.8.5.rbi +267 -0
- data/sorbet/rbi/gems/shale@1.2.2.rbi +2323 -0
- data/sorbet/rbi/gems/shoulda-context@2.0.0.rbi +563 -0
- data/sorbet/rbi/gems/spoom@1.7.11.rbi +5878 -0
- data/sorbet/rbi/gems/stringio@3.2.0.rbi +9 -0
- data/sorbet/rbi/gems/tapioca@0.17.4.rbi +3507 -0
- data/sorbet/rbi/gems/thor@1.4.0.rbi +4399 -0
- data/sorbet/rbi/gems/tsort@0.2.0.rbi +393 -0
- data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +5919 -0
- data/sorbet/rbi/gems/unicode-display_width@3.2.0.rbi +132 -0
- data/sorbet/rbi/gems/unicode-emoji@4.2.0.rbi +254 -0
- data/sorbet/rbi/gems/uri@1.1.1.rbi +2407 -0
- data/sorbet/rbi/gems/vcr@6.4.0.rbi +3055 -0
- data/sorbet/rbi/gems/webmock@3.26.1.rbi +1816 -0
- data/sorbet/rbi/shims/gems/set.rbi +2 -0
- data/sorbet/rbi/shims/gems/shale.rbi +27 -0
- data/sorbet/rbi/shims/gems/shoulda-context.rbi +20 -0
- data/sorbet/tapioca/config.yml +21 -0
- data/sorbet/tapioca/extensions/load_gem.rb +1 -0
- data/sorbet/tapioca/require.rb +15 -0
- 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
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
|
+
[](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
|