webhookdb 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86109800d36b097754f33ad1319331d4de0c4f90345a062c7f3222e57ce020db
4
- data.tar.gz: 4ac7ca8c78b01ea0144f3c7b4ecba7f89bebd581a1eb119a580526d9c99a3c67
3
+ metadata.gz: '0285d7331a0f43ff14a35e0b578d011c4d330caa9a1b9acdc04d741bbd1f35ae'
4
+ data.tar.gz: 807c8366605a9de9ebd6f13502e88a892b077a1435793c5a3db6bc6b2c400dc2
5
5
  SHA512:
6
- metadata.gz: 98e8f1f6dc67c6be2921270bf8c577c2702cf438251606bb0dbf58cb24660b078d9b2e5c54e5f4c4794aa6b2bf168abefafd5be620c56d5d8b8ca37cea9e32a3
7
- data.tar.gz: 1f0800e477cb27e927debf7e7a05bb0eed867ff972f036eaaca733d8a3ca1927f7b73f1e006a49b85a79e5c781e8b8295b9c1c208773ae6df1790b08fada1076
6
+ metadata.gz: 89bf0867a274a37410d35de3ade1bef240898d518cf9377ff49acc006b56094221821e86c8ceda7ea2b2d6da68e004b58aff694c0ee778837f034f73cb0bbb22
7
+ data.tar.gz: 21cc2b77bb8779ceb7e451499a90b82cd6ac211108d52441bfc203ad1334001b4a02e0d1761506d8dee6fbd56ed4fe534eb151dda96da5aa49fddfbacfaf6464
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/eventually"
4
+
5
+ require "webhookdb/async"
6
+
7
+ RSpec.describe "async workers", :integration do
8
+ it "emails the customer on reset code create" do
9
+ cu = with_async_publisher do
10
+ Webhookdb::Fixtures.reset_code.email.create
11
+ end
12
+
13
+ expect { cu.customer.refresh.message_deliveries }.to eventually(have_attributes(length: 1))
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "auth", :integration do
4
+ let(:password) { Webhookdb::Fixtures::Customers::PASSWORD }
5
+
6
+ it "allows me to sign up with a token, and log out" do
7
+ customer = Webhookdb::Fixtures.customer.create
8
+ code = Webhookdb::Fixtures.reset_code(customer:).create
9
+
10
+ login_resp = post(
11
+ "/v1/auth",
12
+ body: {email: customer.email, token: code.token},
13
+ )
14
+ expect(login_resp).to party_status(200)
15
+
16
+ customer_resp = get("/v1/me")
17
+ expect(customer_resp).to party_status(200)
18
+
19
+ logout_resp = post("/v1/auth/logout")
20
+ expect(logout_resp).to party_status(200)
21
+ end
22
+
23
+ it "allows me to login via OTP, and logout" do
24
+ customer = Webhookdb::Fixtures.customer.instance
25
+
26
+ login_resp = post("/v1/auth", body: {email: customer.email})
27
+ expect(login_resp).to party_status(202)
28
+
29
+ customer = Webhookdb::Customer[email: customer.email]
30
+ login_resp = post("/v1/auth/login_otp/#{customer.opaque_id}", body: {value: customer.reset_codes.last.token})
31
+ expect(login_resp).to party_status(200)
32
+
33
+ customer_resp = get("/v1/me")
34
+ expect(customer_resp).to party_status(200)
35
+
36
+ logout_resp = post("/v1/auth/logout")
37
+ expect(logout_resp).to party_status(200)
38
+ end
39
+
40
+ it "can access admin endpoints only if the customer authed as an admin and retains the role" do
41
+ customer = Webhookdb::Fixtures.customer.admin.instance
42
+ auth_customer(customer)
43
+
44
+ resp = get("/admin/v1/auth")
45
+ expect(resp).to party_status(200)
46
+ expect(resp).to party_response(match(hash_including(name: customer.name)))
47
+
48
+ customer.remove_role(Webhookdb::Role.admin_role)
49
+
50
+ resp = get("/admin/v1/auth")
51
+ expect(resp).to party_status(401)
52
+ end
53
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "database", :integration do
4
+ def setup_integration_with_data(rows)
5
+ org = Webhookdb::Fixtures.organization.create
6
+ org.prepare_database_connections
7
+ sint = Webhookdb::Fixtures.service_integration(organization: org).create
8
+ sint.replicator.create_table
9
+ Array.new(rows) do |i|
10
+ t = (Time.now - i.days).iso8601
11
+ sint.replicator.upsert_webhook_body({"my_id" => i.to_s, "at" => t})
12
+ end
13
+ Webhookdb::Organization::DbBuilder.new(org).prepare_database_connections
14
+ return sint
15
+ end
16
+
17
+ it "can sync to database sync targets" do
18
+ sint = setup_integration_with_data(5)
19
+ sync_tgt = Webhookdb::Fixtures.sync_target(
20
+ service_integration: sint,
21
+ connection_url: sint.organization.admin_connection_url,
22
+ ).create
23
+ @to_destroy << sync_tgt
24
+ require "webhookdb/jobs/sync_target_run_sync"
25
+ Webhookdb::Jobs::SyncTargetRunSync.perform_async(sync_tgt.id)
26
+ expect { sync_tgt.refresh }.to eventually(have_attributes(last_synced_at: be_present))
27
+ Sequel.connect(sint.organization.readonly_connection_url) do |db|
28
+ expect(db[sint.table_name.to_sym].all).to have_attributes(size: 5)
29
+ end
30
+ expect(sync_tgt.advisory_lock(sync_tgt.db).dataset(this: true).all).to be_empty
31
+ end
32
+
33
+ it "can sync to http sync targets" do
34
+ sint = setup_integration_with_data(5)
35
+ sync_tgt = Webhookdb::Fixtures.sync_target(
36
+ service_integration: sint,
37
+ connection_url: "http://u:p@localhost:18015/mypath",
38
+ ).create
39
+ @to_destroy << sync_tgt
40
+
41
+ require "socket"
42
+ server = TCPServer.new "localhost", 18_015
43
+ received = []
44
+ server_thread = Thread.new do
45
+ # Will only have one session
46
+ session = server.accept
47
+ # Processing line by line isn't needed here, we're just testing so grab the whole body
48
+ received << session.recv(4096)
49
+ session.print "HTTP/1.1 200\r\n"
50
+ session.print "Content-Type: text/plain\r\n"
51
+ session.print "\r\n"
52
+ session.print "ok"
53
+ session.close
54
+ end
55
+
56
+ # We need to do this in-process so the sync can POST back to localhost;
57
+ # if the worker was on another machine, the tcp server wouldn't be reachable.
58
+ sync_tgt.run_sync(now: Time.now)
59
+ expect { sync_tgt.refresh }.to eventually(have_attributes(last_synced_at: be_present))
60
+ expect { received }.to eventually(contain_exactly(include("POST /mypath").and(include('"rows":'))))
61
+ Thread.kill(server_thread)
62
+ expect(sync_tgt.advisory_lock(sync_tgt.db).dataset(this: true).all).to be_empty
63
+ end
64
+
65
+ it "can run a database migration" do
66
+ sint = setup_integration_with_data(5)
67
+ org = sint.organization
68
+ dbmigration = with_async_publisher do
69
+ Webhookdb::Organization::DatabaseMigration.enqueue(
70
+ admin_connection_url_raw: org.admin_connection_url,
71
+ readonly_connection_url_raw: org.readonly_connection_url,
72
+ public_host: org.public_host,
73
+ started_by: nil,
74
+ organization: org,
75
+ )
76
+ end
77
+ expect { dbmigration.refresh }.to eventually(have_attributes(status: "finished"))
78
+ Sequel.connect(org.readonly_connection_url) do |db|
79
+ expect(db[Sequel[org.replication_schema.to_sym][sint.table_name.to_sym]].all).to have_attributes(size: 5)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "helpers", :integration do
4
+ it "can use the redis cache" do
5
+ key = "integration-test-key"
6
+ Webhookdb::Redis.cache.with do |r|
7
+ r.call("SET", key, "1")
8
+ expect(r.call("GET", key)).to eq("1")
9
+ end
10
+ t = Thread.start do
11
+ Webhookdb::Redis.cache.with do |r|
12
+ r.call("DEL", key)
13
+ expect(r.call("GET", key)).to be_nil
14
+ end
15
+ end
16
+ t.join
17
+ Webhookdb::Redis.cache.with do |r|
18
+ expect(r.call("GET", key)).to be_nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/eventually"
4
+
5
+ RSpec.describe "service integrations", :integration do
6
+ def catch_missing_db(default)
7
+ yield
8
+ rescue Sequel::DatabaseError
9
+ return default
10
+ end
11
+
12
+ it "can create a full webhookdb customer integration and POST webhooks" do
13
+ c = auth_customer
14
+ expect { c.refresh.all_memberships }.to eventually(have_attributes(length: 1))
15
+ org = c.verified_memberships.last.organization
16
+ expect { org.refresh }.to eventually(have_attributes(readonly_connection_url: be_present))
17
+ org.add_feature_role(Webhookdb::Role.find_or_create(name: "internal"))
18
+
19
+ resp = post(
20
+ "/v1/organizations/#{org.id}/service_integrations/create",
21
+ body: {service_name: "webhookdb_customer_v1"},
22
+ )
23
+ expect(resp).to party_status(200)
24
+
25
+ expect(org.refresh.service_integrations).to have_attributes(length: 1)
26
+ sint = org.service_integrations.first
27
+
28
+ expect do
29
+ catch_missing_db(["default"]) { sint.replicator.readonly_dataset(&:all) }
30
+ end.to eventually(be_empty)
31
+
32
+ with_async_publisher do
33
+ Webhookdb::Fixtures.customer.create
34
+ end
35
+
36
+ expect do
37
+ catch_missing_db(["default"]) { sint.replicator.readonly_dataset(&:all) }
38
+ end.to eventually(have_attributes(length: 1))
39
+
40
+ # puts sint.opaque_id, "/v1/service_integrations/#{sint.opaque_id}"
41
+ resp = post(
42
+ "/v1/service_integrations/#{sint.opaque_id}",
43
+ body: c.values.as_json,
44
+ headers: {"Whdb-Secret" => sint.webhook_secret},
45
+ json: true,
46
+ )
47
+ expect(resp).to party_status(202)
48
+ expect(resp).to party_response(match(o: "k"))
49
+ logged_whs = Webhookdb::LoggedWebhook.where(service_integration_opaque_id: sint.opaque_id).all
50
+ expect(logged_whs).to_not be_empty
51
+ end
52
+
53
+ it "can upsert data synchrononously through endpoint" do
54
+ c = auth_customer
55
+ expect { c.refresh.all_memberships }.to eventually(have_attributes(length: 1))
56
+ org = c.verified_memberships.last.organization
57
+ expect { org.refresh }.to eventually(have_attributes(readonly_connection_url: be_present))
58
+ org.add_feature_role(Webhookdb::Role.find_or_create(name: "internal"))
59
+ sint = Webhookdb::Fixtures.service_integration(organization: org).create
60
+ sint.replicator.create_table
61
+
62
+ resp = post(
63
+ "/v1/organizations/#{org.id}/service_integrations/#{sint.opaque_id}/upsert",
64
+ body: {my_id: "id", at: Time.now},
65
+ json: true,
66
+ )
67
+ expect(resp).to party_status(200)
68
+ expect(resp).to party_response(match(hash_including(message: /You have upserted/)))
69
+
70
+ expect(sint.replicator.readonly_dataset(&:all)).to contain_exactly(include(my_id: "id"))
71
+ end
72
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "system", :integration do
4
+ it "responds to a health check" do
5
+ response = HTTParty.get(url("/healthz"))
6
+ expect(response).to party_status(200)
7
+ expect(response).to party_response(eq(o: "k"))
8
+ end
9
+
10
+ it "responds to a status check" do
11
+ response = HTTParty.get(url("/statusz"))
12
+ expect(response).to party_status(200)
13
+ expect(response).to party_response(include(:version))
14
+ end
15
+ end
@@ -13,7 +13,10 @@ class Webhookdb::API::System < Webhookdb::Service
13
13
  helpers Webhookdb::Service::Helpers
