fathom-ruby 1.0.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.
data/lib/fathom.rb ADDED
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+
7
+ require_relative "fathom/version"
8
+ require_relative "fathom/errors"
9
+ require_relative "fathom/client"
10
+ require_relative "fathom/rate_limiter"
11
+ require_relative "fathom/resource"
12
+ require_relative "fathom/resources/meeting"
13
+ require_relative "fathom/resources/recording"
14
+ require_relative "fathom/resources/team"
15
+ require_relative "fathom/resources/team_member"
16
+ require_relative "fathom/resources/webhook"
17
+
18
+ module Fathom
19
+ class << self
20
+ attr_writer :api_key, :auto_retry, :max_retries, :debug, :debug_http
21
+
22
+ def configure
23
+ yield self
24
+ end
25
+
26
+ def api_key
27
+ @api_key || raise(Error, "Fathom.api_key is not configured")
28
+ end
29
+
30
+ def auto_retry = @auto_retry.nil? || @auto_retry
31
+
32
+ def max_retries = @max_retries || 3
33
+
34
+ def debug = @debug || false
35
+
36
+ def debug_http = @debug_http || false
37
+
38
+ def reset!
39
+ @api_key = nil
40
+ @auto_retry = true
41
+ @max_retries = 3
42
+ @debug = false
43
+ @debug_http = false
44
+ end
45
+
46
+ def log(message)
47
+ return unless debug
48
+
49
+ puts "[Fathom] #{message}"
50
+ end
51
+
52
+ def log_http(message)
53
+ return unless debug_http
54
+
55
+ puts "[Fathom HTTP] #{message}"
56
+ end
57
+ end
58
+ end
data/scripts/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # Scripts
2
+
3
+ This directory contains utility scripts for development and testing.
4
+
5
+ ## test_live_api.rb
6
+
7
+ Integration test script to verify the gem works correctly with the real Fathom API.
8
+
9
+ ### Prerequisites
10
+
11
+ 1. A Fathom account
12
+ 2. An API key from your Fathom account (get it at: https://app.fathom.video/settings/integrations)
13
+
14
+ ### Usage
15
+
16
+ **Option 1: Inline environment variable**
17
+
18
+ ```bash
19
+ FATHOM_API_KEY=your_api_key_here ruby scripts/test_live_api.rb
20
+ ```
21
+
22
+ **Option 2: Export environment variable**
23
+
24
+ ```bash
25
+ export FATHOM_API_KEY=your_api_key_here
26
+ ruby scripts/test_live_api.rb
27
+ ```
28
+
29
+ **Option 3: Use .env file (recommended for development)**
30
+
31
+ Create a `.env` file in the project root (already in .gitignore):
32
+
33
+ ```bash
34
+ echo "export FATHOM_API_KEY=your_api_key_here" > .env
35
+ ```
36
+
37
+ Then load it and run:
38
+
39
+ ```bash
40
+ source .env
41
+ ruby scripts/test_live_api.rb
42
+ ```
43
+
44
+ ### What It Tests
45
+
46
+ The script performs the following tests against your live Fathom account:
47
+
48
+ 1. **Meetings API**
49
+ - Fetch meetings list
50
+ - Access meeting attributes
51
+ - Fetch meeting summaries (if recordings exist)
52
+ - Fetch meeting transcripts (if recordings exist)
53
+
54
+ 2. **Teams API**
55
+ - Fetch teams list
56
+ - Fetch team members for each team
57
+
58
+ 3. **Team Members API**
59
+ - Fetch all team members directly
60
+
61
+ 4. **Webhooks API**
62
+ - Fetch webhooks list
63
+ - Create a test webhook
64
+ - Retrieve the created webhook
65
+ - Delete the test webhook
66
+ - Verify deletion
67
+
68
+ 5. **Error Handling**
69
+ - Test 404 responses for invalid IDs
70
+
71
+ 6. **Rate Limiting**
72
+ - Verify rate limit headers are processed
73
+
74
+ 7. **Pagination**
75
+ - Test pagination with limit parameter
76
+
77
+ ### Sample Output
78
+
79
+ ```
80
+ ✓ Fathom API Test Suite
81
+ Testing against live API with your credentials
82
+
83
+ ================================================================================
84
+ 1. Testing Meetings API
85
+ ================================================================================
86
+ Fetch meetings list... ✓ PASS
87
+ Found 5 meeting(s)
88
+
89
+ First meeting details:
90
+ ID: 123456
91
+ Title: Weekly Team Sync
92
+ Created: 2025-01-15T10:00:00Z
93
+ Recording ID: 789012
94
+
95
+ Access meeting attributes... ✓ PASS
96
+ Fetch meeting summary... ✓ PASS
97
+ Fetch meeting transcript... ✓ PASS
98
+
99
+ ...
100
+
101
+ ================================================================================
102
+ Test Results Summary
103
+ ================================================================================
104
+
105
+ Passed: 15
106
+ Failed: 0
107
+ Skipped: 0
108
+ Total: 15
109
+
110
+ Pass Rate: 100.0%
111
+
112
+ ✓ All tests passed!
113
+ ```
114
+
115
+ ### Notes
116
+
117
+ - **Mostly read-only**: This script performs read operations for meetings, teams, and team members.
118
+ - **Webhook testing**: Creates a temporary test webhook and immediately deletes it to verify full CRUD operations.
119
+ - **Safe to run**: The test webhook is automatically cleaned up. You can run this script as many times as you want.
120
+ - **Rate limits**: The script respects Fathom's rate limits and will automatically retry if needed.
121
+
122
+ ### Troubleshooting
123
+
124
+ **Error: FATHOM_API_KEY environment variable not set**
125
+ - Make sure you've set the environment variable before running the script
126
+
127
+ **401 Authentication Error**
128
+ - Your API key is invalid or has expired
129
+ - Get a new API key from https://app.fathom.video/settings/integrations
130
+
131
+ **404 Not Found (for meetings/teams)**
132
+ - Your account may not have any meetings or teams yet
133
+ - Try recording a meeting in Fathom first
134
+
135
+ **Rate Limit Exceeded**
136
+ - Wait a minute and try again
137
+ - The script will automatically retry with exponential backoff
138
+
@@ -0,0 +1,374 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # rubocop:disable Metrics/BlockNesting
5
+ # Integration test script for fathom-ruby gem against live API
6
+ # Usage: FATHOM_API_KEY=your_key_here ruby scripts/test_live_api.rb
7
+
8
+ require "bundler/setup"
9
+ require "securerandom"
10
+ require_relative "../lib/fathom"
11
+
12
+ # ANSI color codes for pretty output
13
+ def green(text)
14
+ "\e[32m#{text}\e[0m"
15
+ end
16
+
17
+ def red(text)
18
+ "\e[31m#{text}\e[0m"
19
+ end
20
+
21
+ def yellow(text)
22
+ "\e[33m#{text}\e[0m"
23
+ end
24
+
25
+ def blue(text)
26
+ "\e[34m#{text}\e[0m"
27
+ end
28
+
29
+ def section(title)
30
+ puts "\n#{blue("=" * 80)}"
31
+ puts blue(" #{title}")
32
+ puts blue("=" * 80)
33
+ end
34
+
35
+ def test(description)
36
+ print " #{description}... "
37
+ result = yield
38
+ puts green("✓ PASS")
39
+ result
40
+ rescue StandardError => e
41
+ puts red("✗ FAIL")
42
+ puts red(" Error: #{e.class}: #{e.message}")
43
+ nil
44
+ end
45
+
46
+ # Check for API key
47
+ api_key = ENV.fetch("FATHOM_API_KEY", nil)
48
+ if api_key.nil? || api_key.empty?
49
+ puts red("ERROR: FATHOM_API_KEY environment variable not set!")
50
+ puts "\nUsage:"
51
+ puts " FATHOM_API_KEY=your_key_here ruby scripts/test_live_api.rb"
52
+ puts "\nOr export it first:"
53
+ puts " export FATHOM_API_KEY=your_key_here"
54
+ puts " ruby scripts/test_live_api.rb"
55
+ exit 1
56
+ end
57
+
58
+ # Configure the gem
59
+ Fathom.configure do |config|
60
+ config.api_key = api_key
61
+ config.auto_retry = true
62
+ config.max_retries = 3
63
+ end
64
+
65
+ puts green("\n✓ Fathom API Test Suite")
66
+ puts " Testing against live API with your credentials\n"
67
+
68
+ # Track results
69
+ results = {
70
+ passed: 0,
71
+ failed: 0,
72
+ skipped: 0
73
+ }
74
+
75
+ # =============================================================================
76
+ # Test: Meetings
77
+ # =============================================================================
78
+ section "1. Testing Meetings API"
79
+
80
+ meetings = test("Fetch meetings list") do
81
+ Fathom::Meeting.all(limit: 5)
82
+ end
83
+
84
+ if meetings
85
+ results[:passed] += 1
86
+ puts " Found #{meetings.count} meeting(s)"
87
+
88
+ if meetings.any?
89
+ meeting = meetings.first
90
+ puts "\n First meeting details:"
91
+ puts " Recording ID: #{meeting.recording_id || "N/A"}"
92
+ puts " Title: #{meeting["title"] || "N/A"}"
93
+ puts " Created: #{meeting["created_at"]}"
94
+ puts " URL: #{meeting["url"] || "N/A"}"
95
+
96
+ # Test meeting attributes
97
+ test("Access meeting attributes") do
98
+ raise "Missing attributes" if meeting.attributes.empty?
99
+
100
+ true
101
+ end
102
+ results[:passed] += 1
103
+
104
+ # Test fetching summary if recording exists
105
+ if meeting.recording_id
106
+ summary = test("Fetch meeting summary") do
107
+ meeting.fetch_summary
108
+ end
109
+ results[:passed] += 1 if summary
110
+
111
+ transcript = test("Fetch meeting transcript") do
112
+ meeting.fetch_transcript
113
+ end
114
+ results[:passed] += 1 if transcript
115
+ else
116
+ puts yellow(" ⊘ Skipping summary/transcript tests (no recording_id)")
117
+ results[:skipped] += 2
118
+ end
119
+ else
120
+ puts yellow(" ⊘ No meetings found - some tests skipped")
121
+ results[:skipped] += 3
122
+ end
123
+ else
124
+ results[:failed] += 1
125
+ end
126
+
127
+ # =============================================================================
128
+ # Test: Teams
129
+ # =============================================================================
130
+ section "2. Testing Teams API"
131
+
132
+ teams = test("Fetch teams list") do
133
+ Fathom::Team.all
134
+ end
135
+
136
+ if teams
137
+ results[:passed] += 1
138
+ puts " Found #{teams.count} team(s)"
139
+
140
+ if teams.any?
141
+ team = teams.first
142
+ puts "\n First team details:"
143
+ puts " ID: #{team.id}"
144
+ puts " Name: #{team.name}"
145
+ puts " Created: #{team.created_at}"
146
+
147
+ # Test team members
148
+ members = test("Fetch team members") do
149
+ team.members
150
+ end
151
+
152
+ if members
153
+ results[:passed] += 1
154
+ puts " Found #{members.count} member(s) in team '#{team.name}'"
155
+
156
+ if members.any?
157
+ member = members.first
158
+ puts "\n First member details:"
159
+ puts " Name: #{member.name}"
160
+ puts " Email: #{member.email}"
161
+ end
162
+ else
163
+ results[:failed] += 1
164
+ end
165
+ else
166
+ puts yellow(" ⊘ No teams found")
167
+ results[:skipped] += 1
168
+ end
169
+ else
170
+ results[:failed] += 1
171
+ end
172
+
173
+ # =============================================================================
174
+ # Test: Team Members (Direct API)
175
+ # =============================================================================
176
+ section "3. Testing Team Members API"
177
+
178
+ team_members = test("Fetch all team members") do
179
+ Fathom::TeamMember.all(limit: 5)
180
+ end
181
+
182
+ if team_members
183
+ results[:passed] += 1
184
+ puts " Found #{team_members.count} team member(s)"
185
+
186
+ if team_members.any?
187
+ member = team_members.first
188
+ puts "\n Member details:"
189
+ puts " Name: #{member.name}"
190
+ puts " Email: #{member.email}"
191
+ puts " Created: #{member.created_at}"
192
+ end
193
+ else
194
+ results[:failed] += 1
195
+ end
196
+
197
+ # =============================================================================
198
+ # Test: Webhooks API (Full CRUD)
199
+ # =============================================================================
200
+ section "4. Testing Webhooks API"
201
+
202
+ # Test listing webhooks
203
+ webhooks = test("Fetch webhooks list") do
204
+ Fathom::Webhook.all
205
+ rescue Fathom::NotFoundError
206
+ puts yellow(" ⊘ List endpoint returned 404")
207
+ :not_available
208
+ end
209
+
210
+ if webhooks && webhooks != :not_available
211
+ results[:passed] += 1
212
+ puts " Found #{webhooks.count} existing webhook(s)"
213
+
214
+ if webhooks.any?
215
+ webhook = webhooks.first
216
+ puts "\n First webhook details:"
217
+ puts " ID: #{webhook.id}"
218
+ puts " URL: #{webhook.url}"
219
+ puts " Active: #{webhook.active?}"
220
+ puts " Triggered for: #{webhook.triggered_for&.join(", ") || "N/A"}"
221
+ puts " Include transcript: #{webhook.include_transcript?}"
222
+ puts " Include summary: #{webhook.include_summary?}"
223
+ end
224
+ elsif webhooks == :not_available
225
+ results[:skipped] += 1
226
+ else
227
+ results[:failed] += 1
228
+ end
229
+
230
+ # Test creating a webhook (independent of list endpoint)
231
+ # Using webhook.site for a valid HTTPS endpoint that accepts webhooks
232
+ created_webhook = test("Create test webhook") do
233
+ Fathom::Webhook.create(
234
+ url: "https://webhook.site/28c3ce21-4221-4d89-bab3-1c88d1cb0f0b",
235
+ triggered_for: ["my_recordings"],
236
+ include_transcript: true,
237
+ include_summary: true,
238
+ include_action_items: false,
239
+ include_crm_matches: false
240
+ )
241
+ rescue Fathom::BadRequestError, Fathom::ForbiddenError => e
242
+ puts yellow(" ⊘ Webhooks not available: #{e.message}")
243
+ :not_available
244
+ end
245
+
246
+ if created_webhook && created_webhook != :not_available
247
+ results[:passed] += 1
248
+ puts " Created webhook with ID: #{created_webhook.id}"
249
+ puts " URL: #{created_webhook.url}"
250
+ puts " Secret: #{created_webhook.secret[0..15]}..." if created_webhook.secret
251
+
252
+ # Test retrieving the webhook
253
+ retrieved_webhook = test("Retrieve created webhook") do
254
+ Fathom::Webhook.retrieve(created_webhook.id)
255
+ end
256
+
257
+ if retrieved_webhook
258
+ results[:passed] += 1
259
+ puts " Successfully retrieved webhook #{retrieved_webhook.id}"
260
+ else
261
+ results[:failed] += 1
262
+ end
263
+
264
+ # Test deleting the webhook
265
+ deleted = test("Delete test webhook") do
266
+ created_webhook.delete
267
+ true
268
+ end
269
+
270
+ if deleted
271
+ results[:passed] += 1
272
+ puts " Successfully deleted webhook #{created_webhook.id}"
273
+
274
+ # Verify deletion
275
+ verify_deleted = test("Verify webhook was deleted") do
276
+ Fathom::Webhook.retrieve(created_webhook.id)
277
+ raise "Webhook still exists!"
278
+ rescue Fathom::NotFoundError
279
+ true
280
+ end
281
+
282
+ if verify_deleted
283
+ results[:passed] += 1
284
+ else
285
+ results[:failed] += 1
286
+ end
287
+ else
288
+ results[:failed] += 1
289
+ end
290
+ elsif created_webhook == :not_available
291
+ results[:skipped] += 4 # Skip create, retrieve, delete, and verify tests
292
+ else
293
+ results[:failed] += 1
294
+ end
295
+
296
+ # =============================================================================
297
+ # Test: Error Handling
298
+ # =============================================================================
299
+ section "5. Testing Error Handling"
300
+
301
+ test("Handle invalid meeting ID (404)") do
302
+ Fathom::Meeting.retrieve("invalid_id_that_does_not_exist_12345")
303
+ raise "Should have raised NotFoundError"
304
+ rescue Fathom::NotFoundError
305
+ true
306
+ end
307
+ results[:passed] += 1
308
+
309
+ # =============================================================================
310
+ # Test: Rate Limiting
311
+ # =============================================================================
312
+ section "6. Testing Rate Limiting"
313
+
314
+ test("Check rate limit headers") do
315
+ Fathom::Meeting.all(limit: 1)
316
+ rate_limiter = Fathom::Client.new.instance_variable_get(:@rate_limiter)
317
+ info = rate_limiter.to_h
318
+
319
+ puts "\n Rate limit status:"
320
+ if info[:limit].nil?
321
+ puts yellow(" No rate limit headers present in API response")
322
+ else
323
+ puts " Limit: #{info[:limit]}"
324
+ puts " Remaining: #{info[:remaining]}"
325
+ puts " Reset: #{info[:reset]}s"
326
+ end
327
+
328
+ true
329
+ end
330
+ results[:passed] += 1
331
+
332
+ # =============================================================================
333
+ # Test: Pagination
334
+ # =============================================================================
335
+ section "7. Testing Pagination"
336
+
337
+ paginated_meetings = test("Fetch meetings with pagination") do
338
+ Fathom::Meeting.all(limit: 2)
339
+ end
340
+
341
+ if paginated_meetings
342
+ results[:passed] += 1
343
+ puts " Retrieved #{paginated_meetings.count} meeting(s) with limit=2"
344
+
345
+ if paginated_meetings.respond_to?(:next_cursor)
346
+ puts " Next cursor available: #{paginated_meetings.next_cursor ? "Yes" : "No"}"
347
+ end
348
+ else
349
+ results[:failed] += 1
350
+ end
351
+
352
+ # =============================================================================
353
+ # Summary
354
+ # =============================================================================
355
+ section "Test Results Summary"
356
+
357
+ total = results[:passed] + results[:failed] + results[:skipped]
358
+ pass_rate = total.positive? ? (results[:passed].to_f / total * 100).round(1) : 0
359
+
360
+ puts "\n #{green("Passed:")} #{results[:passed]}"
361
+ puts " #{red("Failed:")} #{results[:failed]}"
362
+ puts " #{yellow("Skipped:")} #{results[:skipped]}"
363
+ puts " #{blue("Total:")} #{total}"
364
+ puts "\n Pass Rate: #{pass_rate}%"
365
+
366
+ if results[:failed].zero?
367
+ puts "\n#{green("\u2713 All tests passed!")}"
368
+ exit 0
369
+ else
370
+ puts "\n#{red("\u2717 Some tests failed. Please review the output above.")}"
371
+ exit 1
372
+ end
373
+
374
+ # rubocop:enable Metrics/BlockNesting
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fathom-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Juan Rodriguez
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A comprehensive Ruby gem for interacting with the Fathom API, supporting
13
+ meetings, recordings, teams, webhooks, and more.
14
+ email:
15
+ - jrodriguez@example.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rspec"
21
+ - ".rubocop.yml"
22
+ - CHANGELOG.md
23
+ - CODE_OF_CONDUCT.md
24
+ - Gemfile
25
+ - LICENSE
26
+ - README.md
27
+ - Rakefile
28
+ - TESTING.md
29
+ - fathom-ruby.gemspec
30
+ - lib/fathom.rb
31
+ - lib/fathom/client.rb
32
+ - lib/fathom/errors.rb
33
+ - lib/fathom/rate_limiter.rb
34
+ - lib/fathom/resource.rb
35
+ - lib/fathom/resources/meeting.rb
36
+ - lib/fathom/resources/recording.rb
37
+ - lib/fathom/resources/team.rb
38
+ - lib/fathom/resources/team_member.rb
39
+ - lib/fathom/resources/webhook.rb
40
+ - lib/fathom/version.rb
41
+ - scripts/README.md
42
+ - scripts/test_live_api.rb
43
+ homepage: https://github.com/yourusername/fathom-ruby
44
+ licenses:
45
+ - MIT
46
+ metadata:
47
+ homepage_uri: https://github.com/yourusername/fathom-ruby
48
+ source_code_uri: https://github.com/yourusername/fathom-ruby
49
+ changelog_uri: https://github.com/yourusername/fathom-ruby/blob/main/CHANGELOG.md
50
+ rubygems_mfa_required: 'true'
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 3.1.0
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.6.9
66
+ specification_version: 4
67
+ summary: Ruby library for the Fathom API
68
+ test_files: []