attio 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +39 -15
  3. data/.github/workflows/coverage.yml +67 -0
  4. data/.github/workflows/pr_checks.yml +25 -7
  5. data/.github/workflows/release.yml +27 -13
  6. data/.github/workflows/tests.yml +67 -0
  7. data/.rubocop.yml +362 -90
  8. data/CHANGELOG.md +49 -1
  9. data/CONCEPTS.md +428 -0
  10. data/CONTRIBUTING.md +4 -4
  11. data/Gemfile +8 -5
  12. data/Gemfile.lock +4 -4
  13. data/README.md +164 -2
  14. data/Rakefile +8 -6
  15. data/attio.gemspec +6 -7
  16. data/danger/Dangerfile +22 -34
  17. data/docs/example.rb +30 -29
  18. data/examples/advanced_filtering.rb +178 -0
  19. data/examples/basic_usage.rb +110 -0
  20. data/examples/collaboration_example.rb +173 -0
  21. data/examples/full_workflow.rb +348 -0
  22. data/examples/notes_and_tasks.rb +200 -0
  23. data/lib/attio/client.rb +67 -29
  24. data/lib/attio/connection_pool.rb +26 -14
  25. data/lib/attio/errors.rb +4 -2
  26. data/lib/attio/http_client.rb +70 -41
  27. data/lib/attio/logger.rb +37 -27
  28. data/lib/attio/resources/attributes.rb +12 -5
  29. data/lib/attio/resources/base.rb +66 -27
  30. data/lib/attio/resources/comments.rb +147 -0
  31. data/lib/attio/resources/lists.rb +21 -24
  32. data/lib/attio/resources/notes.rb +110 -0
  33. data/lib/attio/resources/objects.rb +11 -4
  34. data/lib/attio/resources/records.rb +49 -67
  35. data/lib/attio/resources/tasks.rb +131 -0
  36. data/lib/attio/resources/threads.rb +154 -0
  37. data/lib/attio/resources/users.rb +10 -4
  38. data/lib/attio/resources/workspaces.rb +9 -1
  39. data/lib/attio/retry_handler.rb +19 -11
  40. data/lib/attio/version.rb +3 -1
  41. data/lib/attio.rb +15 -9
  42. metadata +13 -18
  43. data/run_tests.rb +0 -52
  44. data/test_basic.rb +0 -51
  45. data/test_typhoeus.rb +0 -31
@@ -1,41 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Handles all record-related API operations.
4
+ #
5
+ # Records are the main data entities in Attio, representing things like
6
+ # people, companies, deals, etc. This class provides methods to create,
7
+ # read, update, delete, and query records.
8
+ #
9
+ # @example List records
10
+ # records = client.records.list(object: 'people', filters: { name: 'John' })
11
+ #
12
+ # @example Create a record
13
+ # record = client.records.create(
14
+ # object: 'people',
15
+ # data: { name: 'Jane Doe', email: 'jane@example.com' }
16
+ # )
17
+ #
18
+ # @author Ernest Sim
19
+ # @since 1.0.0
1
20
  module Attio
2
21
  module Resources
3
- # Handles all record-related API operations.
4
- #
5
- # Records are the main data entities in Attio, representing things like
6
- # people, companies, deals, etc. This class provides methods to create,
7
- # read, update, delete, and query records.
8
- #
9
- # @example List records
10
- # records = client.records.list(object: 'people', filters: { name: 'John' })
11
- #
12
- # @example Create a record
13
- # record = client.records.create(
14
- # object: 'people',
15
- # data: { name: 'Jane Doe', email: 'jane@example.com' }
16
- # )
17
- #
18
- # @author Ernest Sim
19
- # @since 1.0.0
20
22
  class Records < Base
21
23
  # Query and list records for a specific object type.
22
- #
24
+ #
23
25
  # This method allows you to retrieve records with optional filtering,
24
26
  # sorting, and pagination parameters.
25
- #
27
+ #
26
28
  # @param object [String] The object type to query (e.g., 'people', 'companies')
27
29
  # @param params [Hash] Query parameters including filters, sorts, and pagination
28
30
  # @option params [Hash] :filters Filtering criteria
29
31
  # @option params [Array] :sorts Sorting options
30
32
  # @option params [Integer] :limit Number of records to return
31
33
  # @option params [String] :cursor Pagination cursor for next page
32
- #
34
+ #
33
35
  # @return [Hash] API response containing records and pagination info
