rcs 2.0.18 → 2.0.20.pre.rc.1

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 (494) hide show
  1. checksums.yaml +4 -4
  2. data/.fern/metadata.json +6 -4
  3. data/.rubocop.yml +34 -0
  4. data/CONTRIBUTING.md +120 -0
  5. data/lib/pinnacle/audiences/client.rb +0 -4
  6. data/lib/pinnacle/audiences/contacts/types/add_contacts_params.rb +1 -0
  7. data/lib/pinnacle/audiences/contacts/types/remove_contacts_params.rb +1 -0
  8. data/lib/pinnacle/audiences/types/audiences_get_request.rb +2 -0
  9. data/lib/pinnacle/audiences/types/audiences_get_response.rb +1 -0
  10. data/lib/pinnacle/audiences/types/create_audience_params.rb +2 -0
  11. data/lib/pinnacle/audiences/types/list_audiences_params.rb +2 -0
  12. data/lib/pinnacle/audiences/types/update_audience_params.rb +2 -0
  13. data/lib/pinnacle/brands/client.rb +1 -3
  14. data/lib/pinnacle/brands/types/autofill_brand_params.rb +3 -0
  15. data/lib/pinnacle/brands/types/brands_get_request.rb +1 -0
  16. data/lib/pinnacle/brands/types/list_brands_params.rb +4 -0
  17. data/lib/pinnacle/brands/types/upsert_brand_params.rb +11 -0
  18. data/lib/pinnacle/brands/types/upsert_brand_schema_contact.rb +3 -0
  19. data/lib/pinnacle/brands/types/vet_brand_params.rb +3 -0
  20. data/lib/pinnacle/calls/client.rb +359 -0
  21. data/lib/pinnacle/calls/types/calls_download_recording_request.rb +13 -0
  22. data/lib/pinnacle/calls/types/calls_list_events_request.rb +15 -0
  23. data/lib/pinnacle/calls/types/calls_list_request.rb +25 -0
  24. data/lib/pinnacle/calls/types/create_call_params.rb +17 -0
  25. data/lib/pinnacle/calls/types/create_stream_token_params.rb +17 -0
  26. data/lib/pinnacle/calls/types/update_call_params.rb +13 -0
  27. data/lib/pinnacle/campaigns/dlc/types/dlc_campaign_help_keywords.rb +1 -0
  28. data/lib/pinnacle/campaigns/dlc/types/dlc_campaign_keywords.rb +2 -0
  29. data/lib/pinnacle/campaigns/dlc/types/dlc_campaign_links.rb +1 -0
  30. data/lib/pinnacle/campaigns/dlc/types/dlc_campaign_opt_in_keywords.rb +1 -0
  31. data/lib/pinnacle/campaigns/dlc/types/dlc_campaign_opt_out_keywords.rb +1 -0
  32. data/lib/pinnacle/campaigns/dlc/types/dlc_campaign_options.rb +5 -0
  33. data/lib/pinnacle/campaigns/dlc/types/dlc_campaign_use_case.rb +1 -0
  34. data/lib/pinnacle/campaigns/dlc/types/list_dlc_campaigns_params.rb +4 -0
  35. data/lib/pinnacle/campaigns/dlc/types/upsert_dlc_campaign_params.rb +10 -0
  36. data/lib/pinnacle/campaigns/rcs/types/list_rcs_campaigns_params.rb +4 -0
  37. data/lib/pinnacle/campaigns/rcs/types/rcs_agent.rb +7 -0
  38. data/lib/pinnacle/campaigns/rcs/types/rcs_agent_email.rb +1 -0
  39. data/lib/pinnacle/campaigns/rcs/types/rcs_agent_phone.rb +1 -0
  40. data/lib/pinnacle/campaigns/rcs/types/rcs_agent_website.rb +1 -0
  41. data/lib/pinnacle/campaigns/rcs/types/rcs_campaign_help_keywords.rb +1 -0
  42. data/lib/pinnacle/campaigns/rcs/types/rcs_campaign_keywords.rb +2 -0
  43. data/lib/pinnacle/campaigns/rcs/types/rcs_campaign_opt_in_keywords.rb +1 -0
  44. data/lib/pinnacle/campaigns/rcs/types/rcs_campaign_opt_out_keywords.rb +1 -0
  45. data/lib/pinnacle/campaigns/rcs/types/rcs_campaign_traffic.rb +1 -0
  46. data/lib/pinnacle/campaigns/rcs/types/rcs_links.rb +1 -0
  47. data/lib/pinnacle/campaigns/rcs/types/upsert_rcs_campaign_params.rb +12 -0
  48. data/lib/pinnacle/campaigns/toll_free/types/list_toll_free_campaigns_params.rb +4 -0
  49. data/lib/pinnacle/campaigns/toll_free/types/toll_free_campaign_keywords.rb +1 -0
  50. data/lib/pinnacle/campaigns/toll_free/types/toll_free_campaign_links.rb +1 -0
  51. data/lib/pinnacle/campaigns/toll_free/types/toll_free_campaign_opt_in.rb +2 -0
  52. data/lib/pinnacle/campaigns/toll_free/types/toll_free_campaign_opt_in_keywords.rb +1 -0
  53. data/lib/pinnacle/campaigns/toll_free/types/toll_free_campaign_use_case.rb +1 -0
  54. data/lib/pinnacle/campaigns/toll_free/types/upsert_toll_free_campaign_params.rb +9 -0
  55. data/lib/pinnacle/client.rb +12 -2
  56. data/lib/pinnacle/contacts/client.rb +0 -2
  57. data/lib/pinnacle/contacts/types/contacts_get_request.rb +1 -0
  58. data/lib/pinnacle/contacts/types/create_contact_params.rb +4 -0
  59. data/lib/pinnacle/contacts/types/list_contacts_params.rb +5 -0
  60. data/lib/pinnacle/contacts/types/update_contact_params.rb +4 -0
  61. data/lib/pinnacle/conversations/client.rb +0 -2
  62. data/lib/pinnacle/conversations/types/conversations_list_messages_request.rb +8 -0
  63. data/lib/pinnacle/conversations/types/list_conversations_params.rb +6 -0
  64. data/lib/pinnacle/conversations/types/update_conversation_params.rb +1 -0
  65. data/lib/pinnacle/forms/client.rb +2 -2
  66. data/lib/pinnacle/forms/submissions/client.rb +1 -1
  67. data/lib/pinnacle/forms/submissions/types/list_form_submissions_params.rb +2 -0
  68. data/lib/pinnacle/forms/types/forms_send_response.rb +1 -0
  69. data/lib/pinnacle/forms/types/list_forms_params.rb +1 -0
  70. data/lib/pinnacle/forms/types/update_form_params.rb +7 -0
  71. data/lib/pinnacle/internal/http/raw_client.rb +3 -2
  72. data/lib/pinnacle/internal/iterators/cursor_page_iterator.rb +14 -2
  73. data/lib/pinnacle/internal/iterators/item_iterator.rb +6 -0
  74. data/lib/pinnacle/internal/iterators/offset_page_iterator.rb +22 -2
  75. data/lib/pinnacle/internal/types/utils.rb +2 -2
  76. data/lib/pinnacle/messages/blast/types/blast_mms.rb +3 -0
  77. data/lib/pinnacle/messages/blast/types/blast_mms_options.rb +1 -0
  78. data/lib/pinnacle/messages/blast/types/blast_mms_response.rb +1 -0
  79. data/lib/pinnacle/messages/blast/types/blast_rcs.rb +4 -0
  80. data/lib/pinnacle/messages/blast/types/blast_rcs_options.rb +3 -0
  81. data/lib/pinnacle/messages/blast/types/blast_rcs_request_options_standalone_card.rb +1 -0
  82. data/lib/pinnacle/messages/blast/types/blast_rcs_response.rb +1 -0
  83. data/lib/pinnacle/messages/blast/types/blast_sms.rb +3 -0
  84. data/lib/pinnacle/messages/blast/types/blast_sms_response.rb +1 -0
  85. data/lib/pinnacle/messages/blasts/types/list_blasts_params.rb +4 -0
  86. data/lib/pinnacle/messages/mms/types/mms.rb +4 -0
  87. data/lib/pinnacle/messages/mms/types/mms_send_response.rb +1 -0
  88. data/lib/pinnacle/messages/mms/types/send_mms_options.rb +3 -0
  89. data/lib/pinnacle/messages/rcs/types/send_rich_message_response.rb +3 -0
  90. data/lib/pinnacle/messages/rcs/types/send_typing_indicator_schema.rb +1 -0
  91. data/lib/pinnacle/messages/schedules/types/list_scheduled_messages_params.rb +4 -0
  92. data/lib/pinnacle/messages/sms/types/send_sms_options.rb +1 -0
  93. data/lib/pinnacle/messages/sms/types/sms.rb +3 -0
  94. data/lib/pinnacle/messages/sms/types/sms_send_response.rb +1 -0
  95. data/lib/pinnacle/messages/types/list_messages_params.rb +10 -0
  96. data/lib/pinnacle/messages/types/react_message_params.rb +2 -0
  97. data/lib/pinnacle/network/client.rb +34 -0
  98. data/lib/pinnacle/network/requests/client.rb +94 -0
  99. data/lib/pinnacle/network/requests/types/list_network_requests_params.rb +21 -0
  100. data/lib/pinnacle/network/silent_auth/client.rb +107 -0
  101. data/lib/pinnacle/network/silent_auth/types/silent_auth_check_request.rb +15 -0
  102. data/lib/pinnacle/network/silent_auth/types/silent_auth_request.rb +17 -0
  103. data/lib/pinnacle/network/sim_swap/client.rb +55 -0
  104. data/lib/pinnacle/network/sim_swap/types/sim_swap_request.rb +15 -0
  105. data/lib/pinnacle/network/subscriber_match/client.rb +55 -0
  106. data/lib/pinnacle/network/subscriber_match/types/subscriber_match_request.rb +15 -0
  107. data/lib/pinnacle/phone_numbers/campaign/types/attach_campaign_params.rb +2 -0
  108. data/lib/pinnacle/phone_numbers/types/list_phone_numbers_params.rb +1 -0
  109. data/lib/pinnacle/phone_numbers/types/phone_numbers_get_response.rb +1 -0
  110. data/lib/pinnacle/phone_numbers/types/retrieve_phone_number_details_options.rb +2 -0
  111. data/lib/pinnacle/phone_numbers/types/retrieve_phone_number_details_params.rb +2 -0
  112. data/lib/pinnacle/phone_numbers/types/search_phone_number_by_digits.rb +2 -0
  113. data/lib/pinnacle/phone_numbers/types/search_phone_number_by_location.rb +3 -0
  114. data/lib/pinnacle/phone_numbers/types/search_phone_number_params.rb +4 -0
  115. data/lib/pinnacle/pinnacle_client.rb +8 -0
  116. data/lib/pinnacle/rcs/agents/types/list_agents_params.rb +3 -0
  117. data/lib/pinnacle/rcs/test/client.rb +2 -4
  118. data/lib/pinnacle/rcs/test/types/create_test_agent_request.rb +11 -0
  119. data/lib/pinnacle/rcs/test/types/test_agent_whitelist_request.rb +1 -0
  120. data/lib/pinnacle/rcs/test/types/test_get_whitelist_status_request.rb +1 -0
  121. data/lib/pinnacle/rcs/test/types/update_test_agent_request.rb +12 -0
  122. data/lib/pinnacle/rcs/types/rcs_capabilities_query.rb +1 -0
  123. data/lib/pinnacle/rcs/types/rcs_link_request.rb +2 -0
  124. data/lib/pinnacle/rcs/whitelisted_numbers/types/list_test_numbers_params.rb +4 -0
  125. data/lib/pinnacle/tools/contact_card/types/get_vcard_params.rb +1 -0
  126. data/lib/pinnacle/tools/contact_card/types/upsert_vcard_params.rb +16 -0
  127. data/lib/pinnacle/tools/file/types/upload_file_options.rb +1 -0
  128. data/lib/pinnacle/tools/file/types/upload_file_params.rb +3 -0
  129. data/lib/pinnacle/tools/url/client.rb +1 -1
  130. data/lib/pinnacle/tools/url/types/create_url_params.rb +1 -0
  131. data/lib/pinnacle/tools/url/types/list_links_params.rb +2 -0
  132. data/lib/pinnacle/tools/url/types/update_url_params.rb +2 -0
  133. data/lib/pinnacle/types/address_field.rb +3 -0
  134. data/lib/pinnacle/types/advanced_phone_information.rb +5 -0
  135. data/lib/pinnacle/types/advanced_phone_information_carrier.rb +3 -0
  136. data/lib/pinnacle/types/advanced_phone_information_contact.rb +9 -0
  137. data/lib/pinnacle/types/advanced_phone_information_location.rb +7 -0
  138. data/lib/pinnacle/types/advanced_phone_information_location_coordinates.rb +1 -0
  139. data/lib/pinnacle/types/advanced_phone_information_location_country.rb +2 -0
  140. data/lib/pinnacle/types/advanced_phone_information_type.rb +3 -0
  141. data/lib/pinnacle/types/agent.rb +1 -0
  142. data/lib/pinnacle/types/agent_email_entry.rb +1 -0
  143. data/lib/pinnacle/types/agent_phone_entry.rb +1 -0
  144. data/lib/pinnacle/types/agent_summary.rb +6 -0
  145. data/lib/pinnacle/types/agent_summary_carrier_launches.rb +6 -1
  146. data/lib/pinnacle/types/agent_summary_config.rb +11 -0
  147. data/lib/pinnacle/types/agent_summary_config_emails_item.rb +1 -0
  148. data/lib/pinnacle/types/agent_summary_config_phones_item.rb +1 -0
  149. data/lib/pinnacle/types/agent_summary_config_websites_item.rb +1 -0
  150. data/lib/pinnacle/types/agent_website_entry.rb +1 -0
  151. data/lib/pinnacle/types/attach_webhook_response_webhook.rb +4 -0
  152. data/lib/pinnacle/types/attach_webhook_result.rb +3 -0
  153. data/lib/pinnacle/types/attached_phone_number_result.rb +1 -0
  154. data/lib/pinnacle/types/audience_count_only.rb +3 -0
  155. data/lib/pinnacle/types/audience_summary.rb +4 -0
  156. data/lib/pinnacle/types/audience_with_pagination.rb +5 -0
  157. data/lib/pinnacle/types/autofill_campaign_params.rb +1 -0
  158. data/lib/pinnacle/types/autofill_dlc_campaign_response.rb +10 -0
  159. data/lib/pinnacle/types/autofill_dlc_response_keywords.rb +2 -0
  160. data/lib/pinnacle/types/autofill_dlc_response_keywords_help.rb +1 -0
  161. data/lib/pinnacle/types/autofill_dlc_response_keywords_opt_in.rb +1 -0
  162. data/lib/pinnacle/types/autofill_dlc_response_keywords_opt_out.rb +1 -0
  163. data/lib/pinnacle/types/autofill_dlc_response_links.rb +1 -0
  164. data/lib/pinnacle/types/autofill_dlc_response_options.rb +5 -0
  165. data/lib/pinnacle/types/autofill_dlc_response_use_case.rb +1 -0
  166. data/lib/pinnacle/types/bad_request_error_body.rb +1 -0
  167. data/lib/pinnacle/types/base_rich_message.rb +3 -0
  168. data/lib/pinnacle/types/basic_phone_information.rb +5 -0
  169. data/lib/pinnacle/types/basic_phone_information_location.rb +1 -0
  170. data/lib/pinnacle/types/basic_phone_information_location_country.rb +2 -0
  171. data/lib/pinnacle/types/blast_details.rb +5 -0
  172. data/lib/pinnacle/types/blast_summary.rb +7 -0
  173. data/lib/pinnacle/types/brand_status.rb +2 -0
  174. data/lib/pinnacle/types/button_clicked.rb +1 -0
  175. data/lib/pinnacle/types/button_clicked_data.rb +1 -0
  176. data/lib/pinnacle/types/button_clicked_data_button.rb +4 -0
  177. data/lib/pinnacle/types/button_clicked_data_button_raw.rb +1 -0
  178. data/lib/pinnacle/types/buy_response_capabilities.rb +2 -0
  179. data/lib/pinnacle/types/call.rb +31 -0
  180. data/lib/pinnacle/types/call_direction.rb +12 -0
  181. data/lib/pinnacle/types/call_event.rb +27 -0
  182. data/lib/pinnacle/types/call_event_source.rb +14 -0
  183. data/lib/pinnacle/types/call_metadata.rb +23 -0
  184. data/lib/pinnacle/types/call_state.rb +19 -0
  185. data/lib/pinnacle/types/call_status_event.rb +14 -0
  186. data/lib/pinnacle/types/call_status_event_call.rb +17 -0
  187. data/lib/pinnacle/types/call_stream_token.rb +13 -0
  188. data/lib/pinnacle/types/campaign_query.rb +1 -0
  189. data/lib/pinnacle/types/campaign_status_event.rb +5 -0
  190. data/lib/pinnacle/types/campaign_status_event_agent.rb +1 -0
  191. data/lib/pinnacle/types/campaign_status_event_brand.rb +1 -0
  192. data/lib/pinnacle/types/campaign_status_event_campaign.rb +1 -0
  193. data/lib/pinnacle/types/campaign_status_event_carrier_launches.rb +1 -0
  194. data/lib/pinnacle/types/campaign_status_event_carrier_launches_carriers.rb +3 -0
  195. data/lib/pinnacle/types/campaign_status_event_carrier_launches_verification.rb +1 -0
  196. data/lib/pinnacle/types/campaign_validation_response_errors_item.rb +2 -0
  197. data/lib/pinnacle/types/campaign_validation_result.rb +1 -0
  198. data/lib/pinnacle/types/carrier_launches.rb +1 -0
  199. data/lib/pinnacle/types/carrier_launches_carriers.rb +3 -0
  200. data/lib/pinnacle/types/carrier_launches_verification.rb +1 -0
  201. data/lib/pinnacle/types/checkbox_field.rb +2 -0
  202. data/lib/pinnacle/types/contact.rb +5 -0
  203. data/lib/pinnacle/types/conversation.rb +7 -0
  204. data/lib/pinnacle/types/conversation_by_participants_params.rb +1 -0
  205. data/lib/pinnacle/types/conversation_contact.rb +1 -0
  206. data/lib/pinnacle/types/conversation_list.rb +2 -0
  207. data/lib/pinnacle/types/conversation_sender.rb +1 -0
  208. data/lib/pinnacle/types/created_call.rb +33 -0
  209. data/lib/pinnacle/types/date_field.rb +2 -0
  210. data/lib/pinnacle/types/datetime_field.rb +2 -0
  211. data/lib/pinnacle/types/detach_webhook_result.rb +2 -0
  212. data/lib/pinnacle/types/detached_phone_number_result.rb +1 -0
  213. data/lib/pinnacle/types/dlc_campaign_status.rb +3 -0
  214. data/lib/pinnacle/types/dlc_campaign_summary.rb +6 -0
  215. data/lib/pinnacle/types/dlc_campaign_with_extended_brand_and_status.rb +13 -0
  216. data/lib/pinnacle/types/dlc_with_extended_brand_and_status_keywords.rb +2 -0
  217. data/lib/pinnacle/types/dlc_with_extended_brand_and_status_keywords_help.rb +1 -0
  218. data/lib/pinnacle/types/dlc_with_extended_brand_and_status_keywords_opt_in.rb +1 -0
  219. data/lib/pinnacle/types/dlc_with_extended_brand_and_status_keywords_opt_out.rb +1 -0
  220. data/lib/pinnacle/types/dlc_with_extended_brand_and_status_links.rb +1 -0
  221. data/lib/pinnacle/types/dlc_with_extended_brand_and_status_options.rb +5 -0
  222. data/lib/pinnacle/types/dlc_with_extended_brand_and_status_use_case.rb +1 -0
  223. data/lib/pinnacle/types/e_164_phone_number.rb +23 -0
  224. data/lib/pinnacle/types/enhanced_contact_item.rb +4 -0
  225. data/lib/pinnacle/types/extended_brand.rb +4 -0
  226. data/lib/pinnacle/types/extended_brand_with_vetting.rb +2 -0
  227. data/lib/pinnacle/types/extended_rcs_campaign.rb +14 -0
  228. data/lib/pinnacle/types/failed_sender.rb +1 -0
  229. data/lib/pinnacle/types/fallback_message.rb +2 -0
  230. data/lib/pinnacle/types/field_base.rb +3 -0
  231. data/lib/pinnacle/types/form.rb +12 -0
  232. data/lib/pinnacle/types/form_background.rb +3 -0
  233. data/lib/pinnacle/types/form_background_gradient.rb +1 -0
  234. data/lib/pinnacle/types/form_background_image.rb +3 -0
  235. data/lib/pinnacle/types/form_color_palette.rb +2 -0
  236. data/lib/pinnacle/types/form_definition.rb +5 -0
  237. data/lib/pinnacle/types/form_field.rb +15 -0
  238. data/lib/pinnacle/types/form_field_option.rb +1 -0
  239. data/lib/pinnacle/types/form_gradient.rb +2 -0
  240. data/lib/pinnacle/types/form_submission.rb +9 -0
  241. data/lib/pinnacle/types/form_submission_answer.rb +3 -0
  242. data/lib/pinnacle/types/form_submission_event.rb +4 -0
  243. data/lib/pinnacle/types/form_submission_event_conversation.rb +2 -0
  244. data/lib/pinnacle/types/form_submission_event_form.rb +2 -0
  245. data/lib/pinnacle/types/form_submission_event_submission.rb +7 -0
  246. data/lib/pinnacle/types/form_submitted_field.rb +3 -0
  247. data/lib/pinnacle/types/form_theme_override.rb +14 -0
  248. data/lib/pinnacle/types/form_theme_override_colors.rb +1 -0
  249. data/lib/pinnacle/types/get_conversation_params.rb +1 -0
  250. data/lib/pinnacle/types/get_dlc_campaign_status_response_updates.rb +2 -0
  251. data/lib/pinnacle/types/get_toll_free_campaign_status_response_updates.rb +2 -0
  252. data/lib/pinnacle/types/hosted_silent_auth_response.rb +13 -0
  253. data/lib/pinnacle/types/json_silent_auth_response.rb +13 -0
  254. data/lib/pinnacle/types/link_click_event.rb +48 -0
  255. data/lib/pinnacle/types/link_summary.rb +3 -0
  256. data/lib/pinnacle/types/list_agents_response.rb +2 -0
  257. data/lib/pinnacle/types/list_audiences_response.rb +2 -0
  258. data/lib/pinnacle/types/list_blasts_response.rb +2 -0
  259. data/lib/pinnacle/types/list_brands_response.rb +2 -0
  260. data/lib/pinnacle/types/list_call_events_response.rb +11 -0
  261. data/lib/pinnacle/types/list_calls_response.rb +11 -0
  262. data/lib/pinnacle/types/list_contacts_response.rb +2 -0
  263. data/lib/pinnacle/types/list_dlc_campaigns_response.rb +2 -0
  264. data/lib/pinnacle/types/list_form_submissions_response.rb +2 -0
  265. data/lib/pinnacle/types/list_forms_response.rb +2 -0
  266. data/lib/pinnacle/types/list_links_response.rb +2 -0
  267. data/lib/pinnacle/types/list_messages_response.rb +2 -0
  268. data/lib/pinnacle/types/list_network_requests_response.rb +13 -0
  269. data/lib/pinnacle/types/list_phone_numbers_response.rb +2 -0
  270. data/lib/pinnacle/types/list_rcs_campaigns_response.rb +2 -0
  271. data/lib/pinnacle/types/list_scheduled_messages_response.rb +2 -0
  272. data/lib/pinnacle/types/list_test_numbers_response.rb +2 -0
  273. data/lib/pinnacle/types/list_toll_free_campaigns_response.rb +2 -0
  274. data/lib/pinnacle/types/list_webhooks_response.rb +2 -0
  275. data/lib/pinnacle/types/location_share_action_data.rb +3 -0
  276. data/lib/pinnacle/types/message.rb +11 -0
  277. data/lib/pinnacle/types/message_content.rb +3 -0
  278. data/lib/pinnacle/types/message_event.rb +9 -0
  279. data/lib/pinnacle/types/message_event_content.rb +6 -0
  280. data/lib/pinnacle/types/message_event_conversation.rb +2 -0
  281. data/lib/pinnacle/types/message_event_fallback_message.rb +5 -0
  282. data/lib/pinnacle/types/message_event_mms_content.rb +2 -0
  283. data/lib/pinnacle/types/message_event_rcs_button_data.rb +2 -0
  284. data/lib/pinnacle/types/message_event_rcs_button_data_button.rb +4 -0
  285. data/lib/pinnacle/types/message_event_rcs_button_data_button_raw.rb +1 -0
  286. data/lib/pinnacle/types/message_event_rcs_cards_content.rb +2 -0
  287. data/lib/pinnacle/types/message_event_rcs_cards_content_cards_item.rb +3 -0
  288. data/lib/pinnacle/types/message_event_rcs_location_data.rb +2 -0
  289. data/lib/pinnacle/types/message_event_rcs_location_data_data.rb +3 -0
  290. data/lib/pinnacle/types/message_event_rcs_media_content.rb +2 -0
  291. data/lib/pinnacle/types/message_event_rcs_text_content.rb +2 -0
  292. data/lib/pinnacle/types/message_event_sms_content.rb +1 -0
  293. data/lib/pinnacle/types/message_list.rb +2 -0
  294. data/lib/pinnacle/types/message_schedule.rb +3 -0
  295. data/lib/pinnacle/types/message_summary.rb +16 -0
  296. data/lib/pinnacle/types/message_with_reactions.rb +1 -0
  297. data/lib/pinnacle/types/mms_content.rb +1 -0
  298. data/lib/pinnacle/types/mms_validation_response_segments.rb +2 -0
  299. data/lib/pinnacle/types/mms_validation_response_segments_value_item.rb +2 -0
  300. data/lib/pinnacle/types/mms_validation_result.rb +2 -0
  301. data/lib/pinnacle/types/network_insight_status.rb +14 -0
  302. data/lib/pinnacle/types/network_request_id.rb +23 -0
  303. data/lib/pinnacle/types/network_request_result.rb +16 -0
  304. data/lib/pinnacle/types/network_request_status.rb +15 -0
  305. data/lib/pinnacle/types/network_request_summary.rb +27 -0
  306. data/lib/pinnacle/types/network_request_type.rb +13 -0
  307. data/lib/pinnacle/types/number_field.rb +3 -0
  308. data/lib/pinnacle/types/number_format.rb +2 -0
  309. data/lib/pinnacle/types/optional_brand_info.rb +10 -0
  310. data/lib/pinnacle/types/optional_contact.rb +3 -0
  311. data/lib/pinnacle/types/optional_contacts.rb +3 -0
  312. data/lib/pinnacle/types/owned_phone_number.rb +5 -0
  313. data/lib/pinnacle/types/pagination.rb +3 -0
  314. data/lib/pinnacle/types/phone.rb +4 -0
  315. data/lib/pinnacle/types/phone_capabilities.rb +2 -0
  316. data/lib/pinnacle/types/phone_number_campaign_attach_failed_item.rb +1 -0
  317. data/lib/pinnacle/types/phone_number_campaign_attach_phone_numbers_item.rb +1 -0
  318. data/lib/pinnacle/types/phone_number_campaign_attach_phone_numbers_item_campaign.rb +2 -0
  319. data/lib/pinnacle/types/phone_number_campaign_detach_failed_item.rb +1 -0
  320. data/lib/pinnacle/types/phone_number_campaign_detach_phone_numbers_item.rb +1 -0
  321. data/lib/pinnacle/types/phone_number_campaign_detach_phone_numbers_item_campaign.rb +2 -0
  322. data/lib/pinnacle/types/phone_number_cost.rb +2 -0
  323. data/lib/pinnacle/types/phone_number_details.rb +4 -0
  324. data/lib/pinnacle/types/phone_number_region.rb +3 -0
  325. data/lib/pinnacle/types/phone_number_status.rb +2 -0
  326. data/lib/pinnacle/types/pinnacle_file_upload_metadata.rb +3 -0
  327. data/lib/pinnacle/types/pinnacle_url_config.rb +1 -0
  328. data/lib/pinnacle/types/purchased_number.rb +1 -0
  329. data/lib/pinnacle/types/range_field.rb +2 -0
  330. data/lib/pinnacle/types/rating_field.rb +1 -0
  331. data/lib/pinnacle/types/rcs_agent_details.rb +11 -0
  332. data/lib/pinnacle/types/rcs_agent_details_emails_item.rb +1 -0
  333. data/lib/pinnacle/types/rcs_agent_details_phones_item.rb +1 -0
  334. data/lib/pinnacle/types/rcs_agent_details_websites_item.rb +1 -0
  335. data/lib/pinnacle/types/rcs_agent_response.rb +4 -0
  336. data/lib/pinnacle/types/rcs_button_call.rb +2 -0
  337. data/lib/pinnacle/types/rcs_button_open_url.rb +3 -0
  338. data/lib/pinnacle/types/rcs_button_request_user_location.rb +1 -0
  339. data/lib/pinnacle/types/rcs_button_schedule_event.rb +5 -0
  340. data/lib/pinnacle/types/rcs_button_send_location.rb +3 -0
  341. data/lib/pinnacle/types/rcs_button_send_location_lat_long.rb +1 -0
  342. data/lib/pinnacle/types/rcs_button_trigger.rb +2 -0
  343. data/lib/pinnacle/types/rcs_campaign.rb +11 -0
  344. data/lib/pinnacle/types/rcs_campaign_schema_agent.rb +7 -0
  345. data/lib/pinnacle/types/rcs_campaign_schema_agent_emails_item.rb +1 -0
  346. data/lib/pinnacle/types/rcs_campaign_schema_agent_phones_item.rb +1 -0
  347. data/lib/pinnacle/types/rcs_campaign_schema_agent_websites_item.rb +1 -0
  348. data/lib/pinnacle/types/rcs_campaign_schema_extra_agent.rb +7 -0
  349. data/lib/pinnacle/types/rcs_campaign_schema_extra_agent_emails_item.rb +1 -0
  350. data/lib/pinnacle/types/rcs_campaign_schema_extra_agent_phones_item.rb +1 -0
  351. data/lib/pinnacle/types/rcs_campaign_schema_extra_agent_websites_item.rb +1 -0
  352. data/lib/pinnacle/types/rcs_campaign_schema_extra_keywords.rb +2 -0
  353. data/lib/pinnacle/types/rcs_campaign_schema_extra_keywords_help.rb +1 -0
  354. data/lib/pinnacle/types/rcs_campaign_schema_extra_keywords_opt_in.rb +1 -0
  355. data/lib/pinnacle/types/rcs_campaign_schema_extra_keywords_opt_out.rb +1 -0
  356. data/lib/pinnacle/types/rcs_campaign_schema_extra_links.rb +1 -0
  357. data/lib/pinnacle/types/rcs_campaign_schema_extra_traffic.rb +1 -0
  358. data/lib/pinnacle/types/rcs_campaign_schema_keywords.rb +2 -0
  359. data/lib/pinnacle/types/rcs_campaign_schema_keywords_help.rb +1 -0
  360. data/lib/pinnacle/types/rcs_campaign_schema_keywords_opt_in.rb +1 -0
  361. data/lib/pinnacle/types/rcs_campaign_schema_keywords_opt_out.rb +1 -0
  362. data/lib/pinnacle/types/rcs_campaign_schema_links.rb +1 -0
  363. data/lib/pinnacle/types/rcs_campaign_schema_traffic.rb +1 -0
  364. data/lib/pinnacle/types/rcs_campaign_status.rb +2 -0
  365. data/lib/pinnacle/types/rcs_campaign_summary.rb +6 -0
  366. data/lib/pinnacle/types/rcs_capability.rb +1 -0
  367. data/lib/pinnacle/types/rcs_capability_actions.rb +5 -0
  368. data/lib/pinnacle/types/rcs_capability_cards.rb +1 -0
  369. data/lib/pinnacle/types/rcs_cards_content.rb +1 -0
  370. data/lib/pinnacle/types/rcs_cards_content_cards_item.rb +3 -0
  371. data/lib/pinnacle/types/rcs_content.rb +2 -0
  372. data/lib/pinnacle/types/rcs_link_result.rb +1 -0
  373. data/lib/pinnacle/types/rcs_media_content.rb +1 -0
  374. data/lib/pinnacle/types/rcs_media_details_content.rb +2 -0
  375. data/lib/pinnacle/types/rcs_validate_content.rb +2 -0
  376. data/lib/pinnacle/types/rcs_validate_content_media.rb +1 -0
  377. data/lib/pinnacle/types/rcs_validation_result.rb +3 -0
  378. data/lib/pinnacle/types/reaction_result.rb +1 -0
  379. data/lib/pinnacle/types/recording_download.rb +11 -0
  380. data/lib/pinnacle/types/recording_state.rb +14 -0
  381. data/lib/pinnacle/types/refreshed_file.rb +1 -0
  382. data/lib/pinnacle/types/rich_button.rb +5 -0
  383. data/lib/pinnacle/types/rich_card.rb +3 -0
  384. data/lib/pinnacle/types/rich_cards.rb +1 -0
  385. data/lib/pinnacle/types/rich_cards_message.rb +3 -0
  386. data/lib/pinnacle/types/rich_media_message.rb +1 -0
  387. data/lib/pinnacle/types/rich_message.rb +2 -0
  388. data/lib/pinnacle/types/rich_standalone_card_options.rb +1 -0
  389. data/lib/pinnacle/types/rich_text.rb +1 -0
  390. data/lib/pinnacle/types/scheduled_blast_details.rb +1 -0
  391. data/lib/pinnacle/types/scheduled_blast_response_config.rb +3 -0
  392. data/lib/pinnacle/types/scheduled_form_send_response_form.rb +1 -0
  393. data/lib/pinnacle/types/scheduled_form_send_response_submission.rb +1 -0
  394. data/lib/pinnacle/types/scheduled_form_send_result.rb +3 -0
  395. data/lib/pinnacle/types/scheduled_message.rb +1 -0
  396. data/lib/pinnacle/types/scheduled_message_summary.rb +8 -0
  397. data/lib/pinnacle/types/scheduled_send_response_config.rb +3 -0
  398. data/lib/pinnacle/types/select_field.rb +1 -0
  399. data/lib/pinnacle/types/send_form_options.rb +1 -0
  400. data/lib/pinnacle/types/send_form_params.rb +1 -0
  401. data/lib/pinnacle/types/send_form_result.rb +2 -0
  402. data/lib/pinnacle/types/send_form_via_rcs_params.rb +4 -0
  403. data/lib/pinnacle/types/send_form_via_rcs_request_form.rb +1 -0
  404. data/lib/pinnacle/types/send_form_via_sms_params.rb +3 -0
  405. data/lib/pinnacle/types/send_form_via_sms_request_form.rb +1 -0
  406. data/lib/pinnacle/types/send_rich_cards_options.rb +4 -0
  407. data/lib/pinnacle/types/send_rich_message_options.rb +3 -0
  408. data/lib/pinnacle/types/send_rich_message_options_4.rb +3 -0
  409. data/lib/pinnacle/types/send_sms_response_segments.rb +1 -0
  410. data/lib/pinnacle/types/send_typing_indicator_response.rb +4 -0
  411. data/lib/pinnacle/types/sent_mms_details.rb +5 -0
  412. data/lib/pinnacle/types/sent_rich_message.rb +5 -0
  413. data/lib/pinnacle/types/sent_rich_message_fallback_mms.rb +1 -0
  414. data/lib/pinnacle/types/sent_rich_message_fallback_sms.rb +1 -0
  415. data/lib/pinnacle/types/sent_sms_details.rb +5 -0
  416. data/lib/pinnacle/types/shortened_url.rb +1 -0
  417. data/lib/pinnacle/types/silent_auth_check_response.rb +11 -0
  418. data/lib/pinnacle/types/silent_auth_check_response_status.rb +12 -0
  419. data/lib/pinnacle/types/silent_auth_response.rb +15 -0
  420. data/lib/pinnacle/types/sim_swap_response.rb +15 -0
  421. data/lib/pinnacle/types/simulate_message_input.rb +1 -0
  422. data/lib/pinnacle/types/simulate_user_button.rb +2 -0
  423. data/lib/pinnacle/types/simulate_user_message.rb +2 -0
  424. data/lib/pinnacle/types/simulate_user_params.rb +1 -0
  425. data/lib/pinnacle/types/sms_validation_response_segments.rb +1 -0
  426. data/lib/pinnacle/types/sms_validation_response_segments_gsm_7.rb +2 -0
  427. data/lib/pinnacle/types/sms_validation_response_segments_utf_16.rb +1 -0
  428. data/lib/pinnacle/types/sms_validation_response_total.rb +1 -0
  429. data/lib/pinnacle/types/sms_validation_result.rb +3 -0
  430. data/lib/pinnacle/types/subscriber_match_attributes.rb +30 -0
  431. data/lib/pinnacle/types/subscriber_match_response.rb +13 -0
  432. data/lib/pinnacle/types/subscriber_match_response_matches.rb +41 -0
  433. data/lib/pinnacle/types/subscriber_match_result.rb +18 -0
  434. data/lib/pinnacle/types/test_agent_response.rb +3 -0
  435. data/lib/pinnacle/types/text_field.rb +3 -0
  436. data/lib/pinnacle/types/textarea_field.rb +3 -0
  437. data/lib/pinnacle/types/time_field.rb +2 -0
  438. data/lib/pinnacle/types/toll_free_campaign.rb +8 -0
  439. data/lib/pinnacle/types/toll_free_campaign_schema_keywords.rb +1 -0
  440. data/lib/pinnacle/types/toll_free_campaign_schema_keywords_opt_in.rb +1 -0
  441. data/lib/pinnacle/types/toll_free_campaign_schema_links.rb +1 -0
  442. data/lib/pinnacle/types/toll_free_campaign_schema_opt_in.rb +2 -0
  443. data/lib/pinnacle/types/toll_free_campaign_schema_use_case.rb +1 -0
  444. data/lib/pinnacle/types/toll_free_campaign_status.rb +2 -0
  445. data/lib/pinnacle/types/toll_free_campaign_summary.rb +6 -0
  446. data/lib/pinnacle/types/toll_free_campaign_with_extended_brand_and_status.rb +10 -0
  447. data/lib/pinnacle/types/toll_free_with_extended_brand_and_status_keywords.rb +1 -0
  448. data/lib/pinnacle/types/toll_free_with_extended_brand_and_status_keywords_opt_in.rb +1 -0
  449. data/lib/pinnacle/types/toll_free_with_extended_brand_and_status_links.rb +1 -0
  450. data/lib/pinnacle/types/toll_free_with_extended_brand_and_status_opt_in.rb +2 -0
  451. data/lib/pinnacle/types/toll_free_with_extended_brand_and_status_use_case.rb +1 -0
  452. data/lib/pinnacle/types/upload_results.rb +2 -0
  453. data/lib/pinnacle/types/user_button_press.rb +5 -0
  454. data/lib/pinnacle/types/user_button_press_call.rb +2 -0
  455. data/lib/pinnacle/types/user_button_press_open_url.rb +2 -0
  456. data/lib/pinnacle/types/user_button_press_request_user_location.rb +2 -0
  457. data/lib/pinnacle/types/user_button_press_request_user_location_location.rb +3 -0
  458. data/lib/pinnacle/types/user_button_press_schedule_event.rb +5 -0
  459. data/lib/pinnacle/types/user_button_press_send_location.rb +3 -0
  460. data/lib/pinnacle/types/user_button_press_send_location_lat_long.rb +1 -0
  461. data/lib/pinnacle/types/user_button_press_trigger.rb +2 -0
  462. data/lib/pinnacle/types/user_event.rb +2 -0
  463. data/lib/pinnacle/types/user_event_conversation.rb +2 -0
  464. data/lib/pinnacle/types/v_card_data_file.rb +1 -0
  465. data/lib/pinnacle/types/v_card_geo.rb +1 -0
  466. data/lib/pinnacle/types/v_card_name.rb +4 -0
  467. data/lib/pinnacle/types/v_card_organization.rb +1 -0
  468. data/lib/pinnacle/types/validate_campaign_params.rb +1 -0
  469. data/lib/pinnacle/types/validation_error_details.rb +2 -0
  470. data/lib/pinnacle/types/validation_results.rb +1 -0
  471. data/lib/pinnacle/types/vcard.rb +15 -0
  472. data/lib/pinnacle/types/vcard_address.rb +8 -0
  473. data/lib/pinnacle/types/vcard_email.rb +1 -0
  474. data/lib/pinnacle/types/vcard_phone.rb +1 -0
  475. data/lib/pinnacle/types/vcard_resource.rb +1 -0
  476. data/lib/pinnacle/types/vetting_feedback.rb +3 -0
  477. data/lib/pinnacle/types/vetting_history.rb +4 -0
  478. data/lib/pinnacle/types/webhook_event_enum.rb +1 -0
  479. data/lib/pinnacle/types/webhook_summary.rb +6 -0
  480. data/lib/pinnacle/types/webhooks.rb +3 -0
  481. data/lib/pinnacle/types/whitelisted_number_summary.rb +3 -0
  482. data/lib/pinnacle/types/zod_error.rb +1 -0
  483. data/lib/pinnacle/version.rb +1 -1
  484. data/lib/pinnacle/webhooks/types/attach_webhook_params.rb +5 -0
  485. data/lib/pinnacle/webhooks/types/detach_webhook_params.rb +1 -0
  486. data/lib/pinnacle/webhooks/types/list_webhooks_params.rb +3 -0
  487. data/lib/pinnacle/wrapper/messages/client.rb +4 -1
  488. data/lib/pinnacle/wrapper/voice/client.rb +125 -0
  489. data/lib/pinnacle/wrapper/voice/types.rb +38 -0
  490. data/lib/pinnacle/wrapper/voice/voice_socket.rb +354 -0
  491. data/lib/pinnacle.rb +54 -0
  492. data/lib/rcs.rb +1 -637
  493. data/reference.md +2011 -804
  494. metadata +76 -3
