@friggframework/admin-scripts 2.0.0--canary.545.b4ca16d.0 → 2.0.0--canary.517.8eaf5df.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +277 -0
  2. package/index.js +23 -6
  3. package/package.json +6 -6
  4. package/src/adapters/__tests__/aws-scheduler-adapter.test.js +106 -45
  5. package/src/adapters/__tests__/local-scheduler-adapter.test.js +24 -10
  6. package/src/adapters/__tests__/scheduler-adapter-factory.test.js +30 -9
  7. package/src/adapters/__tests__/scheduler-adapter.test.js +6 -2
  8. package/src/adapters/aws-scheduler-adapter.js +55 -28
  9. package/src/adapters/local-scheduler-adapter.js +2 -2
  10. package/src/adapters/scheduler-adapter-factory.js +3 -1
  11. package/src/adapters/scheduler-adapter.js +9 -3
  12. package/src/application/__tests__/admin-frigg-commands.test.js +73 -30
  13. package/src/application/__tests__/admin-script-base.test.js +23 -6
  14. package/src/application/__tests__/script-factory.test.js +30 -6
  15. package/src/application/__tests__/script-runner.test.js +113 -24
  16. package/src/application/__tests__/validate-script-input.test.js +54 -15
  17. package/src/application/admin-frigg-commands.js +21 -9
  18. package/src/application/admin-script-base.js +3 -2
  19. package/src/application/script-factory.js +3 -1
  20. package/src/application/script-runner.js +90 -48
  21. package/src/application/use-cases/__tests__/delete-schedule-use-case.test.js +16 -7
  22. package/src/application/use-cases/__tests__/get-effective-schedule-use-case.test.js +9 -4
  23. package/src/application/use-cases/__tests__/upsert-schedule-use-case.test.js +21 -10
  24. package/src/application/use-cases/delete-schedule-use-case.js +6 -4
  25. package/src/application/use-cases/get-effective-schedule-use-case.js +3 -1
  26. package/src/application/use-cases/index.js +3 -1
  27. package/src/application/use-cases/upsert-schedule-use-case.js +30 -11
  28. package/src/application/validate-script-input.js +10 -3
  29. package/src/builtins/__tests__/integration-health-check.test.js +232 -127
  30. package/src/builtins/__tests__/oauth-token-refresh.test.js +128 -75
  31. package/src/builtins/index.js +1 -4
  32. package/src/builtins/integration-health-check.js +63 -30
  33. package/src/builtins/oauth-token-refresh.js +64 -29
  34. package/src/infrastructure/__tests__/admin-auth-middleware.test.js +9 -3
  35. package/src/infrastructure/__tests__/admin-script-router.test.js +125 -52
  36. package/src/infrastructure/admin-auth-middleware.js +3 -1
  37. package/src/infrastructure/admin-script-router.js +129 -14
  38. package/src/infrastructure/bootstrap.js +87 -0
  39. package/src/infrastructure/script-executor-handler.js +119 -52
  40. package/src/application/__tests__/dry-run-http-interceptor.test.js +0 -313
  41. package/src/application/__tests__/dry-run-repository-wrapper.test.js +0 -257
  42. package/src/application/__tests__/schedule-management-use-case.test.js +0 -276
  43. package/src/application/dry-run-http-interceptor.js +0 -296
  44. package/src/application/dry-run-repository-wrapper.js +0 -261
  45. package/src/application/schedule-management-use-case.js +0 -230
