smswire 0.0.1.pre → 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 +4 -4
- data/CHANGELOG.md +67 -3
- data/README.md +222 -9
- data/RELEASING.md +49 -0
- data/app/controllers/smswire/development_controller.rb +17 -0
- data/app/controllers/smswire/inbound_messages_controller.rb +9 -0
- data/app/controllers/smswire/inbox_controller.rb +31 -0
- data/app/controllers/smswire/previews_controller.rb +22 -0
- data/app/controllers/smswire/status_callbacks_controller.rb +8 -0
- data/app/controllers/smswire/webhooks_controller.rb +49 -0
- data/app/models/smswire/application_record.rb +5 -0
- data/app/models/smswire/consent.rb +71 -0
- data/app/models/smswire/delivery.rb +157 -0
- data/app/models/smswire/inbound_message.rb +25 -0
- data/app/views/layouts/smswire/application.html.erb +60 -0
- data/app/views/smswire/inbox/index.html.erb +56 -0
- data/app/views/smswire/previews/index.html.erb +21 -0
- data/app/views/smswire/previews/show.html.erb +34 -0
- data/config/routes.rb +10 -0
- data/db/migrate/20261008000000_create_smswire_deliveries.rb +47 -0
- data/db/migrate/20261008000001_create_smswire_consents_and_inbound_messages.rb +34 -0
- data/docs/SPEC.md +164 -43
- data/docs/guides/compliance.md +124 -0
- data/docs/guides/getting-started.md +154 -0
- data/docs/guides/migrating-from-noticed-twilio.md +105 -0
- data/docs/guides/migrating-from-twilio-ruby.md +146 -0
- data/docs/guides/writing-a-provider.md +126 -0
- data/lib/generators/smswire/install/install_generator.rb +44 -0
- data/lib/generators/smswire/install/templates/application_messenger.rb.tt +3 -0
- data/lib/generators/smswire/install/templates/initializer.rb.tt +35 -0
- data/lib/generators/smswire/messenger/messenger_generator.rb +51 -0
- data/lib/generators/smswire/messenger/templates/messenger.rb.tt +14 -0
- data/lib/generators/smswire/messenger/templates/preview.rb.tt +13 -0
- data/lib/generators/smswire/messenger/templates/test.rb.tt +18 -0
- data/lib/generators/smswire/messenger/templates/view.text.erb.tt +1 -0
- data/lib/generators/smswire/provider/provider_generator.rb +36 -0
- data/lib/generators/smswire/provider/templates/provider.rb.tt +52 -0
- data/lib/generators/smswire/provider/templates/test.rb.tt +29 -0
- data/lib/smswire/base.rb +123 -0
- data/lib/smswire/body_formatter.rb +14 -0
- data/lib/smswire/callbacks.rb +24 -0
- data/lib/smswire/configuration.rb +224 -0
- data/lib/smswire/delivery_job.rb +29 -0
- data/lib/smswire/engine.rb +52 -0
- data/lib/smswire/errors.rb +59 -0
- data/lib/smswire/http.rb +65 -0
- data/lib/smswire/inbound.rb +11 -0
- data/lib/smswire/inbound_handler.rb +29 -0
- data/lib/smswire/interceptors/allowlist.rb +36 -0
- data/lib/smswire/keyword_messenger.rb +12 -0
- data/lib/smswire/keywords.rb +51 -0
- data/lib/smswire/log_subscriber.rb +57 -0
- data/lib/smswire/message.rb +72 -0
- data/lib/smswire/message_delivery.rb +69 -0
- data/lib/smswire/noticed_delivery_method.rb +54 -0
- data/lib/smswire/parameterized_messenger.rb +24 -0
- data/lib/smswire/phone_number.rb +65 -0
- data/lib/smswire/pipeline.rb +114 -0
- data/lib/smswire/preview.rb +54 -0
- data/lib/smswire/provider_contract.rb +158 -0
- data/lib/smswire/providers/base.rb +66 -0
- data/lib/smswire/providers/log.rb +23 -0
- data/lib/smswire/providers/null.rb +12 -0
- data/lib/smswire/providers/telnyx.rb +178 -0
- data/lib/smswire/providers/test.rb +59 -0
- data/lib/smswire/providers/twilio.rb +167 -0
- data/lib/smswire/providers/vonage.rb +193 -0
- data/lib/smswire/providers.rb +38 -0
- data/lib/smswire/quiet_hours.rb +45 -0
- data/lib/smswire/rate_limit.rb +27 -0
- data/lib/smswire/receipt.rb +11 -0
- data/lib/smswire/recipient.rb +38 -0
- data/lib/smswire/result.rb +40 -0
- data/lib/smswire/rspec.rb +133 -0
- data/lib/smswire/segments.rb +81 -0
- data/lib/smswire/sender.rb +27 -0
- data/lib/smswire/status_handler.rb +25 -0
- data/lib/smswire/status_update.rb +8 -0
- data/lib/smswire/test_helper.rb +81 -0
- data/lib/smswire/testing.rb +72 -0
- data/lib/smswire/version.rb +1 -1
- data/lib/smswire.rb +70 -6
- data/smswire.gemspec +9 -5
- metadata +195 -10
- data/Gemfile +0 -7
- data/Rakefile +0 -8
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require "active_job/test_helper"
|
|
2
|
+
|
|
3
|
+
module Smswire
|
|
4
|
+
# Minitest assertions for messengers.
|
|
5
|
+
#
|
|
6
|
+
# class OrderTest < ActiveSupport::TestCase
|
|
7
|
+
# include Smswire::TestHelper
|
|
8
|
+
#
|
|
9
|
+
# test "ships" do
|
|
10
|
+
# assert_sms_delivered(to: "+15551234567", messenger: OrderMessenger, action: :shipped) do
|
|
11
|
+
# Order.ship!(order)
|
|
12
|
+
# end
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# Deliveries are cleared before each test. With a block, enqueued
|
|
17
|
+
# Smswire::DeliveryJob jobs are performed so deliver_later is covered.
|
|
18
|
+
module TestHelper
|
|
19
|
+
include ActiveJob::TestHelper
|
|
20
|
+
|
|
21
|
+
def before_setup
|
|
22
|
+
Smswire::Testing.clear!
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def sms_deliveries
|
|
27
|
+
Smswire::Testing.deliveries
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def assert_sms_delivered(count = nil, **filters, &block)
|
|
31
|
+
delivered =
|
|
32
|
+
if block
|
|
33
|
+
before = Smswire::Testing.deliveries.size
|
|
34
|
+
perform_enqueued_jobs(only: Smswire::DeliveryJob, &block)
|
|
35
|
+
Smswire::Testing.deliveries.drop(before)
|
|
36
|
+
else
|
|
37
|
+
Smswire::Testing.deliveries
|
|
38
|
+
end
|
|
39
|
+
matching = Smswire::Testing.match_deliveries(delivered, **filters)
|
|
40
|
+
described = Smswire::Testing.describe_filters(filters)
|
|
41
|
+
|
|
42
|
+
if count
|
|
43
|
+
assert_equal count, matching.size,
|
|
44
|
+
"Expected #{count} SMS#{described}, got #{matching.size} (#{delivered.size} delivered in total)"
|
|
45
|
+
else
|
|
46
|
+
assert matching.any?, "Expected an SMS#{described}, but none was delivered (#{delivered.size} in total)"
|
|
47
|
+
end
|
|
48
|
+
matching
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def assert_no_sms_delivered(**filters, &block)
|
|
52
|
+
assert_sms_delivered(0, **filters, &block)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def assert_enqueued_sms(messenger = nil, action = nil, count: nil, params: nil, args: nil, kwargs: nil, &block)
|
|
56
|
+
jobs =
|
|
57
|
+
if block
|
|
58
|
+
before = enqueued_jobs.size
|
|
59
|
+
block.call
|
|
60
|
+
enqueued_jobs.drop(before)
|
|
61
|
+
else
|
|
62
|
+
enqueued_jobs
|
|
63
|
+
end
|
|
64
|
+
entries = Smswire::Testing.enqueued(jobs)
|
|
65
|
+
matching = Smswire::Testing.match_enqueued(entries, messenger:, action:, params:, args:, kwargs:)
|
|
66
|
+
label = [messenger, action].compact.join("#")
|
|
67
|
+
label = label.empty? ? "an SMS" : label
|
|
68
|
+
|
|
69
|
+
if count
|
|
70
|
+
assert_equal count, matching.size, "Expected #{count} enqueued #{label}, got #{matching.size}"
|
|
71
|
+
else
|
|
72
|
+
assert matching.any?, "Expected #{label} to be enqueued, but it was not (#{entries.size} SMS enqueued)"
|
|
73
|
+
end
|
|
74
|
+
matching
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def assert_no_enqueued_sms(messenger = nil, action = nil, **filters, &block)
|
|
78
|
+
assert_enqueued_sms(messenger, action, count: 0, **filters, &block)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Smswire
|
|
2
|
+
# Shared matching logic for Smswire::TestHelper and the RSpec matchers.
|
|
3
|
+
module Testing
|
|
4
|
+
DELIVERY_FILTERS = %i[to from body messenger action category provider].freeze
|
|
5
|
+
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def deliveries
|
|
9
|
+
Providers::Test.deliveries
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def clear!
|
|
13
|
+
Providers::Test.clear!
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def match_deliveries(messages, **filters)
|
|
17
|
+
unknown = filters.keys - DELIVERY_FILTERS
|
|
18
|
+
raise ArgumentError, "Unknown filter(s): #{unknown.join(", ")}" if unknown.any?
|
|
19
|
+
|
|
20
|
+
messages.select do |message|
|
|
21
|
+
filters.all? do |key, expected|
|
|
22
|
+
actual = message.public_send(key)
|
|
23
|
+
case key
|
|
24
|
+
when :to then expected_phone?(actual, expected)
|
|
25
|
+
when :messenger then matches?(actual, expected.is_a?(Class) ? expected.name : expected)
|
|
26
|
+
else matches?(actual, expected)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Enqueued Smswire::DeliveryJob entries from an ActiveJob test adapter,
|
|
33
|
+
# deserialized into hashes with :messenger, :action, :params, :args, :kwargs.
|
|
34
|
+
def enqueued(jobs)
|
|
35
|
+
jobs.filter_map do |job|
|
|
36
|
+
job_class = job[:job] || job["job_class"]
|
|
37
|
+
next unless job_class.to_s == DeliveryJob.name
|
|
38
|
+
|
|
39
|
+
messenger, action, params, args, kwargs = ActiveJob::Arguments.deserialize(job[:args] || job["arguments"])
|
|
40
|
+
{messenger:, action:, params:, args:, kwargs:, queue: job[:queue], at: job[:at]}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def match_enqueued(entries, messenger: nil, action: nil, params: nil, args: nil, kwargs: nil)
|
|
45
|
+
entries.select do |entry|
|
|
46
|
+
(messenger.nil? || entry[:messenger] == (messenger.is_a?(Class) ? messenger.name : messenger.to_s)) &&
|
|
47
|
+
(action.nil? || entry[:action] == action.to_s) &&
|
|
48
|
+
(params.nil? || entry[:params] == params) &&
|
|
49
|
+
(args.nil? || entry[:args] == args) &&
|
|
50
|
+
(kwargs.nil? || entry[:kwargs] == kwargs)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def describe_filters(filters)
|
|
55
|
+
filters.empty? ? "" : " matching #{filters.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def matches?(actual, expected)
|
|
59
|
+
case expected
|
|
60
|
+
when Regexp then expected.match?(actual.to_s)
|
|
61
|
+
when Symbol then actual.to_s == expected.to_s
|
|
62
|
+
else actual == expected
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def expected_phone?(actual, expected)
|
|
67
|
+
return expected.match?(actual.to_s) if expected.is_a?(Regexp)
|
|
68
|
+
|
|
69
|
+
actual == expected || actual == PhoneNumber.normalize(expected)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/smswire/version.rb
CHANGED
data/lib/smswire.rb
CHANGED
|
@@ -1,11 +1,75 @@
|
|
|
1
|
-
|
|
1
|
+
require "zeitwerk"
|
|
2
|
+
require "active_support"
|
|
3
|
+
require "active_support/core_ext/object/blank"
|
|
4
|
+
require "active_support/core_ext/string/filters"
|
|
5
|
+
require "active_support/core_ext/hash/keys"
|
|
6
|
+
require "active_support/core_ext/class/attribute"
|
|
7
|
+
require "active_support/core_ext/numeric/time"
|
|
8
|
+
require "active_job"
|
|
9
|
+
|
|
10
|
+
loader = Zeitwerk::Loader.for_gem
|
|
11
|
+
loader.inflector.inflect("http" => "HTTP", "rspec" => "RSpec")
|
|
12
|
+
loader.ignore(
|
|
13
|
+
"#{__dir__}/generators",
|
|
14
|
+
"#{__dir__}/smswire/errors.rb",
|
|
15
|
+
"#{__dir__}/smswire/engine.rb",
|
|
16
|
+
"#{__dir__}/smswire/noticed_delivery_method.rb",
|
|
17
|
+
"#{__dir__}/smswire/rspec.rb"
|
|
18
|
+
)
|
|
19
|
+
loader.setup
|
|
20
|
+
|
|
21
|
+
require_relative "smswire/errors"
|
|
2
22
|
|
|
3
23
|
# Smswire is the production SMS layer for Rails: messenger classes and
|
|
4
|
-
# templates, a provider-agnostic message object,
|
|
5
|
-
#
|
|
6
|
-
# sandboxing, previews, and test helpers.
|
|
24
|
+
# templates, a provider-agnostic message object, a delivery pipeline with
|
|
25
|
+
# typed outcomes, provider adapters, retries, and test helpers.
|
|
7
26
|
#
|
|
8
|
-
#
|
|
27
|
+
# See docs/SPEC.md for the full design.
|
|
9
28
|
module Smswire
|
|
10
|
-
class
|
|
29
|
+
class << self
|
|
30
|
+
def config
|
|
31
|
+
@config ||= Configuration.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def configure
|
|
35
|
+
yield config
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def reset_config!
|
|
39
|
+
@config = Configuration.new
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def logger
|
|
43
|
+
config.logger || ActiveSupport::Logger.new($stdout)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Check the credentials of +provider+ (default: the default provider)
|
|
47
|
+
# with one read-only API call, for boot checks and health endpoints.
|
|
48
|
+
def verify_credentials!(provider = nil)
|
|
49
|
+
Providers.resolve(provider).verify_credentials!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Interceptors respond to +delivering_sms(message)+. They run after the
|
|
53
|
+
# recipient is normalized and before the provider is called, and may
|
|
54
|
+
# mutate the message or cancel it with +message.cancel!+.
|
|
55
|
+
def register_interceptor(interceptor)
|
|
56
|
+
config.interceptors << interceptor unless config.interceptors.include?(interceptor)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def unregister_interceptor(interceptor)
|
|
60
|
+
config.interceptors.delete(interceptor)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Observers respond to +delivered_sms(result)+. They are called with
|
|
64
|
+
# every pipeline outcome except transient errors, which raise.
|
|
65
|
+
def register_observer(observer)
|
|
66
|
+
config.observers << observer unless config.observers.include?(observer)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def unregister_observer(observer)
|
|
70
|
+
config.observers.delete(observer)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
11
73
|
end
|
|
74
|
+
|
|
75
|
+
require_relative "smswire/engine" if defined?(Rails::Railtie)
|
data/smswire.gemspec
CHANGED
|
@@ -22,17 +22,21 @@ Gem::Specification.new do |spec|
|
|
|
22
22
|
spec.metadata["source_code_uri"] = "https://github.com/timimsms/smswire"
|
|
23
23
|
spec.metadata["changelog_uri"] = "https://github.com/timimsms/smswire/blob/main/CHANGELOG.md"
|
|
24
24
|
spec.metadata["bug_tracker_uri"] = "https://github.com/timimsms/smswire/issues"
|
|
25
|
-
spec.metadata["documentation_uri"] = "https://github.com/timimsms/smswire/
|
|
25
|
+
spec.metadata["documentation_uri"] = "https://github.com/timimsms/smswire/tree/main/docs/guides"
|
|
26
26
|
spec.metadata["rubygems_mfa_required"] = "true"
|
|
27
27
|
|
|
28
28
|
spec.files = Dir.chdir(__dir__) do
|
|
29
29
|
`git ls-files -z`.split("\x0").reject do |f|
|
|
30
|
-
f.start_with?("test/", "bin/", ".github/", ".gitignore")
|
|
30
|
+
f.start_with?("test/", "bin/", ".github/", ".gitignore", "Gemfile", "Rakefile")
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
spec.require_paths = ["lib"]
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
rails_requirement = [">= 7.1", "< 9"]
|
|
36
|
+
spec.add_dependency "actionpack", *rails_requirement
|
|
37
|
+
spec.add_dependency "activejob", *rails_requirement
|
|
38
|
+
spec.add_dependency "activerecord", *rails_requirement
|
|
39
|
+
spec.add_dependency "activesupport", *rails_requirement
|
|
40
|
+
spec.add_dependency "railties", *rails_requirement
|
|
41
|
+
spec.add_dependency "zeitwerk", "~> 2.6"
|
|
38
42
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,128 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smswire
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tim Walsh
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: actionpack
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.1'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '9'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '7.1'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '9'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: activejob
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '7.1'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '9'
|
|
42
|
+
type: :runtime
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '7.1'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '9'
|
|
52
|
+
- !ruby/object:Gem::Dependency
|
|
53
|
+
name: activerecord
|
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '7.1'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '9'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '7.1'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '9'
|
|
72
|
+
- !ruby/object:Gem::Dependency
|
|
73
|
+
name: activesupport
|
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - ">="
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: '7.1'
|
|
79
|
+
- - "<"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '9'
|
|
82
|
+
type: :runtime
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '7.1'
|
|
89
|
+
- - "<"
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '9'
|
|
92
|
+
- !ruby/object:Gem::Dependency
|
|
93
|
+
name: railties
|
|
94
|
+
requirement: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
- - ">="
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '7.1'
|
|
99
|
+
- - "<"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '9'
|
|
102
|
+
type: :runtime
|
|
103
|
+
prerelease: false
|
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - ">="
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '7.1'
|
|
109
|
+
- - "<"
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '9'
|
|
112
|
+
- !ruby/object:Gem::Dependency
|
|
113
|
+
name: zeitwerk
|
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - "~>"
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: '2.6'
|
|
119
|
+
type: :runtime
|
|
120
|
+
prerelease: false
|
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - "~>"
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: '2.6'
|
|
13
126
|
description: |-
|
|
14
127
|
Smswire gives Rails applications Action Mailer-style messenger classes and
|
|
15
128
|
templates for SMS, a provider-agnostic message object, persisted deliveries
|
|
@@ -23,12 +136,86 @@ extensions: []
|
|
|
23
136
|
extra_rdoc_files: []
|
|
24
137
|
files:
|
|
25
138
|
- CHANGELOG.md
|
|
26
|
-
- Gemfile
|
|
27
139
|
- LICENSE.txt
|
|
28
140
|
- README.md
|
|
29
|
-
-
|
|
141
|
+
- RELEASING.md
|
|
142
|
+
- app/controllers/smswire/development_controller.rb
|
|
143
|
+
- app/controllers/smswire/inbound_messages_controller.rb
|
|
144
|
+
- app/controllers/smswire/inbox_controller.rb
|
|
145
|
+
- app/controllers/smswire/previews_controller.rb
|
|
146
|
+
- app/controllers/smswire/status_callbacks_controller.rb
|
|
147
|
+
- app/controllers/smswire/webhooks_controller.rb
|
|
148
|
+
- app/models/smswire/application_record.rb
|
|
149
|
+
- app/models/smswire/consent.rb
|
|
150
|
+
- app/models/smswire/delivery.rb
|
|
151
|
+
- app/models/smswire/inbound_message.rb
|
|
152
|
+
- app/views/layouts/smswire/application.html.erb
|
|
153
|
+
- app/views/smswire/inbox/index.html.erb
|
|
154
|
+
- app/views/smswire/previews/index.html.erb
|
|
155
|
+
- app/views/smswire/previews/show.html.erb
|
|
156
|
+
- config/routes.rb
|
|
157
|
+
- db/migrate/20261008000000_create_smswire_deliveries.rb
|
|
158
|
+
- db/migrate/20261008000001_create_smswire_consents_and_inbound_messages.rb
|
|
30
159
|
- docs/SPEC.md
|
|
160
|
+
- docs/guides/compliance.md
|
|
161
|
+
- docs/guides/getting-started.md
|
|
162
|
+
- docs/guides/migrating-from-noticed-twilio.md
|
|
163
|
+
- docs/guides/migrating-from-twilio-ruby.md
|
|
164
|
+
- docs/guides/writing-a-provider.md
|
|
165
|
+
- lib/generators/smswire/install/install_generator.rb
|
|
166
|
+
- lib/generators/smswire/install/templates/application_messenger.rb.tt
|
|
167
|
+
- lib/generators/smswire/install/templates/initializer.rb.tt
|
|
168
|
+
- lib/generators/smswire/messenger/messenger_generator.rb
|
|
169
|
+
- lib/generators/smswire/messenger/templates/messenger.rb.tt
|
|
170
|
+
- lib/generators/smswire/messenger/templates/preview.rb.tt
|
|
171
|
+
- lib/generators/smswire/messenger/templates/test.rb.tt
|
|
172
|
+
- lib/generators/smswire/messenger/templates/view.text.erb.tt
|
|
173
|
+
- lib/generators/smswire/provider/provider_generator.rb
|
|
174
|
+
- lib/generators/smswire/provider/templates/provider.rb.tt
|
|
175
|
+
- lib/generators/smswire/provider/templates/test.rb.tt
|
|
31
176
|
- lib/smswire.rb
|
|
177
|
+
- lib/smswire/base.rb
|
|
178
|
+
- lib/smswire/body_formatter.rb
|
|
179
|
+
- lib/smswire/callbacks.rb
|
|
180
|
+
- lib/smswire/configuration.rb
|
|
181
|
+
- lib/smswire/delivery_job.rb
|
|
182
|
+
- lib/smswire/engine.rb
|
|
183
|
+
- lib/smswire/errors.rb
|
|
184
|
+
- lib/smswire/http.rb
|
|
185
|
+
- lib/smswire/inbound.rb
|
|
186
|
+
- lib/smswire/inbound_handler.rb
|
|
187
|
+
- lib/smswire/interceptors/allowlist.rb
|
|
188
|
+
- lib/smswire/keyword_messenger.rb
|
|
189
|
+
- lib/smswire/keywords.rb
|
|
190
|
+
- lib/smswire/log_subscriber.rb
|
|
191
|
+
- lib/smswire/message.rb
|
|
192
|
+
- lib/smswire/message_delivery.rb
|
|
193
|
+
- lib/smswire/noticed_delivery_method.rb
|
|
194
|
+
- lib/smswire/parameterized_messenger.rb
|
|
195
|
+
- lib/smswire/phone_number.rb
|
|
196
|
+
- lib/smswire/pipeline.rb
|
|
197
|
+
- lib/smswire/preview.rb
|
|
198
|
+
- lib/smswire/provider_contract.rb
|
|
199
|
+
- lib/smswire/providers.rb
|
|
200
|
+
- lib/smswire/providers/base.rb
|
|
201
|
+
- lib/smswire/providers/log.rb
|
|
202
|
+
- lib/smswire/providers/null.rb
|
|
203
|
+
- lib/smswire/providers/telnyx.rb
|
|
204
|
+
- lib/smswire/providers/test.rb
|
|
205
|
+
- lib/smswire/providers/twilio.rb
|
|
206
|
+
- lib/smswire/providers/vonage.rb
|
|
207
|
+
- lib/smswire/quiet_hours.rb
|
|
208
|
+
- lib/smswire/rate_limit.rb
|
|
209
|
+
- lib/smswire/receipt.rb
|
|
210
|
+
- lib/smswire/recipient.rb
|
|
211
|
+
- lib/smswire/result.rb
|
|
212
|
+
- lib/smswire/rspec.rb
|
|
213
|
+
- lib/smswire/segments.rb
|
|
214
|
+
- lib/smswire/sender.rb
|
|
215
|
+
- lib/smswire/status_handler.rb
|
|
216
|
+
- lib/smswire/status_update.rb
|
|
217
|
+
- lib/smswire/test_helper.rb
|
|
218
|
+
- lib/smswire/testing.rb
|
|
32
219
|
- lib/smswire/version.rb
|
|
33
220
|
- smswire.gemspec
|
|
34
221
|
homepage: https://smswire.dev
|
|
@@ -39,9 +226,8 @@ metadata:
|
|
|
39
226
|
source_code_uri: https://github.com/timimsms/smswire
|
|
40
227
|
changelog_uri: https://github.com/timimsms/smswire/blob/main/CHANGELOG.md
|
|
41
228
|
bug_tracker_uri: https://github.com/timimsms/smswire/issues
|
|
42
|
-
documentation_uri: https://github.com/timimsms/smswire/
|
|
229
|
+
documentation_uri: https://github.com/timimsms/smswire/tree/main/docs/guides
|
|
43
230
|
rubygems_mfa_required: 'true'
|
|
44
|
-
post_install_message:
|
|
45
231
|
rdoc_options: []
|
|
46
232
|
require_paths:
|
|
47
233
|
- lib
|
|
@@ -56,8 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
56
242
|
- !ruby/object:Gem::Version
|
|
57
243
|
version: '0'
|
|
58
244
|
requirements: []
|
|
59
|
-
rubygems_version: 3.
|
|
60
|
-
signing_key:
|
|
245
|
+
rubygems_version: 3.6.9
|
|
61
246
|
specification_version: 4
|
|
62
247
|
summary: The production SMS layer for Rails.
|
|
63
248
|
test_files: []
|
data/Gemfile
DELETED