@@ -4,6 +4,7 @@ module Pinnacle
4
4
  module Types
5
5
  class ZodError < Internal::Types::Model
6
6
  field :description, -> { String }, optional: false, nullable: false
7
+
7
8
  field :errors, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
8
9
  end
9
10
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pinnacle
4
- VERSION = "2.0.18"
4
+ VERSION = "2.0.20.pre.rc.1"
5
5
  end
@@ -5,10 +5,15 @@ module Pinnacle
5
5
  module Types
6
6
  class AttachWebhookParams < Internal::Types::Model
7
7
  field :senders, -> { Internal::Types::Array[String] }, optional: false, nullable: false
8
+
8
9
  field :webhook_id, -> { String }, optional: true, nullable: false, api_name: "webhookId"
10
+
9
11
  field :name, -> { String }, optional: true, nullable: false
12
+
10
13
  field :url, -> { String }, optional: true, nullable: false
14
+
11
15
  field :event, -> { Pinnacle::Types::WebhookEventEnum }, optional: true, nullable: false
16
+
12
17
  field :headers, -> { Internal::Types::Hash[String, String] }, optional: true, nullable: false
13
18
  end
14
19
  end
@@ -5,6 +5,7 @@ module Pinnacle
5
5
  module Types
6
6
  class DetachWebhookParams < Internal::Types::Model
