@forge/teamwork-graph 1.2.0-next.5 → 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 (83) hide show
  1. package/README.md +276 -169
  2. package/out/__test__/entity-operations.test.js +1155 -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/build.d.ts +33 -0
  15. package/out/types/entities/build.d.ts.map +1 -0
  16. package/out/types/entities/build.js +2 -0
  17. package/out/types/entities/calendar-event.d.ts +45 -0
  18. package/out/types/entities/calendar-event.d.ts.map +1 -0
  19. package/out/types/entities/calendar-event.js +2 -0
  20. package/out/types/entities/comment.d.ts +18 -0
  21. package/out/types/entities/comment.d.ts.map +1 -0
  22. package/out/types/entities/comment.js +2 -0
  23. package/out/types/entities/conversation.d.ts +28 -0
  24. package/out/types/entities/conversation.d.ts.map +1 -0
  25. package/out/types/entities/conversation.js +2 -0
  26. package/out/types/entities/customer-org.d.ts +36 -0
  27. package/out/types/entities/customer-org.d.ts.map +1 -0
  28. package/out/types/entities/customer-org.js +2 -0
  29. package/out/types/entities/deal.d.ts +37 -0
  30. package/out/types/entities/deal.d.ts.map +1 -0
  31. package/out/types/entities/deal.js +2 -0
  32. package/out/types/entities/deployment.d.ts +43 -0
  33. package/out/types/entities/deployment.d.ts.map +1 -0
  34. package/out/types/entities/deployment.js +2 -0
  35. package/out/types/entities/design.d.ts +15 -0
  36. package/out/types/entities/design.d.ts.map +1 -0
  37. package/out/types/entities/design.js +2 -0
  38. package/out/types/entities/index.d.ts +20 -2
  39. package/out/types/entities/index.d.ts.map +1 -1
  40. package/out/types/entities/position.d.ts +24 -0
  41. package/out/types/entities/position.d.ts.map +1 -0
  42. package/out/types/entities/position.js +2 -0
  43. package/out/types/entities/project.d.ts +40 -0
  44. package/out/types/entities/project.d.ts.map +1 -0
  45. package/out/types/entities/project.js +2 -0
  46. package/out/types/entities/pull-request.d.ts +44 -0
  47. package/out/types/entities/pull-request.d.ts.map +1 -0
  48. package/out/types/entities/pull-request.js +2 -0
  49. package/out/types/entities/remote-link.d.ts +33 -0
  50. package/out/types/entities/remote-link.d.ts.map +1 -0
  51. package/out/types/entities/remote-link.js +2 -0
  52. package/out/types/entities/repository.d.ts +14 -0
  53. package/out/types/entities/repository.d.ts.map +1 -0
  54. package/out/types/entities/repository.js +2 -0
  55. package/out/types/entities/software-service.d.ts +17 -0
  56. package/out/types/entities/software-service.d.ts.map +1 -0
  57. package/out/types/entities/software-service.js +2 -0
  58. package/out/types/entities/space.d.ts +21 -0
  59. package/out/types/entities/space.d.ts.map +1 -0
  60. package/out/types/entities/space.js +2 -0
  61. package/out/types/entities/video.d.ts +48 -0
  62. package/out/types/entities/video.d.ts.map +1 -0
  63. package/out/types/entities/video.js +2 -0
  64. package/out/types/entities/work-item.d.ts +44 -0
  65. package/out/types/entities/work-item.d.ts.map +1 -0
  66. package/out/types/entities/work-item.js +2 -0
  67. package/out/types/entities/worker.d.ts +23 -0
  68. package/out/types/entities/worker.d.ts.map +1 -0
  69. package/out/types/entities/worker.js +2 -0
  70. package/out/types/requests.d.ts +29 -8
  71. package/out/types/requests.d.ts.map +1 -1
  72. package/out/utils/error-handling.d.ts +4 -0
  73. package/out/utils/error-handling.d.ts.map +1 -0
  74. package/out/utils/error-handling.js +77 -0
  75. package/out/utils/errors.d.ts +21 -15
  76. package/out/utils/errors.d.ts.map +1 -1
  77. package/out/utils/errors.js +43 -15
  78. package/out/utils/validators.d.ts.map +1 -1
  79. package/out/utils/validators.js +18 -15
  80. package/package.json +2 -2
  81. package/out/error-handling.d.ts +0 -3
  82. package/out/error-handling.d.ts.map +0 -1
  83. package/out/error-handling.js +0 -36
