@checkstack/integration-teams-backend 0.0.24 → 0.0.25
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.
- package/CHANGELOG.md +19 -0
- package/package.json +3 -3
- package/src/provider.test.ts +15 -15
- package/src/provider.ts +12 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @checkstack/integration-teams-backend
|
|
2
2
|
|
|
3
|
+
## 0.0.25
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8d1ef12: ## Downstream consumer bumps for the anomaly detection + cache system rollout
|
|
8
|
+
|
|
9
|
+
Packages on this branch were updated as part of the anomaly detection feature (schema annotations on result fields, plugin metadata for the modular cache system) but were not listed in the upstream changesets.
|
|
10
|
+
|
|
11
|
+
- **`@checkstack/healthcheck-common`** (minor) — new RPC contract additions and schema changes supporting per-field anomaly metadata.
|
|
12
|
+
- **`@checkstack/cache-memory-common`** (minor) — new package providing access rules + plugin metadata for the in-memory cache backend.
|
|
13
|
+
- **healthcheck plugins** (patch) — adopt the new `x-anomaly-*` schema annotations on their result fields so anomaly detection works automatically against their checks. No public API changes.
|
|
14
|
+
- **integration / notification / auth / queue / collector plugins** (patch) — minor internal updates as consumers of upstream API changes (cache plugin registry, schema additions). No public API changes.
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [8d1ef12]
|
|
17
|
+
- Updated dependencies [8d1ef12]
|
|
18
|
+
- @checkstack/common@0.7.0
|
|
19
|
+
- @checkstack/backend-api@0.13.0
|
|
20
|
+
- @checkstack/integration-backend@0.1.20
|
|
21
|
+
|
|
3
22
|
## 0.0.24
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/integration-teams-backend",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"checkstack": {
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"lint:code": "eslint . --max-warnings 0"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@checkstack/backend-api": "0.
|
|
16
|
-
"@checkstack/integration-backend": "0.1.
|
|
15
|
+
"@checkstack/backend-api": "0.12.0",
|
|
16
|
+
"@checkstack/integration-backend": "0.1.19",
|
|
17
17
|
"@checkstack/common": "0.6.5",
|
|
18
18
|
"zod": "^4.2.1"
|
|
19
19
|
},
|
package/src/provider.test.ts
CHANGED
|
@@ -177,7 +177,7 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
177
177
|
it("returns success when Graph API is accessible", async () => {
|
|
178
178
|
let requestCount = 0;
|
|
179
179
|
const mockFetch = spyOn(globalThis, "fetch").mockImplementation((async (
|
|
180
|
-
url: RequestInfo | URL
|
|
180
|
+
url: RequestInfo | URL,
|
|
181
181
|
) => {
|
|
182
182
|
requestCount++;
|
|
183
183
|
const urlStr = url.toString();
|
|
@@ -186,7 +186,7 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
186
186
|
if (urlStr.includes("oauth2/v2.0/token")) {
|
|
187
187
|
return new Response(
|
|
188
188
|
JSON.stringify({ access_token: "test-token", expires_in: 3600 }),
|
|
189
|
-
{ status: 200 }
|
|
189
|
+
{ status: 200 },
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -199,7 +199,7 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
199
199
|
{ id: "team-2", displayName: "DevOps" },
|
|
200
200
|
],
|
|
201
201
|
}),
|
|
202
|
-
{ status: 200 }
|
|
202
|
+
{ status: 200 },
|
|
203
203
|
);
|
|
204
204
|
}
|
|
205
205
|
|
|
@@ -224,7 +224,7 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
224
224
|
const mockFetch = spyOn(globalThis, "fetch").mockImplementation(
|
|
225
225
|
(async () => {
|
|
226
226
|
return new Response("Unauthorized", { status: 401 });
|
|
227
|
-
}) as unknown as typeof fetch
|
|
227
|
+
}) as unknown as typeof fetch,
|
|
228
228
|
);
|
|
229
229
|
|
|
230
230
|
try {
|
|
@@ -249,14 +249,14 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
249
249
|
describe("getConnectionOptions", () => {
|
|
250
250
|
it("returns team options", async () => {
|
|
251
251
|
const mockFetch = spyOn(globalThis, "fetch").mockImplementation((async (
|
|
252
|
-
url: RequestInfo | URL
|
|
252
|
+
url: RequestInfo | URL,
|
|
253
253
|
) => {
|
|
254
254
|
const urlStr = url.toString();
|
|
255
255
|
|
|
256
256
|
if (urlStr.includes("oauth2/v2.0/token")) {
|
|
257
257
|
return new Response(
|
|
258
258
|
JSON.stringify({ access_token: "test-token", expires_in: 3600 }),
|
|
259
|
-
{ status: 200 }
|
|
259
|
+
{ status: 200 },
|
|
260
260
|
);
|
|
261
261
|
}
|
|
262
262
|
|
|
@@ -268,7 +268,7 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
268
268
|
{ id: "team-2", displayName: "DevOps" },
|
|
269
269
|
],
|
|
270
270
|
}),
|
|
271
|
-
{ status: 200 }
|
|
271
|
+
{ status: 200 },
|
|
272
272
|
);
|
|
273
273
|
}
|
|
274
274
|
|
|
@@ -300,14 +300,14 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
300
300
|
|
|
301
301
|
it("returns channel options when teamId is provided", async () => {
|
|
302
302
|
const mockFetch = spyOn(globalThis, "fetch").mockImplementation((async (
|
|
303
|
-
url: RequestInfo | URL
|
|
303
|
+
url: RequestInfo | URL,
|
|
304
304
|
) => {
|
|
305
305
|
const urlStr = url.toString();
|
|
306
306
|
|
|
307
307
|
if (urlStr.includes("oauth2/v2.0/token")) {
|
|
308
308
|
return new Response(
|
|
309
309
|
JSON.stringify({ access_token: "test-token", expires_in: 3600 }),
|
|
310
|
-
{ status: 200 }
|
|
310
|
+
{ status: 200 },
|
|
311
311
|
);
|
|
312
312
|
}
|
|
313
313
|
|
|
@@ -319,7 +319,7 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
319
319
|
{ id: "ch-2", displayName: "Alerts" },
|
|
320
320
|
],
|
|
321
321
|
}),
|
|
322
|
-
{ status: 200 }
|
|
322
|
+
{ status: 200 },
|
|
323
323
|
);
|
|
324
324
|
}
|
|
325
325
|
|
|
@@ -351,13 +351,13 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
351
351
|
|
|
352
352
|
it("returns empty array when teamId is missing for channel options", async () => {
|
|
353
353
|
const mockFetch = spyOn(globalThis, "fetch").mockImplementation((async (
|
|
354
|
-
url: RequestInfo | URL
|
|
354
|
+
url: RequestInfo | URL,
|
|
355
355
|
) => {
|
|
356
356
|
const urlStr = url.toString();
|
|
357
357
|
if (urlStr.includes("oauth2/v2.0/token")) {
|
|
358
358
|
return new Response(
|
|
359
359
|
JSON.stringify({ access_token: "test-token", expires_in: 3600 }),
|
|
360
|
-
{ status: 200 }
|
|
360
|
+
{ status: 200 },
|
|
361
361
|
);
|
|
362
362
|
}
|
|
363
363
|
return new Response("Not Found", { status: 404 });
|
|
@@ -396,14 +396,14 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
396
396
|
|
|
397
397
|
const mockFetch = spyOn(globalThis, "fetch").mockImplementation((async (
|
|
398
398
|
url: RequestInfo | URL,
|
|
399
|
-
options?: RequestInit
|
|
399
|
+
options?: RequestInit,
|
|
400
400
|
) => {
|
|
401
401
|
const urlStr = url.toString();
|
|
402
402
|
|
|
403
403
|
if (urlStr.includes("oauth2/v2.0/token")) {
|
|
404
404
|
return new Response(
|
|
405
405
|
JSON.stringify({ access_token: "test-token", expires_in: 3600 }),
|
|
406
|
-
{ status: 200 }
|
|
406
|
+
{ status: 200 },
|
|
407
407
|
);
|
|
408
408
|
}
|
|
409
409
|
|
|
@@ -454,7 +454,7 @@ describe("Microsoft Teams Integration Provider", () => {
|
|
|
454
454
|
const parsedBody = JSON.parse(capturedBody!);
|
|
455
455
|
expect(parsedBody.attachments).toHaveLength(1);
|
|
456
456
|
expect(parsedBody.attachments[0].contentType).toBe(
|
|
457
|
-
"application/vnd.microsoft.card.adaptive"
|
|
457
|
+
"application/vnd.microsoft.card.adaptive",
|
|
458
458
|
);
|
|
459
459
|
} finally {
|
|
460
460
|
mockFetch.mockRestore();
|
package/src/provider.ts
CHANGED
|
@@ -30,7 +30,7 @@ export const TeamsConnectionSchema = z.object({
|
|
|
30
30
|
tenantId: configString({}).describe("Azure AD Tenant ID"),
|
|
31
31
|
clientId: configString({}).describe("Azure AD Application (Client) ID"),
|
|
32
32
|
clientSecret: configString({ "x-secret": true }).describe(
|
|
33
|
-
"Azure AD Client Secret"
|
|
33
|
+
"Azure AD Client Secret",
|
|
34
34
|
),
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -90,7 +90,7 @@ interface TokenResponse {
|
|
|
90
90
|
* Get an app-only access token using client credentials flow.
|
|
91
91
|
*/
|
|
92
92
|
async function getAppToken(
|
|
93
|
-
config: TeamsConnectionConfig
|
|
93
|
+
config: TeamsConnectionConfig,
|
|
94
94
|
): Promise<
|
|
95
95
|
{ success: true; token: string } | { success: false; error: string }
|
|
96
96
|
> {
|
|
@@ -117,7 +117,7 @@ async function getAppToken(
|
|
|
117
117
|
success: false,
|
|
118
118
|
error: `Token request failed (${response.status}): ${errorText.slice(
|
|
119
119
|
0,
|
|
120
|
-
200
|
|
120
|
+
200,
|
|
121
121
|
)}`,
|
|
122
122
|
};
|
|
123
123
|
}
|
|
@@ -131,7 +131,7 @@ async function getAppToken(
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
async function fetchTeams(
|
|
134
|
-
token: string
|
|
134
|
+
token: string,
|
|
135
135
|
): Promise<
|
|
136
136
|
{ success: true; teams: GraphTeam[] } | { success: false; error: string }
|
|
137
137
|
> {
|
|
@@ -157,7 +157,7 @@ async function fetchTeams(
|
|
|
157
157
|
|
|
158
158
|
async function fetchChannels(
|
|
159
159
|
token: string,
|
|
160
|
-
teamId: string
|
|
160
|
+
teamId: string,
|
|
161
161
|
): Promise<
|
|
162
162
|
| { success: true; channels: GraphChannel[] }
|
|
163
163
|
| { success: false; error: string }
|
|
@@ -289,7 +289,7 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
289
289
|
},
|
|
290
290
|
|
|
291
291
|
async getConnectionOptions(
|
|
292
|
-
params: GetConnectionOptionsParams
|
|
292
|
+
params: GetConnectionOptionsParams,
|
|
293
293
|
): Promise<ConnectionOption[]> {
|
|
294
294
|
const {
|
|
295
295
|
resolverName,
|
|
@@ -298,7 +298,6 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
298
298
|
getConnectionWithCredentials,
|
|
299
299
|
} = params;
|
|
300
300
|
|
|
301
|
-
|
|
302
301
|
const connection = await getConnectionWithCredentials(connectionId);
|
|
303
302
|
if (!connection) {
|
|
304
303
|
return [];
|
|
@@ -306,7 +305,6 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
306
305
|
|
|
307
306
|
const config = connection.config as TeamsConnectionConfig;
|
|
308
307
|
|
|
309
|
-
|
|
310
308
|
const tokenResult = await getAppToken(config);
|
|
311
309
|
if (!tokenResult.success) {
|
|
312
310
|
return [];
|
|
@@ -368,8 +366,7 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
368
366
|
message: `Connected successfully. Found ${teamsResult.teams.length} team(s).`,
|
|
369
367
|
};
|
|
370
368
|
} catch (error) {
|
|
371
|
-
const message =
|
|
372
|
-
extractErrorMessage(error, "Invalid configuration");
|
|
369
|
+
const message = extractErrorMessage(error, "Invalid configuration");
|
|
373
370
|
return {
|
|
374
371
|
success: false,
|
|
375
372
|
message: `Validation failed: ${message}`,
|
|
@@ -378,7 +375,7 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
378
375
|
},
|
|
379
376
|
|
|
380
377
|
async deliver(
|
|
381
|
-
context: IntegrationDeliveryContext<TeamsSubscriptionConfig
|
|
378
|
+
context: IntegrationDeliveryContext<TeamsSubscriptionConfig>,
|
|
382
379
|
): Promise<IntegrationDeliveryResult> {
|
|
383
380
|
const { event, subscription, providerConfig, logger } = context;
|
|
384
381
|
|
|
@@ -392,7 +389,7 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
392
389
|
}
|
|
393
390
|
|
|
394
391
|
const connection = await context.getConnectionWithCredentials(
|
|
395
|
-
config.connectionId
|
|
392
|
+
config.connectionId,
|
|
396
393
|
);
|
|
397
394
|
|
|
398
395
|
if (!connection) {
|
|
@@ -404,7 +401,6 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
404
401
|
|
|
405
402
|
const connectionConfig = connection.config as TeamsConnectionConfig;
|
|
406
403
|
|
|
407
|
-
|
|
408
404
|
const tokenResult = await getAppToken(connectionConfig);
|
|
409
405
|
if (!tokenResult.success) {
|
|
410
406
|
logger.error("Failed to get Graph API token", {
|
|
@@ -416,7 +412,6 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
416
412
|
};
|
|
417
413
|
}
|
|
418
414
|
|
|
419
|
-
|
|
420
415
|
const adaptiveCard = buildAdaptiveCard({
|
|
421
416
|
eventId: event.eventId,
|
|
422
417
|
payload: event.payload as Record<string, unknown>,
|
|
@@ -424,7 +419,6 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
424
419
|
timestamp: event.timestamp,
|
|
425
420
|
});
|
|
426
421
|
|
|
427
|
-
|
|
428
422
|
try {
|
|
429
423
|
const response = await fetch(
|
|
430
424
|
`${GRAPH_API_BASE}/teams/${config.teamId}/channels/${config.channelId}/messages`,
|
|
@@ -448,7 +442,7 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
448
442
|
],
|
|
449
443
|
}),
|
|
450
444
|
signal: AbortSignal.timeout(10_000),
|
|
451
|
-
}
|
|
445
|
+
},
|
|
452
446
|
);
|
|
453
447
|
|
|
454
448
|
if (!response.ok) {
|
|
@@ -461,7 +455,7 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
461
455
|
success: false,
|
|
462
456
|
error: `Graph API error (${response.status}): ${errorText.slice(
|
|
463
457
|
0,
|
|
464
|
-
100
|
|
458
|
+
100,
|
|
465
459
|
)}`,
|
|
466
460
|
};
|
|
467
461
|
}
|
|
@@ -474,8 +468,7 @@ For the app to send messages, it must be installed in the target Team:
|
|
|
474
468
|
externalId: messageData.id,
|
|
475
469
|
};
|
|
476
470
|
} catch (error) {
|
|
477
|
-
const message =
|
|
478
|
-
extractErrorMessage(error, "Unknown Graph API error");
|
|
471
|
+
const message = extractErrorMessage(error, "Unknown Graph API error");
|
|
479
472
|
logger.error("Teams delivery error", { error: message });
|
|
480
473
|
return {
|
|
481
474
|
success: false,
|