34
36
  # @raise [ArgumentError] if object is nil or empty
35
- #
37
+ #
36
38
  # @example Basic listing
37
39
  # records = client.records.list(object: 'people')
38
- #
40
+ #
39
41
  # @example With filters
40
42
  # records = client.records.list(
41
43
  # object: 'people',
@@ -43,34 +45,34 @@ module Attio
43
45
  # limit: 50
44
46
  # )
45
47
  def list(object:, **params)
46
- validate_object!(object)
48
+ validate_required_string!(object, "Object type")
47
49
  request(:post, "objects/#{object}/records/query", params)
48
50
  end
49
51
 
50
52
  # Retrieve a specific record by ID.
51
- #
53
+ #
52
54
  # @param object [String] The object type (e.g., 'people', 'companies')
53
55
  # @param id [String] The record ID
54
- #
56
+ #
55
57
  # @return [Hash] The record data
56
58
  # @raise [ArgumentError] if object or id is nil or empty
57
- #
59
+ #
58
60
  # @example
59
61
  # record = client.records.get(object: 'people', id: 'abc123')
60
62
  def get(object:, id:)
61
- validate_object!(object)
62
- validate_id!(id)
63
+ validate_required_string!(object, "Object type")
64
+ validate_id!(id, "Record")
63
65
  request(:get, "objects/#{object}/records/#{id}")
64
66
  end
65
67
 
66
68
  # Create a new record.
67
- #
69
+ #
68
70
  # @param object [String] The object type to create the record in
69
71
  # @param data [Hash] The record data to create
70
- #
72
+ #
71
73
  # @return [Hash] The created record data
72
74
  # @raise [ArgumentError] if object is nil/empty or data is invalid
73
- #
75
+ #
74
76
  # @example Create a person
75
77
  # record = client.records.create(
76
78
  # object: 'people',
@@ -81,20 +83,20 @@ module Attio
81
83
  # }
82
84
  # )
83
85
  def create(object:, data:)
84
- validate_object!(object)
85
- validate_data!(data)
86
+ validate_required_string!(object, "Object type")
87
+ validate_record_data!(data)
86
88
  request(:post, "objects/#{object}/records", data)
87
89
  end
88
90
 
89
91
  # Update an existing record.
90
- #
92
+ #
91
93
  # @param object [String] The object type
92
94
  # @param id [String] The record ID to update
93
95
  # @param data [Hash] The updated record data
94
- #
96
+ #
95
97
  # @return [Hash] The updated record data
96
98
  # @raise [ArgumentError] if object, id, or data is invalid
97
- #
99
+ #
98
100
  # @example Update a person's name
99
101
  # record = client.records.update(
100
102
  # object: 'people',
@@ -102,57 +104,37 @@ module Attio
102
104
  # data: { name: 'Jane Smith' }
103
105
  # )
104
106
  def update(object:, id:, data:)
105
- validate_object!(object)
106
- validate_id!(id)
107
- validate_data!(data)
107
+ validate_required_string!(object, "Object type")
108
+ validate_id!(id, "Record")
109
+ validate_record_data!(data)
108
110
  request(:patch, "objects/#{object}/records/#{id}", data)
109
111
  end
110
112
 
111
113
  # Delete a record.
112
- #
114
+ #
113
115
  # @param object [String] The object type
114
116
  # @param id [String] The record ID to delete
115
- #
117
+ #
116
118
  # @return [Hash] Deletion confirmation
117
119
  # @raise [ArgumentError] if object or id is nil or empty
118
- #
120
+ #
119
121
  # @example
120
122
  # client.records.delete(object: 'people', id: 'abc123')
121
123
  def delete(object:, id:)
122
- validate_object!(object)
123
- validate_id!(id)
124
+ validate_required_string!(object, "Object type")
125
+ validate_id!(id, "Record")
124
126
  request(:delete, "objects/#{object}/records/#{id}")
125
127
  end
126
128
 
127
- private
128
-
129
- # Validates that the object parameter is present and not empty.
130
- #
131
- # @param object [String, nil] The object type to validate
132
- # @raise [ArgumentError] if object is nil or empty
133
- # @api private
134
- def validate_object!(object)
135
- raise ArgumentError, "Object type is required" if object.nil? || object.to_s.strip.empty?
136
- end
137
-
138
- # Validates that the ID parameter is present and not empty.
139
- #
140
- # @param id [String, nil] The record ID to validate
141
- # @raise [ArgumentError] if id is nil or empty
142
- # @api private
143
- def validate_id!(id)
144
- raise ArgumentError, "Record ID is required" if id.nil? || id.to_s.strip.empty?
145
- end
146
-
147
129
  # Validates that the data parameter is present and is a hash.