@@ -3,10 +3,15 @@ const { OAuthTokenRefreshScript } = require('../oauth-token-refresh');
3
3
  describe('OAuthTokenRefreshScript', () => {
4
4
  describe('Definition', () => {
5
5
  it('should have correct name and metadata', () => {
6
- expect(OAuthTokenRefreshScript.Definition.name).toBe('oauth-token-refresh');
6
+ expect(OAuthTokenRefreshScript.Definition.name).toBe(
7
+ 'oauth-token-refresh'
8
+ );
7
9
  expect(OAuthTokenRefreshScript.Definition.version).toBe('1.0.0');
8
10
  expect(OAuthTokenRefreshScript.Definition.source).toBe('BUILTIN');
9
- expect(OAuthTokenRefreshScript.Definition.config.requireIntegrationInstance).toBe(true);
11
+ expect(
12
+ OAuthTokenRefreshScript.Definition.config
13
+ .requireIntegrationInstance
14
+ ).toBe(true);
10
15
  });
11
16
 
12
17
  it('should have valid input schema', () => {
@@ -27,15 +32,23 @@ describe('OAuthTokenRefreshScript', () => {
27
32
  });
28
33
 
29
34
  it('should have appropriate timeout configuration', () => {
30
- expect(OAuthTokenRefreshScript.Definition.config.timeout).toBe(600000); // 10 minutes
35
+ expect(OAuthTokenRefreshScript.Definition.config.timeout).toBe(
36
+ 600000
37
+ ); // 10 minutes
31
38
  });
32
39
 
33
40
  it('should have clean display object without redundant fields', () => {
34
41
  expect(OAuthTokenRefreshScript.Definition.display).toBeDefined();
35
- expect(OAuthTokenRefreshScript.Definition.display.category).toBe('maintenance');
42
+ expect(OAuthTokenRefreshScript.Definition.display.category).toBe(
43
+ 'maintenance'
44
+ );
36
45
  // Should NOT have redundant label/description
37
- expect(OAuthTokenRefreshScript.Definition.display.label).toBeUndefined();
38
- expect(OAuthTokenRefreshScript.Definition.display.description).toBeUndefined();
46
+ expect(
47
+ OAuthTokenRefreshScript.Definition.display.label
48
+ ).toBeUndefined();
49
+ expect(
50
+ OAuthTokenRefreshScript.Definition.display.description
51
+ ).toBeUndefined();
39
52
  });
40
53
  });
41
54
 
@@ -56,7 +69,9 @@ describe('OAuthTokenRefreshScript', () => {
56
69
  });
57
70
 
58
71
  it('should return empty results when no integrations found', async () => {
59
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([]);
72
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
73
+ []
74
+ );
60
75
 
61
76
  const result = await script.execute({});
62
77
 
@@ -64,15 +79,21 @@ describe('OAuthTokenRefreshScript', () => {
64
79
  expect(result.failed).toBe(0);
65
80
  expect(result.skipped).toBe(0);
66
81
  expect(result.details).toEqual([]);
67
- expect(mockContext.log).toHaveBeenCalledWith('info', expect.any(String), expect.any(Object));
82
+ expect(mockContext.log).toHaveBeenCalledWith(
83
+ 'info',
84
+ expect.any(String),
85
+ expect.any(Object)
86
+ );
68
87
  });
69
88
 
70
89
  it('should skip integrations without OAuth credentials', async () => {
71
90
  const integration = {
72
91
  id: 'int-1',
73
- config: {} // No credentials
92
+ config: {}, // No credentials
74
93
  };
75
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
94
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
95
+ [integration]
96
+ );
76
97
 
77
98
  const result = await script.execute({});
78
99
 
@@ -81,7 +102,7 @@ describe('OAuthTokenRefreshScript', () => {
81
102
  expect(result.details[0]).toMatchObject({
82
103
  integrationId: 'int-1',
83
104
  action: 'skipped',
84
- reason: 'No OAuth credentials found'
105
+ reason: 'No OAuth credentials found',
85
106
  });
86
107
  });
87
108
 
@@ -90,12 +111,14 @@ describe('OAuthTokenRefreshScript', () => {
90
111
  id: 'int-1',
91
112
  config: {
92
113
  credentials: {
93
- access_token: 'token123'
114
+ access_token: 'token123',
94
115
  // No expires_at
95
- }
96
- }
116
+ },
117
+ },
97
118
  };
98
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
119
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
120
+ [integration]
121
+ );
99
122
 
100
123
  const result = await script.execute({});
101
124
 
@@ -103,7 +126,7 @@ describe('OAuthTokenRefreshScript', () => {
103
126
  expect(result.details[0]).toMatchObject({
104
127
  integrationId: 'int-1',
105
128
  action: 'skipped',
106
- reason: 'No expiry time found'
129
+ reason: 'No expiry time found',
107
130
  });
108
131
  });
109
132
 
@@ -114,21 +137,23 @@ describe('OAuthTokenRefreshScript', () => {
114
137
  config: {
115
138
  credentials: {
116
139
  access_token: 'token123',
117
- expires_at: farFutureExpiry.toISOString()
118
- }
119
- }
140
+ expires_at: farFutureExpiry.toISOString(),
141
+ },
142
+ },
120
143
  };
121
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
144
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
145
+ [integration]
146
+ );
122
147
 
123
148
  const result = await script.execute({
124
- expiryThresholdHours: 24
149
+ expiryThresholdHours: 24,
125
150
  });
126
151
 
127
152
  expect(result.skipped).toBe(1);
128
153
  expect(result.details[0]).toMatchObject({
129
154
  integrationId: 'int-1',
130
155
  action: 'skipped',
131
- reason: 'Token not near expiry'
156
+ reason: 'Token not near expiry',
132
157
  });
133
158
  });
