e2a 4.0.0__tar.gz → 5.2.0__tar.gz

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 (219) hide show
  1. {e2a-4.0.0 → e2a-5.2.0}/.gitignore +3 -0
  2. e2a-5.2.0/CHANGELOG.md +381 -0
  3. e2a-5.2.0/PKG-INFO +448 -0
  4. e2a-5.2.0/README.md +410 -0
  5. {e2a-4.0.0 → e2a-5.2.0}/pyproject.toml +22 -4
  6. e2a-5.2.0/scripts/generate-oag.sh +84 -0
  7. e2a-5.2.0/src/e2a/__init__.py +123 -0
  8. e2a-5.2.0/src/e2a/v1/__init__.py +157 -0
  9. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/_retry.py +34 -16
  10. e2a-5.2.0/src/e2a/v1/client.py +924 -0
  11. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/errors.py +141 -17
  12. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/__init__.py +131 -15
  13. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/__init__.py +1 -0
  14. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/account_api.py +133 -39
  15. e2a-5.2.0/src/e2a/v1/generated/api/agents_api.py +3430 -0
  16. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/conversations_api.py +1 -1
  17. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/domains_api.py +60 -19
  18. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/events_api.py +37 -37
  19. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/messages_api.py +320 -244
  20. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/meta_api.py +1 -1
  21. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/reviews_api.py +86 -34
  22. e2a-4.0.0/src/e2a/v1/generated/api/agents_api.py → e2a-5.2.0/src/e2a/v1/generated/api/templates_api.py +359 -321
  23. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api/webhooks_api.py +126 -18
  24. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api_client.py +1 -1
  25. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/configuration.py +1 -1
  26. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/exceptions.py +1 -1
  27. e2a-5.2.0/src/e2a/v1/generated/models/__init__.py +153 -0
  28. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/account_user_view.py +14 -1
  29. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/account_view.py +19 -6
  30. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/agent_identity.py +28 -11
  31. e2a-5.2.0/src/e2a/v1/generated/models/agent_suppression_added_data.py +102 -0
  32. e2a-5.2.0/src/e2a/v1/generated/models/agent_suppression_view.py +107 -0
  33. e2a-5.2.0/src/e2a/v1/generated/models/agent_view.py +113 -0
  34. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/api_key_export_entry.py +14 -1
  35. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/api_key_view.py +19 -6
  36. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/approve_request.py +25 -11
  37. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/attachment.py +16 -3
  38. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/attachment_meta_view.py +20 -5
  39. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/attachment_view.py +19 -4
  40. e2a-5.2.0/src/e2a/v1/generated/models/authentication.py +120 -0
  41. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/conversation_detail_view.py +19 -6
  42. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/conversation_summary_view.py +19 -6
  43. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/create_agent_request.py +18 -4
  44. e2a-5.2.0/src/e2a/v1/generated/models/create_agent_suppression_request.py +101 -0
  45. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/create_api_key_request.py +19 -5
  46. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/create_api_key_response.py +19 -6
  47. e2a-5.2.0/src/e2a/v1/generated/models/create_template_request.py +110 -0
  48. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/create_webhook_request.py +19 -6
  49. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/create_webhook_response.py +15 -2
  50. e2a-5.2.0/src/e2a/v1/generated/models/delete_agent_result.py +104 -0
  51. e2a-5.2.0/src/e2a/v1/generated/models/delete_api_key_result.py +102 -0
  52. e2a-5.2.0/src/e2a/v1/generated/models/delete_domain_result.py +102 -0
  53. e2a-5.2.0/src/e2a/v1/generated/models/delete_message_result.py +102 -0
  54. e2a-5.2.0/src/e2a/v1/generated/models/delete_suppression_result.py +102 -0
  55. e2a-5.2.0/src/e2a/v1/generated/models/delete_template_result.py +102 -0
  56. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/delete_user_data_result.py +22 -3
  57. e2a-5.2.0/src/e2a/v1/generated/models/delete_webhook_result.py +102 -0
  58. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/delivery_status_json.py +14 -1
  59. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/deployment_info_view.py +14 -1
  60. e2a-5.2.0/src/e2a/v1/generated/models/dkim_result.py +122 -0
  61. e2a-5.2.0/src/e2a/v1/generated/models/dmarc_result.py +117 -0
  62. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/dns_record.py +16 -3
  63. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/domain.py +17 -4
  64. e2a-5.2.0/src/e2a/v1/generated/models/domain_sending_failed_data.py +104 -0
  65. e2a-5.2.0/src/e2a/v1/generated/models/domain_sending_verified_data.py +102 -0
  66. e2a-5.2.0/src/e2a/v1/generated/models/domain_suppression_added_data.py +106 -0
  67. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/domain_view.py +21 -2
  68. e2a-5.2.0/src/e2a/v1/generated/models/email_bounced_data.py +114 -0
  69. e2a-5.2.0/src/e2a/v1/generated/models/email_complained_data.py +110 -0
  70. e2a-5.2.0/src/e2a/v1/generated/models/email_delivered_data.py +110 -0
  71. e2a-5.2.0/src/e2a/v1/generated/models/email_failed_data.py +126 -0
  72. e2a-5.2.0/src/e2a/v1/generated/models/email_received_data.py +161 -0
  73. e2a-5.2.0/src/e2a/v1/generated/models/email_sent_data.py +122 -0
  74. e2a-5.2.0/src/e2a/v1/generated/models/error_body.py +106 -0
  75. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/error_envelope.py +14 -1
  76. e2a-5.2.0/src/e2a/v1/generated/models/event_envelope.py +107 -0
  77. e2a-4.0.0/src/e2a/v1/generated/models/event_json.py → e2a-5.2.0/src/e2a/v1/generated/models/event_view.py +12 -12
  78. e2a-5.2.0/src/e2a/v1/generated/models/field_error.py +102 -0
  79. e2a-5.2.0/src/e2a/v1/generated/models/forward_request.py +129 -0
  80. e2a-5.2.0/src/e2a/v1/generated/models/hold_reason_view.py +110 -0
  81. e2a-5.2.0/src/e2a/v1/generated/models/limit_exceeded_details.py +108 -0
  82. e2a-5.2.0/src/e2a/v1/generated/models/limit_exceeded_envelope.py +104 -0
  83. e2a-5.2.0/src/e2a/v1/generated/models/limit_exceeded_error_body.py +110 -0
  84. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/limits_caps_view.py +16 -3
  85. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/limits_usage_view.py +16 -3
  86. e2a-5.2.0/src/e2a/v1/generated/models/message.py +258 -0
  87. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/message_body_view.py +14 -1
  88. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/message_parsed_view.py +14 -1
  89. e2a-5.2.0/src/e2a/v1/generated/models/message_summary_view.py +162 -0
  90. e2a-5.2.0/src/e2a/v1/generated/models/message_view.py +222 -0
  91. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/o_auth_connection_entry.py +14 -1
  92. e2a-5.2.0/src/e2a/v1/generated/models/page_agent_suppression_view.py +113 -0
  93. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_agent_view.py +14 -1
  94. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_api_key_view.py +14 -1
  95. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_conversation_summary_view.py +14 -1
  96. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_domain_view.py +14 -1
  97. e2a-4.0.0/src/e2a/v1/generated/models/page_event_json.py → e2a-5.2.0/src/e2a/v1/generated/models/page_event_view.py +21 -8
  98. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_message_summary_view.py +14 -1
  99. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_review_view.py +14 -1
  100. e2a-5.2.0/src/e2a/v1/generated/models/page_starter_template_view.py +115 -0
  101. e2a-5.2.0/src/e2a/v1/generated/models/page_suppression_view.py +115 -0
  102. e2a-5.2.0/src/e2a/v1/generated/models/page_template_summary_view.py +115 -0
  103. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_webhook_delivery_view.py +14 -1
  104. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/page_webhook_view.py +14 -1
  105. e2a-5.2.0/src/e2a/v1/generated/models/payload_too_large_details.py +107 -0
  106. e2a-5.2.0/src/e2a/v1/generated/models/protection_config_request.py +115 -0
  107. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/protection_config_view.py +14 -1
  108. e2a-5.2.0/src/e2a/v1/generated/models/protection_direction_request.py +110 -0
  109. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/protection_direction_view.py +14 -1
  110. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/protection_event_export_entry.py +22 -9
  111. e2a-5.2.0/src/e2a/v1/generated/models/protection_finding_view.py +123 -0
  112. e2a-4.0.0/src/e2a/v1/generated/models/protection_gate_view.py → e2a-5.2.0/src/e2a/v1/generated/models/protection_gate_request.py +20 -7
  113. e2a-5.2.0/src/e2a/v1/generated/models/protection_gate_view.py +105 -0
  114. e2a-5.2.0/src/e2a/v1/generated/models/protection_holds_request.py +105 -0
  115. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/protection_holds_view.py +19 -4
  116. e2a-5.2.0/src/e2a/v1/generated/models/protection_scan_request.py +100 -0
  117. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/protection_scan_view.py +16 -3
  118. e2a-5.2.0/src/e2a/v1/generated/models/rate_limited_details.py +100 -0
  119. e2a-5.2.0/src/e2a/v1/generated/models/rate_limited_envelope.py +104 -0
  120. e2a-5.2.0/src/e2a/v1/generated/models/rate_limited_error_body.py +110 -0
  121. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/redeliver_delivery.py +14 -1
  122. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/redeliver_event_request.py +14 -1
  123. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/redeliver_view.py +14 -1
  124. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/register_domain_request.py +14 -1
  125. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/reject_request.py +17 -3
  126. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/reject_result_view.py +14 -1
  127. e2a-4.0.0/src/e2a/v1/generated/models/send_email_request.py → e2a-5.2.0/src/e2a/v1/generated/models/rendered_template_view.py +23 -28
  128. e2a-5.2.0/src/e2a/v1/generated/models/reply_request.py +129 -0
  129. e2a-5.2.0/src/e2a/v1/generated/models/retry_after_details.py +101 -0
  130. e2a-5.2.0/src/e2a/v1/generated/models/review_view.py +146 -0
  131. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/rotate_secret_response.py +14 -1
  132. e2a-5.2.0/src/e2a/v1/generated/models/send_email_request.py +137 -0
  133. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/send_result_view.py +16 -3
  134. e2a-5.2.0/src/e2a/v1/generated/models/sending_ramp_view.py +112 -0
  135. e2a-5.2.0/src/e2a/v1/generated/models/spf_result.py +115 -0
  136. e2a-5.2.0/src/e2a/v1/generated/models/starter_template_detail_view.py +122 -0
  137. e2a-5.2.0/src/e2a/v1/generated/models/starter_template_variable_view.py +108 -0
  138. e2a-5.2.0/src/e2a/v1/generated/models/starter_template_view.py +118 -0
  139. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/suppression_export_entry.py +17 -2
  140. e2a-4.0.0/src/e2a/v1/generated/models/suppression.py → e2a-5.2.0/src/e2a/v1/generated/models/suppression_view.py +18 -5
  141. e2a-5.2.0/src/e2a/v1/generated/models/template_part_error.py +102 -0
  142. e2a-5.2.0/src/e2a/v1/generated/models/template_summary_view.py +111 -0
  143. e2a-5.2.0/src/e2a/v1/generated/models/template_view.py +119 -0
  144. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/test_webhook_request.py +4 -4
  145. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/test_webhook_response.py +14 -1
  146. e2a-5.2.0/src/e2a/v1/generated/models/threat_category_view.py +102 -0
  147. e2a-5.2.0/src/e2a/v1/generated/models/too_many_recipients_details.py +103 -0
  148. e2a-5.2.0/src/e2a/v1/generated/models/unsubscribe_options.py +98 -0
  149. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/update_agent_request.py +15 -2
  150. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/update_message_request.py +14 -1
  151. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/update_message_result_view.py +14 -1
  152. e2a-5.2.0/src/e2a/v1/generated/models/update_template_request.py +108 -0
  153. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/update_webhook_request.py +19 -6
  154. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/usage_event_entry.py +20 -7
  155. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/user_export.py +16 -3
  156. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/user_export_user.py +14 -1
  157. e2a-5.2.0/src/e2a/v1/generated/models/validate_template_request.py +106 -0
  158. e2a-5.2.0/src/e2a/v1/generated/models/validate_template_response.py +118 -0
  159. e2a-5.2.0/src/e2a/v1/generated/models/validation_error_details.py +108 -0
  160. e2a-5.2.0/src/e2a/v1/generated/models/verify_domain_view.py +111 -0
  161. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/webhook_delivery_view.py +18 -5
  162. e2a-5.2.0/src/e2a/v1/generated/models/webhook_filters_request.py +104 -0
  163. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/webhook_filters_view.py +17 -4
  164. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/models/webhook_view.py +15 -2
  165. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/rest.py +1 -1
  166. e2a-5.2.0/src/e2a/v1/inbound.py +327 -0
  167. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/pagination.py +16 -0
  168. e2a-5.2.0/src/e2a/v1/sync_client.py +477 -0
  169. e2a-5.2.0/src/e2a/v1/webhook_signature.py +446 -0
  170. e2a-5.2.0/src/e2a/v1/websocket.py +353 -0
  171. e2a-5.2.0/tests/test_e2e.py +120 -0
  172. {e2a-4.0.0 → e2a-5.2.0}/tests/test_enum_forward_compat.py +7 -7
  173. e2a-5.2.0/tests/test_exports.py +163 -0
  174. e2a-5.2.0/tests/test_v1_client.py +1128 -0
  175. e2a-5.2.0/tests/test_v1_client_side_validation.py +72 -0
  176. {e2a-4.0.0 → e2a-5.2.0}/tests/test_v1_errors.py +113 -0
  177. e2a-5.2.0/tests/test_v1_inbound.py +131 -0
  178. {e2a-4.0.0 → e2a-5.2.0}/tests/test_v1_pagination.py +34 -0
  179. {e2a-4.0.0 → e2a-5.2.0}/tests/test_v1_retry.py +95 -3
  180. e2a-5.2.0/tests/test_v1_sync_client.py +520 -0
  181. e2a-5.2.0/tests/test_v1_websocket.py +593 -0
  182. e2a-5.2.0/tests/test_webhook_payloads.py +273 -0
  183. {e2a-4.0.0 → e2a-5.2.0}/tests/test_webhook_signature.py +72 -4
  184. e2a-5.2.0/tests/typecheck_event_envelope.py +36 -0
  185. e2a-5.2.0/tests/typecheck_inbound.py +26 -0
  186. {e2a-4.0.0 → e2a-5.2.0}/uv.lock +729 -343
  187. e2a-4.0.0/CHANGELOG.md +0 -190
  188. e2a-4.0.0/PKG-INFO +0 -178
  189. e2a-4.0.0/README.md +0 -141
  190. e2a-4.0.0/scripts/generate-oag.sh +0 -39
  191. e2a-4.0.0/src/e2a/__init__.py +0 -52
  192. e2a-4.0.0/src/e2a/v1/__init__.py +0 -71
  193. e2a-4.0.0/src/e2a/v1/client.py +0 -644
  194. e2a-4.0.0/src/e2a/v1/generated/models/__init__.py +0 -96
  195. e2a-4.0.0/src/e2a/v1/generated/models/agent_view.py +0 -98
  196. e2a-4.0.0/src/e2a/v1/generated/models/auth_verdict.py +0 -101
  197. e2a-4.0.0/src/e2a/v1/generated/models/check_result.py +0 -89
  198. e2a-4.0.0/src/e2a/v1/generated/models/error_body.py +0 -98
  199. e2a-4.0.0/src/e2a/v1/generated/models/forward_request.py +0 -107
  200. e2a-4.0.0/src/e2a/v1/generated/models/message.py +0 -208
  201. e2a-4.0.0/src/e2a/v1/generated/models/message_summary_view.py +0 -134
  202. e2a-4.0.0/src/e2a/v1/generated/models/message_view.py +0 -160
  203. e2a-4.0.0/src/e2a/v1/generated/models/page_suppression.py +0 -102
  204. e2a-4.0.0/src/e2a/v1/generated/models/reply_request.py +0 -107
  205. e2a-4.0.0/src/e2a/v1/generated/models/result.py +0 -101
  206. e2a-4.0.0/src/e2a/v1/generated/models/review_view.py +0 -108
  207. e2a-4.0.0/src/e2a/v1/generated/models/verify_domain_view.py +0 -98
  208. e2a-4.0.0/src/e2a/v1/webhook_signature.py +0 -141
  209. e2a-4.0.0/src/e2a/v1/websocket.py +0 -215
  210. e2a-4.0.0/tests/test_exports.py +0 -84
  211. e2a-4.0.0/tests/test_v1_client.py +0 -422
  212. e2a-4.0.0/tests/test_v1_websocket.py +0 -372
  213. {e2a-4.0.0 → e2a-5.2.0}/scripts/strip-enum-validators.py +0 -0
  214. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/py.typed +0 -0
  215. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/api_response.py +0 -0
  216. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/generated/py.typed +0 -0
  217. {e2a-4.0.0 → e2a-5.2.0}/src/e2a/v1/py.typed +0 -0
  218. {e2a-4.0.0 → e2a-5.2.0}/tests/__init__.py +0 -0
  219. {e2a-4.0.0 → e2a-5.2.0}/tests/test_contract.py +0 -0