148
- #
130
+ #
149
131
  # @param data [Hash, nil] The data to validate
150
132
  # @raise [ArgumentError] if data is nil or not a hash
151
133
  # @api private
152
- def validate_data!(data)
134
+ private def validate_record_data!(data)
153
135
  raise ArgumentError, "Data is required" if data.nil?
154
136
  raise ArgumentError, "Data must be a hash" unless data.is_a?(Hash)
155
137
  end
156
138
  end
157
139
  end
158
- end
140
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Attio
4
+ module Resources
5
+ # API resource for managing tasks in Attio
6
+ #
7
+ # Tasks help track action items and to-dos associated with records.
8
+ #
9
+ # @example Creating a task
10
+ # client.tasks.create(
11
+ # parent_object: "people",
12
+ # parent_record_id: "person_123",
13
+ # title: "Follow up on proposal",
14
+ # due_date: "2025-02-01",
15
+ # assignee_id: "user_456"
16
+ # )
17
+ #
18
+ # @example Listing tasks with filters
19
+ # client.tasks.list(
20
+ # status: "pending",
21
+ # assignee_id: "user_456"
22
+ # )
23
+ class Tasks < Base
24
+ # List tasks with optional filters
25
+ #
26
+ # @param params [Hash] Query parameters
27
+ # @option params [String] :parent_object Filter by parent object type
28
+ # @option params [String] :parent_record_id Filter by parent record
29
+ # @option params [String] :status Filter by status (pending, completed)
30
+ # @option params [String] :assignee_id Filter by assignee
31
+ # @option params [Integer] :limit Number of tasks to return
32
+ # @option params [String] :cursor Pagination cursor
33
+ #
34
+ # @return [Hash] API response containing tasks
35
+ def list(**params)
36
+ request(:get, "tasks", params)
37
+ end
38
+
39
+ # Get a specific task by ID
40
+ #
41
+ # @param id [String] The task ID
42
+ #
43
+ # @return [Hash] The task data
44
+ # @raise [ArgumentError] if id is nil or empty
45
+ def get(id:)
46
+ validate_id!(id, "Task")
47
+ request(:get, "tasks/#{id}")
48
+ end
49
+
50
+ # Create a new task
51
+ #
52
+ # @param parent_object [String] The parent object type
53
+ # @param parent_record_id [String] The ID of the parent record
54
+ # @param title [String] The task title
55
+ # @param data [Hash] Additional task data
56
+ # @option data [String] :description Task description
57
+ # @option data [String] :due_date Due date (ISO 8601 format)
58
+ # @option data [String] :assignee_id User ID to assign the task to
59
+ # @option data [String] :status Task status (pending, completed)
60
+ # @option data [Integer] :priority Task priority (1-5)
61
+ #
62
+ # @return [Hash] The created task
63
+ # @raise [ArgumentError] if required parameters are missing
64
+ def create(parent_object:, parent_record_id:, title:, **data)
65
+ validate_parent!(parent_object, parent_record_id)
66
+ validate_required_string!(title, "Task title")
67
+
68
+ request(:post, "tasks", data.merge(
69
+ parent_object: parent_object,
70
+ parent_record_id: parent_record_id,
71
+ title: title
72
+ ))
73
+ end
74
+
75
+ # Update an existing task
76
+ #
77
+ # @param id [String] The task ID
78
+ # @param data [Hash] The fields to update
79
+ # @option data [String] :title New title
80
+ # @option data [String] :description New description
81
+ # @option data [String] :due_date New due date
82
+ # @option data [String] :assignee_id New assignee
83
+ # @option data [String] :status New status
84
+ # @option data [Integer] :priority New priority
85
+ #
86
+ # @return [Hash] The updated task
87
+ # @raise [ArgumentError] if id is invalid
88
+ def update(id:, **data)
89
+ validate_id!(id, "Task")
90
+ validate_data!(data, "Update")
91
+ request(:patch, "tasks/#{id}", data)
92
+ end
93
+
94
+ # Mark a task as completed
95
+ #
96
+ # @param id [String] The task ID
97
+ # @param completed_at [String] Optional completion timestamp (defaults to now)
98
+ #
99
+ # @return [Hash] The updated task
100
+ # @raise [ArgumentError] if id is nil or empty
101
+ def complete(id:, completed_at: nil)
102
+ validate_id!(id, "Task")
103
+ data = { status: "completed" }
104
+ data[:completed_at] = completed_at if completed_at
105
+ request(:patch, "tasks/#{id}", data)
106
+ end
107
+
108
+ # Reopen a completed task
109
+ #
110
+ # @param id [String] The task ID
111
+ #
112
+ # @return [Hash] The updated task
113
+ # @raise [ArgumentError] if id is nil or empty
114
+ def reopen(id:)
115
+ validate_id!(id, "Task")
116
+ request(:patch, "tasks/#{id}", { status: "pending", completed_at: nil })
117
+ end
118
+
119
+ # Delete a task
120
+ #
121
+ # @param id [String] The task ID to delete
122
+ #
123
+ # @return [Hash] Deletion confirmation
124
+ # @raise [ArgumentError] if id is nil or empty
125
+ def delete(id:)
126
+ validate_id!(id, "Task")
127
+ request(:delete, "tasks/#{id}")
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Attio
4
+ module Resources
5
+ # API resource for managing threads in Attio
6
+ #
7
+ # Threads represent conversations or discussion topics related to records.
8
+ #
9
+ # @example Listing threads for a record
10
+ # client.threads.list(
11
+ # parent_object: "companies",
12
+ # parent_record_id: "company_123"
13
+ # )
14
+ #
15
+ # @example Getting a specific thread
16
+ # client.threads.get(id: "thread_456")
17
+ class Threads < Base
18
+ # List threads for a parent record
19
+ #
20
+ # @param parent_object [String] The parent object type
21
+ # @param parent_record_id [String] The parent record ID
22
+ # @param params [Hash] Additional query parameters
23
+ # @option params [Integer] :limit Number of threads to return
24
+ # @option params [String] :cursor Pagination cursor
25
+ # @option params [String] :status Filter by status (open, closed)
26
+ #
27
+ # @return [Hash] API response containing threads
28
+ # @raise [ArgumentError] if parent_object or parent_record_id is missing
29
+ def list(parent_object:, parent_record_id:, **params)
30
+ validate_parent!(parent_object, parent_record_id)
31
+ request(:get, "threads", params.merge(
32
+ parent_object: parent_object,
33
+ parent_record_id: parent_record_id
34
+ ))
35
+ end
36
+
37
+ # Get a specific thread by ID
38
+ #
39
+ # @param id [String] The thread ID
40
+ # @param include_comments [Boolean] Whether to include comments in the response
41
+ #
42
+ # @return [Hash] The thread data
43
+ # @raise [ArgumentError] if id is nil or empty
44
+ def get(id:, include_comments: false)
45
+ validate_id!(id, "Thread")
46
+ params = include_comments ? { include: "comments" } : {}
47
+ request(:get, "threads/#{id}", params)
48
+ end
49
+
50
+ # Create a new thread
51
+ #
52
+ # @param parent_object [String] The parent object type
53
+ # @param parent_record_id [String] The parent record ID
54
+ # @param title [String] The thread title
55
+ # @param data [Hash] Additional thread data
56
+ # @option data [String] :description Thread description
57
+ # @option data [String] :status Thread status (open, closed)
58
+ # @option data [Array<String>] :participant_ids User IDs of participants
59
+ #
60
+ # @return [Hash] The created thread
61
+ # @raise [ArgumentError] if required parameters are missing
62
+ def create(parent_object:, parent_record_id:, title:, **data)
63
+ validate_parent!(parent_object, parent_record_id)
64
+ validate_required_string!(title, "Thread title")
65
+
66
+ request(:post, "threads", data.merge(
67
+ parent_object: parent_object,
68
+ parent_record_id: parent_record_id,
69
+ title: title
70
+ ))
71
+ end
72
+
73
+ # Update an existing thread
74
+ #
75
+ # @param id [String] The thread ID
76
+ # @param data [Hash] The fields to update
77
+ # @option data [String] :title New title
78
+ # @option data [String] :description New description
79
+ # @option data [String] :status New status (open, closed)
80
+ #
81
+ # @return [Hash] The updated thread
82
+ # @raise [ArgumentError] if id is invalid
83
+ def update(id:, **data)
84
+ validate_id!(id, "Thread")
85
+ validate_data!(data, "Update")
86
+ request(:patch, "threads/#{id}", data)
87
+ end
88
+
89
+ # Close a thread
90
+ #
91
+ # @param id [String] The thread ID
92
+ #
93
+ # @return [Hash] The updated thread
94
+ # @raise [ArgumentError] if id is nil or empty
95
+ def close(id:)
96
+ validate_id!(id, "Thread")
97
+ request(:patch, "threads/#{id}", { status: "closed" })
98
+ end
99
+
100
+ # Reopen a closed thread
101
+ #
102
+ # @param id [String] The thread ID
103
+ #
104
+ # @return [Hash] The updated thread
105
+ # @raise [ArgumentError] if id is nil or empty
106
+ def reopen(id:)
107
+ validate_id!(id, "Thread")
108
+ request(:patch, "threads/#{id}", { status: "open" })
109
+ end
110
+
111
+ # Delete a thread
112
+ #
113
+ # @param id [String] The thread ID to delete
114
+ #
115
+ # @return [Hash] Deletion confirmation
116
+ # @raise [ArgumentError] if id is nil or empty
117
+ def delete(id:)
118
+ validate_id!(id, "Thread")
119
+ request(:delete, "threads/#{id}")
120
+ end
121
+
122
+ # Add participants to a thread
123
+ #
124
+ # @param id [String] The thread ID
125
+ # @param user_ids [Array<String>] User IDs to add as participants
126
+ #
127
+ # @return [Hash] The updated thread
128
+ # @raise [ArgumentError] if id or user_ids is invalid
129
+ def add_participants(id:, user_ids:)
130
+ validate_id!(id, "Thread")
131
+ validate_user_ids!(user_ids)
132
+ request(:post, "threads/#{id}/participants", { user_ids: user_ids })
133
+ end
134
+
135
+ # Remove participants from a thread
136
+ #
137
+ # @param id [String] The thread ID
138
+ # @param user_ids [Array<String>] User IDs to remove
139
+ #
140
+ # @return [Hash] The updated thread
141
+ # @raise [ArgumentError] if id or user_ids is invalid
142
+ def remove_participants(id:, user_ids:)
143
+ validate_id!(id, "Thread")
144
+ validate_user_ids!(user_ids)
145
+ request(:delete, "threads/#{id}/participants", { user_ids: user_ids })
146
+ end
147
+
148
+ private def validate_user_ids!(user_ids)
149
+ raise ArgumentError, "User IDs are required" if user_ids.nil? || user_ids.empty?
150
+ raise ArgumentError, "User IDs must be an array" unless user_ids.is_a?(Array)
151
+ end
152
+ end
153
+ end
154
+ end
@@ -1,5 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Attio
2
4
  module Resources
