@forge/teamwork-graph 2.0.0-next.7 → 2.1.0-next.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 (121) hide show
  1. package/README.md +289 -174
  2. package/out/__test__/entity-operations.test.js +468 -420
  3. package/out/__test__/error-handling.test.js +9 -9
  4. package/out/__test__/validators.test.js +43 -43
  5. package/out/graph.d.ts +5 -5
  6. package/out/graph.d.ts.map +1 -1
  7. package/out/graph.js +19 -19
  8. package/out/types/graph.d.ts +5 -5
  9. package/out/types/graph.d.ts.map +1 -1
  10. package/out/types/index.d.ts +2 -2
  11. package/out/types/index.d.ts.map +1 -1
  12. package/out/types/index.js +2 -2
  13. package/out/types/objects/branch.d.ts +14 -0
  14. package/out/types/objects/branch.d.ts.map +1 -0
  15. package/out/types/{entities → objects}/build.d.ts +3 -3
  16. package/out/types/objects/build.d.ts.map +1 -0
  17. package/out/types/{entities → objects}/calendar-event.d.ts +3 -3
  18. package/out/types/objects/calendar-event.d.ts.map +1 -0
  19. package/out/types/{entities → objects}/comment.d.ts +4 -4
  20. package/out/types/objects/comment.d.ts.map +1 -0
  21. package/out/types/{entities → objects}/commit.d.ts +3 -3
  22. package/out/types/objects/commit.d.ts.map +1 -0
  23. package/out/types/{common.d.ts → objects/common.d.ts} +7 -10
  24. package/out/types/objects/common.d.ts.map +1 -0
  25. package/out/types/{entities → objects}/conversation.d.ts +3 -3
  26. package/out/types/objects/conversation.d.ts.map +1 -0
  27. package/out/types/{entities → objects}/customer-org.d.ts +3 -3
  28. package/out/types/objects/customer-org.d.ts.map +1 -0
  29. package/out/types/{entities → objects}/deal.d.ts +3 -3
  30. package/out/types/objects/deal.d.ts.map +1 -0
  31. package/out/types/{entities → objects}/deployment.d.ts +3 -3
  32. package/out/types/objects/deployment.d.ts.map +1 -0
  33. package/out/types/{entities → objects}/design.d.ts +3 -3
  34. package/out/types/objects/design.d.ts.map +1 -0
  35. package/out/types/{entities → objects}/document.d.ts +3 -3
  36. package/out/types/objects/document.d.ts.map +1 -0
  37. package/out/types/objects/index.d.ts +26 -0
  38. package/out/types/objects/index.d.ts.map +1 -0
  39. package/out/types/{entities → objects}/message.d.ts +3 -3
  40. package/out/types/objects/message.d.ts.map +1 -0
  41. package/out/types/objects/organisation.d.ts +9 -0
  42. package/out/types/objects/organisation.d.ts.map +1 -0
  43. package/out/types/{entities → objects}/position.d.ts +3 -3
  44. package/out/types/objects/position.d.ts.map +1 -0
  45. package/out/types/{entities → objects}/project.d.ts +4 -4
  46. package/out/types/objects/project.d.ts.map +1 -0
  47. package/out/types/{entities → objects}/pull-request.d.ts +3 -3
  48. package/out/types/objects/pull-request.d.ts.map +1 -0
  49. package/out/types/{entities → objects}/remote-link.d.ts +3 -3
  50. package/out/types/objects/remote-link.d.ts.map +1 -0
  51. package/out/types/{entities → objects}/repository.d.ts +3 -3
  52. package/out/types/objects/repository.d.ts.map +1 -0
  53. package/out/types/{entities → objects}/software-service.d.ts +3 -3
  54. package/out/types/objects/software-service.d.ts.map +1 -0
  55. package/out/types/{entities → objects}/space.d.ts +3 -3
  56. package/out/types/objects/space.d.ts.map +1 -0
  57. package/out/types/{entities → objects}/video.d.ts +3 -3
  58. package/out/types/objects/video.d.ts.map +1 -0
  59. package/out/types/{entities → objects}/work-item.d.ts +3 -3
  60. package/out/types/objects/work-item.d.ts.map +1 -0
  61. package/out/types/{entities → objects}/worker.d.ts +3 -3
  62. package/out/types/objects/worker.d.ts.map +1 -0
  63. package/out/types/requests.d.ts +15 -15
  64. package/out/types/requests.d.ts.map +1 -1
  65. package/out/utils/validators.d.ts +6 -6
  66. package/out/utils/validators.d.ts.map +1 -1
  67. package/out/utils/validators.js +16 -16
  68. package/package.json +2 -2
  69. package/out/types/common.d.ts.map +0 -1
  70. package/out/types/entities/branch.d.ts +0 -14
  71. package/out/types/entities/branch.d.ts.map +0 -1
  72. package/out/types/entities/build.d.ts.map +0 -1
  73. package/out/types/entities/calendar-event.d.ts.map +0 -1
  74. package/out/types/entities/comment.d.ts.map +0 -1
  75. package/out/types/entities/commit.d.ts.map +0 -1
  76. package/out/types/entities/conversation.d.ts.map +0 -1
  77. package/out/types/entities/customer-org.d.ts.map +0 -1
  78. package/out/types/entities/deal.d.ts.map +0 -1
  79. package/out/types/entities/deployment.d.ts.map +0 -1
  80. package/out/types/entities/design.d.ts.map +0 -1
  81. package/out/types/entities/document.d.ts.map +0 -1
  82. package/out/types/entities/index.d.ts +0 -26
  83. package/out/types/entities/index.d.ts.map +0 -1
  84. package/out/types/entities/message.d.ts.map +0 -1
  85. package/out/types/entities/organisation.d.ts +0 -9
  86. package/out/types/entities/organisation.d.ts.map +0 -1
  87. package/out/types/entities/position.d.ts.map +0 -1
  88. package/out/types/entities/project.d.ts.map +0 -1
  89. package/out/types/entities/pull-request.d.ts.map +0 -1
  90. package/out/types/entities/remote-link.d.ts.map +0 -1
  91. package/out/types/entities/repository.d.ts.map +0 -1
  92. package/out/types/entities/software-service.d.ts.map +0 -1
  93. package/out/types/entities/space.d.ts.map +0 -1
  94. package/out/types/entities/video.d.ts.map +0 -1
  95. package/out/types/entities/work-item.d.ts.map +0 -1
  96. package/out/types/entities/worker.d.ts.map +0 -1
  97. /package/out/types/{entities → objects}/branch.js +0 -0
  98. /package/out/types/{entities → objects}/build.js +0 -0
  99. /package/out/types/{entities → objects}/calendar-event.js +0 -0
  100. /package/out/types/{entities → objects}/comment.js +0 -0
  101. /package/out/types/{entities → objects}/commit.js +0 -0
  102. /package/out/types/{common.js → objects/common.js} +0 -0
  103. /package/out/types/{entities → objects}/conversation.js +0 -0
  104. /package/out/types/{entities → objects}/customer-org.js +0 -0
  105. /package/out/types/{entities → objects}/deal.js +0 -0
  106. /package/out/types/{entities → objects}/deployment.js +0 -0
  107. /package/out/types/{entities → objects}/design.js +0 -0
  108. /package/out/types/{entities → objects}/document.js +0 -0
  109. /package/out/types/{entities → objects}/index.js +0 -0
  110. /package/out/types/{entities → objects}/message.js +0 -0
  111. /package/out/types/{entities → objects}/organisation.js +0 -0
  112. /package/out/types/{entities → objects}/position.js +0 -0
  113. /package/out/types/{entities → objects}/project.js +0 -0
  114. /package/out/types/{entities → objects}/pull-request.js +0 -0
  115. /package/out/types/{entities → objects}/remote-link.js +0 -0
  116. /package/out/types/{entities → objects}/repository.js +0 -0
  117. /package/out/types/{entities → objects}/software-service.js +0 -0
  118. /package/out/types/{entities → objects}/space.js +0 -0
  119. /package/out/types/{entities → objects}/video.js +0 -0
  120. /package/out/types/{entities → objects}/work-item.js +0 -0
  121. /package/out/types/{entities → objects}/worker.js +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Forge Graph Client
