hooksniff 0.3.0 → 1.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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +56 -0
  4. data/README.md +23 -199
  5. data/Rakefile +2 -0
  6. data/hooksniff.gemspec +48 -0
  7. data/lib/hooksniff/api/authentication.rb +36 -0
  8. data/lib/hooksniff/api/endpoint.rb +102 -0
  9. data/lib/hooksniff/api/event_type.rb +66 -0
  10. data/lib/hooksniff/api/health.rb +16 -0
  11. data/lib/hooksniff/api/integration.rb +42 -0
  12. data/lib/hooksniff/api/message.rb +48 -0
  13. data/lib/hooksniff/api/message_attempt.rb +38 -0
  14. data/lib/hooksniff/api/statistics.rb +37 -0
  15. data/lib/hooksniff/api/stream.rb +45 -0
  16. data/lib/{openapi_client → hooksniff}/api_error.rb +8 -18
  17. data/lib/hooksniff/background_task.rb +21 -0
  18. data/lib/hooksniff/connector.rb +33 -0
  19. data/lib/hooksniff/environment.rb +53 -0
  20. data/lib/hooksniff/errors.rb +129 -0
  21. data/lib/hooksniff/hooksniff.rb +52 -0
  22. data/lib/hooksniff/hooksniff_http_client.rb +128 -0
  23. data/lib/hooksniff/http_error_out.rb +18 -0
  24. data/lib/hooksniff/http_validation_error.rb +18 -0
  25. data/lib/hooksniff/inbound.rb +25 -0
  26. data/lib/hooksniff/internal.rb +7 -0
  27. data/lib/hooksniff/message_poller.rb +32 -0
  28. data/lib/hooksniff/models/endpoint_created_event.rb +50 -0
  29. data/lib/hooksniff/models/endpoint_created_event_data.rb +63 -0
  30. data/lib/hooksniff/models/endpoint_deleted_event.rb +50 -0
  31. data/lib/hooksniff/models/endpoint_deleted_event_data.rb +63 -0
  32. data/lib/hooksniff/models/endpoint_disabled_event.rb +53 -0
  33. data/lib/hooksniff/models/endpoint_disabled_event_data.rb +69 -0
  34. data/lib/hooksniff/models/endpoint_enabled_event.rb +50 -0
  35. data/lib/hooksniff/models/endpoint_enabled_event_data.rb +63 -0
  36. data/lib/hooksniff/models/endpoint_headers_in.rb +46 -0
  37. data/lib/hooksniff/models/endpoint_headers_out.rb +52 -0
  38. data/lib/hooksniff/models/endpoint_headers_patch_in.rb +53 -0
  39. data/lib/hooksniff/models/endpoint_in.rb +102 -0
  40. data/lib/hooksniff/models/endpoint_out.rb +104 -0
  41. data/lib/hooksniff/models/endpoint_patch.rb +97 -0
  42. data/lib/hooksniff/models/endpoint_secret_out.rb +50 -0
  43. data/lib/hooksniff/models/endpoint_secret_rotate_in.rb +53 -0
  44. data/lib/hooksniff/models/endpoint_update.rb +90 -0
  45. data/lib/hooksniff/models/endpoint_updated_event.rb +50 -0
  46. data/lib/hooksniff/models/endpoint_updated_event_data.rb +63 -0
  47. data/lib/hooksniff/models/event_in.rb +50 -0
  48. data/lib/hooksniff/models/event_out.rb +53 -0
  49. data/lib/hooksniff/models/event_type_in.rb +80 -0
  50. data/lib/hooksniff/models/event_type_out.rb +87 -0
  51. data/lib/hooksniff/models/event_type_patch.rb +66 -0
  52. data/lib/hooksniff/models/event_type_update.rb +67 -0
  53. data/lib/hooksniff/models/list_response_endpoint_out.rb +58 -0
  54. data/lib/hooksniff/models/list_response_event_type_out.rb +58 -0
  55. data/lib/hooksniff/models/list_response_message_attempt_out.rb +58 -0
  56. data/lib/hooksniff/models/list_response_message_out.rb +58 -0
  57. data/lib/hooksniff/models/message_attempt_exhausted_event.rb +53 -0
  58. data/lib/hooksniff/models/message_attempt_exhausted_event_data.rb +70 -0
  59. data/lib/hooksniff/models/message_attempt_failed_data.rb +56 -0
  60. data/lib/hooksniff/models/message_attempt_failing_event.rb +54 -0
  61. data/lib/hooksniff/models/message_attempt_failing_event_data.rb +70 -0
  62. data/lib/hooksniff/models/message_attempt_log.rb +112 -0
  63. data/lib/hooksniff/models/message_attempt_log_event.rb +53 -0
  64. data/lib/hooksniff/models/message_attempt_out.rb +96 -0
  65. data/lib/hooksniff/models/message_attempt_trigger_type.rb +33 -0
  66. data/lib/hooksniff/models/message_endpoint_out.rb +112 -0
  67. data/lib/hooksniff/models/message_in.rb +99 -0
  68. data/lib/hooksniff/models/message_out.rb +71 -0
  69. data/lib/hooksniff/models/message_status.rb +39 -0
  70. data/lib/hooksniff/models/message_status_text.rb +32 -0
  71. data/lib/hooksniff/models/ordering.rb +30 -0
  72. data/lib/hooksniff/models/status_code_class.rb +41 -0
  73. data/lib/hooksniff/operational_webhook.rb +12 -0
  74. data/lib/hooksniff/util.rb +69 -0
  75. data/lib/hooksniff/validation_error.rb +28 -0
  76. data/lib/hooksniff/version.rb +5 -0
  77. data/lib/hooksniff/webhook.rb +84 -0
  78. data/lib/hooksniff.rb +78 -0
  79. data/test/test_hooksniff.rb +86 -0
  80. metadata +131 -159
  81. data/lib/openapi_client/api/admin_api.rb +0 -452
  82. data/lib/openapi_client/api/alerts_api.rb +0 -322
  83. data/lib/openapi_client/api/analytics_api.rb +0 -208
  84. data/lib/openapi_client/api/api_keys_api.rb +0 -252
  85. data/lib/openapi_client/api/audit_log_api.rb +0 -140
  86. data/lib/openapi_client/api/auth_api.rb +0 -1080
  87. data/lib/openapi_client/api/billing_api.rb +0 -500
  88. data/lib/openapi_client/api/contact_api.rb +0 -88
  89. data/lib/openapi_client/api/custom_domains_api.rb +0 -253
  90. data/lib/openapi_client/api/customer_portal_api.rb +0 -700
  91. data/lib/openapi_client/api/delivery_details_api.rb +0 -146
  92. data/lib/openapi_client/api/devices_api.rb +0 -202
  93. data/lib/openapi_client/api/embed_api.rb +0 -128
  94. data/lib/openapi_client/api/endpoints_api.rb +0 -468
  95. data/lib/openapi_client/api/events_api.rb +0 -75
  96. data/lib/openapi_client/api/health_api.rb +0 -193
  97. data/lib/openapi_client/api/inbound_api.rb +0 -170
  98. data/lib/openapi_client/api/notifications_api.rb +0 -309
  99. data/lib/openapi_client/api/o_auth_api.rb +0 -181
  100. data/lib/openapi_client/api/outbound_ips_api.rb +0 -77
  101. data/lib/openapi_client/api/playground_api.rb +0 -143
  102. data/lib/openapi_client/api/rate_limits_api.rb +0 -252
  103. data/lib/openapi_client/api/routing_api.rb +0 -393
  104. data/lib/openapi_client/api/schemas_api.rb +0 -268
  105. data/lib/openapi_client/api/search_api.rb +0 -96
  106. data/lib/openapi_client/api/simulator_api.rb +0 -82
  107. data/lib/openapi_client/api/sso_api.rb +0 -241
  108. data/lib/openapi_client/api/stats_api.rb +0 -77
  109. data/lib/openapi_client/api/stream_api.rb +0 -88
  110. data/lib/openapi_client/api/teams_api.rb +0 -476
  111. data/lib/openapi_client/api/templates_api.rb +0 -213
  112. data/lib/openapi_client/api/transforms_api.rb +0 -368
  113. data/lib/openapi_client/api/webhooks_api.rb +0 -534
  114. data/lib/openapi_client/api_client.rb +0 -397
  115. data/lib/openapi_client/api_model_base.rb +0 -88
  116. data/lib/openapi_client/configuration.rb +0 -312
  117. data/lib/openapi_client/models/admin_revenue_get200_response_inner.rb +0 -165
  118. data/lib/openapi_client/models/admin_sdk_update_post_request.rb +0 -156
  119. data/lib/openapi_client/models/admin_users_id_plan_put_request.rb +0 -181
  120. data/lib/openapi_client/models/admin_users_id_status_put_request.rb +0 -147
  121. data/lib/openapi_client/models/alert_rule.rb +0 -237
  122. data/lib/openapi_client/models/api_key_info.rb +0 -185
  123. data/lib/openapi_client/models/apply_template_request.rb +0 -173
  124. data/lib/openapi_client/models/apply_template_response.rb +0 -156
  125. data/lib/openapi_client/models/auth2fa_enable_post200_response.rb +0 -156
  126. data/lib/openapi_client/models/auth_login_post200_response.rb +0 -104
  127. data/lib/openapi_client/models/auth_response.rb +0 -167
  128. data/lib/openapi_client/models/batch_replay_request.rb +0 -166
  129. data/lib/openapi_client/models/batch_response.rb +0 -160
  130. data/lib/openapi_client/models/batch_response_errors_inner.rb +0 -156
  131. data/lib/openapi_client/models/batch_webhook_request.rb +0 -166
  132. data/lib/openapi_client/models/billing_portal_post200_response.rb +0 -147
  133. data/lib/openapi_client/models/change_password_request.rb +0 -199
  134. data/lib/openapi_client/models/change_role_request.rb +0 -188
  135. data/lib/openapi_client/models/confirm2fa_request.rb +0 -182
  136. data/lib/openapi_client/models/contact_request.rb +0 -242
  137. data/lib/openapi_client/models/contact_response.rb +0 -156
  138. data/lib/openapi_client/models/create_alert_request.rb +0 -277
  139. data/lib/openapi_client/models/create_api_key_response.rb +0 -175
  140. data/lib/openapi_client/models/create_endpoint_request.rb +0 -288
  141. data/lib/openapi_client/models/create_team_request.rb +0 -164
  142. data/lib/openapi_client/models/create_transform_rule_request.rb +0 -216
  143. data/lib/openapi_client/models/create_webhook_request.rb +0 -201
  144. data/lib/openapi_client/models/custom_domains_post_request.rb +0 -147
  145. data/lib/openapi_client/models/customer_response.rb +0 -256
  146. data/lib/openapi_client/models/delivery.rb +0 -246
  147. data/lib/openapi_client/models/delivery_attempt.rb +0 -205
  148. data/lib/openapi_client/models/delivery_list_response.rb +0 -176
  149. data/lib/openapi_client/models/delivery_trend_response.rb +0 -158
  150. data/lib/openapi_client/models/delivery_trend_response_buckets_inner.rb +0 -174
  151. data/lib/openapi_client/models/device_token_response.rb +0 -174
  152. data/lib/openapi_client/models/disable2fa_request.rb +0 -164
  153. data/lib/openapi_client/models/enable2fa_request.rb +0 -164
  154. data/lib/openapi_client/models/endpoint.rb +0 -321
  155. data/lib/openapi_client/models/endpoint_health.rb +0 -183
  156. data/lib/openapi_client/models/endpoints_endpoint_id_transforms_test_post_request.rb +0 -156
  157. data/lib/openapi_client/models/endpoints_id_rotate_secret_post200_response.rb +0 -156
  158. data/lib/openapi_client/models/error.rb +0 -165
  159. data/lib/openapi_client/models/forgot_password_request.rb +0 -164
  160. data/lib/openapi_client/models/invite_request.rb +0 -207
  161. data/lib/openapi_client/models/invoice_response.rb +0 -183
  162. data/lib/openapi_client/models/latency_trend_response.rb +0 -167
  163. data/lib/openapi_client/models/latency_trend_response_buckets_inner.rb +0 -165
  164. data/lib/openapi_client/models/login_request.rb +0 -190
  165. data/lib/openapi_client/models/notification.rb +0 -193
  166. data/lib/openapi_client/models/notification_list_response.rb +0 -167
  167. data/lib/openapi_client/models/notification_preferences.rb +0 -201
  168. data/lib/openapi_client/models/notifications_unread_count_get200_response.rb +0 -147
  169. data/lib/openapi_client/models/outbound_ips_response.rb +0 -158
  170. data/lib/openapi_client/models/paginated_users.rb +0 -176
  171. data/lib/openapi_client/models/playground_get200_response.rb +0 -160
  172. data/lib/openapi_client/models/portal_notifications_put200_response.rb +0 -156
  173. data/lib/openapi_client/models/portal_profile.rb +0 -184
  174. data/lib/openapi_client/models/refresh_token_request.rb +0 -164
  175. data/lib/openapi_client/models/register_device_request.rb +0 -208
  176. data/lib/openapi_client/models/register_request.rb +0 -201
  177. data/lib/openapi_client/models/register_schema_request.rb +0 -191
  178. data/lib/openapi_client/models/resend_verification_request.rb +0 -164
  179. data/lib/openapi_client/models/reset_password_request.rb +0 -199
  180. data/lib/openapi_client/models/retry_policy.rb +0 -216
  181. data/lib/openapi_client/models/routing_info.rb +0 -193
  182. data/lib/openapi_client/models/search_result.rb +0 -158
  183. data/lib/openapi_client/models/simulator_post_request.rb +0 -165
  184. data/lib/openapi_client/models/sso_config_post_request.rb +0 -190
  185. data/lib/openapi_client/models/stats_response.rb +0 -210
  186. data/lib/openapi_client/models/stream_params.rb +0 -201
  187. data/lib/openapi_client/models/subscription_response.rb +0 -201
  188. data/lib/openapi_client/models/success_rate_response.rb +0 -183
  189. data/lib/openapi_client/models/system_stats.rb +0 -185
  190. data/lib/openapi_client/models/system_stats_plan_breakdown_inner.rb +0 -156
  191. data/lib/openapi_client/models/system_status.rb +0 -210
  192. data/lib/openapi_client/models/system_status_components_inner.rb +0 -184
  193. data/lib/openapi_client/models/team.rb +0 -165
  194. data/lib/openapi_client/models/team_detail_response.rb +0 -169
  195. data/lib/openapi_client/models/team_invite.rb +0 -174
  196. data/lib/openapi_client/models/team_member.rb +0 -193
  197. data/lib/openapi_client/models/test_webhook_request.rb +0 -199
  198. data/lib/openapi_client/models/test_webhook_response.rb +0 -174
  199. data/lib/openapi_client/models/transform_rule.rb +0 -201
  200. data/lib/openapi_client/models/two_factor_required_response.rb +0 -165
  201. data/lib/openapi_client/models/update_endpoint_request.rb +0 -278
  202. data/lib/openapi_client/models/update_notification_preferences.rb +0 -195
  203. data/lib/openapi_client/models/update_profile_request.rb +0 -190
  204. data/lib/openapi_client/models/update_routing_request.rb +0 -190
  205. data/lib/openapi_client/models/upgrade_request.rb +0 -209
  206. data/lib/openapi_client/models/upgrade_response.rb +0 -166
  207. data/lib/openapi_client/models/usage_response.rb +0 -201
  208. data/lib/openapi_client/models/user_summary.rb +0 -193
  209. data/lib/openapi_client/models/validate_event_request.rb +0 -164
  210. data/lib/openapi_client/models/verify2fa_request.rb +0 -208
  211. data/lib/openapi_client/models/verify_email_request.rb +0 -164
  212. data/lib/openapi_client/models/webhook_template.rb +0 -183
  213. data/lib/openapi_client/version.rb +0 -15
  214. data/lib/openapi_client.rb +0 -169
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+
5
+ module HookSniff
6
+ class MessageAttempt
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def list_by_msg(message_id, options = {})
12
+ options = options.transform_keys(&:to_s)
13
+ res = @client.execute_request(
14
+ "GET",
15
+ "/v1/webhooks/#{message_id}/attempts",
16
+ query_params: {
17
+ "limit" => options["limit"],
18
+ "offset" => options["offset"],
19
+ "status" => options["status"]
20
+ }
21
+ )
22
+ ListResponseMessageAttemptOut.deserialize(res)
23
+ end
24
+
25
+ def get(attempt_id)
26
+ res = @client.execute_request("GET", "/v1/webhooks/attempts/#{attempt_id}")
27
+ MessageAttemptOut.deserialize(res)
28
+ end
29
+
30
+ def resend(message_id, endpoint_id)
31
+ res = @client.execute_request(
32
+ "POST",
33
+ "/v1/webhooks/#{message_id}/attempts/#{endpoint_id}/resend"
34
+ )
35
+ nil
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+
5
+ module HookSniff
6
+ class Statistics
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def aggregate_event_types(options = {})
12
+ options = options.transform_keys(&:to_s)
13
+ res = @client.execute_request(
14
+ "GET",
15
+ "/v1/stats/event-types",
16
+ query_params: {
17
+ "since" => options["since"],
18
+ "until" => options["until"]
19
+ }
20
+ )
21
+ AggregateEventTypesOut.deserialize(res)
22
+ end
23
+
24
+ def app_stats(app_id, options = {})
25
+ options = options.transform_keys(&:to_s)
26
+ res = @client.execute_request(
27
+ "GET",
28
+ "/v1/stats/app/#{app_id}",
29
+ query_params: {
30
+ "since" => options["since"],
31
+ "until" => options["until"]
32
+ }
33
+ )
34
+ res
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class StreamApi
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ def list_channels
10
+ @client.request(:get, "/api/v1/stream/channels")
11
+ end
12
+
13
+ def get_channel(id)
14
+ @client.request(:get, "/api/v1/stream/channels/#{id}")
15
+ end
16
+
17
+ def create_channel(attrs)
18
+ @client.request(:post, "/api/v1/stream/channels", attrs)
19
+ end
20
+
21
+ def update_channel(id, attrs)
22
+ @client.request(:put, "/api/v1/stream/channels/#{id}", attrs)
23
+ end
24
+
25
+ def delete_channel(id)
26
+ @client.request(:delete, "/api/v1/stream/channels/#{id}")
27
+ end
28
+
29
+ def list_messages(id, params = {})
30
+ @client.request(:get, "/api/v1/stream/channels/#{id}/messages", params)
31
+ end
32
+
33
+ def list_subscriptions
34
+ @client.request(:get, "/api/v1/stream/subscriptions")
35
+ end
36
+
37
+ def disconnect_subscription(id)
38
+ @client.request(:delete, "/api/v1/stream/subscriptions/#{id}")
39
+ end
40
+
41
+ def publish(body)
42
+ @client.request(:post, "/api/v1/stream/publish", body)
43
+ end
44
+ end
45
+ end
@@ -1,16 +1,6 @@
1
- =begin
2
- #HookSniff API
1
+ # frozen_string_literal: true
3
2
 