@@ -25,6 +25,7 @@ cli/dist/
25
25
  # TypeScript SDK
26
26
  sdks/typescript/node_modules/
27
27
  sdks/typescript/dist/
28
+ sdks/typescript/.oag-openapi.yaml
28
29
 
29
30
  # Python SDK
30
31
  sdks/python/.venv/
@@ -33,6 +34,8 @@ sdks/python/__pycache__/
33
34
  sdks/python/src/*.egg-info/
34
35
  sdks/python/dist/
35
36
  sdks/python/.pytest_cache/
37
+ sdks/python/.oag-openapi.yaml
38
+ sdks/python/.oag-tmp/
36
39
  *.pyc
37
40
  .gstack/
38
41
  .claude/
e2a-5.2.0/CHANGELOG.md ADDED
@@ -0,0 +1,381 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ### Added
6
+ - `client.inbound.from_event(event)` returns `AsyncInboundEmail` on
7
+ `AsyncE2AClient` and a blocking `InboundEmail` on `E2AClient`. The facade
8
+ exposes explicit envelope/auth verdicts, reply targets, parsed-body
9
+ truncation, policy flags, bound reply/forward, and lazy attachment `get()`.
10
+ Shared cross-SDK vectors gate async/sync/TypeScript semantics.
11
+
12
+ ### Breaking (pre-GA)
13
+ - **Inbound sender and authentication fields now use the final DMARC-aligned
14
+ contract.** Generated message models and raw webhook/WS payloads expose the
15
+ literal RFC 5322 ``header_from``, SMTP ``envelope_from``, nullable
16
+ ``verified_domain``, and structured ``authentication`` (``spf``, every
17
+ ``dkim`` result, and ``dmarc``). The old aggregate and signed nested-header
18
+ fields are removed. A non-null ``verified_domain`` means DMARC passed for that
19
+ From domain; it does not authenticate the mailbox local part, a person, or
20
+ message content.
21
+
22
+ | Previous 5.x generated property/model | Replacement |
23
+ |---|---|
24
+ | ``from_`` | ``header_from``. Reply routing remains in ``reply_to``. |
25
+ | ``authenticated_from`` | ``verified_domain``, or inspect ``authentication.dmarc.status == "pass"``. |
26
+ | ``auth: AuthVerdict`` | ``authentication: Optional[Authentication]``; ``AuthVerdict`` is removed. |
27
+ | ``CheckResult`` | ``SPFResult``; DKIM and DMARC use the new ``DKIMResult`` and ``DMARCResult`` models. |
28
+ | ``auth_headers`` / ``X-E2A-Auth-*`` | Removed. For webhooks, verify the envelope ``X-E2A-Signature``; REST and WebSocket already use authenticated transports. |
29
+
30
+ - **Implementation-leaked schema names renamed; duplicate schemas collapsed.**
31
+ Generated models: ``EventJSON`` → ``EventView`` (module
32
+ ``event_json`` → ``event_view``), ``PageEventJSON`` → ``PageEventView``,
33
+ ``Suppression`` → ``SuppressionView``, ``PageSuppression`` →
34
+ ``PageSuppressionView``; the duplicate ``Result`` collapsed into the
35
+ existing ``AuthVerdict``, and the duplicate ``AttachmentMeta`` collapsed
36
+ into the canonical ``AttachmentMetaView`` (one attachment-metadata shape for
37
+ REST responses, stable event payloads, and the account export — the
38
+ hand-written webhook payload TypedDict in ``webhook_signature.py`` follows
39
+ the same rename). The wire JSON is unchanged — field names, optionality, and
40
+ values are identical; only the exported type names changed. Migrate:
41
+ ``EventJSON`` → ``EventView``, ``Suppression`` → ``SuppressionView``,
42
+ ``Result`` → ``AuthVerdict``, ``AttachmentMeta`` → ``AttachmentMetaView``.
43
+
44
+ ## 5.2.0
45
+
46
+ ### Breaking (pre-GA)
47
+ - **The reserved-word wire field `from` is now uniformly exposed as `from_`
48
+ (PEP 8 trailing underscore) on generated models** (was the generator-mangled
49
+ `var_from`). Affected models: `Message`, `MessageView`, `MessageSummaryView`,
50
+ `ReviewView`, `EmailReceivedData`, `EmailSentData`, `EmailFailedData`
51
+ (generated), plus the generated `list_messages` sender filter parameter. The
52
+ hand-written layer's `messages.list(from_=...)` already used `from_`, so the
53
+ SDK now teaches exactly one spelling; the TypeScript SDK exposes the same
54
+ `from_`. The wire JSON is unchanged — requests and responses still carry
55
+ `from` (pydantic alias). The webhook/WS `data` payload TypedDicts are
56
+ wire-true dicts and keep the literal `"from"` key (access as
57
+ `data["from"]`). Migrate: `message.var_from` → `message.from_`.
58
+
59
+ ## 5.1.0
60
+
61
+ ### Breaking (pre-GA)
62
+ - **Uniform DELETE responses: every `.delete(...)` now returns a typed deletion
63
+ object instead of `None`.** The API's seven delete endpoints all return
64
+ `200 OK` with `{"deleted": true, <identity key>}` instead of the previous mix
65
+ of `204 No Content` and `200`. New return types: `agents.delete` →
66
+ `DeleteAgentResult` (`deleted`, `email`, `messages_deleted` — the message
67
+ cascade count), `domains.delete` → `DeleteDomainResult` (`domain`),
68
+ `webhooks.delete` → `DeleteWebhookResult` (`id`), `templates.delete` →
69
+ `DeleteTemplateResult` (`id`), `account.api_keys.delete` →
70
+ `DeleteApiKeyResult` (`id`), `account.suppressions.delete` →
71
+ `DeleteSuppressionResult` (`address`); `account.delete()` still returns
72
+ `DeleteUserDataResult`, which now also carries `deleted: true`. `deleted` is
73
+ always `True` — a failed delete raises a typed error, never returns
74
+ `deleted: False`. Applies identically to the sync `E2AClient` facade (it
75
+ mirrors the async surface). Callers that ignored the old `None` return need
76
+ no changes; the SDK still auto-sends the `?confirm=DELETE` guard. Older SDK
77
+ versions whose generated bases expected `204` are incompatible with servers
78
+ running this contract — upgrade together (pre-GA break).
79
+
80
+ ## 5.0.0
81
+
82
+ Breaking: the async client class was renamed (the freed name now ships a
83
+ synchronous client), and the WebSocket frame is now the versioned event
84
+ envelope (server #456).
85
+
86
+ ### Changed
87
+ - **`E2AClient` → `AsyncE2AClient`.** The 4.x client was async-only, but its
88
+ name inverted the Python-ecosystem convention (httpx, openai, anthropic:
89
+ plain name = sync client, `Async*` prefix = async client) and squatted the
90
+ name the synchronous client needs. The class, exports (`e2a` and `e2a.v1`),
91
+ docs, and examples all now use `AsyncE2AClient`; its behavior is unchanged.
92
+ Migration from 4.x is mechanical: `from e2a.v1 import AsyncE2AClient`.
93
+ - **The WebSocket frame is the versioned event envelope** — the same
94
+ ``{type, id, schema_version, created_at, data}`` shape a webhook delivery
95
+ carries, so one parser (and one dedup key: the event ``id``) serves both
96
+ channels. Frames were previously a flat ad-hoc notification object.
97
+ - **`WSNotification` is removed.** ``client.listen(...)`` now yields
98
+ ``WSEvent`` envelopes: branch on ``event.type`` (tolerate unknown values —
99
+ forward-compat) and read the payload from ``event.data`` (for
100
+ ``email.received`` the flat ``notif.message_id`` / ``notif.delivered_to``
101
+ attributes become ``event.data["message_id"]`` /
102
+ ``event.data["delivered_to"]``). The ``is_email_*`` / ``is_domain_*``
103
+ guards narrow the stable payloads.
104
+
105
+ ### Added
106
+ - **Typed per-event payload models** for the nine stable event types
107
+ (``EmailReceivedData``, ``EmailSentData``, ``EmailFailedData``,
108
+ ``EmailDeliveredData``, ``EmailBouncedData``, ``EmailComplainedData``,
109
+ ``DomainSendingVerifiedData``, ``DomainSendingFailedData``,
110
+ ``DomainSuppressionAddedData``, plus ``AttachmentMeta``) with narrowing
111
+ guards (``is_email_received``, ``is_email_sent``, …) shared by the webhook
112
+ and WS channels. The shapes are locked to the server's committed golden
113
+ fixtures.
114
+ - ``client.webhooks.fetch_message(event)`` accepts both a verified
115
+ ``WebhookEvent`` and a ``WSEvent`` (any envelope-shaped object with
116
+ ``type`` and ``data``).
117
+ - **`E2AClient` — the synchronous client** — under the name the rename freed
118
+ (there is deliberately no compatibility alias to the async client). It is a
119
+ facade over `AsyncE2AClient`: a background daemon thread runs an event loop
120
+ for the client's lifetime and every call bridges the corresponding async
121
+ coroutine onto it, so there is exactly one implementation of
122
+ resources/retries/typed errors/pagination and the two surfaces cannot drift.
123
+ - Identical constructor (`api_key`, `base_url`, `max_retries`,
124
+ `max_elapsed_ms`, `timeout_ms`) and resource tree; typed `E2AError`
125
+ subclasses propagate unwrapped, so `except E2ALimitExceededError:` works
126
+ the same as in async code.
127
+ - List endpoints return a **sync pager**: plain `for` iteration, plus
128
+ `page(cursor)` / `to_list(limit=N)` / `for_each(fn)`.
129
+ - `client.listen(address)` returns a plain iterable of `WSEvent` envelopes
130
+ (the same envelope the async `listen()` yields); `close()` from another
131
+ thread unblocks a pending iteration cleanly.
132
+ - Lifecycle: use as a context manager or call `close()` (idempotent). An
133
+ unclosed client is cleaned up at GC/interpreter exit and cannot hang
134
+ shutdown.
135
+ - **Async-context guard:** calling any sync method while an event loop is
136
+ running in the current thread raises a guiding `RuntimeError`
137
+ ("use AsyncE2AClient") instead of blocking the loop. 4.x code that still
138
+ imports `E2AClient` now gets the sync client — update those imports to
139
+ `AsyncE2AClient`.
140
+
141
+ ## 4.3.0
142
+
143
+ ### Breaking (pre-GA)
144
+ - **`AgentIdentity.webhook_healthy` (bool) replaced by `AgentIdentity.webhook_status`
145
+ (optional string enum).** The bool could not distinguish "no webhook
146
+ configured" from "healthy". The new field is an open set — tolerate unknown
147
+ values. Known values: `none` (no webhook matches the agent), `healthy` (an
148
+ enabled matching webhook, no terminally-failed delivery in the last 24h),
149
+ `failing` (an enabled matching webhook had a terminally-failed delivery in
150
+ the last 24h), `disabled` (matching webhooks exist but all are manually
151
+ disabled), `auto_disabled` (all matching webhooks disabled, at least one by
152
+ the chronic-failure sweep). `AgentIdentity` only appears in the account
153
+ export (`account.export()`), so most integrations are unaffected.
154
+
155
+ ## 4.2.0
156
+
157
+ Additive, no breaking changes.
158
+
159
+ ### Fixed
160
+ - **`templates.list()` / `templates.list_starters()` silently truncated to the
161
+ first page.** Both ignored the server's `next_cursor` and stopped after one
162
+ request, dropping every template/starter past page one. They now thread the
163
+ cursor and auto-page to completion like every other `.list()` (TS SDK
164
+ parity), and accept a `limit=` per-page size.
165
+
166
+ ### Added
167
+ - **`AutoPager.page(cursor=None)`** — the manual, caller-driven pagination
168
+ primitive (parity with the TS SDK's `pager.page()`): fetch a SINGLE page and
169
+ get back a `Page` of `items` + `next_cursor`. Pass the previous page's
170
+ `next_cursor` to resume (e.g. checkpoint/restart from a queue); a `None`
171
+ `next_cursor` in the result means there are no more pages. The page size is
172
+ the `limit` baked into the list call that produced the pager.
173
+
174
+ ## 4.1.0
175
+
176
+ Additive, no breaking changes.
177
+
178
+ ### Added
179
+ - **`E2ALimitExceededError`** — the typed error for a `402 limit_exceeded`
180
+ response (a per-account **quota** cap: monthly messages, storage, agent/domain
181
+ counts). It is **not** retryable. This completes the permanent GA split with
182
+ `E2ARateLimitError` (`429 rate_limited`, a request-**rate**/throughput limit,
183
+ which **is** retryable): branch on the exception type (equivalently the HTTP
184
+ status) — `402` → surface a quota/upgrade path, `429` → back off
185
+ `retry_after_seconds` and retry. A `402` previously surfaced as the base
186
+ `E2AError`; it now surfaces as this subclass (still an `E2AError`, so existing
187
+ `except E2AError` handlers are unaffected).
188
+ - `email.received` is a metadata-only notification; `webhooks.fetch_message(event)`
189
+ + the `EmailReceivedPayload` type fetch the full message (body + attachments)
190
+ on demand (#321).
191
+ - Per-axis SES sending status surfaced on the domain/sending types (#309).
192
+ - DKIM verification support (#312).
193
+
194
+ ## 4.0.0
195
+
196
+ Breaking: the domain DNS-records shape changed (server #304).
197
+
198
+ ### Changed
199
+ - **`DomainView.dns_records` is now a single purpose-tagged array
200
+ (`list[DNSRecord]`).** Each record carries `type`, `name`, `value`,
201
+ `priority`, `purpose`, and `status`. Replaces the old
202
+ `dns_records.{ mx, txt, dkim }` object and the separate `sending_dns_records`
203
+ list. Address records by `purpose` (`ownership`, `inbound_mx`, `dkim`,
204
+ `mail_from_mx`, `mail_from_spf`) rather than `dns_records.mx`/`.txt`/`.dkim`.
205
+ The MAIL FROM records live in the same list (returned at registration when the
206
+ sending feature is enabled), and each record now has a per-record `status`
207
+ (`verified`/`pending`/`missing`/`failed`). `purpose` and `status` are open
208
+ sets — tolerate unknown values.
209
+
210
+ ## 3.0.0
211
+
212
+ Breaking redesign. The SDK is now a namespaced, **async-only** `E2AClient`
213
+ wrapping a generated client over the agent-scoped `/v1` API surface, with a
214
+ typed error hierarchy, automatic retries + idempotency, and async
215
+ auto-pagination.
216
+
217
+ ### Changed
218
+ - **Namespaced, async-only surface.** Resources are grouped under the client:
219
+ `client.agents`, `client.messages`, `client.conversations`, `client.domains`,
220
+ `client.events`, `client.webhooks`, `client.account`. Per-agent methods take
221
+ the agent `address` as the first argument
222
+ (`await client.messages.send(address, {...})`,
223
+ `await client.messages.list(address).to_list(limit=...)`,
224
+ `await client.messages.get(address, id)`,
225
+ `await client.messages.reply(address, id, {...})`). Use the client as an async
226
+ context manager (`async with E2AClient() as client:`).
227
+ - **Webhook verification.** Verify and decode a delivery with the standalone
228
+ `construct_event(raw_body, signature_header, secret)`, which checks the
229
+ `X-E2A-Signature` header and returns a typed event (raising
230
+ `E2AWebhookSignatureError` on a bad signature). Per-webhook `whsec_…` secrets,
231
+ Stripe-style.
232
+ - **Typed errors.** Failures raise `E2AError` subclasses (`E2ANotFoundError`,
233
+ `E2AConflictError`, `E2AValidationError`, `E2ARateLimitError`,
234
+ `E2AWebhookSignatureError`, …) carrying `.code`, `.status`, `.request_id`, and
235
+ `.retryable`.
236
+
237
+ ### Removed
238
+ - The flat methods `send` / `reply` / `get_messages` / `get_message` and the
239
+ per-call `agent_email` inference. Pass the agent `address` explicitly.
240
+ - The lower-level `E2AApi` class.
241
+ - The synchronous client — the SDK is async-only.
242
+ - `InboundEmail` / `AsyncInboundEmail` and the `parse_webhook` / `parse` +
243
+ `verify_signature()` flow. Replaced by `construct_event`. There is no
244
+ unverified-email type and no field-access gating.
245
+
246
+ ## 2.5.0
247
+
248
+ ### Added
249
+ - Generated types for the per-user resource-limits primitive that
250
+ shipped with #158: `LimitsInfo`, `LimitsCaps`, `LimitsUsage`. These
251
+ describe the response shape of `GET /api/v1/users/me/limits`, which
252
+ the hosted dashboard uses to render the upgrade affordance and the
253
+ "you've used X of Y" surface. The high-level `E2AClient` doesn't
254
+ yet expose a typed helper for this endpoint — it's surfaced as a
255
+ dashboard-only concern today, and SDK consumers querying their own
256
+ usage should call `/agents` / `/messages` directly. The types are
257
+ emitted so anyone consuming the raw OpenAPI generation has the
258
+ shapes available.
259
+
260
+ ### Notes
261
+ - No runtime client behavior changed in this release. If you're not
262
+ using the limits primitive (self-host deployments without a paid
263
+ tier), 2.5.0 is functionally identical to 2.4.0.
264
+
265
+ ## 2.4.0
266
+
267
+ ### Added
268
+ - `idempotency_key` parameter on `E2AClient.approve_message()` and its
269
+ async counterpart (and on the lower-level `E2AApi.approve_message()`).
270
+ Approve fires a real SES send, so without a stable key a retry after
271
+ a transient failure could double-send. When supplied it's threaded
272
+ through as the `Idempotency-Key` header; when omitted the SDK mints
273
+ a fresh UUIDv4 per call — that gives network-layer retry safety only.
274
+ Supply a stable key derived from the review event (typically the
275
+ pending `message_id`) to dedupe across an explicit retry loop.
276
+ - `sort`, `from_`, `subject_contains`, `conversation_id`, `since`,
277
+ `until` kwargs on `E2AApi.list_messages()` and the high-level
278
+ `E2AClient.get_messages()` (sync + async). `sort` defaults
279
+ server-side to newest-first; pass `"asc"` for FIFO polling. The
280
+ substring filters are case-insensitive and capped at 200 chars
281
+ server-side. `since` / `until` accept RFC3339 timestamps and
282
+ bracket `created_at`. Filter values are encoded into `next_token`,
283
+ so continuation requests must keep the same filter values.
284
+
285
+ ### Changed
286
+ - **Default sort flipped to newest-first** on `GET /messages`. Prior
287
+ releases silently returned oldest-first for `direction=inbound` (the
288
+ SDK default) and newest-first for `direction=all`. A polling agent
289
+ that relied on FIFO drain order should now pass `sort="asc"` to
290
+ preserve the old behavior.
291
+ - `agent_mode` is now a required field on `RegisterAgentRequest`. The
292
+ server previously silently defaulted to `"cloud"` and then 400'd
293
+ with a cryptic "webhook_url is required" message; it now explicitly
294
+ rejects requests missing `agent_mode` with a clear error. Pydantic
295
+ v2 will raise a validation error if you instantiate the request
296
+ without it. Set `agent_mode="local"` or `"cloud"` explicitly.
297
+
298
+ ## 2.3.0
299
+
300
+ ### Added
301
+ - `idempotency_key` parameter on `E2AClient.send()` / `.reply()` and their async
302
+ counterparts (and on the lower-level `E2AApi.send_email()` /
303
+ `reply_to_message()`). When supplied, it is sent as the `Idempotency-Key`
304
+ header so the server can deduplicate retries of the same send/reply. When
305
+ omitted, the SDK generates a fresh UUIDv4 per call — that gives
306
+ network-layer retry safety only; supply a stable key derived from the
307
+ triggering event (e.g. the inbound message id or a job id) to deduplicate
308
+ across an explicit retry loop.
309
+ - `InboundEmail.reply_to` and `AsyncInboundEmail.reply_to` (`list[str]`) — the
310
+ parsed `Reply-To:` header from the inbound message, surfaced as a first-class
311
+ field so consumers no longer need to re-parse `raw_message` with stdlib
312
+ `email.message_from_bytes()`. Empty list when the header is absent; the SDK
313
+ never silently falls back to `sender`. Use this when the sender is a no-reply
314
+ notifications mailbox (Granola, GitHub, CI bots) and you need the actual
315
+ correspondent.
316
+ - `MessageSummary.reply_to` (`list[str]`) on the REST polling path — the list
317
+ endpoint now mirrors the same field.
318
+ - `reply_to` added to `unverified_payload` for forensic inspection without
319
+ unlocking gated access.
320
+
321
+ ### Reply-To trust path (decision)
322
+ `reply_to` is trusted on the same terms as `to`, `cc`, `recipient`,
323
+ `subject`, and the body fields: the e2a server parses it from
324
+ `raw_message`, places it in the JSON envelope, and TLS protects the wire
325
+ to your webhook URL. Treat the field as trustworthy once
326
+ `verify_signature()` succeeds **and** you're confident in your
327
+ relay-to-webhook connection (or via `client.get_message(...)`, which uses
328
+ the authenticated REST channel).
329
+
330
+ **What `verify_signature()` does not prove:** the HMAC binds a fixed set
331
+ of auth headers and `body_hash = SHA-256(raw_message)`. It does not sign
332
+ the JSON envelope itself, and the SDK reads `reply_to`, `to`, `cc`, etc.
333
+ from that envelope rather than re-parsing `raw_message`. So an attacker
334
+ who can modify the JSON wrapping after signing — but cannot modify
335
+ `raw_message` or the signed headers — can rewrite `reply_to` and the
336
+ HMAC will still verify. TLS to your webhook URL is the actual integrity
337
+ layer for the envelope fields; the HMAC is defense-in-depth for proven
338
+ origin and covers the body bytes. If you need byte-exact assurance for a
339
+ specific field, re-parse it from `raw_message` (whose integrity
340
+ `body_hash` *does* cover).
341
+
342
+ **Also not guaranteed:** upstream-DKIM coverage of `Reply-To:`. If the
343
+ original sender's DKIM signature did not sign `Reply-To` (whether
344
+ because they didn't sign it, or there was no DKIM at all), a MITM
345
+ between sender and e2a could have rewritten the header before it reached
346
+ the relay. e2a does not re-verify or surface per-header DKIM coverage
347
+ today — the `Authentication-Results` / SPF/DKIM surface is unchanged.
348
+ For routing decisions where attacker-controlled `Reply-To` would matter,
349
+ also confirm `email.is_verified` and that the sender's domain is one you
350
+ expect.
351
+
352
+ We chose to keep `reply_to` populated whenever it's present (rather than
353
+ masking it on partially-trusted messages or exposing a `reply_to_signed`
354
+ flag) so the field shape stays uniform with `to`/`cc` and consumers can
355
+ make their own policy decision. The trust model is documented on the
356
+ property docstring.
357
+
358
+ ### Wire change
359
+ The webhook payload schema now includes an optional `reply_to: string[]`
360
+ field. Existing consumers that ignore unknown fields are unaffected; older
361
+ SDK versions parsing the same payload continue to work and simply do not
362
+ see the new key.
363
+
364
+ ### Other generated-type additions
365
+ The high-level surface above is what most consumers will touch. For users
366
+ of `client.api.*` or `e2a.v1.generated.*` directly, the following backend
367
+ endpoints / fields also landed since 2.2.0 and are reflected in the
368
+ regenerated types:
369
+
370
+ - Per-record DNS verification — separate MX / SPF / DKIM diagnostic
371
+ responses on the domain-verification endpoints.
372
+ - Enriched `DashboardAgent` — `Inbound7d`, `Outbound7d`, `Pending`,
373
+ `LastDelivery`, `WebhookHealthy` fields on the dashboard list.
374
+ - OAuth 2.1 authorization-server endpoints (fosite-backed) used by the
375
+ MCP server flow.
376
+ - Per-domain DKIM key generation endpoint.
377
+ - One-time signing-secret reveal on creation.
378
+ - Pending-review polish — provenance, quoted-inbound, headers-preview,
379
+ draft-footer fields on the review payload.
380
+
381
+ These are additive and don't break existing 2.2.0 callers.