134
159
 
@@ -139,32 +164,38 @@ describe('OAuthTokenRefreshScript', () => {
139
164
  config: {
140
165
  credentials: {
141
166
  access_token: 'token123',
142
- expires_at: soonExpiry.toISOString()
143
- }
144
- }
167
+ expires_at: soonExpiry.toISOString(),
168
+ },
169
+ },
145
170
  };
146
171
 
147
172
  const mockInstance = {
148
173
  primary: {
149
174
  api: {
150
- refreshAccessToken: jest.fn().mockResolvedValue(undefined)
151
- }
152
- }
175
+ refreshAccessToken: jest
176
+ .fn()
177
+ .mockResolvedValue(undefined),
178
+ },
179
+ },
153
180
  };
154
181
 
155
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
182
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
183
+ [integration]
184
+ );
156
185
  mockContext.instantiate.mockResolvedValue(mockInstance);
157
186
 
158
187
  const result = await script.execute({
159
- expiryThresholdHours: 24
188
+ expiryThresholdHours: 24,
160
189
  });
161
190
 
162
191
  expect(result.refreshed).toBe(1);
163
192
  expect(result.skipped).toBe(0);
164
- expect(mockInstance.primary.api.refreshAccessToken).toHaveBeenCalled();
193
+ expect(
194
+ mockInstance.primary.api.refreshAccessToken
195
+ ).toHaveBeenCalled();
165
196
  expect(result.details[0]).toMatchObject({
166
197
  integrationId: 'int-1',
167
- action: 'refreshed'
198
+ action: 'refreshed',
168
199
  });
169
200
  });
170
201
 
@@ -175,16 +206,18 @@ describe('OAuthTokenRefreshScript', () => {
175
206
  config: {
176
207
  credentials: {
177
208
  access_token: 'token123',
178
- expires_at: soonExpiry.toISOString()
179
- }
180
- }
209
+ expires_at: soonExpiry.toISOString(),
210
+ },
211
+ },
181
212
  };
182
213
 
183
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
214
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
215
+ [integration]
216
+ );
184
217
 
185
218
  const result = await script.execute({
186
219
  expiryThresholdHours: 24,
187
- dryRun: true
220
+ dryRun: true,
188
221
  });
189
222
 
190
223
  expect(result.refreshed).toBe(0);
@@ -193,7 +226,7 @@ describe('OAuthTokenRefreshScript', () => {
193
226
  expect(result.details[0]).toMatchObject({
194
227
  integrationId: 'int-1',
195
228
  action: 'skipped',
196
- reason: 'Dry run - would have refreshed'
229
+ reason: 'Dry run - would have refreshed',
197
230
  });
198
231
  });
199
232
 
@@ -204,24 +237,28 @@ describe('OAuthTokenRefreshScript', () => {
204
237
  config: {
205
238
  credentials: {
206
239
  access_token: 'token123',
207
- expires_at: soonExpiry.toISOString()
208
- }
209
- }
240
+ expires_at: soonExpiry.toISOString(),
241
+ },
242
+ },
210
243
  };
211
244
 
212
245
  const mockInstance = {
213
246
  primary: {
214
247
  api: {
215
- refreshAccessToken: jest.fn().mockRejectedValue(new Error('API Error'))
216
- }
217
- }
248
+ refreshAccessToken: jest
249
+ .fn()
250
+ .mockRejectedValue(new Error('API Error')),
251
+ },
252
+ },
218
253
  };
219
254
 
220
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
255
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
256
+ [integration]
257
+ );
221
258
  mockContext.instantiate.mockResolvedValue(mockInstance);
222
259
 
223
260
  const result = await script.execute({
224
- expiryThresholdHours: 24
261
+ expiryThresholdHours: 24,
225
262
  });
226
263
 
227
264
  expect(result.failed).toBe(1);
@@ -229,7 +266,7 @@ describe('OAuthTokenRefreshScript', () => {
229
266
  expect(result.details[0]).toMatchObject({
230
267
  integrationId: 'int-1',
231
268
  action: 'failed',
232
- reason: 'API Error'
269
+ reason: 'API Error',
233
270
  });
234
271
  });