7
7
  field :webhook_id, -> { String }, optional: false, nullable: false, api_name: "webhookId"
8
+
8
9
  field :senders, -> { Internal::Types::Array[String] }, optional: false, nullable: false
9
10
  end
10
11
  end
@@ -5,8 +5,11 @@ module Pinnacle
5
5
  module Types
6
6
  class ListWebhooksParams < Internal::Types::Model
7
7
  field :page_index, -> { Integer }, optional: true, nullable: false, api_name: "pageIndex"
8
+
8
9
  field :page_size, -> { Integer }, optional: true, nullable: false, api_name: "pageSize"
10
+
9
11
  field :status, -> { Pinnacle::Webhooks::Types::ListWebhooksRequestStatus }, optional: true, nullable: false
12
+
10
13
  field :endpoint, -> { String }, optional: true, nullable: false
11
14
  end
12
15
  end
@@ -5,6 +5,7 @@ require_relative "../../types/message_event"
5
5
  require_relative "../../types/user_event"
6
6
  require_relative "../../types/form_submission_event"
7
7
  require_relative "../../types/campaign_status_event"
8
+ require_relative "../../types/call_status_event"
8
9
 
9
10
  module Pinnacle
10
11
  module Wrapper
@@ -23,7 +24,7 @@ module Pinnacle
23
24
  # @param request [Hash] Request with :headers and :body keys