14
14
 
15
15
  get :healthz do
16
- Webhookdb::Postgres::Model.db.execute("SELECT 1=1")
16
+ # Do not bother looking at dependencies like databases.
17
+ # If the primary is down, we can still accept webhooks
18
+ # if LoggedWebhook resiliency is configured,
19
+ # which is the primary thing about whether we're healthy or not.
17
20
  status 200
18
21
  {o: "k"}
19
22
  end
@@ -29,9 +32,11 @@ class Webhookdb::API::System < Webhookdb::Service
29
32
  }
30
33
  end
31
34
 
32
- resource :debug do
33
- get :echo do
34
- pp params.to_h
35
+ if ["development", "test"].include?(Webhookdb::RACK_ENV)
36
+ resource :debug do
37
+ get :echo do
38
+ pp params.to_h
39
+ end
35
40
  end
36
41
  end
37
42
  end
@@ -34,6 +34,32 @@ require "webhookdb/admin_api/roles"
34
34
  require "webterm/apps"
35
35
 
36
36
  module Webhookdb::Apps
37
+ # Call this from your rackup file, like config.ru.
38
+ #
39
+ # @example
40
+ # lib = File.expand_path("lib", __dir__)
41
+ # $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
42
+ # require "webhookdb"
43
+ # Webhookdb.load_app
44
+ # require "webhookdb/apps"
45
+ # Webhookdb::Apps.rack_up(self)
46
+ #
47
+ def self.rack_up(config_ru)
48
+ Webhookdb::Async.setup_web
49
+ config_ru.instance_exec do
50
+ map "/admin" do
51
+ run Webhookdb::Apps::AdminAPI.build_app
52
+ end
53
+ map "/sidekiq" do
54
+ run Webhookdb::Apps::SidekiqWeb.to_app
55
+ end
56
+ map "/terminal" do
57
+ run Webhookdb::Apps::Webterm.to_app
58
+ end
59
+ run Webhookdb::Apps::API.build_app
60
+ end
61
+ end
62
+
37
63
  class API < Webhookdb::Service