235
272
 
@@ -240,57 +277,67 @@ describe('OAuthTokenRefreshScript', () => {
240
277
  config: {
241
278
  credentials: {
242
279
  access_token: 'token123',
243
- expires_at: soonExpiry.toISOString()
244
- }
245
- }
280
+ expires_at: soonExpiry.toISOString(),
281
+ },
282
+ },
246
283
  };
247
284
 
248
285
  const mockInstance = {
249
286
  primary: {
250
287
  api: {
251
288
  // No refreshAccessToken method
252
- }
253
- }
289
+ },
290
+ },
254
291
  };
255
292
 
256
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
293
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
294
+ [integration]
295
+ );
257
296
  mockContext.instantiate.mockResolvedValue(mockInstance);
258
297
 
259
298
  const result = await script.execute({
260
- expiryThresholdHours: 24
299
+ expiryThresholdHours: 24,
261
300
  });
262
301
 
263
302
  expect(result.skipped).toBe(1);
264
303
  expect(result.details[0]).toMatchObject({
265
304
  integrationId: 'int-1',
266
305
  action: 'skipped',
267
- reason: 'API does not support token refresh'
306
+ reason: 'API does not support token refresh',
268
307
  });
269
308
  });
270
309
 
271
310
  it('should filter by specific integration IDs', async () => {
272
311
  const integration1 = {
273
312
  id: 'int-1',
274
- config: { credentials: { access_token: 'token1' } }
313
+ config: { credentials: { access_token: 'token1' } },
275
314
  };
276
315
  const integration2 = {
277
316
  id: 'int-2',
278
- config: { credentials: { access_token: 'token2' } }
317
+ config: { credentials: { access_token: 'token2' } },
279
318
  };
280
319
 
281
- mockContext.integrationRepository.findIntegrationById.mockImplementation((id) => {
282
- if (id === 'int-1') return Promise.resolve(integration1);
283
- if (id === 'int-2') return Promise.resolve(integration2);
284
- return Promise.reject(new Error('Not found'));
285
- });
320
+ mockContext.integrationRepository.findIntegrationById.mockImplementation(
321
+ (id) => {
322
+ if (id === 'int-1') return Promise.resolve(integration1);
323
+ if (id === 'int-2') return Promise.resolve(integration2);
324
+ return Promise.reject(new Error('Not found'));
325
+ }
326
+ );
286
327
 
287
328
  const result = await script.execute({
288
- integrationIds: ['int-1', 'int-2']
329
+ integrationIds: ['int-1', 'int-2'],
289
330
  });
290
331
 
291
- expect(mockContext.integrationRepository.findIntegrationById).toHaveBeenCalledWith('int-1');
292
- expect(mockContext.integrationRepository.findIntegrationById).toHaveBeenCalledWith('int-2');
293
- expect(mockContext.integrationRepository.findIntegrations).not.toHaveBeenCalled();
332
+ expect(
333
+ mockContext.integrationRepository.findIntegrationById
334
+ ).toHaveBeenCalledWith('int-1');
335
+ expect(
336
+ mockContext.integrationRepository.findIntegrationById
337
+ ).toHaveBeenCalledWith('int-2');
338
+ expect(
339
+ mockContext.integrationRepository.findIntegrations
340
+ ).not.toHaveBeenCalled();
294
341
  expect(result.details).toHaveLength(2);
295
342
  });
296
343
 
@@ -300,23 +347,29 @@ describe('OAuthTokenRefreshScript', () => {
300
347
  config: {
301
348
  credentials: {
302
349
  access_token: 'token123',
303
- expires_at: new Date(Date.now() + 12 * 60 * 60 * 1000).toISOString()
304
- }
305
- }
350
+ expires_at: new Date(
351
+ Date.now() + 12 * 60 * 60 * 1000
352
+ ).toISOString(),
353
+ },
354
+ },
306
355
  };
307
356
 
308
- mockContext.integrationRepository.findIntegrations.mockResolvedValue([integration]);
309
- mockContext.instantiate.mockRejectedValue(new Error('Instantiation failed'));
357
+ mockContext.integrationRepository.findIntegrations.mockResolvedValue(
358
+ [integration]
359
+ );
360
+ mockContext.instantiate.mockRejectedValue(
361
+ new Error('Instantiation failed')
362
+ );
310
363
 
