@forge/teamwork-graph 1.2.0-next.2 → 1.2.0-next.3

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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=entity-operations.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-operations.test.d.ts","sourceRoot":"","sources":["../../src/__test__/entity-operations.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,405 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const api_1 = require("@forge/api");
4
+ const graph_1 = require("../graph");
5
+ jest.mock('@forge/api');
6
+ describe('TeamWorkGraphClient - setEntities', () => {
7
+ let graphClient;
8
+ let mockFetch;
9
+ beforeEach(() => {
10
+ graphClient = new graph_1.TeamWorkGraphClient();
11
+ mockFetch = jest.fn();
12
+ api_1.__fetchProduct.mockReturnValue(mockFetch);
13
+ jest.clearAllMocks();
14
+ });
15
+ it('throws if entities array is empty', async () => {
16
+ const req = { entities: [] };
17
+ await expect(graphClient.setEntities(req)).rejects.toThrow('entities array cannot be empty');
18
+ });
19
+ it('throws if more than 100 entities', async () => {
20
+ const documentEntity = {
21
+ schemaVersion: '1.0',
22
+ id: 'my-document',
23
+ updateSequenceNumber: 123,
24
+ displayName: 'My Document',
25
+ url: 'https://document.com',
26
+ createdAt: '2024-04-16T09:01:32+00:00',
27
+ lastUpdatedAt: '2024-04-16T09:01:32+00:00',
28
+ permissions: {
29
+ accessControls: [
30
+ {
31
+ principals: [
32
+ {
33
+ type: 'EVERYONE'
34
+ }
35
+ ]
36
+ }
37
+ ]
38
+ },
39
+ 'atlassian:document': {
40
+ type: {
41
+ category: 'document',
42
+ iconUrl: 'http://icon.com'
43
+ },
44
+ content: {
45
+ mimeType: 'text/plain',
46
+ text: 'Really large content here...'
47
+ }
48
+ }
49
+ };
50
+ const req = {
51
+ entities: Array(101).fill(documentEntity)
52
+ };
53
+ await expect(graphClient.setEntities(req)).rejects.toThrow('Bulk ingestion supports maximum 100 entities');
54
+ });
55
+ it('posts to /api/v1/entities/bulk and returns response', async () => {
56
+ const documentEntity = {
57
+ schemaVersion: '1.0',
58
+ id: 'my-document',
59
+ updateSequenceNumber: 123,
60
+ displayName: 'My Document',
61
+ url: 'https://document.com',
62
+ createdAt: '2024-04-16T09:01:32+00:00',
63
+ lastUpdatedAt: '2024-04-16T09:01:32+00:00',
64
+ permissions: {
65
+ accessControls: [
66
+ {
67
+ principals: [
68
+ {
69
+ type: 'EVERYONE'
70
+ }
71
+ ]
72
+ }
73
+ ]
74
+ },
75
+ 'atlassian:document': {
76
+ type: {
77
+ category: 'document',
78
+ iconUrl: 'http://icon.com'
79
+ },
80
+ content: {
81
+ mimeType: 'text/plain',
82
+ text: 'Really large content here...'
83
+ }
84
+ }
85
+ };
86
+ const req = { entities: [documentEntity] };
87
+ const expected = { success: true, results: [{ entityId: 'my-document', success: true }] };
88
+ mockFetch.mockResolvedValueOnce({
89
+ ok: true,
90
+ json: () => Promise.resolve(expected)
91
+ });
92
+ const result = await graphClient.setEntities(req);
93
+ expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
94
+ expect(result).toEqual(expected);
95
+ });
96
+ it('posts message entities to /api/v1/entities/bulk and returns response', async () => {
97
+ const messageEntity = {
98
+ schemaVersion: '2.0',
99
+ id: 'message-1',
100
+ updateSequenceNumber: 1,
101
+ description: 'Hello everyone!',
102
+ url: 'https://atlassian.slack.com/archives/C03DZ3WCN94/p1722400000000000',
103
+ createdAt: '2024-07-09T14:27:37.000Z',
104
+ lastUpdatedAt: '2024-07-09T14:27:37.000Z',
105
+ permissions: {
106
+ accessControls: [
107
+ {
108
+ principals: [
109
+ {
110
+ type: 'EVERYONE'
111
+ }
112
+ ]
113
+ }
114
+ ]
115
+ },
116
+ containerKey: {
117
+ type: 'atlassian:conversation',
118
+ value: {
119
+ entityId: 'CFG3W7TKJ'
120
+ }
121
+ },
122
+ 'atlassian:message': {
123
+ hidden: false,
124
+ isPinned: false,
125
+ attachments: [
126
+ {
127
+ url: 'https://atlassian.enterprise.slack.com/files/U02S327DT62/F07FAUT3L00/img_4659.png',
128
+ mimeType: 'image/png',
129
+ byteSize: 140288
130
+ }
131
+ ],
132
+ lastActive: '2024-07-09T15:27:37.000Z'
133
+ }
134
+ };
135
+ const req = { entities: [messageEntity] };
136
+ const expected = { success: true, results: [{ entityId: 'message-1', success: true }] };
137
+ mockFetch.mockResolvedValueOnce({
138
+ ok: true,
139
+ json: () => Promise.resolve(expected)
140
+ });
141
+ const result = await graphClient.setEntities(req);
142
+ expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
143
+ expect(result).toEqual(expected);
144
+ });
145
+ it('posts organisation entities to /api/v1/entities/bulk and returns response', async () => {
146
+ const organisationEntity = {
147
+ schemaVersion: '2.0',
148
+ id: 'org-1',
149
+ updateSequenceNumber: 2,
150
+ displayName: 'pos 2',
151
+ url: 'https://workday.atlassian.com/path-to-org',
152
+ createdAt: '2024-07-09T14:27:37.000Z',
153
+ lastUpdatedAt: '2024-07-09T14:27:37.000Z',
154
+ permissions: {
155
+ accessControls: [
156
+ {
157
+ principals: [
158
+ {
159
+ type: 'EVERYONE'
160
+ }
161
+ ]
162
+ }
163
+ ]
164
+ },
165
+ parentKey: {
166
+ type: 'atlassian:organisation',
167
+ value: {
168
+ entityId: 'id of the parent org of this org'
169
+ }
170
+ },
171
+ 'atlassian:organisation': {}
172
+ };
173
+ const req = { entities: [organisationEntity] };
174
+ const expected = { success: false, results: [{ entityId: 'org-1', success: true }] };
175
+ mockFetch.mockResolvedValueOnce({
176
+ ok: true,
177
+ json: () => Promise.resolve(expected)
178
+ });
179
+ const result = await graphClient.setEntities(req);
180
+ expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
181
+ expect(result).toEqual(expected);
182
+ });
183
+ it('throws if entities is not an array', async () => {
184
+ const req = { entities: null };
185
+ await expect(graphClient.setEntities(req)).rejects.toThrow('entities must be an array');
186
+ });
187
+ });
188
+ describe('TeamWorkGraphClient - getEntityByExternalId', () => {
189
+ let graphClient;
190
+ let mockFetch;
191
+ beforeEach(() => {
192
+ graphClient = new graph_1.TeamWorkGraphClient();
193
+ mockFetch = jest.fn();
194
+ api_1.__fetchProduct.mockReturnValue(mockFetch);
195
+ jest.clearAllMocks();
196
+ });
197
+ it('should successfully get entity by external ID and entity type', async () => {
198
+ const expectedEntity = {
199
+ id: 'ari:cloud:teamwork-graph:entity/123',
200
+ externalId: 'pipelines/123/builds/456',
201
+ entityType: 'atlassian:document',
202
+ displayName: 'Build Documentation',
203
+ description: 'Documentation for build process',
204
+ url: 'https://example.com/builds/456',
205
+ createdAt: '2024-01-01T00:00:00Z',
206
+ lastUpdatedAt: '2024-01-01T00:00:00Z',
207
+ meta: {
208
+ resourceType: 'Document',
209
+ created: '2024-01-01T00:00:00Z',
210
+ lastModified: '2024-01-01T00:00:00Z',
211
+ location: 'https://example.com/v2/entities/123'
212
+ }
213
+ };
214
+ mockFetch.mockResolvedValueOnce({
215
+ ok: true,
216
+ json: () => Promise.resolve(expectedEntity)
217
+ });
218
+ const result = await graphClient.getEntityByExternalId({
219
+ entityType: 'atlassian:document',
220
+ externalId: 'pipelines/123/builds/456'
221
+ });
222
+ expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities?entityType=atlassian%3Adocument&externalId=pipelines%2F123%2Fbuilds%2F456', {
223
+ method: 'GET',
224
+ redirect: 'follow',
225
+ headers: { 'Content-Type': 'application/json' }
226
+ });
227
+ expect(result).toEqual({
228
+ success: true,
229
+ entity: expectedEntity
230
+ });
231
+ });
232
+ it('should handle entity not found', async () => {
233
+ const errorResponse = {
234
+ ok: false,
235
+ status: 404,
236
+ statusText: 'Not Found',
237
+ headers: {
238
+ get: () => null
239
+ },
240
+ text: () => Promise.resolve(JSON.stringify({
241
+ code: 'ENTITY_NOT_FOUND',
242
+ message: 'Entity not found'
243
+ }))
244
+ };
245
+ mockFetch.mockResolvedValueOnce(errorResponse);
246
+ const result = await graphClient.getEntityByExternalId({
247
+ entityType: 'atlassian:document',
248
+ externalId: 'nonexistent-entity'
249
+ });
250
+ expect(result).toEqual({
251
+ success: false,
252
+ error: 'Entity not found'
253
+ });
254
+ });
255
+ it('should throw error when entityType is missing', async () => {
256
+ await expect(graphClient.getEntityByExternalId({
257
+ entityType: '',
258
+ externalId: 'pipelines/123/builds/456'
259
+ })).rejects.toThrow('entityType is required');
260
+ });
261
+ it('should throw error when externalId is missing', async () => {
262
+ await expect(graphClient.getEntityByExternalId({
263
+ entityType: 'atlassian:document',
264
+ externalId: ''
265
+ })).rejects.toThrow('externalId is required');
266
+ });
267
+ });
268
+ describe('TeamWorkGraphClient - deleteEntitiesByExternalId', () => {
269
+ let graphClient;
270
+ let mockFetch;
271
+ beforeEach(() => {
272
+ graphClient = new graph_1.TeamWorkGraphClient();
273
+ mockFetch = jest.fn();
274
+ api_1.__fetchProduct.mockReturnValue(mockFetch);
275
+ jest.clearAllMocks();
276
+ });
277
+ it('should successfully delete entities in bulk', async () => {
278
+ const expectedResponse = {
279
+ success: true,
280
+ results: [
281
+ { externalId: 'pipelines/123/builds/456', success: true },
282
+ { externalId: 'pipelines/123/builds/789', success: true }
283
+ ]
284
+ };
285
+ mockFetch.mockResolvedValueOnce({
286
+ ok: true,
287
+ json: () => Promise.resolve(expectedResponse)
288
+ });
289
+ const result = await graphClient.deleteEntitiesByExternalId({
290
+ entityType: 'atlassian:document',
291
+ externalIds: ['pipelines/123/builds/456', 'pipelines/123/builds/789']
292
+ });
293
+ expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk/delete', {
294
+ method: 'DELETE',
295
+ body: JSON.stringify({
296
+ entityType: 'atlassian:document',
297
+ externalIds: ['pipelines/123/builds/456', 'pipelines/123/builds/789']
298
+ }),
299
+ redirect: 'follow',
300
+ headers: { 'Content-Type': 'application/json' }
301
+ });
302
+ expect(result).toEqual(expectedResponse);
303
+ });
304
+ it('should throw error when entityType is missing', async () => {
305
+ await expect(graphClient.deleteEntitiesByExternalId({
306
+ entityType: '',
307
+ externalIds: ['pipelines/123/builds/456']
308
+ })).rejects.toThrow('entityType is required');
309
+ });
310
+ it('should throw error when externalIds array is empty', async () => {
311
+ await expect(graphClient.deleteEntitiesByExternalId({
312
+ entityType: 'atlassian:document',
313
+ externalIds: []
314
+ })).rejects.toThrow('externalIds array cannot be empty');
315
+ });
316
+ it('should throw error when externalIds array exceeds limit', async () => {
317
+ const manyExternalIds = Array(101).fill('pipelines/123/builds/456');
318
+ await expect(graphClient.deleteEntitiesByExternalId({
319
+ entityType: 'atlassian:document',
320
+ externalIds: manyExternalIds
321
+ })).rejects.toThrow('Bulk entity deletion supports maximum 100 entities');
322
+ });
323
+ it('should throw error when externalIds is not an array', async () => {
324
+ await expect(graphClient.deleteEntitiesByExternalId({
325
+ entityType: 'atlassian:document',
326
+ externalIds: null
327
+ })).rejects.toThrow('externalIds must be an array');
328
+ });
329
+ });
330
+ describe('TeamWorkGraphClient - deleteEntitiesByProperties', () => {
331
+ let graphClient;
332
+ let mockFetch;
333
+ beforeEach(() => {
334
+ graphClient = new graph_1.TeamWorkGraphClient();
335
+ mockFetch = jest.fn();
336
+ api_1.__fetchProduct.mockReturnValue(mockFetch);
337
+ jest.clearAllMocks();
338
+ });
339
+ it('should successfully delete entities by properties', async () => {
340
+ const expectedResponse = {
341
+ success: true,
342
+ results: [
343
+ { entityId: 'entity-123', success: true },
344
+ { entityId: 'entity-456', success: true }
345
+ ]
346
+ };
347
+ mockFetch.mockResolvedValueOnce({
348
+ ok: true,
349
+ json: () => Promise.resolve(expectedResponse)
350
+ });
351
+ const result = await graphClient.deleteEntitiesByProperties({
352
+ environment: 'staging',
353
+ status: 'failed'
354
+ });
355
+ expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk/delete-by-properties', {
356
+ method: 'DELETE',
357
+ body: JSON.stringify({
358
+ environment: 'staging',
359
+ status: 'failed'
360
+ }),
361
+ redirect: 'follow',
362
+ headers: { 'Content-Type': 'application/json' }
363
+ });
364
+ expect(result).toEqual(expectedResponse);
365
+ });
366
+ it('should handle complex properties object', async () => {
367
+ const expectedResponse = {
368
+ success: true,
369
+ results: [{ entityId: 'entity-789', success: true }]
370
+ };
371
+ mockFetch.mockResolvedValueOnce({
372
+ ok: true,
373
+ json: () => Promise.resolve(expectedResponse)
374
+ });
375
+ const result = await graphClient.deleteEntitiesByProperties({
376
+ environment: 'production',
377
+ status: 'completed',
378
+ priority: 'high',
379
+ team: 'backend',
380
+ region: 'us-east-1'
381
+ });
382
+ expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk/delete-by-properties', {
383
+ method: 'DELETE',
384
+ body: JSON.stringify({
385
+ environment: 'production',
386
+ status: 'completed',
387
+ priority: 'high',
388
+ team: 'backend',
389
+ region: 'us-east-1'
390
+ }),
391
+ redirect: 'follow',
392
+ headers: { 'Content-Type': 'application/json' }
393
+ });
394
+ expect(result).toEqual(expectedResponse);
395
+ });
396
+ it('should throw error when properties is missing', async () => {
397
+ await expect(graphClient.deleteEntitiesByProperties(null)).rejects.toThrow('properties must be an object');
398
+ });
399
+ it('should throw error when properties is not an object', async () => {
400
+ await expect(graphClient.deleteEntitiesByProperties('not-an-object')).rejects.toThrow('properties must be an object');
401
+ });
402
+ it('should throw error when properties object is empty', async () => {
403
+ await expect(graphClient.deleteEntitiesByProperties({})).rejects.toThrow('properties object cannot be empty');
404
+ });
405
+ });
package/out/graph.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { Result } from '@forge/api';
2
- import { TeamWorkGraph, ForgeExtendedContext, RequestConfig, BulkEntityRequest, BulkEntityResponse, BulkUsersRequest, BulkUsersResponse, DeleteUsersByExternalIdRequest, DeleteUsersByExternalIdResponse, GetUserByExternalIdRequest, GetUserByExternalIdResponse, MapUsersRequest, MapUsersResponse, BulkGroupsRequest, BulkGroupsResponse, DeleteGroupsByExternalIdRequest, DeleteGroupsByExternalIdResponse, GetGroupByExternalIdRequest, GetGroupByExternalIdResponse } from './types';
1
+ import { TeamWorkGraph, ForgeExtendedContext, RequestConfig, BulkEntityRequest, BulkEntityResponse, BulkUsersRequest, BulkUsersResponse, DeleteUsersByExternalIdRequest, DeleteUsersByExternalIdResponse, GetUserByExternalIdRequest, GetUserByExternalIdResponse, MapUsersRequest, MapUsersResponse, BulkGroupsRequest, BulkGroupsResponse, DeleteGroupsByExternalIdRequest, DeleteGroupsByExternalIdResponse, GetGroupByExternalIdRequest, GetGroupByExternalIdResponse, GetEntityByExternalIdRequest, GetEntityByExternalIdResponse, DeleteEntitiesByExternalIdRequest, DeleteEntitiesByExternalIdResponse, DeleteEntitiesByPropertiesRequest, DeleteEntitiesByPropertiesResponse } from './types';
3
2
  export declare class TeamWorkGraphClient implements TeamWorkGraph {
4
3
  setEntities: (request: BulkEntityRequest) => Promise<BulkEntityResponse>;
5
- deleteEntity: (context: ForgeExtendedContext, entityId: string) => Promise<Result>;
4
+ getEntityByExternalId: (request: GetEntityByExternalIdRequest) => Promise<GetEntityByExternalIdResponse>;
5
+ deleteEntitiesByExternalId: (request: DeleteEntitiesByExternalIdRequest) => Promise<DeleteEntitiesByExternalIdResponse>;
6
+ deleteEntitiesByProperties: (request: DeleteEntitiesByPropertiesRequest) => Promise<DeleteEntitiesByPropertiesResponse>;
6
7
  setGroups: (request: BulkGroupsRequest) => Promise<BulkGroupsResponse>;
7
8
  deleteGroupsByExternalId: (request: DeleteGroupsByExternalIdRequest) => Promise<DeleteGroupsByExternalIdResponse>;
8
9
  getGroupByExternalId: (request: GetGroupByExternalIdRequest) => Promise<GetGroupByExternalIdResponse>;
@@ -1 +1 @@
1
- {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,MAAM,EAAsB,MAAM,YAAY,CAAC;AAErF,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,SAAS,CAAC;AAQjB,qBAAa,mBAAoB,YAAW,aAAa;IACvD,WAAW,YAAmB,iBAAiB,KAAG,QAAQ,kBAAkB,CAAC,CAe3E;IAEF,YAAY,YAAmB,oBAAoB,YAAY,MAAM,KAAG,QAAQ,MAAM,CAAC,CAIrF;IAKF,SAAS,YAAmB,iBAAiB,KAAG,QAAQ,kBAAkB,CAAC,CAezE;IAKF,wBAAwB,YACb,+BAA+B,KACvC,QAAQ,gCAAgC,CAAC,CAc1C;IAKF,oBAAoB,YAAmB,2BAA2B,KAAG,QAAQ,4BAA4B,CAAC,CAsBxG;IAEF,QAAQ,YAAmB,gBAAgB,KAAG,QAAQ,iBAAiB,CAAC,CAetE;IAEF,uBAAuB,YACZ,8BAA8B,KACtC,QAAQ,+BAA+B,CAAC,CAczC;IAEF,mBAAmB,YAAmB,0BAA0B,KAAG,QAAQ,2BAA2B,CAAC,CAsBrG;IAEF,QAAQ,YAAmB,eAAe,KAAG,QAAQ,gBAAgB,CAAC,CA+BpE;IAEF,SAAS,YAAmB,oBAAoB,iBAAiB,aAAa,mBAAmB,GAAG,KAAK,GAAG,kBAuB1G;IAEF,aAAa,YAAmB,oBAAoB,QAAQ,GAAG,0BAA0B,GAAG,KAAK,GAAG,kBAIlG;YAEY,WAAW;YAIX,YAAY;IAI1B,OAAO,CAAC,eAAe;YAQT,eAAe;YAaf,iBAAiB;YAajB,cAAc;YAYd,WAAW;CAY1B;AAED,eAAO,MAAM,aAAa,qBAA4B,CAAC"}
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,4BAA4B,EAC5B,4BAA4B,EAC5B,6BAA6B,EAC7B,iCAAiC,EACjC,kCAAkC,EAClC,iCAAiC,EACjC,kCAAkC,EACnC,MAAM,SAAS,CAAC;AASjB,qBAAa,mBAAoB,YAAW,aAAa;IACvD,WAAW,YAAmB,iBAAiB,KAAG,QAAQ,kBAAkB,CAAC,CAe3E;IAKF,qBAAqB,YAAmB,4BAA4B,KAAG,QAAQ,6BAA6B,CAAC,CA0B3G;IAKF,0BAA0B,YACf,iCAAiC,KACzC,QAAQ,kCAAkC,CAAC,CAuB5C;IAKF,0BAA0B,YACf,iCAAiC,KACzC,QAAQ,kCAAkC,CAAC,CAU5C;IAKF,SAAS,YAAmB,iBAAiB,KAAG,QAAQ,kBAAkB,CAAC,CAezE;IAKF,wBAAwB,YACb,+BAA+B,KACvC,QAAQ,gCAAgC,CAAC,CAc1C;IAKF,oBAAoB,YAAmB,2BAA2B,KAAG,QAAQ,4BAA4B,CAAC,CAsBxG;IAEF,QAAQ,YAAmB,gBAAgB,KAAG,QAAQ,iBAAiB,CAAC,CAetE;IAEF,uBAAuB,YACZ,8BAA8B,KACtC,QAAQ,+BAA+B,CAAC,CAczC;IAEF,mBAAmB,YAAmB,0BAA0B,KAAG,QAAQ,2BAA2B,CAAC,CAsBrG;IAEF,QAAQ,YAAmB,eAAe,KAAG,QAAQ,gBAAgB,CAAC,CA+BpE;IAEF,SAAS,YAAmB,oBAAoB,iBAAiB,aAAa,mBAAmB,GAAG,KAAK,GAAG,kBAuB1G;IAEF,aAAa,YAAmB,oBAAoB,QAAQ,GAAG,0BAA0B,GAAG,KAAK,GAAG,kBAIlG;YAEY,WAAW;YAIX,YAAY;IAI1B,OAAO,CAAC,eAAe;YAQT,eAAe;YAaf,iBAAiB;YAajB,cAAc;YAYd,WAAW;CAY1B;AAED,eAAO,MAAM,aAAa,qBAA4B,CAAC"}
package/out/graph.js CHANGED
@@ -7,6 +7,7 @@ const STARGATE_BASE = '/graph/connector';
7
7
  const MAX_BULK_ENTITIES = 100;
8
8
  const MAX_BULK_USERS = 100;
9
9
  const MAX_BULK_GROUPS = 100;
10
+ const MAX_BULK_ENTITIES_DELETE = 100;
10
11
  const MAX_USER_MAPPINGS = 100;
11
12
  class TeamWorkGraphClient {
12
13
  setEntities = async (request) => {
@@ -23,10 +24,61 @@ class TeamWorkGraphClient {
23
24
  const response = await this.sendPostRequest('/api/v1/entities/bulk', { entities });
24
25
  return response;
25
26
  };
26
- deleteEntity = async (context, entityId) => {
27
- this.validateContext(context);
28
- const path = '/api/v1/entity/?resourceId=' + entityId;
29
- return this.sendDeleteRequest(path);
27
+ getEntityByExternalId = async (request) => {
28
+ const { entityType, externalId } = request;
29
+ if (!entityType || entityType.trim() === '') {
30
+ throw new Error('entityType is required');
31
+ }
32
+ if (!externalId || externalId.trim() === '') {
33
+ throw new Error('externalId is required');
34
+ }
35
+ try {
36
+ const url = new URL('/api/v1/entities', 'https://teamwork-graph.atlassian.net/api');
37
+ url.searchParams.set('entityType', entityType);
38
+ url.searchParams.set('externalId', externalId);
39
+ const path = url.pathname + url.search;
40
+ const response = await this.sendGetRequest(path);
41
+ return {
42
+ success: true,
43
+ entity: response
44
+ };
45
+ }
46
+ catch (error) {
47
+ return {
48
+ success: false,
49
+ error: error instanceof Error ? error.message : 'Unknown error'
50
+ };
51
+ }
52
+ };
53
+ deleteEntitiesByExternalId = async (request) => {
54
+ const { entityType, externalIds } = request;
55
+ if (!entityType || entityType.trim() === '') {
56
+ throw new Error('entityType is required');
57
+ }
58
+ if (!Array.isArray(externalIds)) {
59
+ throw new Error('externalIds must be an array');
60
+ }
61
+ if (externalIds.length === 0) {
62
+ throw new Error('externalIds array cannot be empty');
63
+ }
64
+ if (externalIds.length > MAX_BULK_ENTITIES_DELETE) {
65
+ throw new Error(`Bulk entity deletion supports maximum ${MAX_BULK_ENTITIES_DELETE} entities. Received ${externalIds.length}`);
66
+ }
67
+ const response = await this.sendDeleteRequest('/api/v1/entities/bulk/delete', {
68
+ entityType,
69
+ externalIds
70
+ });
71
+ return response;
72
+ };
73
+ deleteEntitiesByProperties = async (request) => {
74
+ if (!request || typeof request !== 'object') {
75
+ throw new Error('properties must be an object');
76
+ }
77
+ if (Object.keys(request).length === 0) {
78
+ throw new Error('properties object cannot be empty');
79
+ }
80
+ const response = await this.sendDeleteRequest('/api/v1/entities/bulk/delete-by-properties', request);
81
+ return response;
30
82
  };
31
83
  setGroups = async (request) => {
32
84
  const { groups } = request;
@@ -45,6 +45,7 @@ export declare type BaseEntityProperties = {
45
45
  containerKey?: ContainerKeyObject | string;
46
46
  permissions?: Permissions;
47
47
  associations?: Associations;
48
+ properties?: Record<string, any>;
48
49
  };
49
50
  export declare type AssociationObject = {
50
51
  associationType: string;
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/types/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAE1B,oBAAY,SAAS,GAAG;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,oBAAY,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,qBAAqB,GAAG,WAAW,CAAC;IAC1E,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB,CAAC;AAEF,oBAAY,aAAa,GAAG;IAC1B,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB,CAAC;AAEF,oBAAY,qBAAqB,GAAG;IAClC,aAAa,EAAE,SAAS,CAAC;CAC1B,CAAC;AAEF,oBAAY,WAAW,GAAG;IACxB,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,iBAAiB,CAAC,EAAE,qBAAqB,EAAE,CAAC;CAC7C,CAAC;AAGF,oBAAY,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,CAAC;AAEF,oBAAY,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,CAAC;AAGF,oBAAY,oBAAoB,GAAG;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC;IACrC,YAAY,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC;IAC3C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF,oBAAY,iBAAiB,GAAG;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,oBAAY,YAAY,GAAG;IACzB,GAAG,EAAE,iBAAiB,EAAE,CAAC;CAC1B,CAAC;AAEF,oBAAY,gBAAgB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CAAC;AAEF,oBAAY,oBAAoB,GAAG;IACjC,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC;AAEF,oBAAY,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,GAAG,CAAC;CACf,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/types/common.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,10 @@
1
1
  import { Result } from '@forge/api';
2
- import { ForgeExtendedContext, RequestConfig, BulkEntityRequest, BulkEntityResponse, BulkUsersRequest, BulkUsersResponse, DeleteUsersByExternalIdRequest, DeleteUsersByExternalIdResponse, GetUserByExternalIdRequest, GetUserByExternalIdResponse, MapUsersRequest, MapUsersResponse, BulkGroupsRequest, BulkGroupsResponse, DeleteGroupsByExternalIdRequest, DeleteGroupsByExternalIdResponse, GetGroupByExternalIdRequest, GetGroupByExternalIdResponse } from './';
2
+ import { ForgeExtendedContext, RequestConfig, BulkEntityRequest, BulkEntityResponse, BulkUsersRequest, BulkUsersResponse, DeleteUsersByExternalIdRequest, DeleteUsersByExternalIdResponse, GetUserByExternalIdRequest, GetUserByExternalIdResponse, MapUsersRequest, MapUsersResponse, BulkGroupsRequest, BulkGroupsResponse, DeleteGroupsByExternalIdRequest, DeleteGroupsByExternalIdResponse, GetGroupByExternalIdRequest, GetGroupByExternalIdResponse, GetEntityByExternalIdRequest, GetEntityByExternalIdResponse, DeleteEntitiesByExternalIdRequest, DeleteEntitiesByExternalIdResponse, DeleteEntitiesByPropertiesRequest, DeleteEntitiesByPropertiesResponse } from './';
3
3
  export interface TeamWorkGraph {
4
4
  setEntities(request: BulkEntityRequest): Promise<BulkEntityResponse>;
5
- deleteEntity(context: ForgeExtendedContext, entityId: string): Promise<Result>;
5
+ getEntityByExternalId(request: GetEntityByExternalIdRequest): Promise<GetEntityByExternalIdResponse>;
6
+ deleteEntitiesByExternalId(request: DeleteEntitiesByExternalIdRequest): Promise<DeleteEntitiesByExternalIdResponse>;
7
+ deleteEntitiesByProperties(request: DeleteEntitiesByPropertiesRequest): Promise<DeleteEntitiesByPropertiesResponse>;
6
8
  fetchData(context: ForgeExtendedContext, requestConfig: RequestConfig, onResult: Function): Promise<Result>;
7
9
  transformData(context: ForgeExtendedContext, data: any, transformMethod: Function): Promise<any>;
8
10
  setUsers(request: BulkUsersRequest): Promise<BulkUsersResponse>;
@@ -1 +1 @@
1
- {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/types/graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,IAAI,CAAC;AAEZ,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrE,YAAY,CAAC,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,SAAS,CAAC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5G,aAAa,CAAC,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,GAAG,EAAE,eAAe,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAGjG,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChE,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAC;IAC3G,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC/F,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAG9D,SAAS,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACnE,wBAAwB,CAAC,OAAO,EAAE,+BAA+B,GAAG,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAC9G,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;CACnG"}
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/types/graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,4BAA4B,EAC5B,4BAA4B,EAC5B,6BAA6B,EAC7B,iCAAiC,EACjC,kCAAkC,EAClC,iCAAiC,EACjC,kCAAkC,EACnC,MAAM,IAAI,CAAC;AAEZ,MAAM,WAAW,aAAa;IAE5B,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrE,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAAC;IACrG,0BAA0B,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACpH,0BAA0B,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAAC,kCAAkC,CAAC,CAAC;IAGpH,SAAS,CAAC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5G,aAAa,CAAC,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,GAAG,EAAE,eAAe,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAGjG,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChE,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAC;IAC3G,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC/F,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAG9D,SAAS,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACnE,wBAAwB,CAAC,OAAO,EAAE,+BAA+B,GAAG,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAC9G,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;CACnG"}
@@ -10,6 +10,36 @@ export declare type BulkEntityResponse = {
10
10
  error?: string;
11
11
  }>;
12
12
  };
13
+ export declare type GetEntityByExternalIdRequest = {
14
+ entityType: string;
15
+ externalId: string;
16
+ };
17
+ export declare type GetEntityByExternalIdResponse = {
18
+ success: boolean;
19
+ entity?: Entity;
20
+ error?: string;
21
+ };
22
+ export declare type DeleteEntitiesByExternalIdRequest = {
23
+ entityType: string;
24
+ externalIds: string[];
25
+ };
26
+ export declare type DeleteEntitiesByExternalIdResponse = {
27
+ success: boolean;
28
+ results: Array<{
29
+ externalId: string;
30
+ success: boolean;
31
+ error?: string;
32
+ }>;
33
+ };
34
+ export declare type DeleteEntitiesByPropertiesRequest = Record<string, any>;
35
+ export declare type DeleteEntitiesByPropertiesResponse = {
36
+ success: boolean;
37
+ results: Array<{
38
+ entityId: string;
39
+ success: boolean;
40
+ error?: string;
41
+ }>;
42
+ };
13
43
  export declare type BulkUsersRequest = {
14
44
  users: UserPayload[];
15
45
  };
@@ -1 +1 @@
1
- {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../src/types/requests.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../src/types/requests.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/teamwork-graph",
3
- "version": "1.2.0-next.2",
3
+ "version": "1.2.0-next.3",
4
4
  "description": "Forge TeamworkGraph SDK",
5
5
  "author": "Atlassian",
6
6
  "license": "UNLICENSED",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=entities.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"entities.test.d.ts","sourceRoot":"","sources":["../../src/__test__/entities.test.ts"],"names":[],"mappings":""}
@@ -1,187 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_1 = require("@forge/api");
4
- const graph_1 = require("../graph");
5
- jest.mock('@forge/api');
6
- describe('TeamWorkGraphClient - setEntities', () => {
7
- let graphClient;
8
- let mockFetch;
9
- beforeEach(() => {
10
- graphClient = new graph_1.TeamWorkGraphClient();
11
- mockFetch = jest.fn();
12
- api_1.__fetchProduct.mockReturnValue(mockFetch);
13
- jest.clearAllMocks();
14
- });
15
- it('throws if entities array is empty', async () => {
16
- const req = { entities: [] };
17
- await expect(graphClient.setEntities(req)).rejects.toThrow('entities array cannot be empty');
18
- });
19
- it('throws if more than 100 entities', async () => {
20
- const documentEntity = {
21
- schemaVersion: '1.0',
22
- id: 'my-document',
23
- updateSequenceNumber: 123,
24
- displayName: 'My Document',
25
- url: 'https://document.com',
26
- createdAt: '2024-04-16T09:01:32+00:00',
27
- lastUpdatedAt: '2024-04-16T09:01:32+00:00',
28
- permissions: {
29
- accessControls: [
30
- {
31
- principals: [
32
- {
33
- type: 'EVERYONE'
34
- }
35
- ]
36
- }
37
- ]
38
- },
39
- 'atlassian:document': {
40
- type: {
41
- category: 'document',
42
- iconUrl: 'http://icon.com'
43
- },
44
- content: {
45
- mimeType: 'text/plain',
46
- text: 'Really large content here...'
47
- }
48
- }
49
- };
50
- const req = {
51
- entities: Array(101).fill(documentEntity)
52
- };
53
- await expect(graphClient.setEntities(req)).rejects.toThrow('Bulk ingestion supports maximum 100 entities');
54
- });
55
- it('posts to /api/v1/entities/bulk and returns response', async () => {
56
- const documentEntity = {
57
- schemaVersion: '1.0',
58
- id: 'my-document',
59
- updateSequenceNumber: 123,
60
- displayName: 'My Document',
61
- url: 'https://document.com',
62
- createdAt: '2024-04-16T09:01:32+00:00',
63
- lastUpdatedAt: '2024-04-16T09:01:32+00:00',
64
- permissions: {
65
- accessControls: [
66
- {
67
- principals: [
68
- {
69
- type: 'EVERYONE'
70
- }
71
- ]
72
- }
73
- ]
74
- },
75
- 'atlassian:document': {
76
- type: {
77
- category: 'document',
78
- iconUrl: 'http://icon.com'
79
- },
80
- content: {
81
- mimeType: 'text/plain',
82
- text: 'Really large content here...'
83
- }
84
- }
85
- };
86
- const req = { entities: [documentEntity] };
87
- const expected = { success: true, results: [{ entityId: 'my-document', success: true }] };
88
- mockFetch.mockResolvedValueOnce({
89
- ok: true,
90
- json: () => Promise.resolve(expected)
91
- });
92
- const result = await graphClient.setEntities(req);
93
- expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
94
- expect(result).toEqual(expected);
95
- });
96
- it('posts message entities to /api/v1/entities/bulk and returns response', async () => {
97
- const messageEntity = {
98
- schemaVersion: '2.0',
99
- id: 'message-1',
100
- updateSequenceNumber: 1,
101
- description: 'Hello everyone!',
102
- url: 'https://atlassian.slack.com/archives/C03DZ3WCN94/p1722400000000000',
103
- createdAt: '2024-07-09T14:27:37.000Z',
104
- lastUpdatedAt: '2024-07-09T14:27:37.000Z',
105
- permissions: {
106
- accessControls: [
107
- {
108
- principals: [
109
- {
110
- type: 'EVERYONE'
111
- }
112
- ]
113
- }
114
- ]
115
- },
116
- containerKey: {
117
- type: 'atlassian:conversation',
118
- value: {
119
- entityId: 'CFG3W7TKJ'
120
- }
121
- },
122
- 'atlassian:message': {
123
- hidden: false,
124
- isPinned: false,
125
- attachments: [
126
- {
127
- url: 'https://atlassian.enterprise.slack.com/files/U02S327DT62/F07FAUT3L00/img_4659.png',
128
- mimeType: 'image/png',
129
- byteSize: 140288
130
- }
131
- ],
132
- lastActive: '2024-07-09T15:27:37.000Z'
133
- }
134
- };
135
- const req = { entities: [messageEntity] };
136
- const expected = { success: true, results: [{ entityId: 'message-1', success: true }] };
137
- mockFetch.mockResolvedValueOnce({
138
- ok: true,
139
- json: () => Promise.resolve(expected)
140
- });
141
- const result = await graphClient.setEntities(req);
142
- expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
143
- expect(result).toEqual(expected);
144
- });
145
- it('throws if entities is not an array', async () => {
146
- const req = { entities: null };
147
- await expect(graphClient.setEntities(req)).rejects.toThrow('entities must be an array');
148
- });
149
- it('posts organisation entities to /api/v1/entities/bulk and returns response', async () => {
150
- const organisationEntity = {
151
- schemaVersion: '2.0',
152
- id: 'org-1',
153
- updateSequenceNumber: 2,
154
- displayName: 'pos 2',
155
- url: 'https://workday.atlassian.com/path-to-org',
156
- createdAt: '2024-07-09T14:27:37.000Z',
157
- lastUpdatedAt: '2024-07-09T14:27:37.000Z',
158
- permissions: {
159
- accessControls: [
160
- {
161
- principals: [
162
- {
163
- type: 'EVERYONE'
164
- }
165
- ]
166
- }
167
- ]
168
- },
169
- parentKey: {
170
- type: 'atlassian:organisation',
171
- value: {
172
- entityId: 'id of the parent org of this org'
173
- }
174
- },
175
- 'atlassian:organisation': {}
176
- };
177
- const req = { entities: [organisationEntity] };
178
- const expected = { success: false, results: [{ entityId: 'org-1', success: true }] };
179
- mockFetch.mockResolvedValueOnce({
180
- ok: true,
181
- json: () => Promise.resolve(expected)
182
- });
183
- const result = await graphClient.setEntities(req);
184
- expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
185
- expect(result).toEqual(expected);
186
- });
187
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=graph.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"graph.test.d.ts","sourceRoot":"","sources":["../../src/__test__/graph.test.ts"],"names":[],"mappings":""}
@@ -1,77 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_1 = require("@forge/api");
4
- const graph_1 = require("../graph");
5
- const errors_1 = require("../utils/errors");
6
- jest.mock('@forge/api');
7
- describe('Teamwork Graph Client', () => {
8
- let graphClient;
9
- let mockFetch;
10
- let mockContext;
11
- beforeEach(() => {
12
- graphClient = new graph_1.TeamWorkGraphClient();
13
- mockFetch = jest.fn();
14
- api_1.__fetchProduct.mockReturnValue(mockFetch);
15
- mockContext = {
16
- ingestionContext: { id: 'test' },
17
- installContext: 'test-installation',
18
- principal: { accountId: 'test' },
19
- license: { isActive: true }
20
- };
21
- jest.clearAllMocks();
22
- });
23
- describe('Context Validation', () => {
24
- const errorMessage = 'Please pass the context object in your method. Refer this - https://developer.atlassian.com/platform/forge/function-reference/';
25
- it('should throw error when context is missing for deleteEntity', async () => {
26
- await expect(graphClient.deleteEntity(undefined, 'entity-123')).rejects.toThrow(errorMessage);
27
- });
28
- it('should throw error when context is missing for fetchData', async () => {
29
- const config = {
30
- url: '/test',
31
- method: 'GET',
32
- remoteKey: 'test'
33
- };
34
- await expect(graphClient.fetchData(undefined, config, (data) => {
35
- return data;
36
- })).rejects.toThrow(errorMessage);
37
- });
38
- it('should throw error when context is missing for transformData', async () => {
39
- await expect(graphClient.transformData(undefined, {}, (data) => {
40
- return data;
41
- })).rejects.toThrow(errorMessage);
42
- });
43
- });
44
- describe('deleteEntity', () => {
45
- const entityId = 'entity-123';
46
- it('should successfully delete an entity', async () => {
47
- const expectedResponse = { success: true };
48
- mockFetch.mockResolvedValueOnce({
49
- ok: true,
50
- json: () => Promise.resolve(expectedResponse)
51
- });
52
- const result = await graphClient.deleteEntity(mockContext, entityId);
53
- expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entity/?resourceId=entity-123', {
54
- method: 'DELETE',
55
- redirect: 'follow',
56
- headers: { 'Content-Type': 'application/json' }
57
- });
58
- expect(result).toEqual(expectedResponse);
59
- });
60
- it('should throw ForgeGraphAPIError when delete request fails', async () => {
61
- const errorResponse = {
62
- ok: false,
63
- status: 404,
64
- statusText: 'Not Found',
65
- headers: {
66
- get: () => null
67
- },
68
- text: () => Promise.resolve(JSON.stringify({
69
- code: 'ENTITY_NOT_FOUND',
70
- message: 'Entity not found'
71
- }))
72
- };
73
- mockFetch.mockResolvedValueOnce(errorResponse);
74
- await expect(graphClient.deleteEntity(mockContext, entityId)).rejects.toThrow(errors_1.ForgeGraphAPIError);
75
- });
76
- });
77
- });