1
+ # Forge Teamwork Graph SDK
2
2
 
3
- A client for interacting with the Forge Graph API.
3
+ A TypeScript SDK for interacting with the Forge Teamwork Graph API, providing a clean interface for managing objects, users, groups, and data operations.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,243 +8,358 @@ A client for interacting with the Forge Graph API.
8
8
  npm install @forge/teamwork-graph
9
9
  ```
10
10
 
11
- ## Usage Examples
12
-
13
- ### Document Entity
11
+ ## Quick Start
14
12
 
15
13
  ```typescript
16
14
  import { graph } from '@forge/teamwork-graph';
17
- import type { EntityPayload, DocumentCategory } from '@forge/teamwork-graph';
18
-
15
+ import type { DocumentObject } from '@forge/teamwork-graph';
19
16
 
20
- const documentPayload: EntityPayload = {
21
- // Required base fields
17
+ // Create a document object
18
+ const document: DocumentObject = {
22
19
  schemaVersion: '1.0',
23
20
  id: 'doc-123',
24
21
  updateSequenceNumber: Date.now(),
25
- displayName: 'Project Requirements Doc',
22
+ displayName: 'Project Requirements',
26
23
  url: 'https://example.com/docs/requirements',
27
-
28
- // Optional base fields
29
24
  description: 'Project requirements and specifications',
30
25
  createdAt: new Date().toISOString(),
31
- createdBy: {
32
- accountId: 'acc-123',
33
- email: 'creator@example.com'
34
- },
35
26
  lastUpdatedAt: new Date().toISOString(),
36
- lastUpdatedBy: {
37
- accountId: 'acc-456',
38
- email: 'updater@example.com'
39
- },
40
-
41
- // Document ownership
42
- owners: [
27
+ permissions: [
43
28
  {
44
- accountId: 'acc-123',
45
- email: 'owner@example.com'
29
+ accessControls: [
30
+ {
31
+ principals: [
32
+ {
33
+ { type: 'USER', id: 'user-123' }
34
+ }
35
+ ]
36
+ }
37
+ ]
46
38
  }
47
39
  ],
40
+ 'atlassian:document': {
41
+ type: {
42
+ category: 'document',
43
+ mimeType: 'text/plain'
44
+ },
45
+ content: {
46
+ mimeType: 'text/plain',
47
+ text: 'Document content...'
48
+ }
49
+ }
50
+ };
48
51
 
49
- // Document preview
50
- thumbnail: {
51
- externalUrl: 'https://example.com/thumbnail.png'
52
- },
52
+ const result = await graph.setObjects({ objects: [document] });
53
53
 
54
- // Hierarchical relationships
55
- parentKey: {
56
- type: 'atlassian:document',
57
- value: {
58
- entityId: 'parent-folder-id'
59
- }
60
- },
61
- containerKey: {
62
- type: 'atlassian:space',
63
- value: {
64
- entityId: 'space-123'
65
- }
66
- },
54
+ if (result.success) {
55
+ console.log('Document created successfully:', result.results);
56
+ } else {
57
+ console.error('Failed to create document:', result.error);
58
+ // Access the original error for debugging
59
+ console.error('Original error:', result.originalError);
60
+ }
61
+ ```
67
62
 
68
- // Access control
69
- permissions: {
70
- accessControls: [
71
- {
72
- principals: [
73
- { type: 'USER', id: 'user-123' },
74
- { type: 'GROUP', id: 'group-456' },
75
- { type: 'EVERYONE' }
76
- ]
77
- }
78
- ],
79
- smartLinkViewedBy: [
80
- {
81
- principalUser: {
82
- type: 'USER',
83
- id: 'user-789'
84
- }
85
- }
86
- ]
87
- },
63
+ ## Core Operations
88
64
 
89
- // Relationships
90
- associations: {
91
- set: [
92
- {
93
- associationType: 'issueIdOrKeys',
94
- values: ['PROJ-123', 'PROJ-456']
95
- }
96
- ]
97
- },
65
+ ### Object Management
66
+
67
+ ```typescript
68
+ import { graph } from '@forge/teamwork-graph';
69
+ import type { DocumentObject } from '@forge/teamwork-graph';
98
70
 
99
- // Document-specific attributes
71
+ // Bulk create/update objects
72
+ const document: DocumentObject = {
73
+ schemaVersion: '1.0',
74
+ id: 'doc-123',
75
+ updateSequenceNumber: Date.now(),
76
+ displayName: 'Project Requirements',
77
+ url: 'https://example.com/docs/requirements',
78
+ createdAt: new Date().toISOString(),
79
+ lastUpdatedAt: new Date().toISOString(),
80
+ permissions: [
81
+ {
82
+ accessControls: [
83
+ {
84
+ principals: [
85
+ {
86
+ { type: 'USER', id: 'user-123' }
87
+ }
88
+ ]
89
+ }
90
+ ]
91
+ }
92
+ ],
100
93
  'atlassian:document': {
101
94
  type: {
102
95
  category: 'document',
103
- mimeType: 'text/plain',
104
- iconUrl: 'https://example.com/icon.png',
105
- fileExtension: 'txt'
96
+ mimeType: 'text/plain'
106
97
  },
107
98
  content: {
108
99
  mimeType: 'text/plain',
109
- text: 'Document content...',
110
- // binary: 'base64EncodedContent...' // Alternative to text
111
- },
112
- byteSize: 1234,
113
- exportLinks: [
114
- {
115
- mimeType: 'application/pdf',
116
- url: 'https://example.com/export/pdf'
117
- }
118
- ],
119
- collaborators: [
120
- { email: 'collaborator1@example.com' },
121
- { email: 'collaborator2@example.com' }
122
- ]
100
+ text: 'Document content...'
101
+ }
123
102
  }
124
103
  };
125
104
 
126
- // Send the document to the API - now with context parameter
127
- // context will be provided by the framework
128
- await graph.setEntity(context, documentPayload);
105
+ const bulkResult = await graph.setObjects({
106
+ objects: [document]
107
+ });
108
+
109
+ // Get object by external ID
110
+ const objectResult = await graph.getObjectByExternalId({
111
+ objectType: 'atlassian:document',
112
+ externalId: 'doc-123'
113
+ });
114
+
115
+ if (objectResult.success) {
116
+ console.log('Object found:', objectResult.object);
117
+ } else {
118
+ console.error('Object not found:', objectResult.error);
119
+ }
120
+
121
+ // Delete objects by external IDs
122
+ const deleteResult = await graph.deleteObjectsByExternalId({
123
+ objectType: 'atlassian:document',
124
+ externalIds: ['doc-123', 'doc-456']
125
+ });
126
+
127
+ // Delete objects by properties
128
+ const deleteByPropsResult = await graph.deleteObjectsByProperties({
129
+ environment: 'staging',
130
+ status: 'completed'
131
+ });
129
132
  ```
130
133
 
131
- ### Delete Operations
134
+ ### User Management
132
135
 
133
136
  ```typescript
137
+ import { graph } from '@forge/teamwork-graph';
138
+
139
+ // Bulk create/update users
140
+ const usersResult = await graph.setUsers({
141
+ users: [
142
+ {
143
+ externalId: 'user-123',
144
+ displayName: 'John Doe',
145
+ userName: 'johndoe',
146
+ name: {
147
+ formatted: 'John Doe',
148
+ familyName: 'Doe',
149
+ givenName: 'John'
150
+ },
151
+ emails: [
152
+ { value: 'john@example.com', primary: true }
153
+ ]
154
+ }
155
+ ]
156
+ });
134
157
 
135
- // Delete an entity - now with context parameter
136
- await graph.deleteEntity(context, 'entity-123');
158
+ // Get user by external ID
159
+ const userResult = await graph.getUserByExternalId({
160
+ externalId: 'user-123'
161
+ });
137
162
 
138
- // Delete a user - now with context parameter
139
- await graph.deleteUser(context, 'user-123');
163
+ // Delete users by external IDs
164
+ const deleteUsersResult = await graph.deleteUsersByExternalId({
165
+ externalIds: ['user-123', 'user-456']
166
+ });
140
167
 
141
- // Delete a group - now with context parameter
142
- await graph.deleteGroup(context, 'group-123');
168
+ // Map users to Atlassian accounts
169
+ const mapResult = await graph.mapUsers({
170
+ directMappings: [
171
+ {
172
+ externalId: 'user-123',
173
+ updateSequenceNumber: Date.now(),
174
+ updatedAt: Date.now(),
175
+ accountId: 'acc-123'
176
+ }
177
+ ]
178
+ });
143
179
  ```
144
180
 
145
- ### Fetch External Data
181
+ ### Group Management
146
182
 
147
183
  ```typescript
184
+ import { graph } from '@forge/teamwork-graph';
148
185
 
149
- // Define the request configuration
150
- const requestConfig = () => ({
151
- path: '/api/v1/tasks',
152
- method: 'GET',
153
- remoteKey: 'jira',
154
- url: 'https://your-instance.atlassian.net',
155
- headers: [
156
- { 'Authorization': 'Bearer your-token' }
186
+ // Bulk create/update groups
187
+ const groupsResult = await graph.setGroups({
188
+ groups: [
189
+ {
190
+ externalId: 'group-123',
191
+ displayName: 'Developers',
192
+ description: 'Development team'
193
+ }
157
194
  ]
158
195
  });
159
196
 
160
- // Define the result handler
161
- const handleResult = (data) => {
162
- console.log('Fetched data:', data);
163
- // Process the data as needed
164
- };
197
+ // Get group by external ID
198
+ const groupResult = await graph.getGroupByExternalId({
199
+ externalId: 'group-123'
200
+ });
165
201
 
166
- // Fetch and process the data
167
- await graph.fetchExternalData(context, requestConfig, handleResult);
202
+ // Delete groups by external IDs
203
+ const deleteGroupsResult = await graph.deleteGroupsByExternalId({
204
+ externalIds: ['group-123', 'group-456']
205
+ });
168
206
  ```
169
207
 
170
- ### Transform Data
208
+ ### Data Operations
171
209
 
172
210
  ```typescript
211
+ import { graph } from '@forge/teamwork-graph';
173
212
 
174
- // Define the raw data
175
- const rawData = {
176
- issues: [
177
- { key: 'PROJ-123', summary: 'Fix bug', assignee: { key: 'user1' } },
178
- { key: 'PROJ-456', summary: 'Add feature', assignee: { key: 'user2' } }
179
- ]
180
- };
181
-
182
- // Define the transform function
183
- const transformToEntities = (data) => {
184
- return data.issues.map(issue => ({
185
- id: issue.key,
186
- displayName: issue.summary,
187
- type: 'issue',
188
- assignee: issue.assignee.key
189
- }));
190
- };
213
+ // Fetch external data
214
+ const fetchResult = await graph.fetchData({
215
+ requestConfig: {
216
+ url: 'https://api.example.com/data',
217
+ method: 'GET',
218
+ headers: { 'Authorization': 'Bearer token' }
219
+ },
220
+ onResult: (data) => {
221
+ console.log('Data received:', data);
222
+ return data;
223
+ }
224
+ });
191
225
 
192
- // Transform the data
193
- const transformedData = await graph.transformData(context, rawData, transformToEntities);
226
+ // Transform data
227
+ const transformResult = await graph.transformData({
228
+ data: { items: [{ id: 1, name: 'Item 1' }] },
229
+ transformMethod: (data) => {
230
+ return data.items.map(item => ({
231
+ id: `doc-${item.id}`,
232
+ displayName: item.name,
233
+ // Additional object properties would be added here
234
+ }));
235
+ }
236
+ });
194
237
  ```
195
238
 
196
239
  ## Error Handling
197
240
 
198
- The client throws `ForgeGraphAPIError` for API errors. Error types include:
241
+ The SDK provides comprehensive error handling with consistent error responses and access to original error objects for debugging.
242
+
243
+ ### Error Response Structure
244
+
245
+ All operations return a response with this structure:
199
246
 
200
247
  ```typescript
201
- import { errorCodes } from '@forge/teamwork-graph';
202
-
203
- // Available error codes
204
- errorCodes.INVALID_REQUEST_BODY // 400 Bad Request
205
- errorCodes.INSUFFICIENT_SCOPE // 403 Forbidden
206
- errorCodes.TOO_MANY_REQUESTS // 429 Rate Limit
207
- errorCodes.UNKNOWN_ERROR // Other errors
208
-
209
- try {
210
- const context = { id: 'operation-123', cloudId: 'cloud-123' };
211
- await graph.setEntity(context, /* ... */);
212
- } catch (error) {
213
- if (error instanceof ForgeGraphAPIError) {
214
- console.error(error.code, error.message);
248
+ interface BaseResponse {
249
+ success: boolean;
250
+ error?: string;
251
+ originalError?: unknown;
252
+ }
253
+ ```
254
+
255
+ ### Error Types
256
+
257
+ The SDK uses specific error classes for different types of failures:
258
+
259
+ ```typescript
260
+ // Note: Error classes are not exported from the main package
261
+ // They are used internally by the SDK for error handling
262
+
263
+ // The SDK handles errors internally and returns them in the response
264
+ // You can access error information through the response object:
265
+
266
+ const result = await graph.setObjects({ objects: [] });
267
+
268
+ if (!result.success) {
269
+ console.error('Operation failed:', result.error);
270
+
271
+ // Access original error for debugging
272
+ if (result.originalError) {
273
+ console.error('Original error:', result.originalError);
215
274
  }
216
275
  }
217
276
  ```
218
277
 
219
- ## Available Types
278
+ ### Error Handling Examples
279
+
280
+ ```typescript
281
+ // Handle object operations
282
+ const result = await graph.getObjectByExternalId({
283
+ objectType: 'atlassian:document',
284
+ externalId: 'nonexistent'
285
+ });
286
+
287
+ if (!result.success) {
288
+ console.error('Operation failed:', result.error);
289
+
290
+ // Access original error for debugging
291
+ if (result.originalError) {
292
+ console.error('Original error details:', result.originalError);
293
+ }
294
+ }
295
+
296
+ // Handle validation errors (these are returned in the response)
297
+ const result = await graph.setObjects({
298
+ objects: [] // Empty array will return error in response
299
+ });
300
+
301
+ if (!result.success) {
302
+ console.error('Validation failed:', result.error);
303
+ }
304
+ ```
305
+
306
+ ## TypeScript Support
307
+
308
+ The SDK is fully typed with comprehensive TypeScript definitions:
220
309
 
221
310
  ```typescript
222
311
  import type {
223
- // Entity-related
224
- EntityPayload,
225
- DocumentAttributes,
226
- DocumentCategory,
227
- DocumentType,
228
- DocumentContent,
229
- ExportLink,
230
-
231
- // User and Group
232
- UserObject,
312
+ // Object types
313
+ Object,
314
+ DocumentObject,
315
+ SetObjectsRequest,
316
+ BulkObjectResponse,
317
+ GetObjectByExternalIdRequest,
318
+ GetObjectByExternalIdResponse,
319
+
320
+ // User types
321
+ User,
322
+ UserPayload,
323
+ BulkUsersRequest,
324
+ BulkUsersResponse,
325
+ GetUserByExternalIdRequest,
326
+ GetUserByExternalIdResponse,
327
+ MapUsersRequest,
328
+ MapUsersResponse,
329
+
330
+ // Group types
331
+ Group,
233
332
  GroupPayload,
234
-
235
- // Common types
236
- Permissions,
237
- AccessControl,
238
- Principal,
239
- Thumbnail,
333
+ BulkGroupsRequest,
334
+ BulkGroupsResponse,
335
+ GetGroupByExternalIdRequest,
336
+ GetGroupByExternalIdResponse,
240
337
 
241
- // Relationships
242
- ParentKeyObject,
243
- ContainerKeyObject,
244
- Associations,
245
- AssociationObject,
338
+ // Data operation types
339
+ FetchDataRequest,
340
+ FetchDataResponse,
341
+ TransformDataRequest,
342
+ TransformDataResponse,
246
343
 
247
- // Operations
248
- RequestConfig
344
+ // Common types
345
+ DeleteObjectsByExternalIdRequest,
346
+ DeleteObjectsByExternalIdResponse,
347
+ DeleteObjectsByPropertiesRequest,
348
+ DeleteObjectsByPropertiesResponse,
349
+ DeleteUsersByExternalIdRequest,
350
+ DeleteUsersByExternalIdResponse,
351
+ DeleteGroupsByExternalIdRequest,
352
+ DeleteGroupsByExternalIdResponse
249
353
  } from '@forge/teamwork-graph';
250
354
  ```
355
+
356
+ ## Configuration
357
+
358
+ The SDK automatically handles authentication and configuration through the Forge platform. No additional setup is required.
359
+
360
+ ## Best Practices
361
+
362
+ 1. **Always check success flag**: Verify `result.success` before accessing response data
363
+ 2. **Handle errors gracefully**: Use the `error` field for user-facing messages and `originalError` for debugging
364
+ 3. **Validate input**: The SDK will throw validation errors for invalid input, so handle them appropriately
365
+ 5. **Monitor rate limits**: The SDK handles rate limiting automatically, but monitor for `429` errors