311
364
  const result = await script.execute({
312
- expiryThresholdHours: 24
365
+ expiryThresholdHours: 24,
313
366
  });
314
367
 
315
368
  expect(result.failed).toBe(1);
316
369
  expect(result.details[0]).toMatchObject({
317
370
  integrationId: 'int-1',
318
371
  action: 'failed',
319
- reason: 'Instantiation failed'
372
+ reason: 'Instantiation failed',
320
373
  });
321
374
  });
322
375
  });
@@ -338,12 +391,12 @@ describe('OAuthTokenRefreshScript', () => {
338
391
  // This test validates the method can be called directly
339
392
  const integration = {
340
393
  id: 'int-1',
341
- config: {}
394
+ config: {},
342
395
  };
343
396
 
344
397
  const result = await script.processIntegration(integration, {
345
398
  expiryThresholdHours: 24,
346
- dryRun: false
399
+ dryRun: false,
347
400
  });
348
401
 
349
402
  expect(result).toHaveProperty('integrationId');
@@ -7,10 +7,7 @@ const { IntegrationHealthCheckScript } = require('./integration-health-check');
7
7
  * These scripts ship with @friggframework/admin-scripts and provide
8
8
  * common maintenance and monitoring functionality.
9
9
  */
10
- const builtinScripts = [
11
- OAuthTokenRefreshScript,
12
- IntegrationHealthCheckScript,
13
- ];
10
+ const builtinScripts = [OAuthTokenRefreshScript, IntegrationHealthCheckScript];
14
11
 
15
12
  /**
16
13
  * Register all built-in scripts with a factory
@@ -21,24 +21,25 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
21
21
  integrationIds: {
22
22
  type: 'array',
23
23
  items: { type: 'string' },
24
- description: 'Specific integration IDs to check (optional, defaults to all)'
24
+ description:
25
+ 'Specific integration IDs to check (optional, defaults to all)',
25
26
  },
26
27
  checkCredentials: {
27
28
  type: 'boolean',
28
29
  default: true,
29
- description: 'Verify credential validity'
30
+ description: 'Verify credential validity',
30
31
  },
31
32
  checkConnectivity: {
32
33
  type: 'boolean',
33
34
  default: true,
34
- description: 'Test API connectivity'
35
+ description: 'Test API connectivity',
35
36
  },
36
37
  updateStatus: {
37
38
  type: 'boolean',
38
39
  default: false,
39
- description: 'Update integration status based on health'
40
- }
41
- }
40
+ description: 'Update integration status based on health',
41
+ },
42
+ },
42
43
  },
43
44
 
44
45
  outputSchema: {
@@ -47,18 +48,17 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
47
48
  healthy: { type: 'number' },
48
49
  unhealthy: { type: 'number' },
49
50
  unknown: { type: 'number' },
50
- results: { type: 'array' }
51
- }
51
+ results: { type: 'array' },
52
+ },
52
53
  },
53
54
 
54
55
  config: {
55
56
  timeout: 900000, // 15 minutes
56
- maxRetries: 0,
57
57
  requireIntegrationInstance: true,
58
58
  },
59
59
 
60
60
  schedule: {
61
- enabled: false, // Can be enabled via API
61
+ enabled: false, // Can be enabled via API
62
62
  cronExpression: 'cron(0 6 * * ? *)', // Daily at 6 AM UTC
63
63
  },
64
64
 
@@ -73,40 +73,47 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
73
73
  integrationIds = null,
74
74
  checkCredentials = true,
75
75
  checkConnectivity = true,
76
- updateStatus = false
76
+ updateStatus = false,
77
77
  } = params;
78
78
 
79
79
  const summary = {
80
80
  healthy: 0,
81
81
  unhealthy: 0,
82
82
  unknown: 0,
83
- results: []
83
+ results: [],
84
84
  };
85
85
 
86
86
  this.context.log('info', 'Starting integration health check', {
87
87
  checkCredentials,
88
88
  checkConnectivity,
89
89
  updateStatus,
90
- specificIds: integrationIds?.length || 'all'
90
+ specificIds: integrationIds?.length || 'all',
91
91
  });
92
92
 
93
93
  // Get integrations to check
94
94
  let integrations;
95
95
  if (integrationIds && integrationIds.length > 0) {
96
96
  integrations = await Promise.all(
97
- integrationIds.map(id => this.context.integrationRepository.findIntegrationById(id).catch(() => null))
97
+ integrationIds.map((id) =>
98
+ this.context.integrationRepository
99
+ .findIntegrationById(id)
100
+ .catch(() => null)
101
+ )
98
102
  );
99
103
  integrations = integrations.filter(Boolean);
100
104
  } else {
101
105
  integrations = await this.getAllIntegrations();
102
106
  }
103
107
 
104
- this.context.log('info', `Checking ${integrations.length} integrations`);
108
+ this.context.log(
109
+ 'info',
110
+ `Checking ${integrations.length} integrations`
111
+ );
105
112
 
106
113
  for (const integration of integrations) {
107
114
  const result = await this.checkIntegration(integration, {
108
115
  checkCredentials,
109
- checkConnectivity
116
+ checkConnectivity,
110
117
  });
111
118
 
112
119
  summary.results.push(result);
@@ -122,13 +129,24 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
122
129
  // Optionally update integration status
123
130
  if (updateStatus && result.status !== 'unknown') {
124
131
  try {
125
- const newStatus = result.status === 'healthy' ? 'ACTIVE' : 'ERROR';
126
- await this.context.integrationRepository.updateIntegrationStatus(integration.id, newStatus);
127
- this.context.log('info', `Updated status for ${integration.id} to ${newStatus}`);
132
+ const newStatus =
133
+ result.status === 'healthy' ? 'ACTIVE' : 'ERROR';
134
+ await this.context.integrationRepository.updateIntegrationStatus(
135
+ integration.id,
136
+ newStatus
137
+ );
138
+ this.context.log(
139
+ 'info',
140
+ `Updated status for ${integration.id} to ${newStatus}`
141
+ );
128
142
  } catch (error) {
129
- this.context.log('warn', `Failed to update status for ${integration.id}`, {
130
- error: error.message
131
- });
143
+ this.context.log(
144
+ 'warn',
145
+ `Failed to update status for ${integration.id}`,
146
+ {
147
+ error: error.message,
148
+ }
149
+ );
132
150
  }
133
151
  }
134
152
  }
@@ -136,7 +154,7 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
136
154
  this.context.log('info', 'Health check completed', {
137
155
  healthy: summary.healthy,
138
156
  unhealthy: summary.unhealthy,
139
- unknown: summary.unknown
157
+ unknown: summary.unknown,
140
158
  });
141
159
 
142
160
  return summary;
@@ -151,7 +169,10 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
151
169
  const result = this._createCheckResult(integration);
152
170
 
153
171
  try {
154
- await this._runChecks(integration, result, { checkCredentials, checkConnectivity });
172
+ await this._runChecks(integration, result, {
173
+ checkCredentials,
174
+ checkConnectivity,
175
+ });
155
176
  this._determineOverallStatus(result);
156
177
  } catch (error) {
157
178
  this._handleCheckError(integration, result, error);
@@ -170,7 +191,7 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
170
191
  integrationType: integration.config?.type || 'unknown',
171
192
  status: 'unknown',
172
193
  checks: {},
173
- issues: []
194
+ issues: [],
174
195
  };
175
196
  }
176
197
 
@@ -182,11 +203,19 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
182
203
  const { checkCredentials, checkConnectivity } = options;
183
204
 
184
205
  if (checkCredentials) {
185
- this._addCheckResult(result, 'credentials', this.checkCredentialValidity(integration));
206
+ this._addCheckResult(
207
+ result,
208
+ 'credentials',
209
+ this.checkCredentialValidity(integration)
210
+ );
186
211
  }
187
212
 
188
213
  if (checkConnectivity) {
189
- this._addCheckResult(result, 'connectivity', await this.checkApiConnectivity(integration));
214
+ this._addCheckResult(
215
+ result,
216
+ 'connectivity',
217
+ await this.checkApiConnectivity(integration)
218
+ );
190
219
  }
191
220
  }
192
221
 
@@ -214,9 +243,13 @@ class IntegrationHealthCheckScript extends AdminScriptBase {
214
243
  * @private
215
244
  */
216
245
  _handleCheckError(integration, result, error) {
217
- this.context.log('error', `Error checking integration ${integration.id}`, {
218
- error: error.message
219
- });
246
+ this.context.log(
247
+ 'error',
248
+ `Error checking integration ${integration.id}`,
249
+ {
250
+ error: error.message,
251
+ }
252
+ );
220
253
  result.status = 'unknown';
221
254
  result.issues.push(`Check failed: ${error.message}`);
222
255
  }