@forge/teamwork-graph 1.2.0-next.4 → 2.0.0-experimental-8191ad1

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