4
- #Webhook delivery, monitoring, and management API. All endpoints under `/v1` require authentication via `Authorization: Bearer <api_key>` header unless marked as **Public**.
5
-
6
- The version of the OpenAPI document: 1.0.0
7
- Contact: support@hooksniff.vercel.app
8
- Generated by: https://openapi-generator.tech
9
- Generator version: 7.22.0
10
-
11
- =end
12
-
13
- module OpenapiClient
3
+ module HookSniff
14
4
  class ApiError < StandardError
15
5
  attr_reader :code, :response_headers, :response_body
16
6
 
@@ -20,18 +10,18 @@ module OpenapiClient
20
10
  # ApiError.new(:code => 500, :response_headers => {}, :response_body => "")
21
11
  # ApiError.new(:code => 404, :message => "Not Found")
22
12
  def initialize(arg = nil)
23
- if arg.is_a? Hash
24
- if arg.key?(:message) || arg.key?('message')
25
- super(arg[:message] || arg['message'])
13
+ if arg.is_a?(Hash)
14
+ if arg.key?(:message) || arg.key?("message")
15
+ super(arg[:message] || arg["message"])
26
16
  else
27
- super arg
17
+ super(arg)
28
18
  end
29
19
 
30
20
  arg.each do |k, v|
31
- instance_variable_set "@#{k}", v
21
+ instance_variable_set("@#{k}", v)
32
22
  end
