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,488 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sdk-pricing"
4
+
5
+ require "webhookdb/aws"
6
+ require "webhookdb/replicator/base"
7
+
8
+ class Webhookdb::Replicator::AwsPricingV1 < Webhookdb::Replicator::Base
9
+ include Webhookdb::DBAdapter::ColumnTypes
10
+
11
+ CURRENCIES = ["USD", "CNY"].freeze
12
+
13
+ def self.descriptor
14
+ return Webhookdb::Replicator::Descriptor.new(
15
+ name: "aws_pricing_v1",
16
+ ctor: self,
17
+ resource_name_singular: "AWS Price List",
18
+ feature_roles: [],
19
+ supports_backfill: true,
20
+ description: "Fetch, parse, and process AWS price list information from the API into a " \
21
+ "relational, fully searchable table.",
22
+ api_docs_url: "https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/" \
23
+ "price-list-query-api-find-services-products.html",
24
+ )
25
+ end
26
+
27
+ def _denormalized_columns
28
+ return [
29
+ # Product
30
+ Webhookdb::Replicator::Column.new(:product_sku, TEXT, index: true),
31
+ Webhookdb::Replicator::Column.new(:product_family, TEXT, index: true),
32
+ Webhookdb::Replicator::Column.new(:product_attributes, OBJECT),
33
+ Webhookdb::Replicator::Column.new(:product_group, TEXT, index: true),
34
+ Webhookdb::Replicator::Column.new(:product_location, TEXT, index: true),
35
+ Webhookdb::Replicator::Column.new(:product_region, TEXT, index: true),
36
+ Webhookdb::Replicator::Column.new(:product_operation, TEXT, index: true),
37
+ Webhookdb::Replicator::Column.new(:product_usagetype, TEXT, index: true),
38
+
39
+ Webhookdb::Replicator::Column.new(:publication_date, TIMESTAMP, index: true),
40
+ Webhookdb::Replicator::Column.new(:service_code, TEXT, index: true),
41
+ Webhookdb::Replicator::Column.new(:version, TEXT, index: true),
42
+
43
+ # Term (OnDemand, etc)
44
+ Webhookdb::Replicator::Column.new(:term_type, TEXT),
45
+ Webhookdb::Replicator::Column.new(:term_code, TEXT, index: true),
46
+ Webhookdb::Replicator::Column.new(:offer_term_code, TEXT, index: true),
47
+ Webhookdb::Replicator::Column.new(:effective_date, TIMESTAMP, index: true),
48
+
49
+ # Term fields
50
+ # Webhookdb::Replicator::Column.new(:rate_code, TEXT, index: true),
51
+ Webhookdb::Replicator::Column.new(:applies_to, TEXT_ARRAY),
52
+ Webhookdb::Replicator::Column.new(:begin_range, DECIMAL),
53
+ Webhookdb::Replicator::Column.new(:description, TEXT),
54
+ Webhookdb::Replicator::Column.new(:end_range, DECIMAL),
55
+ Webhookdb::Replicator::Column.new(:unit, TEXT),
56
+ Webhookdb::Replicator::Column.new(:term_attributes, OBJECT),
57
+
58
+ Webhookdb::Replicator::Column.new(:price_per_unit_raw, OBJECT),
59
+ Webhookdb::Replicator::Column.new(:price_per_unit_amount, DECIMAL),
60
+ Webhookdb::Replicator::Column.new(:price_per_unit_currency, TEXT),
61
+ ]
62
+ end
63
+
64
+ def _remote_key_column
65
+ return Webhookdb::Replicator::Column.new(:rate_code, TEXT)
66
+ end
67
+
68
+ def _timestamp_column_name
69
+ return :publication_date
70
+ end
71
+
72
+ def _resource_and_event(request)
73
+ return request.body, nil
74
+ end
75
+
76
+ def _resource_to_data(*)
77
+ return {}
78
+ end
79
+
80
+ def _update_where_expr
81
+ return self.qualified_table_sequel_identifier[:publication_date] < Sequel[:excluded][:publication_date]
82
+ end
83
+
84
+ def _webhook_response(_request)
85
+ # There are no webhooks to respond to, these are backfill-only integrations
86
+ return Webhookdb::WebhookResponse.ok
87
+ end
88
+
89
+ # @return [Webhookdb::Replicator::StateMachineStep]
90
+ def calculate_webhook_state_machine
91
+ step = Webhookdb::Replicator::StateMachineStep.new
92
+ if self.service_integration.backfill_key.blank?
93
+ step.output = %(In order to populate AWS prices, you'll need to allow WebhookDB
94
+ to access the Pricing service in your account. We use 3rd party roles for this.
95
+ (Note: self-hosted WebhookDB customers have other auth methods available).
96
+
97
+ Here's how to do this from the AWS Console; you can do this via CDK or similar if you wish, too.
98
+
99
+ - Log into AWS
100
+ - Go to IAM
101
+ - Go to 'Policies' on the nav bar
102
+ - Create a policy like this (name it whatever you want, we'll use "WebhookDBPricing"):
103
+
104
+ {
105
+ "Version": "2012-10-17",
106
+ "Statement": [
107
+ {
108
+ "Sid": "WebhookDBPricing",
109
+ "Effect": "Allow",
110
+ "Action": [
111
+ "pricing:DescribeServices",
112
+ "pricing:ListPriceLists",
113
+ "pricing:GetAttributeValues",
114
+ "pricing:GetPriceListFileUrl",
115
+ "pricing:GetProducts"
116
+ ],
117
+ "Resource": "*"
118
+ }
119
+ ]
120
+ }
121
+
122
+ - Go to 'Roles' in the nav bar.
123
+ - Choose 'AWS Account' as the entity type.
124
+ - Choose 'Another AWS Account' and enter our Account ID: #{Webhookdb::AWS.external_account_id}
125
+ - Check 'Require an external ID'. Choose whatever you wish. Here's one to try: WHDBPR-#{SecureRandom.hex(8)}
126
+ - Go to the next page. Choose the policy created earlier (WebhookDBPricing).
127
+ - Go to the next page. Give the role a name like 'WebhookDBPricing'.
128
+ - Create the role.
129
+ - Find the newly created role, and copy the ARN and External ID.
130
+ )
131
+ return step.prompting("Role ARN").backfill_key(self.service_integration)
132
+ elsif self.service_integration.backfill_secret.blank?
133
+ return step.prompting("External ID", secret: true).backfill_secret(self.service_integration)
134
+ end
135
+ step.output = %(Your AWS pricing database will be filled shortly.
136
+ It normally takes about 20 minutes to sync.
137
+
138
+ #{self._query_help_output})
139
+ return step.completed
140
+ end
141
+
142
+ def _parallel_backfill = 3
143
+
144
+ def _backfillers
145
+ pricing = self.create_pricing_client
146
+ backfillers = []
147
+ effective_date = Time.now.iso8601
148
+ # backfillers << ServiceBackfiller.new(self, 'AmazonEC2', 'USD', effective_date)
149
+ pricing.describe_services.each do |services_resp|
150
+ services_resp.services.map do |srv|
151
+ CURRENCIES.each do |currency_code|
152
+ backfillers << ServiceBackfiller.new(self, srv.service_code, currency_code, effective_date)
153
+ end
154
+ end
155
+ end
156
+ return backfillers
157
+ end
158
+
159
+ def with_pricing_client
160
+ raise LocalJumpError unless block_given?
161
+ @pricing_client ||= self.create_pricing_client
162
+ begin
163
+ return yield(@pricing_client)
164
+ rescue StandardError => e
165
+ raise e unless e.to_s.include?("The security token included in the request is invalid")
166
+ @pricing_client = self.create_pricing_client
167
+ return yield(@pricing_client)
168
+ end
169
+ end
170
+
171
+ def create_pricing_client
172
+ role_arn = self.service_integration.backfill_key
173
+ external_id = self.service_integration.backfill_secret
174
+ assume_resp = Webhookdb::AWS.sts_client.assume_role(
175
+ role_arn:,
176
+ external_id:,
177
+ role_session_name: "webhoookdb_aws_pricing_v1",
178
+ )
179
+ return Aws::Pricing::Client.new(
180
+ session_token: assume_resp.credentials.session_token,
181
+ region: "us-east-1",
182
+ # Lots of extra retries. It's almost always going to be because throttling.
183
+ retry_base_delay: 5,
184
+ retry_limit: 10,
185
+ )
186
+ end
187
+
188
+ class ServiceBackfiller < Webhookdb::Backfiller
189
+ include Webhookdb::Backfiller::Bulk
190
+
191
+ attr_reader :replicator, :pricing, :service_code, :currency_code, :effective_date
192
+
193
+ def initialize(replicator, service_code, currency_code, effective_date)
194
+ @replicator = replicator
195
+ @service_code = service_code
196
+ @currency_code = currency_code
197
+ @effective_date = effective_date
198
+ super()
199
+ end
200
+
201
+ def upsert_page_size = 500
202
+ def prepare_body(_body) = nil
203
+ def upserting_replicator = @replicator
204
+ def conditional_upsert? = true
205
+
206
+ def fetch_backfill_page(pagination_token, **)
207
+ # Fetch a page of price lists ARNs for this service
208
+ list_req = self.replicator.with_pricing_client do |pricing|
209
+ pricing.build_request(
210
+ :list_price_lists,
211
+ {
212
+ currency_code:,
213
+ effective_date:,
214
+ max_results: 100,
215
+ next_token: pagination_token,
216
+ service_code:,
217
+ },
218
+ )
219
+ end
220
+ arns_to_fetch = []
221
+ list_req.send_request({}).each do |list_resp|
222
+ # We need to enumerate everything at once. Because inserting can take so long
223
+ # that next_tokene xpires.
224
+ list_resp.price_lists.map do |pl|
225
+ arns_to_fetch << pl.price_list_arn
226
+ end
227
+ end
228
+
229
+ # To avoid having to process the entire JSON file into an array of thousands of items,
230
+ # process rates one-by-one. We may have huge memory for the JSON file itself, but won't need it
231
+ # to store the hashes we'll them bulk insert. This is also more responsive because we'll be upserting
232
+ # pages as we have them available, rather than only after everything is converted.
233
+ iter = UrlStreamer.new(self.replicator, arns_to_fetch)
234
+ # next_token is nil when we have processed all price list files for the service.
235
+ return iter, nil
236
+ end
237
+
238
+ class UrlStreamer
239
+ def initialize(replicator, arns)
240
+ @arns = arns
241
+ @replicator = replicator
242
+ end
243
+
244
+ def each
245
+ @arns.each do |price_list_arn|
246
+ url_req = @replicator.with_pricing_client do |client|
247
+ client.build_request(
248
+ :get_price_list_file_url,
249
+ {file_format: "json", price_list_arn:},
250
+ )
251
+ end
252
+ url_resp = url_req.send_request({})
253
+ tmp = Tempfile.new("awspricing", binmode: true)
254
+ # This file can be enormous- 200+ mb of JSON. We CANNOT just parse this directly.
255
+ # Even loading it is too much. We write it directly to a file, then process the file.
256
+ # This is a confusing algorithm. Instead of treating it like JSON, we treat it
257
+ # sort of like a text format:
258
+ # - look for known keys at the start of the file
259
+ # - once we hit 'products', we start collecting lines.
260
+ # - once we hit 'terms', we parse 'products', then keep going for terms.
261
+ # - each /^ "/ is a term type, like 'OnDemand' or 'Reserved'
262
+ # - each /^ "/ is a product id and the start of its rates
263
+ # - Grab the lines until /^ }/ and process it as the product rates.
264
+ # Grab the product from the line offsets.
265
+ Webhookdb::Http.get(url_resp.url, logger: @replicator.logger, stream_body: true,
266
+ timeout: Webhookdb::AWS.http_timeout,) do |fragment|
267
+ tmp.write(fragment)
268
+ end
269
+ tmp.flush
270
+ tmp.seek(0)
271
+ flines = File.foreach(tmp.path)
272
+ # Grab the first section of the file up to 'products', this is the metadata.
273
+ meta_str = +""
274
+ until (mline = flines.next) =~ /^ {2}"products"/
275
+ meta_str << mline
276
+ end
277
+ meta_str << '"":""}'
278
+ meta = Oj.load(meta_str)
279
+ meta_str.clear
280
+ publication_date = Time.parse(meta.fetch("publicationDate"))
281
+ service_code = meta.fetch("offerCode")
282
+ version = meta.fetch("version")
283
+
284
+ # Grab all the products. This is like 170k of 5million, so is small enough for memory.
285
+ products_str = +"{"
286
+ until (pline = flines.next) =~ /^ {2}}/
287
+ products_str << pline
288
+ end
289
+ products_str << "}"
290
+ products = Oj.load(products_str)
291
+ products_str.clear
292
+
293
+ # Read the rest of the file.
294
+ _terms = flines.next
295
+ term_type = nil
296
+ until (line = flines.next) == "}" # next has EOF problems and end the program/iterator
297
+ # Look for 'OnDemand', 'Reserved', etc.
298
+ start_of_term_type = line =~ /^ {4}"/
299
+ if start_of_term_type
300
+ term_type = line[/^ {4}"([A-Za-z0-9]+)"/, 1]
301
+ next
302
+ end
303
+ start_of_product_and_term_map = line =~ /^ {6}"/
304
+ next unless start_of_product_and_term_map
305
+ # Look for the product SKU, which then lists all the terms (and rates).
306
+ # 'ABC': {'ABC.DEF': {}, 'ABC.XYZ': {}}
307
+ # Parse this entire set of product terms at once- it may be a few thousand lines,
308
+ # which is probably faster anyway than trying to split it up.
309
+ product_sku = line[/^ {6}"([A-Za-z0-9]+)"/, 1]
310
+ term_map_str = +"{"
311
+ until (tline = flines.next) =~ /^ {6}}/
312
+ term_map_str << tline
313
+ end
314
+ term_map_str << "}"
315
+ term_map = Oj.load(term_map_str)
316
+ term_map_str.clear
317
+ product = products.fetch(product_sku)
318
+ product_family = product.fetch("productFamily", nil)
319
+ product_attributes = product.fetch("attributes", {})
320
+ product_group = product_attributes.fetch("group", nil)
321
+ product_location = product_attributes.fetch("location", nil)
322
+ product_region = Webhookdb::AWS::LOCATIONS_TO_REGIONS.fetch(product_location, product_location)
323
+ product_operation = product_attributes.fetch("operation", nil)
324
+ product_usagetype = product_attributes.fetch("usagetype", nil)
325
+ term_map.each do |term_code, term|
326
+ term["priceDimensions"].each do |rate_code, rate|
327
+ price_per_unit_currency, price_per_unit_amount = rate.fetch("pricePerUnit").first
328
+ rate = {
329
+ product_sku:,
330
+ product_family:,
331
+ product_attributes:,
332
+ product_group:,
333
+ product_location:,
334
+ product_region:,
335
+ product_operation:,
336
+ product_usagetype:,
337
+ publication_date:,
338
+ service_code:,
339
+ version:,
340
+ term_type:,
341
+ term_code:,
342
+ offer_term_code: term.fetch("offerTermCode"),
343
+ effective_date: Time.parse(term.fetch("effectiveDate")),
344
+ term_attributes: term.fetch("termAttributes", {}),
345
+ rate_code:,
346
+ applies_to: (applies_to = rate.fetch("appliesTo")) ? Sequel.pg_array(applies_to) : nil,
347
+ begin_range: self.parse_range(rate.fetch("beginRange", nil)),
348
+ description: rate.fetch("description"),
349
+ end_range: self.parse_range(rate.fetch("endRange", nil)),
350
+ unit: rate.fetch("unit", nil),
351
+ price_per_unit_raw: rate.fetch("pricePerUnit"),
352
+ price_per_unit_amount:,
353
+ price_per_unit_currency:,
354
+ }.stringify_keys
355
+ yield rate
356
+ end
357
+ end
358
+ end
359
+ tmp.unlink
360
+ end
361
+ end
362
+
363
+ def parse_range(value)
364
+ return nil if value.nil?
365
+ return nil if value == "Inf"
366
+ return BigDecimal(value)
367
+ end
368
+ end
369
+ end
370
+ end
371
+
372
+ # We depend on these beta price list API calls that aren't yet in the SDK.
373
+ # Once they are in the SDK we should remove this code.
374
+ unless Aws::Pricing::ClientApi::API.operation_names.include?(:list_price_lists)
375
+
376
+ # rubocop:disable Style/StructInheritance:
377
+ module ::Aws::Pricing::Types
378
+ class ListPriceListsRequest < Struct.new(
379
+ :currency_code,
380
+ :effective_date,
381
+ :max_results,
382
+ :next_token,
383
+ :region_code,
384
+ :service_code,
385
+ )
386
+ SENSITIVE = [].freeze
387
+ include Aws::Structure
388
+ end
389
+
390
+ class ListPriceListsResponse < Struct.new(
391
+ :next_token,
392
+ :price_lists,
393
+ )
394
+ SENSITIVE = [].freeze
395
+ include Aws::Structure
396
+ end
397
+
398
+ class PriceList < Struct.new(
399
+ :price_list_arn,
400
+ )
401
+ SENSITIVE = [].freeze
402
+ include Aws::Structure
403
+ end
404
+
405
+ class GetPriceListFileUrlRequest < Struct.new(
406
+ :file_format,
407
+ :price_list_arn,
408
+ )
409
+ SENSITIVE = [].freeze
410
+ include Aws::Structure
411
+ end
412
+
413
+ class GetPriceListFileUrlResponse < Struct.new(
414
+ :url,
415
+ )
416
+ SENSITIVE = [].freeze
417
+ include Aws::Structure
418
+ end
419
+ end
420
+ # rubocop:enable Style/StructInheritance
421
+
422
+ # rubocop:disable Layout/LineLength
423
+ module ::Aws::Pricing::ClientApi
424
+ ListPriceListsRequest = Shapes::StructureShape.new(name: "ListPriceListsRequest")
425
+ ListPriceListsResponse = Shapes::StructureShape.new(name: "ListPriceListsResponse")
426
+ EffectiveDate = Shapes::TimestampShape.new(name: "EffectiveDate")
427
+ PriceLists = Shapes::ListShape.new(name: "PriceLists")
428
+ PriceList = Shapes::StructureShape.new(name: "PriceList")
429
+
430
+ ListPriceListsRequest.add_member(:currency_code, Shapes::ShapeRef.new(shape: String, location_name: "CurrencyCode"))
431
+ ListPriceListsRequest.add_member(:service_code, Shapes::ShapeRef.new(shape: String, location_name: "ServiceCode"))
432
+ ListPriceListsRequest.add_member(:effective_date, Shapes::ShapeRef.new(shape: EffectiveDate, location_name: "EffectiveDate"))
433
+ ListPriceListsRequest.add_member(:next_token, Shapes::ShapeRef.new(shape: String, location_name: "NextToken"))
434
+ ListPriceListsRequest.add_member(:max_results, Shapes::ShapeRef.new(shape: BoxedInteger, location_name: "MaxResults", metadata: {"box" => true}))
435
+ ListPriceListsRequest.add_member(:region_code, Shapes::ShapeRef.new(shape: String, location_name: "RegionCode"))
436
+ ListPriceListsRequest.struct_class = Aws::Pricing::Types::ListPriceListsRequest
437
+
438
+ PriceList.add_member(:price_list_arn, Shapes::ShapeRef.new(shape: String, location_name: "PriceListArn"))
439
+ PriceList.struct_class = Aws::Pricing::Types::PriceList
440
+
441
+ PriceLists.member = Shapes::ShapeRef.new(shape: PriceList)
442
+
443
+ ListPriceListsResponse.add_member(:price_lists, Shapes::ShapeRef.new(shape: PriceLists, location_name: "PriceLists"))
444
+ ListPriceListsResponse.add_member(:next_token, Shapes::ShapeRef.new(shape: String, location_name: "NextToken"))
445
+ ListPriceListsResponse.struct_class = Aws::Pricing::Types::ListPriceListsResponse
446
+
447
+ API.add_operation(:list_price_lists, Seahorse::Model::Operation.new.tap do |o|
448
+ o.name = "ListPriceLists"
449
+ o.http_method = "POST"
450
+ o.http_request_uri = "/"
451
+ o.input = Shapes::ShapeRef.new(shape: ListPriceListsRequest)
452
+ o.output = Shapes::ShapeRef.new(shape: ListPriceListsResponse)
453
+ o.errors << Shapes::ShapeRef.new(shape: InternalErrorException)
454
+ o.errors << Shapes::ShapeRef.new(shape: InvalidParameterException)
455
+ o.errors << Shapes::ShapeRef.new(shape: NotFoundException)
456
+ o.errors << Shapes::ShapeRef.new(shape: InvalidNextTokenException)
457
+ o.errors << Shapes::ShapeRef.new(shape: ExpiredNextTokenException)
458
+ o[:pager] = Aws::Pager.new(
459
+ limit_key: "max_results",
460
+ tokens: {
461
+ "next_token" => "next_token",
462
+ },
463
+ )
464
+ end,)
465
+
466
+ GetPriceListFileUrlRequest = Shapes::StructureShape.new(name: "GetPriceListFileUrlRequest")
467
+ GetPriceListFileUrlResponse = Shapes::StructureShape.new(name: "GetPriceListFileUrlResponse")
468
+
469
+ GetPriceListFileUrlRequest.add_member(:file_format, Shapes::ShapeRef.new(shape: String, location_name: "FileFormat"))
470
+ GetPriceListFileUrlRequest.add_member(:price_list_arn, Shapes::ShapeRef.new(shape: String, location_name: "PriceListArn"))
471
+ GetPriceListFileUrlRequest.struct_class = Aws::Pricing::Types::GetPriceListFileUrlRequest
472
+
473
+ GetPriceListFileUrlResponse.add_member(:url, Shapes::ShapeRef.new(shape: String, location_name: "Url"))
474
+ GetPriceListFileUrlResponse.struct_class = Aws::Pricing::Types::GetPriceListFileUrlResponse
475
+
476
+ API.add_operation(:get_price_list_file_url, Seahorse::Model::Operation.new.tap do |o|
477
+ o.name = "GetPriceListFileUrl"
478
+ o.http_method = "POST"
479
+ o.http_request_uri = "/"
480
+ o.input = Shapes::ShapeRef.new(shape: GetPriceListFileUrlRequest)
481
+ o.output = Shapes::ShapeRef.new(shape: GetPriceListFileUrlResponse)
482
+ o.errors << Shapes::ShapeRef.new(shape: InternalErrorException)
483
+ o.errors << Shapes::ShapeRef.new(shape: InvalidParameterException)
484
+ o.errors << Shapes::ShapeRef.new(shape: NotFoundException)
485
+ end,)
486
+ end
487
+ # rubocop:enable Layout/LineLength
488
+ end