5
+ # API resource for managing workspace users
6
+ #
7
+ # Users are people who have access to your Attio workspace.
8
+ #
9
+ # @example Listing all users
10
+ # client.users.list
3
11
  class Users < Base
4
12
  def list(**params)
5
13
  request(:get, "users", params)
@@ -10,11 +18,9 @@ module Attio
10
18
  request(:get, "users/#{id}")
11
19
  end
12
20
 
13
- private
14
-
15
- def validate_id!(id)
21
+ private def validate_id!(id)
16
22
  raise ArgumentError, "User ID is required" if id.nil? || id.to_s.strip.empty?
17
23
  end
18
24
  end
19
25
  end
20
- end
26
+ end
@@ -1,5 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Attio
2
4
  module Resources
5
+ # API resource for managing workspace information
6
+ #
7
+ # Workspaces are the top-level organizational unit in Attio.
8
+ #
9
+ # @example Getting workspace information
10
+ # client.workspaces.get
3
11
  class Workspaces < Base
4
12
  def get
5
13
  request(:get, "workspace")
@@ -10,4 +18,4 @@ module Attio
10
18
  end
11
19
  end
12
20
  end
13
- end
21
+ end
@@ -1,4 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Attio
4
+ # Handles automatic retry logic for failed API requests
5
+ #
6
+ # This class implements exponential backoff retry strategy for
7
+ # transient errors like timeouts and rate limits.
8
+ #
9
+ # @example Using the retry handler
10
+ # handler = RetryHandler.new(max_retries: 5)
11
+ # handler.with_retry { api_client.get("/endpoint") }
2
12
  class RetryHandler