@@ -1,105 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const node_fetch_1 = require("node-fetch");
4
- const error_handling_1 = require("../error-handling");
3
+ const error_handling_1 = require("../utils/error-handling");
5
4
  const errors_1 = require("../utils/errors");
6
- describe('checkResponseError in @forge/teamwork-graph', () => {
7
- const traceId = 'trace-id';
8
- describe('when response has JSON body', () => {
9
- const baseErrorShape = {
10
- responseDetails: {
11
- status: 400,
12
- statusText: 'Bad Request',
13
- traceId
14
- }
15
- };
16
- it('should use provided code and message', async () => {
17
- const mockResponse = new node_fetch_1.Response(JSON.stringify({ code: 'CUSTOM_ERROR', message: 'Custom error message' }), {
18
- status: 400,
19
- statusText: 'Bad Request',
20
- headers: { 'x-trace-id': traceId }
21
- });
22
- await expect((0, error_handling_1.handleResponseError)(mockResponse)).rejects.toMatchObject({
23
- ...baseErrorShape,
24
- code: 'CUSTOM_ERROR',
25
- message: 'Custom error message'
26
- });
5
+ describe('TeamWorkGraphClient - Error Handling Functions', () => {
6
+ describe('handleError', () => {
7
+ test('should handle validation errors correctly', () => {
8
+ const validationError = new errors_1.ForgeTeamWorkGraphValidationError('Invalid entity data', 'entities');
9
+ const result = (0, error_handling_1.handleError)(validationError, 'set entities');
10
+ expect(result.success).toBe(false);
11
+ expect(result.error).toBe('Invalid entity data');
12
+ expect(result.originalError).toBe(validationError);
13
+ expect(result.results).toBeUndefined();
27
14
  });
28
- it('should use status-based code when no code provided', async () => {
29
- const mockResponse = new node_fetch_1.Response(JSON.stringify({ message: 'Error message' }), {
30
- status: 400,
31
- statusText: 'Bad Request',
32
- headers: { 'x-trace-id': traceId }
33
- });
34
- await expect((0, error_handling_1.handleResponseError)(mockResponse)).rejects.toMatchObject({
35
- ...baseErrorShape,
36
- code: errors_1.errorCodes.INVALID_REQUEST_BODY,
37
- message: 'Error message'
38
- });
15
+ test('should handle generic errors correctly', () => {
16
+ const genericError = new Error('Network timeout');
17
+ const result = (0, error_handling_1.handleError)(genericError, 'delete entities');
18
+ expect(result.success).toBe(false);
19
+ expect(result.error).toBe('Failed to delete entities: Network timeout');
20
+ expect(result.originalError).toBe(genericError);
21
+ expect(result.results).toBeUndefined();
39
22
  });
40
- it('should use default message when no message provided', async () => {
41
- const mockResponse = new node_fetch_1.Response(JSON.stringify({ code: 'CUSTOM_ERROR' }), {
42
- status: 400,
43
- statusText: 'Bad Request',
44
- headers: { 'x-trace-id': traceId }
45
- });
46
- await expect((0, error_handling_1.handleResponseError)(mockResponse, 'Default message')).rejects.toMatchObject({
47
- ...baseErrorShape,
48
- code: 'CUSTOM_ERROR',
49
- message: 'Default message'
50
- });
23
+ test('should handle unknown errors correctly', () => {
24
+ const unknownError = 'Something went wrong';
25
+ const result = (0, error_handling_1.handleError)(unknownError, 'fetch data');
26
+ expect(result.success).toBe(false);
27
+ expect(result.error).toBe('Failed to fetch data: Unknown error');
28
+ expect(result.originalError).toBe(unknownError);
29
+ expect(result.data).toBeUndefined();
51
30
  });
52
- it('should include context if provided', async () => {
53
- const mockResponse = new node_fetch_1.Response(JSON.stringify({
54
- code: 'CUSTOM_ERROR',
55
- message: 'Error message',
56
- context: { details: 'Additional info' }
57
- }), {
58
- status: 400,
59
- statusText: 'Bad Request',
60
- headers: { 'x-trace-id': traceId }
61
- });
62
- await expect((0, error_handling_1.handleResponseError)(mockResponse)).rejects.toMatchObject({
63
- ...baseErrorShape,
64
- code: 'CUSTOM_ERROR',
65
- message: 'Error message',
66
- context: { details: 'Additional info' }
67
- });
68
- });
69
- });
70
- describe('when response has invalid or no body', () => {
71
- const serverErrorShape = {
72
- responseDetails: {
73
- status: 500,
74
- statusText: 'Internal Server Error',
75
- traceId
76
- }
77
- };
78
- it('should handle invalid JSON', async () => {
79
- const mockResponse = new node_fetch_1.Response('Invalid JSON', {
80
- status: 500,
81
- statusText: 'Internal Server Error',
82
- headers: { 'x-trace-id': traceId }
83
- });
84
- await expect((0, error_handling_1.handleResponseError)(mockResponse, 'Default message')).rejects.toMatchObject({
85
- ...serverErrorShape,
86
- code: errors_1.errorCodes.UNKNOWN_ERROR,
87
- message: 'Default message',
88
- context: { responseText: 'Invalid JSON' }
89
- });
90
- });
91
- it('should handle empty response', async () => {
92
- const mockResponse = new node_fetch_1.Response('', {
93
- status: 500,
94
- statusText: 'Internal Server Error',
95
- headers: { 'x-trace-id': traceId }
96
- });
97
- await expect((0, error_handling_1.handleResponseError)(mockResponse)).rejects.toMatchObject({
98
- ...serverErrorShape,
99
- code: errors_1.errorCodes.UNKNOWN_ERROR,
100
- message: 'Failed to parse error response',
101
- context: { responseText: '' }
102
- });
31
+ test('should work with different response types', () => {
32
+ const error = new Error('API rate limit exceeded');
33
+ const bulkResult = (0, error_handling_1.handleError)(error, 'set entities');
34
+ const deleteResult = (0, error_handling_1.handleError)(error, 'delete entities');
35
+ const fetchResult = (0, error_handling_1.handleError)(error, 'fetch data');
36
+ expect(bulkResult.success).toBe(false);
37
+ expect(deleteResult.success).toBe(false);
38
+ expect(fetchResult.success).toBe(false);
39
+ expect(bulkResult.error).toBe('Failed to set entities: API rate limit exceeded');
40
+ expect(deleteResult.error).toBe('Failed to delete entities: API rate limit exceeded');
41
+ expect(fetchResult.error).toBe('Failed to fetch data: API rate limit exceeded');
42
+ expect(bulkResult.originalError).toBe(error);
43
+ expect(deleteResult.originalError).toBe(error);
44
+ expect(fetchResult.originalError).toBe(error);
103
45
  });
104
46
  });
105
47
  });
@@ -56,10 +56,15 @@ describe('TeamWorkGraphClient - Extended Features', () => {
56
56
  const result = await graphClient.fetchData(request);
57
57
  expect(result).toEqual({
58
58
  success: false,
59
- error: 'Remote call failed with status: 401'
59
+ error: 'Remote call failed with status: 401',
60
+ originalError: expect.any(Error)
60
61
  });
61
62
  expect(request.onResult).not.toHaveBeenCalled();
62
63
  });
64
+ it('should throw error for validation errors', async () => {
65
+ const request = {};
66
+ await expect(graphClient.fetchData(request)).rejects.toThrow('requestConfig is required and must be an object');
67
+ });
63
68
  });
64
69
  describe('transformData', () => {
65
70
  it('should transform data using the provided transform method', async () => {
@@ -96,8 +101,13 @@ describe('TeamWorkGraphClient - Extended Features', () => {
96
101
  const result = await graphClient.transformData(request);
97
102
  expect(result).toEqual({
98
103
  success: false,
99
- error: 'Transform failed'
104
+ error: 'Transform failed',
105
+ originalError: expect.any(Error)
100
106
  });
101
107
  });
108
+ it('should throw error for validation errors', async () => {
109
+ const request = {};
110
+ await expect(graphClient.transformData(request)).rejects.toThrow('transformMethod is required and must be a function');
111
+ });
102
112
  });
103
113
  });
@@ -91,7 +91,7 @@ describe('TeamWorkGraphClient - Group Operations', () => {
91
91
  const manyGroups = Array(validators_1.MAX_BULK_GROUPS + 1).fill(groupPayload);
92
92
  await expect(graphClient.setGroups({
93
93
  groups: manyGroups
94
- })).rejects.toThrow(`Bulk group ingestion supports maximum ${validators_1.MAX_BULK_GROUPS} groups`);
94
+ })).rejects.toThrow(`Bulk group ingestion supports maximum ${validators_1.MAX_BULK_GROUPS} groups. Received ${validators_1.MAX_BULK_GROUPS + 1}`);
95
95
  });
96
96
  it('should throw error when groups is not an array', async () => {
97
97
  await expect(graphClient.setGroups({
@@ -182,10 +182,10 @@ describe('TeamWorkGraphClient - Group Operations', () => {
182
182
  headers: {
183
183
  get: () => null
184
184
  },
185
- text: () => Promise.resolve(JSON.stringify({
185
+ json: () => Promise.resolve({
186
186
  code: 'GROUP_NOT_FOUND',
187
187
  message: 'Group not found'
188
- }))
188
+ })
189
189
  };
190
190
  mockFetch.mockResolvedValueOnce(errorResponse);
191
191
  const result = await graphClient.getGroupByExternalId({
@@ -193,7 +193,8 @@ describe('TeamWorkGraphClient - Group Operations', () => {
193
193
  });
194
194
  expect(result).toEqual({
195
195
  success: false,
196
- error: 'Group not found'
196
+ error: 'Failed to get group by external ID: Not Found - Group not found',
197
+ originalError: expect.any(Error)
197
198
  });
198
199
  });
199
200
  it('should throw error when externalId is missing', async () => {
@@ -70,7 +70,12 @@ describe('TeamWorkGraphClient - User Operations', () => {
70
70
  const manyUsers = Array(validators_1.MAX_BULK_USERS + 1).fill(userPayload);
71
71
  await expect(graphClient.setUsers({
72
72
  users: manyUsers
73
- })).rejects.toThrow(`Bulk user ingestion supports maximum ${validators_1.MAX_BULK_USERS} users`);
73
+ })).rejects.toThrow(`Bulk user ingestion supports maximum ${validators_1.MAX_BULK_USERS} users. Received ${validators_1.MAX_BULK_USERS + 1}`);
74
+ });
75
+ it('should throw error when users is not an array', async () => {
76
+ await expect(graphClient.setUsers({
77
+ users: null
78
+ })).rejects.toThrow('users must be an array');
74
79
  });
75
80
  });
76
81
  describe('deleteUsersByExternalId', () => {
@@ -102,6 +107,11 @@ describe('TeamWorkGraphClient - User Operations', () => {
102
107
  externalIds: []
103
108
  })).rejects.toThrow('externalIds array cannot be empty');
104
109
  });
110
+ it('should throw error when externalIds is not an array', async () => {
111
+ await expect(graphClient.deleteUsersByExternalId({
112
+ externalIds: null
113
+ })).rejects.toThrow('externalIds must be an array');
114
+ });
105
115
  });
106
116
  describe('getUserByExternalId', () => {
107
117
  const expectedUser = {
@@ -155,10 +165,10 @@ describe('TeamWorkGraphClient - User Operations', () => {
155
165
  headers: {
156
166
  get: () => null
157
167
  },
158
- text: () => Promise.resolve(JSON.stringify({
168
+ json: () => Promise.resolve({
159
169
  code: 'USER_NOT_FOUND',
160
170
  message: 'User not found'
161
- }))
171
+ })
162
172
  };
163
173
  mockFetch.mockResolvedValueOnce(errorResponse);
164
174
  const result = await graphClient.getUserByExternalId({
@@ -166,7 +176,8 @@ describe('TeamWorkGraphClient - User Operations', () => {
166
176
  });
167
177
  expect(result).toEqual({
168
178
  success: false,
169
- error: 'User not found'
179
+ error: 'Failed to get user by external ID: Not Found - User not found',
180
+ originalError: expect.any(Error)
170
181
  });
171
182
  });
172
183
  it('should throw error when externalId is missing', async () => {
@@ -260,7 +271,7 @@ describe('TeamWorkGraphClient - User Operations', () => {
260
271
  const manyMappings = Array(validators_1.MAX_USER_MAPPINGS + 1).fill(mappingWithAccountId);
261
272
  await expect(graphClient.mapUsers({
262
273
  directMappings: manyMappings
263
- })).rejects.toThrow(`Bulk user mapping supports maximum ${validators_1.MAX_USER_MAPPINGS} mappings`);
274
+ })).rejects.toThrow(`Bulk user mapping supports maximum ${validators_1.MAX_USER_MAPPINGS} mappings. Received ${validators_1.MAX_USER_MAPPINGS + 1}`);
264
275
  });
265
276
  it('should throw error when directMappings is not an array', async () => {
266
277
  await expect(graphClient.mapUsers({