24
25
  # @param secret [String, nil] Webhook secret (falls back to PINNACLE_SIGNING_SECRET env var)
25
26
  #
26
- # @return [Pinnacle::Types::MessageEvent, Pinnacle::Types::UserEvent, Pinnacle::Types::FormSubmissionEvent, Pinnacle::Types::CampaignStatusEvent]
27
+ # @return [Pinnacle::Types::MessageEvent, Pinnacle::Types::UserEvent, Pinnacle::Types::FormSubmissionEvent, Pinnacle::Types::CampaignStatusEvent, Pinnacle::Types::CallStatusEvent]
27
28
  # @raise [Pinnacle::Errors::UnauthorizedError] If webhook signature is invalid or missing
28
29
  # @raise [Pinnacle::Errors::ClientError] If request body cannot be parsed
29
30
  def process(request, secret: nil)
@@ -66,6 +67,8 @@ module Pinnacle
66
67
  Pinnacle::Types::FormSubmissionEvent.coerce(parsed)
67
68
  when "CAMPAIGN.STATUS"
68
69
  Pinnacle::Types::CampaignStatusEvent.coerce(parsed)
70
+ when "CALL.STATUS"
71
+ Pinnacle::Types::CallStatusEvent.coerce(parsed)
69
72
  else
70
73
  Pinnacle::Types::MessageEvent.coerce(parsed)