33
23
  else
34
- super arg
24
+ super(arg)
35
25
  @message = arg
36
26
  end
37
27
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class BackgroundTask
5
+ def initialize(api_client)
6
+ @api_client = api_client
7
+ end
8
+
9
+ def list
10
+ @api_client.execute(method: :get, path: "/api/v1/background-tasks")
11
+ end
12
+
13
+ def get(task_id)
14
+ @api_client.execute(method: :get, path: "/api/v1/background-tasks/#{task_id}")
15
+ end
16
+
17
+ def cancel(task_id)
18
+ @api_client.execute(method: :put, path: "/api/v1/background-tasks/#{task_id}")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class Connector
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ def list
10
+ @client.request(:get, "/api/v1/connectors")
11
+ end
12
+
13
+ def get(id)
14
+ @client.request(:get, "/api/v1/connectors/#{id}")
15
+ end
16
+
17
+ def list_configs
18
+ @client.request(:get, "/api/v1/connectors/configs")
19
+ end
20
+
21
+ def create_config(body)
22
+ @client.request(:post, "/api/v1/connectors/configs", body: body)
23
+ end
24
+
25
+ def update_config(id, body)
26
+ @client.request(:put, "/api/v1/connectors/configs/#{id}", body: body)
27
+ end
28
+
29
+ def delete_config(id)
30
+ @client.request(:delete, "/api/v1/connectors/configs/#{id}")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class Environment
5
+ def initialize(api_client)
6
+ @api_client = api_client
7
+ end
8
+
9
+ def list
10
+ @api_client.execute(method: :get, path: "/api/v1/environments")
11
+ end
12
+
13
+ def create(environment_in)
14
+ @api_client.execute(method: :post, path: "/api/v1/environments", body: environment_in)
15
+ end
16
+
17
+ def get(environment_id)
18
+ @api_client.execute(method: :get, path: "/api/v1/environments/#{environment_id}")
19
+ end
20
+
21
+ def update(environment_id, environment_patch)
22
+ @api_client.execute(method: :put, path: "/api/v1/environments/#{environment_id}", body: environment_patch)
23
+ end
24
+
25
+ def delete(environment_id)
26
+ @api_client.execute(method: :delete, path: "/api/v1/environments/#{environment_id}")
27
+ end
28
+
29
+ def list_variables(environment_id)
30
+ @api_client.execute(method: :get, path: "/api/v1/environments/#{environment_id}/variables")
31
+ end
32
+
33
+ def get_variable(environment_id, variable_id)
34
+ @api_client.execute(method: :get, path: "/api/v1/environments/#{environment_id}/variables/#{variable_id}")
35
+ end
36
+
37
+ def create_variable(environment_id, variable_in)
38
+ @api_client.execute(method: :post, path: "/api/v1/environments/#{environment_id}/variables", body: variable_in)
39
+ end
40
+
41
+ def update_variable(environment_id, variable_id, variable_in)
42
+ @api_client.execute(method: :put, path: "/api/v1/environments/#{environment_id}/variables/#{variable_id}", body: variable_in)
43
+ end
44
+
45
+ def delete_variable(environment_id, variable_id)
46
+ @api_client.execute(method: :delete, path: "/api/v1/environments/#{environment_id}/variables/#{variable_id}")
47
+ end
48
+
49
+ def bulk_upsert_variables(environment_id, bulk_in)
50
+ @api_client.execute(method: :post, path: "/api/v1/environments/#{environment_id}/variables/bulk", body: bulk_in)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ # Base error class for all HookSniff API errors
5
+ class ApiError < StandardError
6
+ attr_reader :code, :response_headers, :response_body
7
+
8
+ def initialize(code:, response_headers: {}, response_body: nil)
9
+ @code = code
10
+ @response_headers = response_headers
11
+ @response_body = response_body
12
+ super("HookSniff API error #{code}")
13
+ end
14
+ end
15
+
16
+ # 400 Bad Request
17
+ class BadRequestError < ApiError
18
+ def initialize(response_headers: {}, response_body: nil)
19
+ super(code: 400, response_headers: response_headers, response_body: response_body)
20
+ end
21
+ end
22
+
23
+ # 401 Unauthorized
24
+ class UnauthorizedError < ApiError
25
+ def initialize(response_headers: {}, response_body: nil)
26
+ super(code: 401, response_headers: response_headers, response_body: response_body)
27
+ end
28
+ end
29
+
30
+ # 403 Forbidden
31
+ class ForbiddenError < ApiError
32
+ def initialize(response_headers: {}, response_body: nil)
33
+ super(code: 403, response_headers: response_headers, response_body: response_body)
34
+ end
35
+ end
36
+
37
+ # 404 Not Found
38
+ class NotFoundError < ApiError
39
+ def initialize(response_headers: {}, response_body: nil)
40
+ super(code: 404, response_headers: response_headers, response_body: response_body)
41
+ end
42
+ end
43
+
44
+ # 409 Conflict
45
+ class ConflictError < ApiError
46
+ def initialize(response_headers: {}, response_body: nil)
47
+ super(code: 409, response_headers: response_headers, response_body: response_body)
48
+ end
49
+ end
50
+
51
+ # 422 Unprocessable Entity
52
+ class UnprocessableEntityError < ApiError
53
+ attr_reader :validation_errors
54
+
55
+ def initialize(validation_errors: [], response_headers: {}, response_body: nil)
56
+ super(code: 422, response_headers: response_headers, response_body: response_body)
57
+ @validation_errors = validation_errors
58
+ end
59
+ end
60
+
61
+ # 429 Rate Limited
62
+ class RateLimitError < ApiError
63
+ attr_reader :retry_after
64
+
65
+ def initialize(retry_after: nil, response_headers: {}, response_body: nil)
66
+ super(code: 429, response_headers: response_headers, response_body: response_body)
67
+ @retry_after = retry_after
68
+ end
69
+ end
70
+
71
+ # 500 Internal Server Error
72
+ class InternalServerError < ApiError
73
+ def initialize(response_headers: {}, response_body: nil)
74
+ super(code: 500, response_headers: response_headers, response_body: response_body)
75
+ end
76
+ end
77
+
78
+ # 502 Bad Gateway
79
+ class BadGatewayError < ApiError
80
+ def initialize(response_headers: {}, response_body: nil)
81
+ super(code: 502, response_headers: response_headers, response_body: response_body)
82
+ end
83
+ end
84
+
85
+ # 503 Service Unavailable
86
+ class ServiceUnavailableError < ApiError
87
+ def initialize(response_headers: {}, response_body: nil)
88
+ super(code: 503, response_headers: response_headers, response_body: response_body)
89
+ end
90
+ end
91
+
92
+ # 504 Gateway Timeout
93
+ class GatewayTimeoutError < ApiError
94
+ def initialize(response_headers: {}, response_body: nil)
95
+ super(code: 504, response_headers: response_headers, response_body: response_body)
96
+ end
97
+ end
98
+
99
+ # Create the appropriate error from a status code
100
+ def self.create_error_from_status(status_code, response_headers: {}, response_body: nil)
101
+ case status_code
102
+ when 400
103
+ BadRequestError.new(response_headers: response_headers, response_body: response_body)
104
+ when 401
105
+ UnauthorizedError.new(response_headers: response_headers, response_body: response_body)
106
+ when 403
107
+ ForbiddenError.new(response_headers: response_headers, response_body: response_body)
108
+ when 404
109
+ NotFoundError.new(response_headers: response_headers, response_body: response_body)
110
+ when 409
111
+ ConflictError.new(response_headers: response_headers, response_body: response_body)
112
+ when 422
113
+ UnprocessableEntityError.new(response_headers: response_headers, response_body: response_body)
114
+ when 429
115
+ retry_after = response_headers["retry-after"]&.to_i
116
+ RateLimitError.new(retry_after: retry_after, response_headers: response_headers, response_body: response_body)
117
+ when 500
118
+ InternalServerError.new(response_headers: response_headers, response_body: response_body)
119
+ when 502
120
+ BadGatewayError.new(response_headers: response_headers, response_body: response_body)
121
+ when 503
122
+ ServiceUnavailableError.new(response_headers: response_headers, response_body: response_body)
123
+ when 504
124
+ GatewayTimeoutError.new(response_headers: response_headers, response_body: response_body)
125
+ else
126
+ ApiError.new(code: status_code, response_headers: response_headers, response_body: response_body)
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class HookSniffOptions
5
+ attr_accessor :debug
6
+ attr_accessor :server_url
7
+
8
+ def initialize(debug = false, server_url = nil)
9
+ @debug = debug
10
+ @server_url = server_url
11
+ end
12
+ end
13
+
14
+ class Client
15
+ attr_accessor :authentication
16
+ attr_accessor :endpoint
17
+ attr_accessor :event_type
18
+ attr_accessor :health
19
+ attr_accessor :message
20
+ attr_accessor :message_attempt
21
+ attr_accessor :statistics
22
+ attr_accessor :environment
23
+ attr_accessor :background_task
24
+ attr_accessor :operational_webhook
25
+ attr_accessor :message_poller
26
+ attr_accessor :inbound
27
+ attr_accessor :connector
28
+ attr_accessor :integration
29
+ attr_accessor :stream
30
+
31
+ def initialize(auth_token, options = HookSniffOptions.new)
32
+ uri = URI(options.server_url || "https://hooksniff-api-1046140057667.europe-west1.run.app")
33
+ api_client = HookSniffHttpClient.new(auth_token, uri)
34
+
35
+ @authentication = Authentication.new(api_client)
36
+ @endpoint = Endpoint.new(api_client)
37
+ @event_type = EventType.new(api_client)
38
+ @health = Health.new(api_client)
39
+ @message = Message.new(api_client)
40
+ @message_attempt = MessageAttempt.new(api_client)
41
+ @statistics = Statistics.new(api_client)
42
+ @environment = Environment.new(api_client)
43
+ @background_task = BackgroundTask.new(api_client)
44
+ @operational_webhook = OperationalWebhook.new(api_client)
45
+ @message_poller = MessagePoller.new(api_client)
46
+ @inbound = Inbound.new(api_client)
47
+ @connector = Connector.new(api_client)
48
+ @integration = IntegrationApi.new(api_client)
49
+ @stream = StreamApi.new(api_client)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+ require "cgi"
3
+ require "uri"
4
+ require "net/http"
5
+ require "securerandom"
6
+
7
+
8
+ module HookSniff
9
+ class HookSniffHttpClient
10
+ def initialize(token, base_url)
11
+ @token = token
12
+ @base_url = base_url
13
+ end
14
+
15
+ def execute_request(method, path, **kwargs)
16
+ query_params = kwargs[:query_params] || {}
17
+ headers = kwargs[:headers] || {}
18
+ body = kwargs[:body] || {}
19
+
20
+ uri = URI("#{@base_url}#{path}")
21
+ encoded_query = encode_query_params(query_params)
22
+ if encoded_query != ""
23
+ uri.query = encoded_query
24
+ end
25
+
26
+ http = Net::HTTP.new(uri.host, uri.port)
27
+ http.use_ssl = (uri.scheme == "https")
28
+
29
+ # Dynamically select the request class based on method
30
+ request_class = case method.to_s.upcase
31
+ when "GET"
32
+ Net::HTTP::Get
33
+ when "POST"
34
+ Net::HTTP::Post
35
+ when "PUT"
36
+ Net::HTTP::Put
37
+ when "DELETE"
38
+ Net::HTTP::Delete
39
+ when "PATCH"
40
+ Net::HTTP::Patch
41
+ when "HEAD"
42
+ Net::HTTP::Head
43
+ else
44
+ raise ArgumentError, "Unsupported HTTP method: #{method}"
45
+ end
46
+
47
+ # Create request object
48
+ request = request_class.new(uri.request_uri)
49
+ request["Authorization"] = "Bearer #{@token}"
50
+ request["User-Agent"] = "hooksniff-libs/#{VERSION}/ruby"
51
+ request["hooksniff-req-id"] = rand(0...(2 ** 64))
52
+
53
+ # Add headers
54
+ headers.each { |key, value| request[key] = value }
55
+
56
+ # Check if idempotency-key header already exists
57
+ if !request.key?("idempotency-key") && method.to_s.upcase == "POST"
58
+ request["idempotency-key"] = "auto_" + SecureRandom.uuid.to_s
59
+ end
60
+
61
+ # Add body for non-GET requests
62
+ if %w[POST PUT PATCH].include?(method.to_s.upcase) && !body.nil?
63
+ request.body = body.to_json
64
+ request["Content-Type"] = "application/json"
65
+ end
66
+
67
+ res = execute_request_with_retries(request, http)
68
+
69
+ # Execute request
70
+ if Integer(res.code) == 204
71
+ nil
72
+ elsif Integer(res.code) >= 200 && Integer(res.code) <= 299
73
+ JSON.parse(res.body)
74
+ else
75
+ fail(
76
+ ApiError.new(
77
+ :code => Integer(res.code),
78
+ :response_headers => res.each_header.to_h,
79
+ :response_body => res.body
80
+ )
81
+ )
82
+ end
83
+ end
84
+
85
+ private def execute_request_with_retries(request, http)
86
+ res = http.request(request)
87
+
88
+ [0.05, 0.1, 0.2].each_with_index do |sleep_duration, index|
89
+ # 429 Rate Limit — respect Retry-After header
90
+ if Integer(res.code) == 429
91
+ retry_after = res["Retry-After"]
92
+ delay = retry_after ? retry_after.to_f : sleep_duration
93
+ sleep(delay)
94
+ request["hooksniff-retry-count"] = index + 1
95
+ res = http.request(request)
96
+ next
97
+ end
98
+
99
+ unless Integer(res.code) >= 500
100
+ break
101
+ end
102
+
103
+ sleep(sleep_duration)
104
+ request["hooksniff-retry-count"] = index + 1
105
+ res = http.request(request)
106
+ end
107
+
108
+ res
109
+ end
110
+
111
+ private def encode_query_params(query_params = {})
112
+ encoded_query_pairs = []
113
+ query_params.each do |k, v|
114
+ unless v.nil?
115
+ if v.kind_of?(Array)
116
+ encoded_query_pairs.append("#{k}=" + CGI::escape(v.sort.join(",")))
117
+ elsif v.kind_of?(Time)
118
+ encoded_query_pairs.append("#{k}=#{CGI::escape(v.utc.to_datetime.rfc3339)}")
119
+ else
120
+ encoded_query_pairs.append("#{k}=#{CGI::escape(v)}")
121
+ end
122
+ end
123
+ end
124
+
125
+ encoded_query_pairs.join("&")
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class HttpErrorOut
5
+ attr_accessor :code
6
+
7
+ attr_accessor :detail
8
+
9
+ def initialize(attributes = {})
10
+ if (!attributes.is_a?(Hash))
11
+ fail(ArgumentError, "The input argument (attributes) must be a hash in `HookSniff::HttpErrorOut` initialize method")
12
+ end
13
+
14
+ @detail = attributes[:"detail"]
15
+ @code = attributes[:"code"]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class HTTPValidationError
5
+ attr_accessor :detail
6
+
7
+ def initialize(attributes = {})
8
+ if (!attributes.is_a?(Hash))
9
+ fail(
10
+ ArgumentError,
11
+ "The input argument (attributes) must be a hash in `HookSniff::HTTPValidationError` initialize method"
12
+ )
13
+ end
14
+
15
+ @detail = attributes[:"detail"]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class Inbound
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ def list_configs
10
+ @client.request(:get, "/api/v1/inbound/configs")
11
+ end
12
+
13
+ def create_config(body)
14
+ @client.request(:post, "/api/v1/inbound/configs", body: body)
15
+ end
16
+
17
+ def update_config(id, body)
18
+ @client.request(:put, "/api/v1/inbound/configs/#{id}", body: body)
19
+ end
20
+
21
+ def delete_config(id)
22
+ @client.request(:delete, "/api/v1/inbound/configs/#{id}")
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ private_constant :HttpErrorOut
5
+ private_constant :HTTPValidationError
6
+ private_constant :ValidationError
7
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HookSniff
4
+ class MessagePoller
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ # Poll for new messages since the consumer's cursor.
10
+ def poll(consumer_id, limit: nil, endpoint_id: nil, event_type: nil, include_payload: true)
11
+ params = { consumer_id: consumer_id, include_payload: include_payload }
12
+ params[:limit] = limit if limit
13
+ params[:endpoint_id] = endpoint_id if endpoint_id
14
+ params[:event_type] = event_type if event_type
15
+ @client.request(:get, "/api/v1/message-poller/poll", params: params)
16
+ end
17
+
18
+ # Seek cursor to a specific message.
19
+ def seek(consumer_id, message_id, endpoint_id: nil)
20
+ body = { consumer_id: consumer_id, message_id: message_id }
21
+ body[:endpoint_id] = endpoint_id if endpoint_id
22
+ @client.request(:post, "/api/v1/message-poller/seek", body: body)
23
+ end
24
+
25
+ # Commit cursor — advance past a processed message.
26
+ def commit(consumer_id, message_id, endpoint_id: nil)
27
+ body = { consumer_id: consumer_id, message_id: message_id }
28
+ body[:endpoint_id] = endpoint_id if endpoint_id
29
+ @client.request(:post, "/api/v1/message-poller/commit", body: body)
30
+ end
31
+ end
32
+ end