38
64
  mount Webhookdb::API::Auth
39
65
  mount Webhookdb::API::Db
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb"
4
+
5
+ module Webhookdb::Pry
6
+ # Call this from .pryrc.
7
+ #
8
+ # @example
9
+ # lib = File.expand_path("lib", __dir__)
10
+ # $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
11
+ #
12
+ # require "appydays/dotenviable"
13
+ # Appydays::Dotenviable.load
14
+ #
15
+ # require "webhookdb/pry"
16
+ # Webhookdb::Pry.setup(self)
17
+ def self.setup(main)
18
+ main.instance_exec do
19
+ require "pry/clipboard"
20
+
21
+ Pry.config.commands.alias_command "ch", "copy-history"
22
+ Pry.config.commands.alias_command "cr", "copy-result"
23
+
24
+ # Decode the given cookie string. Since cookies are encrypted,
25
+ # this is useful for debugging what they contain.
26
+ def decode_cookie(s)
27
+ require "webhookdb/service"
28
+ return Webhookdb::Service.decode_cookie(s)
29
+ end
30
+
31
+ # Connect this session of Pry to the database.
32
+ # It also registers subscribers, so changes to the models are handled
33
+ # by their correct async jobs (since async jobs are handled in-process).
34
+ def connect
35
+ require "webhookdb"
36
+ Webhookdb.load_app
37
+ Webhookdb::Async.setup_web if Amigo.subscribers.empty?
38
+ return
39
+ end
40
+
41
+ def copt
42
+ rc = Appydays::Loggable[self].silence(:fatal) do
43
+ Webhookdb::Customer::ResetCode.order(:id).last
44
+ end
45
+ tok = rc.token
46
+ Clipboard.copy tok
47
+ puts "Copied OTP #{tok} for #{rc.customer.email} to clipboard"
48
+ return tok
49
+ end
50
+
51
+ # Load models and fixtures. Use this when riffing locally.
52
+ def repl
53
+ require "webhookdb"
54
+ Webhookdb.load_app
55
+ require "webhookdb/fixtures"
56
+ Webhookdb::Fixtures.load_all
57
+ return
58
+ end
59
+
60
+ def console
61
+ connect
62
+ require "webhookdb/console"
63
+ Webhookdb::Console.enable_safe_mode
64
+ self.extend Webhookdb::Console::MainMethods
65
+ Amigo.register_subscriber do |ev|
66
+ Webhookdb::Console.console_logger(ev)
67
+ end
68
+ return
69
+ end
70
+ end
71
+ end
72
+ end
@@ -3,9 +3,10 @@
3
3
  # Write docs for docs.webhookdb.com Jekyll site.