3
13
  DEFAULT_MAX_RETRIES = 3
4
14
  DEFAULT_RETRY_DELAY = 1 # seconds
@@ -7,12 +17,12 @@ module Attio
7
17
  HttpClient::TimeoutError,
8
18
  HttpClient::ConnectionError,
9
19
  ServerError,
10
- RateLimitError
20
+ RateLimitError,
11
21
  ].freeze
12
22
 
13
23
  attr_reader :max_retries, :retry_delay, :backoff_factor, :logger
14
24
 
15
- def initialize(max_retries: DEFAULT_MAX_RETRIES,
25
+ def initialize(max_retries: DEFAULT_MAX_RETRIES,
16
26
  retry_delay: DEFAULT_RETRY_DELAY,
17
27
  backoff_factor: DEFAULT_BACKOFF_FACTOR,
18
28
  logger: nil)
@@ -22,7 +32,7 @@ module Attio
22
32
  @logger = logger
23
33
  end
24
34
 
25
- def with_retry(&block)
35
+ def with_retry
26
36
  retries = 0
27
37
  delay = retry_delay
28
38
 
@@ -30,7 +40,7 @@ module Attio
30
40
  yield
31
41
  rescue *RETRIABLE_ERRORS => e
32
42
  retries += 1
33
-
43
+
34
44
  if retries <= max_retries
35
45
  log_retry(e, retries, delay)
36
46
  sleep(delay)
@@ -43,11 +53,9 @@ module Attio
43
53
  end
44
54
  end
45
55
 
46
- private
47
-
48
- def log_retry(error, attempt, delay)
56
+ private def log_retry(error, attempt, delay)
49
57
  return unless logger
50
-
58
+
51
59
  logger.warn(
52
60
  "Retry attempt #{attempt}/#{max_retries}",
53
61
  error: error.class.name,
@@ -56,9 +64,9 @@ module Attio
56
64
  )
57
65
  end
58
66
 
59
- def log_failure(error, attempts)
67
+ private def log_failure(error, attempts)
60
68
  return unless logger
61
-
69
+
62
70
  logger.error(
63
71
  "Max retries exceeded",
64
72
  error: error.class.name,
@@ -67,4 +75,4 @@ module Attio
67
75
  )
68
76
  end
69
77
  end
70
- end
78
+ end
data/lib/attio/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Attio
2
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
3
5
  end
data/lib/attio.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "typhoeus"
2
4
 
3
5
  require "attio/version"
@@ -12,34 +14,38 @@ require "attio/resources/lists"
12
14
  require "attio/resources/workspaces"
13
15
  require "attio/resources/attributes"
14
16
  require "attio/resources/users"
17
+ require "attio/resources/notes"
18
+ require "attio/resources/tasks"
19
+ require "attio/resources/comments"
20
+ require "attio/resources/threads"
15
21
 
16
22
  # The main Attio module provides access to the Attio API client.
17
- #
23
+ #
18
24
  # This is the primary entry point for interacting with the Attio API.
19
- #
25
+ #
20
26
  # @example Basic usage
21
27
  # client = Attio.client(api_key: 'your-api-key')
22
- #
28
+ #
23
29
  # @example Working with records
24
30
  # # List records for a specific object type
25
31
  # records = client.records.list(object: 'people', filters: { name: 'John' })
26
- #
32
+ #
27
33
  # # Create a new record
28
34
  # new_record = client.records.create(
29
35
  # object: 'people',
30
36
  # data: { name: 'Jane Doe', email: 'jane@example.com' }
31
37
  # )
32
- #
38
+ #
33
39
  # # Get a specific record
34
40
  # record = client.records.get(object: 'people', id: 'record-id')
35
- #
41
+ #
36
42
  # # Update a record
37
43
  # updated = client.records.update(
38
44
  # object: 'people',
39
45
  # id: 'record-id',
40
46
  # data: { name: 'Jane Smith' }
41
47
  # )
42
- #
48
+ #
43
49
  # # Delete a record
44
50
  # client.records.delete(object: 'people', id: 'record-id')
45
51
  #
@@ -47,11 +53,11 @@ require "attio/resources/users"
47
53
  # @since 1.0.0
48
54
  module Attio
49
55
  # Creates a new Attio API client instance.
50
- #
56
+ #
51
57
  # @param api_key [String] Your Attio API key
52
58
  # @return [Client] A new client instance configured with the provided API key
53
59
  # @raise [ArgumentError] if api_key is nil or empty
54
- #
60
+ #
55
61
  # @example Create a client
56
62
  # client = Attio.client(api_key: 'your-api-key-here')
57
63
  def self.client(api_key:)