webhookdb 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 (364) hide show
  1. checksums.yaml +7 -0
  2. data/data/messages/layouts/blank.email.liquid +10 -0
  3. data/data/messages/layouts/minimal.email.liquid +28 -0
  4. data/data/messages/layouts/standard.email.liquid +28 -0
  5. data/data/messages/partials/button.liquid +15 -0
  6. data/data/messages/partials/environment_banner.liquid +9 -0
  7. data/data/messages/partials/footer.liquid +22 -0
  8. data/data/messages/partials/greeting.liquid +3 -0
  9. data/data/messages/partials/logo_header.liquid +18 -0
  10. data/data/messages/partials/signoff.liquid +1 -0
  11. data/data/messages/styles/v1.liquid +346 -0
  12. data/data/messages/templates/errors/icalendar_fetch.email.liquid +29 -0
  13. data/data/messages/templates/invite.email.liquid +15 -0
  14. data/data/messages/templates/new_customer.email.liquid +24 -0
  15. data/data/messages/templates/org_database_migration_finished.email.liquid +7 -0
  16. data/data/messages/templates/org_database_migration_started.email.liquid +9 -0
  17. data/data/messages/templates/specs/_field_partial.liquid +1 -0
  18. data/data/messages/templates/specs/basic.email.liquid +2 -0
  19. data/data/messages/templates/specs/basic.fake.liquid +1 -0
  20. data/data/messages/templates/specs/with_field.email.liquid +2 -0
  21. data/data/messages/templates/specs/with_field.fake.liquid +1 -0
  22. data/data/messages/templates/specs/with_include.email.liquid +2 -0
  23. data/data/messages/templates/specs/with_partial.email.liquid +1 -0
  24. data/data/messages/templates/verification.email.liquid +14 -0
  25. data/data/messages/templates/verification.sms.liquid +1 -0
  26. data/data/messages/web/install-customer-login.liquid +48 -0
  27. data/data/messages/web/install-error.liquid +17 -0
  28. data/data/messages/web/install-success.liquid +35 -0
  29. data/data/messages/web/install.liquid +20 -0
  30. data/data/messages/web/partials/footer.liquid +4 -0
  31. data/data/messages/web/partials/form_error.liquid +1 -0
  32. data/data/messages/web/partials/header.liquid +3 -0
  33. data/data/messages/web/styles.liquid +134 -0
  34. data/data/windows_tz.txt +461 -0
  35. data/db/migrations/001_testing_pixies.rb +13 -0
  36. data/db/migrations/002_initial.rb +132 -0
  37. data/db/migrations/003_ux_overhaul.rb +20 -0
  38. data/db/migrations/004_incremental_backfill.rb +9 -0
  39. data/db/migrations/005_log_webhooks.rb +24 -0
  40. data/db/migrations/006_generalize_roles.rb +29 -0
  41. data/db/migrations/007_org_dns.rb +12 -0
  42. data/db/migrations/008_webhook_subscriptions.rb +19 -0
  43. data/db/migrations/009_nonunique_stripe_subscription_customer.rb +16 -0
  44. data/db/migrations/010_drop_integration_soft_delete.rb +14 -0
  45. data/db/migrations/011_webhook_subscriptions_created_at.rb +10 -0
  46. data/db/migrations/012_webhook_subscriptions_created_by.rb +9 -0
  47. data/db/migrations/013_default_org_membership.rb +30 -0
  48. data/db/migrations/014_webhook_subscription_deliveries.rb +26 -0
  49. data/db/migrations/015_dependent_integrations.rb +9 -0
  50. data/db/migrations/016_encrypted_columns.rb +9 -0
  51. data/db/migrations/017_skip_verification.rb +9 -0
  52. data/db/migrations/018_sync_targets.rb +25 -0
  53. data/db/migrations/019_org_schema.rb +9 -0
  54. data/db/migrations/020_org_database_migrations.rb +25 -0
  55. data/db/migrations/021_no_default_org_schema.rb +14 -0
  56. data/db/migrations/022_database_document.rb +15 -0
  57. data/db/migrations/023_sync_target_schema.rb +9 -0
  58. data/db/migrations/024_org_semaphore_jobs.rb +9 -0
  59. data/db/migrations/025_integration_backfill_cursor.rb +9 -0
  60. data/db/migrations/026_undo_integration_backfill_cursor.rb +9 -0
  61. data/db/migrations/027_sync_target_http_sync.rb +12 -0
  62. data/db/migrations/028_logged_webhook_path.rb +24 -0
  63. data/db/migrations/029_encrypt_columns.rb +97 -0
  64. data/db/migrations/030_org_sync_target_timeout.rb +9 -0
  65. data/db/migrations/031_org_max_query_rows.rb +9 -0
  66. data/db/migrations/032_remove_db_defaults.rb +12 -0
  67. data/db/migrations/033_backfill_jobs.rb +26 -0
  68. data/db/migrations/034_backfill_job_criteria.rb +9 -0
  69. data/db/migrations/035_synchronous_backfill.rb +9 -0
  70. data/db/migrations/036_oauth.rb +26 -0
  71. data/db/migrations/037_oauth_used.rb +9 -0
  72. data/lib/amigo/durable_job.rb +416 -0
  73. data/lib/pry/clipboard.rb +111 -0
  74. data/lib/sequel/advisory_lock.rb +65 -0
  75. data/lib/webhookdb/admin.rb +4 -0
  76. data/lib/webhookdb/admin_api/auth.rb +36 -0
  77. data/lib/webhookdb/admin_api/customers.rb +63 -0
  78. data/lib/webhookdb/admin_api/database_documents.rb +20 -0
  79. data/lib/webhookdb/admin_api/entities.rb +66 -0
  80. data/lib/webhookdb/admin_api/message_deliveries.rb +61 -0
  81. data/lib/webhookdb/admin_api/roles.rb +15 -0
  82. data/lib/webhookdb/admin_api.rb +34 -0
  83. data/lib/webhookdb/aggregate_result.rb +63 -0
  84. data/lib/webhookdb/api/auth.rb +122 -0
  85. data/lib/webhookdb/api/connstr_auth.rb +36 -0
  86. data/lib/webhookdb/api/db.rb +188 -0
  87. data/lib/webhookdb/api/demo.rb +14 -0
  88. data/lib/webhookdb/api/entities.rb +198 -0
  89. data/lib/webhookdb/api/helpers.rb +253 -0
  90. data/lib/webhookdb/api/install.rb +296 -0
  91. data/lib/webhookdb/api/me.rb +53 -0
  92. data/lib/webhookdb/api/organizations.rb +254 -0
  93. data/lib/webhookdb/api/replay.rb +64 -0
  94. data/lib/webhookdb/api/service_integrations.rb +402 -0
  95. data/lib/webhookdb/api/services.rb +27 -0
  96. data/lib/webhookdb/api/stripe.rb +22 -0
  97. data/lib/webhookdb/api/subscriptions.rb +67 -0
  98. data/lib/webhookdb/api/sync_targets.rb +232 -0
  99. data/lib/webhookdb/api/system.rb +37 -0
  100. data/lib/webhookdb/api/webhook_subscriptions.rb +96 -0
  101. data/lib/webhookdb/api.rb +92 -0
  102. data/lib/webhookdb/apps.rb +93 -0
  103. data/lib/webhookdb/async/audit_logger.rb +38 -0
  104. data/lib/webhookdb/async/autoscaler.rb +84 -0
  105. data/lib/webhookdb/async/job.rb +18 -0
  106. data/lib/webhookdb/async/job_logger.rb +45 -0
  107. data/lib/webhookdb/async/scheduled_job.rb +18 -0
  108. data/lib/webhookdb/async.rb +142 -0
  109. data/lib/webhookdb/aws.rb +98 -0
  110. data/lib/webhookdb/backfill_job.rb +107 -0
  111. data/lib/webhookdb/backfiller.rb +107 -0
  112. data/lib/webhookdb/cloudflare.rb +39 -0
  113. data/lib/webhookdb/connection_cache.rb +177 -0
  114. data/lib/webhookdb/console.rb +71 -0
  115. data/lib/webhookdb/convertkit.rb +14 -0
  116. data/lib/webhookdb/crypto.rb +66 -0
  117. data/lib/webhookdb/customer/reset_code.rb +94 -0
  118. data/lib/webhookdb/customer.rb +347 -0
  119. data/lib/webhookdb/database_document.rb +72 -0
  120. data/lib/webhookdb/db_adapter/column_types.rb +37 -0
  121. data/lib/webhookdb/db_adapter/default_sql.rb +187 -0
  122. data/lib/webhookdb/db_adapter/pg.rb +96 -0
  123. data/lib/webhookdb/db_adapter/snowflake.rb +137 -0
  124. data/lib/webhookdb/db_adapter.rb +208 -0
  125. data/lib/webhookdb/dbutil.rb +92 -0
  126. data/lib/webhookdb/demo_mode.rb +100 -0
  127. data/lib/webhookdb/developer_alert.rb +51 -0
  128. data/lib/webhookdb/email_octopus.rb +21 -0
  129. data/lib/webhookdb/enumerable.rb +18 -0
  130. data/lib/webhookdb/fixtures/backfill_jobs.rb +72 -0
  131. data/lib/webhookdb/fixtures/customers.rb +65 -0
  132. data/lib/webhookdb/fixtures/database_documents.rb +27 -0
  133. data/lib/webhookdb/fixtures/faker.rb +41 -0
  134. data/lib/webhookdb/fixtures/logged_webhooks.rb +56 -0
  135. data/lib/webhookdb/fixtures/message_deliveries.rb +59 -0
  136. data/lib/webhookdb/fixtures/oauth_sessions.rb +24 -0
  137. data/lib/webhookdb/fixtures/organization_database_migrations.rb +37 -0
  138. data/lib/webhookdb/fixtures/organization_memberships.rb +54 -0
  139. data/lib/webhookdb/fixtures/organizations.rb +32 -0
  140. data/lib/webhookdb/fixtures/reset_codes.rb +23 -0
  141. data/lib/webhookdb/fixtures/service_integrations.rb +42 -0
  142. data/lib/webhookdb/fixtures/subscriptions.rb +33 -0
  143. data/lib/webhookdb/fixtures/sync_targets.rb +32 -0
  144. data/lib/webhookdb/fixtures/webhook_subscriptions.rb +35 -0
  145. data/lib/webhookdb/fixtures.rb +15 -0
  146. data/lib/webhookdb/formatting.rb +56 -0
  147. data/lib/webhookdb/front.rb +49 -0
  148. data/lib/webhookdb/github.rb +22 -0
  149. data/lib/webhookdb/google_calendar.rb +29 -0
  150. data/lib/webhookdb/heroku.rb +21 -0
  151. data/lib/webhookdb/http.rb +114 -0
  152. data/lib/webhookdb/icalendar.rb +17 -0
  153. data/lib/webhookdb/id.rb +17 -0
  154. data/lib/webhookdb/idempotency.rb +90 -0
  155. data/lib/webhookdb/increase.rb +42 -0
  156. data/lib/webhookdb/intercom.rb +23 -0
  157. data/lib/webhookdb/jobs/amigo_test_jobs.rb +118 -0
  158. data/lib/webhookdb/jobs/backfill.rb +32 -0
  159. data/lib/webhookdb/jobs/create_mirror_table.rb +18 -0
  160. data/lib/webhookdb/jobs/create_stripe_customer.rb +17 -0
  161. data/lib/webhookdb/jobs/customer_created_notify_internal.rb +22 -0
  162. data/lib/webhookdb/jobs/demo_mode_sync_data.rb +19 -0
  163. data/lib/webhookdb/jobs/deprecated_jobs.rb +19 -0
  164. data/lib/webhookdb/jobs/developer_alert_handle.rb +14 -0
  165. data/lib/webhookdb/jobs/durable_job_recheck_poller.rb +17 -0
  166. data/lib/webhookdb/jobs/emailer.rb +15 -0
  167. data/lib/webhookdb/jobs/icalendar_enqueue_syncs.rb +25 -0
  168. data/lib/webhookdb/jobs/icalendar_sync.rb +23 -0
  169. data/lib/webhookdb/jobs/logged_webhook_replay.rb +17 -0
  170. data/lib/webhookdb/jobs/logged_webhook_resilient_replay.rb +15 -0
  171. data/lib/webhookdb/jobs/message_dispatched.rb +16 -0
  172. data/lib/webhookdb/jobs/organization_database_migration_notify_finished.rb +21 -0
  173. data/lib/webhookdb/jobs/organization_database_migration_notify_started.rb +21 -0
  174. data/lib/webhookdb/jobs/organization_database_migration_run.rb +24 -0
  175. data/lib/webhookdb/jobs/prepare_database_connections.rb +22 -0
  176. data/lib/webhookdb/jobs/process_webhook.rb +47 -0
  177. data/lib/webhookdb/jobs/renew_watch_channel.rb +24 -0
  178. data/lib/webhookdb/jobs/replication_migration.rb +24 -0
  179. data/lib/webhookdb/jobs/reset_code_create_dispatch.rb +23 -0
  180. data/lib/webhookdb/jobs/scheduled_backfills.rb +77 -0
  181. data/lib/webhookdb/jobs/send_invite.rb +15 -0
  182. data/lib/webhookdb/jobs/send_test_webhook.rb +25 -0
  183. data/lib/webhookdb/jobs/send_webhook.rb +20 -0
  184. data/lib/webhookdb/jobs/sync_target_enqueue_scheduled.rb +16 -0
  185. data/lib/webhookdb/jobs/sync_target_run_sync.rb +38 -0
  186. data/lib/webhookdb/jobs/trim_logged_webhooks.rb +15 -0
  187. data/lib/webhookdb/jobs/webhook_resource_notify_integrations.rb +30 -0
  188. data/lib/webhookdb/jobs/webhook_subscription_delivery_attempt.rb +29 -0
  189. data/lib/webhookdb/jobs.rb +4 -0
  190. data/lib/webhookdb/json.rb +113 -0
  191. data/lib/webhookdb/liquid/expose.rb +27 -0
  192. data/lib/webhookdb/liquid/filters.rb +16 -0
  193. data/lib/webhookdb/liquid/liquification.rb +26 -0
  194. data/lib/webhookdb/liquid/partial.rb +12 -0
  195. data/lib/webhookdb/logged_webhook/resilient.rb +95 -0
  196. data/lib/webhookdb/logged_webhook.rb +194 -0
  197. data/lib/webhookdb/message/body.rb +25 -0
  198. data/lib/webhookdb/message/delivery.rb +127 -0
  199. data/lib/webhookdb/message/email_transport.rb +133 -0
  200. data/lib/webhookdb/message/fake_transport.rb +54 -0
  201. data/lib/webhookdb/message/liquid_drops.rb +29 -0
  202. data/lib/webhookdb/message/template.rb +89 -0
  203. data/lib/webhookdb/message/transport.rb +43 -0
  204. data/lib/webhookdb/message.rb +150 -0
  205. data/lib/webhookdb/messages/error_icalendar_fetch.rb +42 -0
  206. data/lib/webhookdb/messages/invite.rb +23 -0
  207. data/lib/webhookdb/messages/new_customer.rb +14 -0
  208. data/lib/webhookdb/messages/org_database_migration_finished.rb +23 -0
  209. data/lib/webhookdb/messages/org_database_migration_started.rb +24 -0
  210. data/lib/webhookdb/messages/specs.rb +57 -0
  211. data/lib/webhookdb/messages/verification.rb +23 -0
  212. data/lib/webhookdb/method_utilities.rb +82 -0
  213. data/lib/webhookdb/microsoft_calendar.rb +36 -0
  214. data/lib/webhookdb/nextpax.rb +14 -0
  215. data/lib/webhookdb/oauth/front.rb +58 -0
  216. data/lib/webhookdb/oauth/intercom.rb +58 -0
  217. data/lib/webhookdb/oauth/session.rb +24 -0
  218. data/lib/webhookdb/oauth.rb +80 -0
  219. data/lib/webhookdb/organization/alerting.rb +35 -0
  220. data/lib/webhookdb/organization/database_migration.rb +151 -0
  221. data/lib/webhookdb/organization/db_builder.rb +429 -0
  222. data/lib/webhookdb/organization.rb +506 -0
  223. data/lib/webhookdb/organization_membership.rb +58 -0
  224. data/lib/webhookdb/phone_number.rb +38 -0
  225. data/lib/webhookdb/plaid.rb +23 -0
  226. data/lib/webhookdb/platform.rb +27 -0
  227. data/lib/webhookdb/plivo.rb +52 -0
  228. data/lib/webhookdb/postgres/maintenance.rb +166 -0
  229. data/lib/webhookdb/postgres/model.rb +82 -0
  230. data/lib/webhookdb/postgres/model_utilities.rb +382 -0
  231. data/lib/webhookdb/postgres/testing_pixie.rb +16 -0
  232. data/lib/webhookdb/postgres/validations.rb +46 -0
  233. data/lib/webhookdb/postgres.rb +176 -0
  234. data/lib/webhookdb/postmark.rb +20 -0
  235. data/lib/webhookdb/redis.rb +35 -0
  236. data/lib/webhookdb/replicator/atom_single_feed_v1.rb +116 -0
  237. data/lib/webhookdb/replicator/aws_pricing_v1.rb +488 -0
  238. data/lib/webhookdb/replicator/base.rb +1185 -0
  239. data/lib/webhookdb/replicator/column.rb +482 -0
  240. data/lib/webhookdb/replicator/convertkit_broadcast_v1.rb +69 -0
  241. data/lib/webhookdb/replicator/convertkit_subscriber_v1.rb +200 -0
  242. data/lib/webhookdb/replicator/convertkit_tag_v1.rb +66 -0
  243. data/lib/webhookdb/replicator/convertkit_v1_mixin.rb +65 -0
  244. data/lib/webhookdb/replicator/docgen.rb +167 -0
  245. data/lib/webhookdb/replicator/email_octopus_campaign_v1.rb +84 -0
  246. data/lib/webhookdb/replicator/email_octopus_contact_v1.rb +159 -0
  247. data/lib/webhookdb/replicator/email_octopus_event_v1.rb +244 -0
  248. data/lib/webhookdb/replicator/email_octopus_list_v1.rb +101 -0
  249. data/lib/webhookdb/replicator/fake.rb +453 -0
  250. data/lib/webhookdb/replicator/front_conversation_v1.rb +45 -0
  251. data/lib/webhookdb/replicator/front_marketplace_root_v1.rb +55 -0
  252. data/lib/webhookdb/replicator/front_message_v1.rb +45 -0
  253. data/lib/webhookdb/replicator/front_v1_mixin.rb +22 -0
  254. data/lib/webhookdb/replicator/github_issue_comment_v1.rb +58 -0
  255. data/lib/webhookdb/replicator/github_issue_v1.rb +83 -0
  256. data/lib/webhookdb/replicator/github_pull_v1.rb +84 -0
  257. data/lib/webhookdb/replicator/github_release_v1.rb +47 -0
  258. data/lib/webhookdb/replicator/github_repo_v1_mixin.rb +250 -0
  259. data/lib/webhookdb/replicator/github_repository_event_v1.rb +45 -0
  260. data/lib/webhookdb/replicator/icalendar_calendar_v1.rb +465 -0
  261. data/lib/webhookdb/replicator/icalendar_event_v1.rb +334 -0
  262. data/lib/webhookdb/replicator/increase_account_number_v1.rb +77 -0
  263. data/lib/webhookdb/replicator/increase_account_transfer_v1.rb +61 -0
  264. data/lib/webhookdb/replicator/increase_account_v1.rb +63 -0
  265. data/lib/webhookdb/replicator/increase_ach_transfer_v1.rb +78 -0
  266. data/lib/webhookdb/replicator/increase_check_transfer_v1.rb +64 -0
  267. data/lib/webhookdb/replicator/increase_limit_v1.rb +78 -0
  268. data/lib/webhookdb/replicator/increase_transaction_v1.rb +74 -0
  269. data/lib/webhookdb/replicator/increase_v1_mixin.rb +121 -0
  270. data/lib/webhookdb/replicator/increase_wire_transfer_v1.rb +61 -0
  271. data/lib/webhookdb/replicator/intercom_contact_v1.rb +36 -0
  272. data/lib/webhookdb/replicator/intercom_conversation_v1.rb +38 -0
  273. data/lib/webhookdb/replicator/intercom_marketplace_root_v1.rb +69 -0
  274. data/lib/webhookdb/replicator/intercom_v1_mixin.rb +105 -0
  275. data/lib/webhookdb/replicator/oauth_refresh_access_token_mixin.rb +65 -0
  276. data/lib/webhookdb/replicator/plivo_sms_inbound_v1.rb +102 -0
  277. data/lib/webhookdb/replicator/postmark_inbound_message_v1.rb +94 -0
  278. data/lib/webhookdb/replicator/postmark_outbound_message_event_v1.rb +107 -0
  279. data/lib/webhookdb/replicator/schema_modification.rb +42 -0
  280. data/lib/webhookdb/replicator/shopify_customer_v1.rb +58 -0
  281. data/lib/webhookdb/replicator/shopify_order_v1.rb +64 -0
  282. data/lib/webhookdb/replicator/shopify_v1_mixin.rb +161 -0
  283. data/lib/webhookdb/replicator/signalwire_message_v1.rb +169 -0
  284. data/lib/webhookdb/replicator/sponsy_customer_v1.rb +54 -0
  285. data/lib/webhookdb/replicator/sponsy_placement_v1.rb +34 -0
  286. data/lib/webhookdb/replicator/sponsy_publication_v1.rb +125 -0
  287. data/lib/webhookdb/replicator/sponsy_slot_v1.rb +41 -0
  288. data/lib/webhookdb/replicator/sponsy_status_v1.rb +35 -0
  289. data/lib/webhookdb/replicator/sponsy_v1_mixin.rb +165 -0
  290. data/lib/webhookdb/replicator/state_machine_step.rb +69 -0
  291. data/lib/webhookdb/replicator/stripe_charge_v1.rb +77 -0
  292. data/lib/webhookdb/replicator/stripe_coupon_v1.rb +62 -0
  293. data/lib/webhookdb/replicator/stripe_customer_v1.rb +60 -0
  294. data/lib/webhookdb/replicator/stripe_dispute_v1.rb +77 -0
  295. data/lib/webhookdb/replicator/stripe_invoice_item_v1.rb +82 -0
  296. data/lib/webhookdb/replicator/stripe_invoice_v1.rb +116 -0
  297. data/lib/webhookdb/replicator/stripe_payout_v1.rb +67 -0
  298. data/lib/webhookdb/replicator/stripe_price_v1.rb +60 -0
  299. data/lib/webhookdb/replicator/stripe_product_v1.rb +60 -0
  300. data/lib/webhookdb/replicator/stripe_refund_v1.rb +101 -0
  301. data/lib/webhookdb/replicator/stripe_subscription_item_v1.rb +56 -0
  302. data/lib/webhookdb/replicator/stripe_subscription_v1.rb +75 -0
  303. data/lib/webhookdb/replicator/stripe_v1_mixin.rb +116 -0
  304. data/lib/webhookdb/replicator/transistor_episode_stats_v1.rb +141 -0
  305. data/lib/webhookdb/replicator/transistor_episode_v1.rb +169 -0
  306. data/lib/webhookdb/replicator/transistor_show_v1.rb +68 -0
  307. data/lib/webhookdb/replicator/transistor_v1_mixin.rb +65 -0
  308. data/lib/webhookdb/replicator/twilio_sms_v1.rb +156 -0
  309. data/lib/webhookdb/replicator/webhook_request.rb +5 -0
  310. data/lib/webhookdb/replicator/webhookdb_customer_v1.rb +74 -0
  311. data/lib/webhookdb/replicator.rb +224 -0
  312. data/lib/webhookdb/role.rb +42 -0
  313. data/lib/webhookdb/sentry.rb +35 -0
  314. data/lib/webhookdb/service/auth.rb +138 -0
  315. data/lib/webhookdb/service/collection.rb +91 -0
  316. data/lib/webhookdb/service/entities.rb +97 -0
  317. data/lib/webhookdb/service/helpers.rb +270 -0
  318. data/lib/webhookdb/service/middleware.rb +124 -0
  319. data/lib/webhookdb/service/types.rb +30 -0
  320. data/lib/webhookdb/service/validators.rb +32 -0
  321. data/lib/webhookdb/service/view_api.rb +63 -0
  322. data/lib/webhookdb/service.rb +219 -0
  323. data/lib/webhookdb/service_integration.rb +332 -0
  324. data/lib/webhookdb/shopify.rb +35 -0
  325. data/lib/webhookdb/signalwire.rb +13 -0
  326. data/lib/webhookdb/slack.rb +68 -0
  327. data/lib/webhookdb/snowflake.rb +90 -0
  328. data/lib/webhookdb/spec_helpers/async.rb +122 -0
  329. data/lib/webhookdb/spec_helpers/citest.rb +88 -0
  330. data/lib/webhookdb/spec_helpers/integration.rb +121 -0
  331. data/lib/webhookdb/spec_helpers/message.rb +41 -0
  332. data/lib/webhookdb/spec_helpers/postgres.rb +220 -0
  333. data/lib/webhookdb/spec_helpers/service.rb +432 -0
  334. data/lib/webhookdb/spec_helpers/shared_examples_for_columns.rb +56 -0
  335. data/lib/webhookdb/spec_helpers/shared_examples_for_replicators.rb +915 -0
  336. data/lib/webhookdb/spec_helpers/whdb.rb +139 -0
  337. data/lib/webhookdb/spec_helpers.rb +63 -0
  338. data/lib/webhookdb/sponsy.rb +14 -0
  339. data/lib/webhookdb/stripe.rb +37 -0
  340. data/lib/webhookdb/subscription.rb +203 -0
  341. data/lib/webhookdb/sync_target.rb +491 -0
  342. data/lib/webhookdb/tasks/admin.rb +49 -0
  343. data/lib/webhookdb/tasks/annotate.rb +36 -0
  344. data/lib/webhookdb/tasks/db.rb +82 -0
  345. data/lib/webhookdb/tasks/docs.rb +42 -0
  346. data/lib/webhookdb/tasks/fixture.rb +35 -0
  347. data/lib/webhookdb/tasks/message.rb +50 -0
  348. data/lib/webhookdb/tasks/regress.rb +87 -0
  349. data/lib/webhookdb/tasks/release.rb +27 -0
  350. data/lib/webhookdb/tasks/sidekiq.rb +23 -0
  351. data/lib/webhookdb/tasks/specs.rb +64 -0
  352. data/lib/webhookdb/theranest.rb +15 -0
  353. data/lib/webhookdb/transistor.rb +13 -0
  354. data/lib/webhookdb/twilio.rb +13 -0
  355. data/lib/webhookdb/typed_struct.rb +44 -0
  356. data/lib/webhookdb/version.rb +5 -0
  357. data/lib/webhookdb/webhook_response.rb +50 -0
  358. data/lib/webhookdb/webhook_subscription/delivery.rb +82 -0
  359. data/lib/webhookdb/webhook_subscription.rb +226 -0
  360. data/lib/webhookdb/windows_tz.rb +32 -0
  361. data/lib/webhookdb/xml.rb +92 -0
  362. data/lib/webhookdb.rb +224 -0
  363. data/lib/webterm/apps.rb +45 -0
  364. metadata +1129 -0
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/github"
4
+ require "webhookdb/replicator/github_repo_v1_mixin"
5
+
6
+ class Webhookdb::Replicator::GithubIssueV1 < Webhookdb::Replicator::Base
7
+ include Appydays::Loggable
8
+ include Webhookdb::Replicator::GithubRepoV1Mixin
9
+
10
+ def _mixin_backfill_url = "/issues"
11
+ def _mixin_webhook_events = ["Issues"]
12
+ def _mixin_webhook_key = "issue"
13
+ def _mixin_fine_grained_permission = "Issues"
14
+ def _mixin_fetch_resource_if_field_missing = "closed_by"
15
+
16
+ def _mixin_query_params(last_backfilled:)
17
+ q = {state: "all"}
18
+ if last_backfilled
19
+ q[:sort] = "updated"
20
+ q[:since] = last_backfilled.utc.iso8601
21
+ end
22
+ return q
23
+ end
24
+
25
+ # @return [Webhookdb::Replicator::Descriptor]
26
+ def self.descriptor
27
+ return Webhookdb::Replicator::Descriptor.new(
28
+ name: "github_issue_v1",
29
+ ctor: ->(sint) { Webhookdb::Replicator::GithubIssueV1.new(sint) },
30
+ feature_roles: [],
31
+ resource_name_singular: "GitHub Issue",
32
+ supports_webhooks: true,
33
+ supports_backfill: true,
34
+ api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/issues/issues"),
35
+ )
36
+ end
37
+
38
+ def _remote_key_column
39
+ return Webhookdb::Replicator::Column.new(:github_id, BIGINT, data_key: "id")
40
+ end
41
+
42
+ def _denormalized_columns
43
+ return [
44
+ Webhookdb::Replicator::Column.new(:node_id, TEXT, index: true),
45
+ Webhookdb::Replicator::Column.new(:number, INTEGER, index: true),
46
+ Webhookdb::Replicator::Column.new(:state, TEXT),
47
+ Webhookdb::Replicator::Column.new(:user_id, BIGINT, index: true, data_key: ["user", "id"], optional: true),
48
+ Webhookdb::Replicator::Column.new(
49
+ :closed_by_id,
50
+ BIGINT,
51
+ index: true,
52
+ data_key: ["closed_by", "id"],
53
+ optional: true,
54
+ ),
55
+ Webhookdb::Replicator::Column.new(
56
+ :assignee_ids,
57
+ BIGINT_ARRAY,
58
+ index: true,
59
+ data_key: "assignees",
60
+ optional: true,
61
+ converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
62
+ ),
63
+ Webhookdb::Replicator::Column.new(
64
+ :milestone_number,
65
+ INTEGER,
66
+ data_key: ["milestone", "number"],
67
+ optional: true,
68
+ ),
69
+ Webhookdb::Replicator::Column.new(
70
+ :label_ids,
71
+ BIGINT_ARRAY,
72
+ data_key: "labels",
73
+ optional: true,
74
+ converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
75
+ ),
76
+ Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
77
+ Webhookdb::Replicator::Column.new(:closed_at, TIMESTAMP, index: true),
78
+ Webhookdb::Replicator::Column.new(:updated_at, TIMESTAMP, index: true),
79
+ ]
80
+ end
81
+
82
+ def _timestamp_column_name = :updated_at
83
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/github"
4
+ require "webhookdb/replicator/github_repo_v1_mixin"
5
+
6
+ class Webhookdb::Replicator::GithubPullV1 < Webhookdb::Replicator::Base
7
+ include Appydays::Loggable
8
+ include Webhookdb::Replicator::GithubRepoV1Mixin
9
+
10
+ def _mixin_backfill_url = "/pulls"
11
+ def _mixin_webhook_events = ["Pull requests"]
12
+ def _mixin_webhook_key = "pull_request"
13
+ def _mixin_fine_grained_permission = "Pull requests"
14
+ def _mixin_fetch_resource_if_field_missing = "merged_by"
15
+
16
+ def _mixin_query_params(last_backfilled:)
17
+ q = {state: "all"}
18
+ if last_backfilled
19
+ q[:sort] = "updated"
20
+ q[:since] = last_backfilled.utc.iso8601
21
+ end
22
+ return q
23
+ end
24
+
25
+ # @return [Webhookdb::Replicator::Descriptor]
26
+ def self.descriptor
27
+ return Webhookdb::Replicator::Descriptor.new(
28
+ name: "github_pull_v1",
29
+ ctor: ->(sint) { Webhookdb::Replicator::GithubPullV1.new(sint) },
30
+ feature_roles: [],
31
+ resource_name_singular: "GitHub Pull Request",
32
+ supports_webhooks: true,
33
+ supports_backfill: true,
34
+ api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/pulls/pulls"),
35
+ )
36
+ end
37
+
38
+ def _remote_key_column
39
+ return Webhookdb::Replicator::Column.new(:github_id, BIGINT, data_key: "id")
40
+ end
41
+
42
+ def _denormalized_columns
43
+ return [
44
+ Webhookdb::Replicator::Column.new(:number, INTEGER, index: true),
45
+ Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
46
+ Webhookdb::Replicator::Column.new(:updated_at, TIMESTAMP, index: true),
47
+ Webhookdb::Replicator::Column.new(:closed_at, TIMESTAMP, index: true, optional: true),
48
+ Webhookdb::Replicator::Column.new(:merged_at, TIMESTAMP, index: true, optional: true),
49
+ Webhookdb::Replicator::Column.new(:state, TEXT),
50
+ Webhookdb::Replicator::Column.new(:user_id, BIGINT, index: true, data_key: ["user", "id"], optional: true),
51
+ Webhookdb::Replicator::Column.new(
52
+ :merged_by_id,
53
+ BIGINT,
54
+ index: true,
55
+ data_key: ["merged_by", "id"],
56
+ optional: true,
57
+ ),
58
+ Webhookdb::Replicator::Column.new(
59
+ :assignee_ids,
60
+ BIGINT_ARRAY,
61
+ index: true,
62
+ data_key: "assignees",
63
+ optional: true,
64
+ converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
65
+ ),
66
+ Webhookdb::Replicator::Column.new(
67
+ :milestone_number,
68
+ INTEGER,
69
+ data_key: ["milestone", "number"],
70
+ optional: true,
71
+ ),
72
+ Webhookdb::Replicator::Column.new(
73
+ :label_ids,
74
+ BIGINT_ARRAY,
75
+ data_key: "labels",
76
+ optional: true,
77
+ converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
78
+ ),
79
+ Webhookdb::Replicator::Column.new(:node_id, TEXT, index: true),
80
+ ]
81
+ end
82
+
83
+ def _timestamp_column_name = :updated_at
84
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/github"
4
+ require "webhookdb/replicator/github_repo_v1_mixin"
5
+
6
+ class Webhookdb::Replicator::GithubReleaseV1 < Webhookdb::Replicator::Base
7
+ include Appydays::Loggable
8
+ include Webhookdb::Replicator::GithubRepoV1Mixin
9
+
10
+ def _mixin_backfill_url = "/releases"
11
+ def _mixin_webhook_events = ["Releases"]
12
+ def _mixin_webhook_key = "release"
13
+ def _mixin_fine_grained_permission = "Contents"
14
+ def _mixin_query_params(*) = {}
15
+
16
+ # @return [Webhookdb::Replicator::Descriptor]
17
+ def self.descriptor
18
+ return Webhookdb::Replicator::Descriptor.new(
19
+ name: "github_release_v1",
20
+ ctor: ->(sint) { Webhookdb::Replicator::GithubReleaseV1.new(sint) },
21
+ feature_roles: [],
22
+ resource_name_singular: "GitHub Release",
23
+ supports_webhooks: true,
24
+ supports_backfill: true,
25
+ api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/releases/releases"),
26
+ )
27
+ end
28
+
29
+ def _remote_key_column
30
+ return Webhookdb::Replicator::Column.new(:github_id, BIGINT, data_key: "id")
31
+ end
32
+
33
+ def _denormalized_columns
34
+ return [
35
+ Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
36
+ Webhookdb::Replicator::Column.new(:published_at, TIMESTAMP, index: true),
37
+ Webhookdb::Replicator::Column.new(:row_updated_at, TIMESTAMP, defaulter: :now, optional: true, index: true),
38
+ Webhookdb::Replicator::Column.new(:node_id, TEXT, index: true),
39
+ Webhookdb::Replicator::Column.new(:tag_name, TEXT, index: true),
40
+ Webhookdb::Replicator::Column.new(
41
+ :author_id, BIGINT, index: true, data_key: ["author", "id"], optional: true,
42
+ ),
43
+ ]
44
+ end
45
+
46
+ def _timestamp_column_name = :row_updated_at
47
+ end
@@ -0,0 +1,250 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/github"
4
+
5
+ # Mixin for repo-specific resources like issues and pull requests.
6
+ module Webhookdb::Replicator::GithubRepoV1Mixin
7
+ API_VERSION = "2022-11-28"
8
+
9
+ def self._api_docs_url(tail)
10
+ return "https://docs.github.com/en/rest#{tail}?apiVersion=#{API_VERSION}"
11
+ end
12
+
13
+ # @!attribute service_integration
14
+ # @return [Webhookdb::ServiceIntegration]
15
+
16
+ def _mixin_backfill_url = raise NotImplementedError("/issues, /pulls, etc")
17
+ def _mixin_webhook_events = raise NotImplementedError("Issues, Pulls, Issue comments, etc")
18
+ # https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=demilestoned#issues
19
+ def _mixin_webhook_key = raise NotImplementedError("issue, etc")
20
+ # https://github.com/settings/personal-access-tokens/new
21
+ def _mixin_fine_grained_permission = raise NotImplementedError("Issues", etc)
22
+ # Query params to use in the list call. Should include sorting when available.
23
+ def _mixin_query_params(last_backfilled:) = raise NotImplementedError
24
+ # Some resources, like issues and pull requests, have a 'simple' representation
25
+ # in the list, and a full representation when fetched individually.
26
+ # Return the field that can be used to determine if the full resource needs to be fetched.
27
+ def _mixin_fetch_resource_if_field_missing = nil
28
+
29
+ def _fullreponame = self.service_integration.api_url
30
+ def _repoowner = self._fullreponame.split("/").first
31
+ def _reponame = self._fullreponame.split("/").last
32
+ def _valid_repo_name?(s) = %r{^[\w\-.]+/[\w\-.]+$} =~ s
33
+
34
+ # Extract the resource from the request.
35
+ # The resource can be a normal resource, or a webhook,
36
+ # with X-GitHub-Hook-ID key as per https://docs.github.com/en/webhooks/webhook-events-and-payloads
37
+ # The headers are the only things that identify a webhook payload consistently.
38
+ #
39
+ # Note that webhooks to a given integration can be for events we do not expect,
40
+ # such as someone sending events we aren't handling (ie, if they don't uncheck Pushes,
41
+ # we may get push events sent to the github_issue_v1 integration),
42
+ # and also for automated events like 'ping'.
43
+ def _resource_and_event(request)
44
+ # Note the canonical casing on the header name. GitHub sends X-GitHub-Hook-ID
45
+ # but it's normalized here.
46
+ is_webhook = (request.headers || {})["X-Github-Hook-Id"]
47
+ return request.body, nil unless is_webhook
48
+ resource = request.body.fetch(self._mixin_webhook_key, nil)
49
+ return nil, nil if resource.nil?
50
+ return resource, request.body
51
+ end
52
+
53
+ def _update_where_expr
54
+ ts = self._timestamp_column_name
55
+ return self.qualified_table_sequel_identifier[ts] < Sequel[:excluded][ts]
56
+ end
57
+
58
+ def _webhook_response(request)
59
+ hash = request.env["HTTP_X_HUB_SIGNATURE_256"]
60
+ return Webhookdb::WebhookResponse.error("missing sha256") if hash.nil?
61
+ secret = self.service_integration.webhook_secret
62
+ return Webhookdb::WebhookResponse.error("no secret set, run `webhookdb integration setup`", status: 409) if
63
+ secret.nil?
64
+ request.body.rewind
65
+ request_data = request.body.read
66
+ verified = Webhookdb::Github.verify_webhook(request_data, hash, secret)
67
+ return Webhookdb::WebhookResponse.ok if verified
68
+ return Webhookdb::WebhookResponse.error("invalid sha256")
69
+ end
70
+
71
+ def _webhook_state_change_fields = super + ["repo_name"]
72
+
73
+ def process_state_change(field, value)
74
+ attr = field == "repo_name" ? "api_url" : field
75
+ return super(field, value, attr:)
76
+ end
77
+
78
+ def calculate_webhook_state_machine
79
+ step = Webhookdb::Replicator::StateMachineStep.new
80
+ return step if self._handle_repo_name_state_machine(step, "repo_name")
81
+ if self.service_integration.webhook_secret.blank?
82
+ step.output = %(Now, head to this route to create a webhook:
83
+
84
+ https://github.com/#{self.service_integration.api_url}/settings/hooks/new
85
+
86
+ For 'Payload URL', use this endpoint that is now available:
87
+
88
+ #{self._webhook_endpoint}
89
+
90
+ For 'Content type', choose 'application/json'. Form encoding works but loses some detail in events.
91
+
92
+ For 'Secret', choose your own secure secret, or use this one: '#{Webhookdb::Id.rand_enc(16)}'
93
+
94
+ For 'Which events would you like to trigger this webhook',
95
+ choose 'Let me select individual events',
96
+ uncheck 'Pushes', and select the following:
97
+
98
+ #{self._mixin_webhook_events.join("\n ")}
99
+
100
+ Make sure 'Active' is checked, and press 'Add webhook'.)
101
+ return step.secret_prompt("Webhook Secret").webhook_secret(self.service_integration)
102
+ end
103
+ step.output = %(Great! WebhookDB is now listening for #{self.resource_name_singular} webhooks.
104
+ #{self._query_help_output})
105
+ return step.completed
106
+ end
107
+
108
+ # If api_url isn't set, prompt for it (via repo_name or api_url field).
109
+ def _handle_repo_name_state_machine(step, tfield)
110
+ if self.service_integration.api_url.blank?
111
+ step.output = %(You are about to start replicating #{self.resource_name_plural} for a repository into WebhookDB.
112
+
113
+ First we need the full repository name, like 'webhookdb/webhookdb-cli'.)
114
+ step.set_prompt("Repository name:").transition_field(self.service_integration, tfield)
115
+ return true
116
+ end
117
+ return false if self._valid_repo_name?(self.service_integration.api_url)
118
+ step.output = %(That repository is not valid. Include both the owner and name, like 'webhookdb/webhookdb-cli'.)
119
+ step.set_prompt("Repository name:").transition_field(self.service_integration, tfield)
120
+ return true
121
+ end
122
+
123
+ # If we can make an unauthed request and find the repo, it is public.
124
+ def _is_repo_public?
125
+ resp = Webhookdb::Http.post(
126
+ "https://github.com/#{self.service_integration.api_url}",
127
+ method: :head,
128
+ check: false,
129
+ timeout: 5,
130
+ logger: nil,
131
+ )
132
+ return resp.code == 200
133
+ end
134
+
135
+ def calculate_backfill_state_machine
136
+ step = Webhookdb::Replicator::StateMachineStep.new
137
+ return step if self._handle_repo_name_state_machine(step, "api_url")
138
+ unless self.service_integration.backfill_secret.present?
139
+ repo_public = self._is_repo_public?
140
+ step.output = %(In order to backfill #{self.resource_name_plural},
141
+ WebhookDB requires an access token to authenticate.
142
+
143
+ You should go to https://github.com/settings/personal-access-tokens/new and create a new Personal Access Token.
144
+
145
+ For 'Expiration', give a custom date far in the future.
146
+
147
+ For 'Resource owner', choose the '#{self._repoowner}' organization.
148
+ **If it does not appear**, Fine-grained tokens are not enabled.
149
+ See instructions below.
150
+
151
+ For 'Repository access', choose 'Only select repositories', and the '#{self._fullreponame}' repository.
152
+
153
+ For 'Repository permissions', go to '#{self._mixin_fine_grained_permission}' and choose 'Read-only access'.
154
+
155
+ If you didn't see the needed owner under 'Resource owner,' it's because fine-grained tokens are not enabled.
156
+ Instead, create a new Classic personal access token from https://github.com/settings/tokens/new.
157
+ In the 'Note', mention this token is for WebhookDB,
158
+ give it an expiration, and under 'Scopes', ensure #{repo_public ? 'repo->public_repo' : 'repo'} is checked,
159
+ since #{self._fullreponame} is #{repo_public ? 'public' : 'private'}.
160
+
161
+ Then click 'Generate token'.)
162
+ return step.secret_prompt("Personal access token").backfill_secret(self.service_integration)
163
+ end
164
+
165
+ unless (result = self.verify_backfill_credentials).verified
166
+ self.service_integration.replicator.clear_backfill_information
167
+ step.output = result.message
168
+ return step.secret_prompt("Personal access token").backfill_secret(self.service_integration)
169
+ end
170
+
171
+ step.output = %(Great! We are going to start backfilling your #{self.resource_name_plural}.
172
+ #{self._query_help_output})
173
+ return step.completed
174
+ end
175
+
176
+ def _verify_backfill_err_msg
177
+ return "That access token didn't seem to work. Please look over the instructions and try again."
178
+ end
179
+
180
+ JSON_CONTENT_TYPE = "application/vnd.github+json"
181
+
182
+ def _fetch_backfill_page(pagination_token, last_backfilled:)
183
+ if pagination_token.present?
184
+ url = pagination_token
185
+ query = {}
186
+ else
187
+ url = "https://api.github.com/repos/#{self.service_integration.api_url}#{self._mixin_backfill_url}"
188
+ query = {per_page: 100}
189
+ query.merge!(self._mixin_query_params(last_backfilled:))
190
+ end
191
+ response, data = self._http_get(url, query)
192
+ next_link = nil
193
+ if response.headers.key?("link")
194
+ links = Webhookdb::Github.parse_link_header(response.headers["link"])
195
+ next_link = links[:next] if links.key?(:next)
196
+ end
197
+ return data, next_link
198
+ end
199
+
200
+ def _http_get(url, query)
201
+ response = Webhookdb::Http.get(
202
+ url,
203
+ query,
204
+ headers: {
205
+ "Accept" => JSON_CONTENT_TYPE,
206
+ "Authorization" => "Bearer #{self.service_integration.backfill_secret}",
207
+ "X-GitHub-Api-Version" => API_VERSION,
208
+ },
209
+ logger: self.logger,
210
+ timeout: Webhookdb::Github.http_timeout,
211
+ )
212
+ # Handle the GH-specific vnd JSON or general application/json
213
+ parsed = response.parsed_response
214
+ (parsed = Oj.load(parsed)) if response.headers["Content-Type"] == JSON_CONTENT_TYPE
215
+ return response, parsed
216
+ end
217
+
218
+ def _fetch_enrichment(resource, _event, _request)
219
+ # If we're not set up to backfill, we cannot make an API call.
220
+ return nil if self.service_integration.backfill_secret.nil?
221
+ # We should fetch the full resource if the replicator needs it,
222
+ # and the resource does not have the key we require.
223
+ sentinel_key = self._mixin_fetch_resource_if_field_missing
224
+ return nil if sentinel_key.nil? || resource.key?(sentinel_key)
225
+ resource_url = resource.fetch("url")
226
+ begin
227
+ _response, data = self._http_get(resource_url, {})
228
+ rescue Webhookdb::Http::Error => e
229
+ # If the HTTP call fails due to an auth issue (or a deleted item),
230
+ # we should still upsert what we have.
231
+ # Tokens expire or can be revoked, but we don't want the webhook to stop inserting.
232
+ ignore_error = [401, 403, 404].include?(e.response.code)
233
+ return nil if ignore_error
234
+ raise e
235
+ end
236
+ return data
237
+ end
238
+
239
+ def _prepare_for_insert(resource, event, request, enrichment)
240
+ # if enrichment is not nil, it's the detailed resource.
241
+ # See _mixin_fetch_resource_if_field_missing
242
+ return super(enrichment || resource, event, request, nil)
243
+ end
244
+
245
+ def _resource_to_data(resource, _event, _request, enrichment)
246
+ # if enrichment is not nil, it's the detailed resource.
247
+ # See _mixin_fetch_resource_if_field_missing
248
+ return enrichment || resource
249
+ end
250
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/github"
4
+ require "webhookdb/replicator/github_repo_v1_mixin"
5
+
6
+ class Webhookdb::Replicator::GithubRepositoryEventV1 < Webhookdb::Replicator::Base
7
+ include Appydays::Loggable
8
+ include Webhookdb::Replicator::GithubRepoV1Mixin
9
+
10
+ def _mixin_backfill_url = "/events"
11
+ def _mixin_fine_grained_permission = "Contents"
12
+ def _mixin_query_params(*) = {}
13
+
14
+ # @return [Webhookdb::Replicator::Descriptor]
15
+ def self.descriptor
16
+ return Webhookdb::Replicator::Descriptor.new(
17
+ name: "github_repository_event_v1",
18
+ ctor: ->(sint) { Webhookdb::Replicator::GithubRepositoryEventV1.new(sint) },
19
+ feature_roles: [],
20
+ resource_name_singular: "GitHub Repository Activity Event",
21
+ supports_webhooks: false,
22
+ supports_backfill: true,
23
+ api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/activity/events"),
24
+ )
25
+ end
26
+
27
+ def calculate_webhook_state_machine = raise NotImplementedError
28
+
29
+ def _remote_key_column
30
+ return Webhookdb::Replicator::Column.new(:github_id, TEXT, data_key: "id")
31
+ end
32
+
33
+ def _denormalized_columns
34
+ return [
35
+ Webhookdb::Replicator::Column.new(:type, TEXT, index: true),
36
+ Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
37
+ Webhookdb::Replicator::Column.new(:row_updated_at, TIMESTAMP, defaulter: :now, optional: true, index: true),
38
+ Webhookdb::Replicator::Column.new(
39
+ :actor_id, BIGINT, index: true, data_key: ["actor", "id"], optional: true,
40
+ ),
41
+ ]
42
+ end
43
+
44
+ def _timestamp_column_name = :row_updated_at
45
+ end