71
74
  end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../calls/client"
4
+ require_relative "voice_socket"
5
+
6
+ module Pinnacle
7
+ module Wrapper
8
+ module Voice
9
+ class Client
10
+ DEFAULT_RECONNECT = { enabled: true }.freeze
11
+
12
+ class DefaultSocket
13
+ attr_reader :ready_state
14
+
15
+ def initialize(url, protocols = nil)
16
+ @ready_state = 0
17
+ @listeners = Hash.new { |hash, key| hash[key] = [] }
18
+ headers = if protocols.nil?
19
+ {}
20
+ else
21
+ { "Sec-WebSocket-Protocol" => Array(protocols).join(", ") }
22
+ end
23
+ @socket = WebSocket::Client::Simple.connect(url, headers: headers)
24
+ @socket.on(:open) do |event|
25
+ @ready_state = 1
26
+ emit("open", event)
27
+ end
28
+ @socket.on(:message) { |message| emit("message", { data: message.data }) }
29
+ @socket.on(:error) { |error| emit("error", error) }
30
+ @socket.on(:close) do |event|
31
+ @ready_state = 3
32
+ emit("close", event)
33
+ end
34
+ end
35
+
36
+ def add_event_listener(event, &listener)
37
+ @listeners[event.to_s] << listener
38
+ end
39
+
40
+ def send(data)
41
+ @socket.send(data)
42
+ end
43
+
44
+ def close(*)
45
+ @socket.close
46
+ end
47
+
48
+ private
49
+
50
+ def emit(event, payload)
51
+ @listeners[event].each { |listener| listener.call(payload) }
52
+ end
53
+ end
54
+
55
+ def initialize(client:)
56
+ @calls = Pinnacle::Calls::Client.new(client: client)
57
+ end
58
+
59
+ def create_and_connect(
60
+ to:,
61
+ from:,
62
+ record: nil,
63
+ metadata: nil,
64
+ token: nil,
65
+ protocols: nil,
66
+ reconnect: nil,
67
+ socket: nil,
68
+ request_options: {}
69
+ )
70
+ call_params = { to: to, from: from }
71
+ call_params[:record] = record unless record.nil?
72
+ call_params[:metadata] = metadata unless metadata.nil?
73
+ call = @calls.create(**call_params, request_options: request_options)
74
+ connection = connect(
75
+ call_id: call.id,
76
+ token: token,
77
+ protocols: protocols,
78
+ reconnect: DEFAULT_RECONNECT.merge(reconnect || {}),
79
+ socket: socket
80
+ )
81
+ connection.call = call
82
+ connection.call_id = call.id
83
+ connection
84
+ end
85
+
86
+ def connect(call_id:, token: nil, protocols: nil, reconnect: nil, socket: nil)
87
+ socket_class = socket || default_socket
88
+ token_params = token || {}
89
+ stream_token = @calls.create_stream_token(**token_params, id: call_id)
90
+ create_socket = -> do
91
+ next_token = @calls.create_stream_token(**token_params, id: call_id)
92
+ new_socket(socket_class, next_token.stream_url, protocols)
93
+ end
94
+
95
+ VoiceSocket.new(
96
+ new_socket(socket_class, stream_token.stream_url, protocols),
97
+ create_socket: create_socket,
98
+ reconnect: DEFAULT_RECONNECT.merge(reconnect || {})
99
+ )
100
+ end
101
+
102
+ def connect_stream(stream_url, protocols: nil, reconnect: nil, socket: nil)
103
+ socket_class = socket || default_socket
104
+ create_socket = -> { new_socket(socket_class, stream_url, protocols) }
105
+ VoiceSocket.new(create_socket.call, create_socket: create_socket, reconnect: reconnect)
106
+ end
107
+
108
+ private
109
+
110
+ def default_socket
111
+ require "websocket-client-simple" unless defined?(::WebSocket::Client::Simple)
112
+ DefaultSocket
113
+ rescue LoadError => e
114
+ raise e, "The rcs gem could not load its websocket-client-simple dependency. Reinstall rcs or pass socket: to client.voice.connect."
115
+ end
116
+
117
+ def new_socket(socket_class, stream_url, protocols)
118
+ return socket_class.new(stream_url) if protocols.nil?
119
+
120
+ socket_class.new(stream_url, protocols)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pinnacle
4
+ module Wrapper
5
+ module Voice
6
+ module Types
7
+ VOICE_COMMAND_ACTIONS = [
8
+ CALL_ANSWER = "call.answer",
9
+ CALL_END = "call.end",
10
+ CALL_TRANSFER = "call.transfer",
11
+ RECORDING_START = "recording.start",
12
+ RECORDING_STOP = "recording.stop",
13
+ AUDIO_PLAY = "audio.play",
14
+ AUDIO_STOP = "audio.stop",
15
+ AUDIO_REDUCE_NOISE = "audio.reduce_noise",
16
+ INPUT_GET = "input.get",
17
+ INPUT_CANCEL = "input.cancel",
18
+ DTMF_SEND = "dtmf.send",
19
+ CALL_UPDATE_STATE = "call.update_state"
20
+ ].freeze
21
+
22
+ USER_BUSY = "user_busy"
23
+ CALL_REJECTED = "call_rejected"
24
+
25
+ NOISE_DEFAULT = "default"
26
+ NOISE_KRISP = "krisp"
27
+ NOISE_AICOUSTICS = "aicoustics"
28
+
29
+ DIRECTION_INBOUND = "inbound"
30
+ DIRECTION_OUTBOUND = "outbound"
31
+ DIRECTION_BOTH = "both"
32
+
33
+ TRACK_INBOUND = "inbound"
34
+ TRACK_OUTBOUND = "outbound"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,354 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "securerandom"
5
+ require "timeout"
6
+
7
+ require_relative "types"
8
+
9
+ module Pinnacle
10
+ module Wrapper
11
+ module Voice
12
+ class VoiceSocket
13
+ attr_accessor :call, :call_id
14
+ attr_reader :socket
15
+
16
+ def initialize(socket, create_socket: nil, reconnect: nil)
17
+ @socket = socket
18
+ @create_socket = create_socket
19
+ @reconnect = normalize_reconnect_options(reconnect || {})
20
+ @listeners = Hash.new { |hash, key| hash[key] = [] }
21
+ @pending_acks = {}
22
+ @closed_by_user = false
23
+ @reconnect_attempts = 0
24
+ @reconnect_thread = nil
25
+ bind_socket
26
+ end
27
+
28
+ def ready_state
29
+ if @socket.respond_to?(:ready_state)
30
+ @socket.ready_state
31
+ elsif @socket.respond_to?(:readyState)
32
+ @socket.readyState
33
+ else
34
+ 0
35
+ end
36
+ end
37
+
38
+ def open?
39
+ ready_state == 1
40
+ end
41
+
42
+ def wait_until_open(timeout_ms: 10_000)
43
+ return if open?
44
+
45
+ mutex = Mutex.new
46
+ condition = ConditionVariable.new
47
+ error = nil
48
+ done = false
49
+ unsubscribers = []
50
+
51
+ cleanup = -> do
52
+ unsubscribers.each(&:call)
53
+ end
54
+ finish = ->(next_error) do
55
+ mutex.synchronize do
56
+ error = next_error
57
+ done = true
58
+ condition.signal
59
+ end
60
+ end
61
+
62
+ unsubscribers << on("open") do
63
+ cleanup.call
64
+ finish.call(nil)
65
+ end
66
+ unsubscribers << on("close") do
67
+ cleanup.call
68
+ finish.call(RuntimeError.new("Voice socket closed before opening."))
69
+ end
70
+ unsubscribers << on("error") do |event|
71
+ cleanup.call
72
+ finish.call(to_error(event))
73
+ end
74
+
75
+ mutex.synchronize do
76
+ condition.wait(mutex, timeout_ms / 1000.0) unless done
77
+ end
78
+ cleanup.call unless done
79
+ raise Timeout::Error, "Timed out waiting for voice socket to open." unless done
80
+ raise error unless error.nil?
81
+ end
82
+
83
+ def connect
84
+ wait_until_open
85
+ end
86
+
87
+ def on(event, &listener)
88
+ @listeners[event] << listener
89
+ -> { @listeners[event].delete(listener) }
90
+ end
91
+
92
+ def send(frame)
93
+ @socket.send(JSON.generate(frame))
94
+ end
95
+
96
+ def command(frame)
97
+ send(frame)
98
+ frame.fetch(:command_id)
99
+ end
100
+
101
+ def command_and_wait(frame, timeout_ms: 10_000)
102
+ waiter = wait_for_ack(frame.fetch(:command_id), timeout_ms: timeout_ms)
103
+ command(frame)
104
+ waiter.call
105
+ end
106
+
107
+ def answer(params = nil, command_id: create_voice_command_id)
108
+ command(with_optional_params(command_frame(command_id, Types::CALL_ANSWER), params))
109
+ end
110
+
111
+ def end_call(params = nil, command_id: create_voice_command_id)
112
+ command(with_optional_params(command_frame(command_id, Types::CALL_END), params))
113
+ end
114
+
115
+ def transfer(params, command_id: create_voice_command_id)
116
+ command(command_frame(command_id, Types::CALL_TRANSFER, params))
117
+ end
118
+
119
+ def start_recording(command_id: create_voice_command_id)
120
+ command(command_frame(command_id, Types::RECORDING_START))
121
+ end
122
+
123
+ def stop_recording(command_id: create_voice_command_id)
124
+ command(command_frame(command_id, Types::RECORDING_STOP))
125
+ end
126
+
127
+ def play_audio(params, command_id: create_voice_command_id)
128
+ command(command_frame(command_id, Types::AUDIO_PLAY, params))
129
+ end
130
+
131
+ def stop_audio(command_id: create_voice_command_id)
132
+ command(command_frame(command_id, Types::AUDIO_STOP))
133
+ end
134
+
135
+ def reduce_noise(params, command_id: create_voice_command_id)
136
+ command(command_frame(command_id, Types::AUDIO_REDUCE_NOISE, params))
137
+ end
138
+
139
+ def get_input(params = nil, command_id: create_voice_command_id)
140
+ command(with_optional_params(command_frame(command_id, Types::INPUT_GET), params))
141
+ end
142
+
143
+ def cancel_input(command_id: create_voice_command_id)
144
+ command(command_frame(command_id, Types::INPUT_CANCEL))
145
+ end
146
+
147
+ def send_dtmf(params, command_id: create_voice_command_id)
148
+ command(command_frame(command_id, Types::DTMF_SEND, params))
149
+ end
150
+
151
+ def update_state(params, command_id: create_voice_command_id)
152
+ command(command_frame(command_id, Types::CALL_UPDATE_STATE, params))
153
+ end
154
+
155
+ def send_media(media)
156
+ send({ event: "media", media: media })
157
+ end
158
+
159
+ def wait_for_ack(command_id, timeout_ms: 10_000)
160
+ raise "Already waiting for ack #{command_id}." if @pending_acks.key?(command_id)
161
+
162
+ mutex = Mutex.new
163
+ condition = ConditionVariable.new
164
+ result = nil
165
+ error = nil
166
+ done = false
167
+ @pending_acks[command_id] = ->(ack, next_error) do
168
+ mutex.synchronize do
169
+ result = ack
170
+ error = next_error
171
+ done = true
172
+ condition.signal
173
+ end
174
+ end
175
+
176
+ -> do
177
+ mutex.synchronize do
178
+ condition.wait(mutex, timeout_ms / 1000.0) unless done
179
+ end
180
+ @pending_acks.delete(command_id)
181
+ raise Timeout::Error, "Timed out waiting for ack #{command_id}." unless done
182
+ raise error unless error.nil?
183
+
184
+ result
185
+ end
186
+ end
187
+
188
+ def close(code = nil, reason = nil)
189
+ @closed_by_user = true
190
+ @reconnect_thread&.kill
191
+ close_socket(@socket, code, reason)
192
+ end
193
+
194
+ def reconnect_now
195
+ raise "Voice socket was not configured with a reconnect factory." if @create_socket.nil?
196
+
197
+ @closed_by_user = false
198
+ @socket = @create_socket.call
199
+ bind_socket
200
+ @reconnect_attempts = 0
201
+ emit("reconnected", @socket)
202
+ self
203
+ end
204
+
205
+ def handle_message(data)
206
+ frame = parse_voice_frame(data)
207
+ emit("frame", frame)
208
+ case frame["event"]
209
+ when "ack"
210
+ resolve_pending_ack(frame)
211
+ emit("ack", frame)
212
+ when "event"
213
+ emit("event", frame)
214
+ when "media"
215
+ emit("media", frame)
216
+ when "connected"
217
+ nil
218
+ else
219
+ raise "Voice socket received an unknown frame event."
220
+ end
221
+ rescue StandardError => e
222
+ emit("error", e)
223
+ end
224
+
225
+ private
226
+
227
+ def bind_socket
228
+ bind_socket_event(@socket, "open") { |event| emit("open", event) }
229
+ bind_socket_event(@socket, "close") { |event| handle_close(event) }
230
+ bind_socket_event(@socket, "error") { |event| emit("error", event) }
231
+ bind_socket_event(@socket, "message") { |event| handle_message(message_data(event)) }
232
+ end
233
+
234
+ def handle_close(event)
235
+ reject_pending_acks(RuntimeError.new("Voice socket closed before an ack was received."))
236
+ emit("close", event)
237
+ schedule_reconnect
238
+ end
239
+
240
+ def resolve_pending_ack(ack)
241
+ resolver = @pending_acks.delete(ack["command_id"])
242
+ resolver&.call(ack, nil)
243
+ end
244
+
245
+ def reject_pending_acks(error)
246
+ @pending_acks.each_value { |resolver| resolver.call(nil, error) }
247
+ @pending_acks.clear
248
+ end
249
+
250
+ def emit(event, payload)
251
+ @listeners[event].each { |listener| listener.call(payload) }
252
+ end
253
+
254
+ def schedule_reconnect
255
+ return if @closed_by_user || !@reconnect[:enabled] || @create_socket.nil? || @reconnect_thread&.alive?
256
+
257
+ if @reconnect_attempts >= @reconnect[:max_attempts]
258
+ emit("error", RuntimeError.new("Voice socket reconnect attempts exhausted."))
259
+ return
260
+ end
261
+
262
+ @reconnect_attempts += 1
263
+ delay_ms = reconnect_delay(@reconnect, @reconnect_attempts)
264
+ emit("reconnecting", { attempt: @reconnect_attempts, delay_ms: delay_ms })
265
+ @reconnect_thread = Thread.new do
266
+ sleep(delay_ms / 1000.0)
267
+ reconnect_now
268
+ rescue StandardError => e
269
+ emit("error", e)
270
+ schedule_reconnect
271
+ end
272
+ end
273
+
274
+ def command_frame(command_id, action, params = nil)
275
+ frame = { event: "command", command_id: command_id, action: action }
276
+ frame[:params] = params unless params.nil?
277
+ frame
278
+ end
279
+
280
+ def with_optional_params(frame, params)
281
+ frame[:params] = params unless params.nil?
282
+ frame
283
+ end
284
+
285
+ def parse_voice_frame(data)
286
+ raise "Voice socket received a non-string frame." unless data.is_a?(String)
287
+
288
+ JSON.parse(data)
289
+ end
290
+
291
+ def bind_socket_event(socket, event, &listener)
292
+ if socket.respond_to?(:add_event_listener)
293
+ socket.add_event_listener(event, &listener)
294
+ elsif socket.respond_to?(:addEventListener)
295
+ socket.addEventListener(event, listener)
296
+ elsif socket.respond_to?(:on)
297
+ socket.on(event, &listener)
298
+ else
299
+ socket.public_send(:"on#{event}=", listener)
300
+ end
301
+ end
302
+
303
+ def message_data(event)
304
+ event.is_a?(Hash) ? event[:data] || event["data"] : event.data
305
+ end
306
+
307
+ def close_socket(socket, code, reason)
308
+ if code.nil? && reason.nil?
309
+ socket.close
310
+ elsif reason.nil?
311
+ socket.close(code)
312
+ else
313
+ socket.close(code, reason)
314
+ end
315
+ end
316
+
317
+ def normalize_reconnect_options(options)
318
+ {
319
+ enabled: options.fetch(:enabled, options.fetch("enabled", false)),
320
+ max_attempts: options.fetch(:max_attempts, options.fetch(:maxAttempts, options.fetch("maxAttempts", 5))),
321
+ initial_delay_ms: options.fetch(
322
+ :initial_delay_ms,
323
+ options.fetch(:initialDelayMs, options.fetch("initialDelayMs", 250))
324
+ ),
325
+ max_delay_ms: options.fetch(:max_delay_ms, options.fetch(:maxDelayMs, options.fetch("maxDelayMs", 5_000))),
326
+ backoff_multiplier: options.fetch(
327
+ :backoff_multiplier,
328
+ options.fetch(:backoffMultiplier, options.fetch("backoffMultiplier", 2))
329
+ )
330
+ }
331
+ end
332
+
333
+ def reconnect_delay(options, attempt)
334
+ delay = options[:initial_delay_ms] * (options[:backoff_multiplier]**[attempt - 1, 0].max)
335
+ [delay, options[:max_delay_ms]].min
336
+ end
337
+
338
+ def create_voice_command_id
339
+ self.class.create_voice_command_id
340
+ end
341
+
342
+ def to_error(error)
343
+ error.is_a?(Exception) ? error : RuntimeError.new("Voice socket error.")
344
+ end
345
+
346
+ class << self
347
+ def create_voice_command_id
348
+ "cmd_#{SecureRandom.uuid}"
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end