4
4
  class Webhookdb::Replicator::Docgen
5
5
  def self.documentable_descriptors
6
- return Webhookdb::Replicator.registry.values.reject do |repl|
7
- repl.name.start_with?("webhookdb_", "fake_")
8
- end.sort_by(&:name)
6
+ return Webhookdb::Replicator.registry.
7
+ values.
8
+ select(&:documentable?).
9
+ sort_by(&:name)
9
10
  end
10
11
 
11
12
  # @!attribute desc
@@ -79,6 +79,8 @@ class Webhookdb::Replicator
79
79
  # Is this an enterprise-only replicator?
80
80
  attr_reader :enterprise
81
81
 
82
+ def documentable? = @documentable
83
+
82
84
  def initialize(
83
85
  name:,
84
86
  ctor:,
@@ -91,7 +93,8 @@ class Webhookdb::Replicator
91
93
  api_docs_url: "",
92
94
  description: nil,
93
95
  enterprise: false,
94
- documentation_url: nil
96
+ documentation_url: nil,
97
+ documentable: nil
95
98
  )
96
99
  raise ArgumentError, "must support one or both of webhooks and backfill" unless
97
100
  supports_webhooks || supports_backfill
@@ -109,7 +112,7 @@ class Webhookdb::Replicator
109
112
  @ctor = ctor.is_a?(Class) ? ctor.method(:new) : ctor
110
113
  @resource_name_plural = resource_name_plural || "#{self.resource_name_singular}s"
111
114
  @description = description || "Replicate #{self.resource_name_plural} into your database."
112
- self.feature_roles
115
+ @documentable = documentable.nil? ? !self.name.start_with?("webhookdb_", "fake_", "theranest_") : documentable
113
116
  end
114
117
 
115
118
  def inspect
@@ -26,12 +26,12 @@ module Webhookdb::IntegrationSpecHelpers
26
26
  example.metadata[:integration]
27
27
 
28
28
  @to_destroy = []
29
- WebMock.allow_net_connect!
29
+ WebMock.allow_net_connect! if defined?(WebMock)
30
30
  end
31
31
 
32
32
  context.after(:each) do
33
33
  @to_destroy.each(&:destroy)
34
- WebMock.disable_net_connect!
34
+ WebMock.disable_net_connect! if defined?(WebMock)
35
35
  end
36
36
  super
37
37
  end
@@ -36,7 +36,7 @@ module Webhookdb::Tasks
36
36
  require "webhookdb/heroku"
37
37
  Webhookdb::Heroku.client.dyno.create(
38
38
  Webhookdb::Heroku.app_name,
39
- command: "bundle exec rake specs:integration_step3",
39
+ command: "bundle exec rake specs:heroku_integration_step3",
40
40
  env: {"INTEGRATION_TESTS" => "true"},
41
41
  attach: false,
42
42
  time_to_live: 10.minute.to_i,
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb"
4
+
5
+ module Webhookdb::Tasks
6
+ # Load all Webhookdb Rake tasks.
7
+ # You can also load them individually.
8
+ def self.load_all
9
+ require "webhookdb/tasks/admin"
10
+ Webhookdb::Tasks::Admin.new
11
+ require "webhookdb/tasks/annotate"
12
+ Webhookdb::Tasks::Annotate.new
13
+ require "webhookdb/tasks/db"
14
+ Webhookdb::Tasks::DB.new
15
+ require "webhookdb/tasks/docs"
16
+ Webhookdb::Tasks::Docs.new
17
+ require "webhookdb/tasks/fixture"
18
+ Webhookdb::Tasks::Fixture.new
19
+ require "webhookdb/tasks/release"
20
+ Webhookdb::Tasks::Release.new
21
+ require "webhookdb/tasks/message"
22
+ Webhookdb::Tasks::Message.new
23
+ require "webhookdb/tasks/regress"
24
+ Webhookdb::Tasks::Regress.new
25
+ require "webhookdb/tasks/sidekiq"
26
+ Webhookdb::Tasks::Sidekiq.new
27
+ require "webhookdb/tasks/specs"
28
+ Webhookdb::Tasks::Specs.new
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Webhookdb
4
- VERSION = "0.1.1"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/webhookdb.rb CHANGED
@@ -54,6 +54,7 @@ module Webhookdb
54
54
  RELEASE = ENV.fetch("HEROKU_RELEASE_VERSION", "unknown-release")
55
55
  RELEASE_CREATED_AT = ENV.fetch("HEROKU_RELEASE_CREATED_AT") { Time.at(0).utc.iso8601 }
56
56
  INTEGRATION_TESTS_ENABLED = ENV.fetch("INTEGRATION_TESTS", false)
57
+ require "webhookdb/version"
57
58
 
58
59
  DATA_DIR = Pathname(__FILE__).dirname.parent + "data"
59
60
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webhookdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - WebhookDB
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-08 00:00:00.000000000 Z
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '1.8'
111
+ - !ruby/object:Gem::Dependency
112
+ name: clipboard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.3'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.3'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: concurrent-ruby
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -810,6 +824,12 @@ files:
810
824
  - db/migrations/035_synchronous_backfill.rb
811
825
  - db/migrations/036_oauth.rb
812
826
  - db/migrations/037_oauth_used.rb
827
+ - integration/async_spec.rb
828
+ - integration/auth_spec.rb
829
+ - integration/database_spec.rb
830
+ - integration/helpers_spec.rb
831
+ - integration/service_integrations_spec.rb
832
+ - integration/system_spec.rb
813
833
  - lib/amigo/durable_job.rb
814
834
  - lib/pry/clipboard.rb
815
835
  - lib/sequel/advisory_lock.rb
@@ -974,6 +994,7 @@ files:
974
994
  - lib/webhookdb/postgres/testing_pixie.rb
975
995
  - lib/webhookdb/postgres/validations.rb
976
996
  - lib/webhookdb/postmark.rb
997
+ - lib/webhookdb/pry.rb
977
998
  - lib/webhookdb/redis.rb
978
999
  - lib/webhookdb/replicator.rb
979
1000
  - lib/webhookdb/replicator/atom_single_feed_v1.rb
@@ -1081,6 +1102,7 @@ files:
1081
1102
  - lib/webhookdb/stripe.rb
1082
1103
  - lib/webhookdb/subscription.rb
1083
1104
  - lib/webhookdb/sync_target.rb
1105
+ - lib/webhookdb/tasks.rb
1084
1106
  - lib/webhookdb/tasks/admin.rb
1085
1107
  - lib/webhookdb/tasks/annotate.rb
1086
1108
  - lib/webhookdb/tasks/db.rb