@auxee/piece-ms-teams-transcripts 0.0.1 → 0.0.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.
- package/package.json +1 -1
- package/src/index.js +2 -1
- package/src/index.js.map +1 -1
- package/src/triggers/meetings-webhook.trigger.d.ts +15 -0
- package/src/triggers/meetings-webhook.trigger.js +129 -0
- package/src/triggers/meetings-webhook.trigger.js.map +1 -0
- package/src/triggers/transcript-generated.trigger.d.ts +18 -25
- package/src/triggers/transcript-generated.trigger.js +83 -226
- package/src/triggers/transcript-generated.trigger.js.map +1 -1
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -54,6 +54,7 @@ exports.msTeamsTranscripts = void 0;
|
|
|
54
54
|
const pieces_framework_1 = require("@activepieces/pieces-framework");
|
|
55
55
|
const shared_1 = require("@activepieces/shared");
|
|
56
56
|
const transcript_generated_trigger_1 = require("./triggers/transcript-generated.trigger");
|
|
57
|
+
const meetings_webhook_trigger_1 = require("./triggers/meetings-webhook.trigger");
|
|
57
58
|
const fetch_transcript_action_1 = require("./actions/fetch-transcript.action");
|
|
58
59
|
const send_message_action_1 = require("./actions/send-message.action");
|
|
59
60
|
exports.msTeamsTranscripts = (0, pieces_framework_1.createPiece)({
|
|
@@ -66,7 +67,7 @@ exports.msTeamsTranscripts = (0, pieces_framework_1.createPiece)({
|
|
|
66
67
|
// No user-facing auth - credentials come from environment variables
|
|
67
68
|
auth: pieces_framework_1.PieceAuth.None(),
|
|
68
69
|
actions: [fetch_transcript_action_1.fetchTranscriptAction, send_message_action_1.sendMessageAction],
|
|
69
|
-
triggers: [transcript_generated_trigger_1.transcriptGeneratedTrigger],
|
|
70
|
+
triggers: [transcript_generated_trigger_1.transcriptGeneratedTrigger, meetings_webhook_trigger_1.meetingsWebhookTrigger],
|
|
70
71
|
authors: ['auxee'],
|
|
71
72
|
});
|
|
72
73
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/pieces/custom/ms-teams-transcripts/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;;;AAEH,qEAAwE;AACxE,iDAAqD;AACrD,0FAAqF;AACrF,+EAA0E;AAC1E,uEAAkE;AAErD,QAAA,kBAAkB,GAAG,IAAA,8BAAW,EAAC;IAC5C,WAAW,EAAE,sBAAsB;IACnC,WAAW,EACT,qFAAqF;QACrF,4DAA4D;IAC9D,uBAAuB,EAAE,QAAQ;IACjC,OAAO,EAAE,yDAAyD;IAClE,UAAU,EAAE,CAAC,sBAAa,CAAC,aAAa,EAAE,sBAAa,CAAC,YAAY,CAAC;IAErE,oEAAoE;IACpE,IAAI,EAAE,4BAAS,CAAC,IAAI,EAAE;IAEtB,OAAO,EAAE,CAAC,+CAAqB,EAAE,uCAAiB,CAAC;IACnD,QAAQ,EAAE,CAAC,yDAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/pieces/custom/ms-teams-transcripts/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;;;AAEH,qEAAwE;AACxE,iDAAqD;AACrD,0FAAqF;AACrF,kFAA6E;AAC7E,+EAA0E;AAC1E,uEAAkE;AAErD,QAAA,kBAAkB,GAAG,IAAA,8BAAW,EAAC;IAC5C,WAAW,EAAE,sBAAsB;IACnC,WAAW,EACT,qFAAqF;QACrF,4DAA4D;IAC9D,uBAAuB,EAAE,QAAQ;IACjC,OAAO,EAAE,yDAAyD;IAClE,UAAU,EAAE,CAAC,sBAAa,CAAC,aAAa,EAAE,sBAAa,CAAC,YAAY,CAAC;IAErE,oEAAoE;IACpE,IAAI,EAAE,4BAAS,CAAC,IAAI,EAAE;IAEtB,OAAO,EAAE,CAAC,+CAAqB,EAAE,uCAAiB,CAAC;IACnD,QAAQ,EAAE,CAAC,yDAA0B,EAAE,iDAAsB,CAAC;IAC9D,OAAO,EAAE,CAAC,OAAO,CAAC;CACnB,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meetings Webhook Trigger
|
|
3
|
+
*
|
|
4
|
+
* A simple webhook trigger that provides a single shared URL per environment.
|
|
5
|
+
* This URL can be used for Microsoft Graph API subscriptions to receive
|
|
6
|
+
* transcript notifications. The endpoint is shared across all users in the environment.
|
|
7
|
+
*/
|
|
8
|
+
import { TriggerStrategy } from '@activepieces/pieces-framework';
|
|
9
|
+
export declare const meetingsWebhookTrigger: import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.WEBHOOK, import("@activepieces/pieces-framework").PieceAuthProperty, {
|
|
10
|
+
instructions: import("dist/packages/pieces/community/framework/src/lib/property/input/markdown-property").MarkDownProperty;
|
|
11
|
+
}> | import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.POLLING, import("@activepieces/pieces-framework").PieceAuthProperty, {
|
|
12
|
+
instructions: import("dist/packages/pieces/community/framework/src/lib/property/input/markdown-property").MarkDownProperty;
|
|
13
|
+
}> | import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.APP_WEBHOOK, import("@activepieces/pieces-framework").PieceAuthProperty, {
|
|
14
|
+
instructions: import("dist/packages/pieces/community/framework/src/lib/property/input/markdown-property").MarkDownProperty;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Meetings Webhook Trigger
|
|
4
|
+
*
|
|
5
|
+
* A simple webhook trigger that provides a single shared URL per environment.
|
|
6
|
+
* This URL can be used for Microsoft Graph API subscriptions to receive
|
|
7
|
+
* transcript notifications. The endpoint is shared across all users in the environment.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.meetingsWebhookTrigger = void 0;
|
|
11
|
+
const tslib_1 = require("tslib");
|
|
12
|
+
const pieces_framework_1 = require("@activepieces/pieces-framework");
|
|
13
|
+
const shared_1 = require("@activepieces/shared");
|
|
14
|
+
const setupMarkdown = `
|
|
15
|
+
## Webhook Setup
|
|
16
|
+
|
|
17
|
+
This trigger provides a **single shared webhook URL** for your environment that you can use for Microsoft Graph API subscriptions.
|
|
18
|
+
|
|
19
|
+
### Webhook URL
|
|
20
|
+
|
|
21
|
+
Use this URL when creating your Microsoft Graph API subscription:
|
|
22
|
+
|
|
23
|
+
\`\`\`text
|
|
24
|
+
https://auxee-ca-workflows-qa-wus.orangerock-849186b3.westus.azurecontainerapps.io/api/v1/webhooks/meetings
|
|
25
|
+
\`\`\`
|
|
26
|
+
|
|
27
|
+
### Setting Up Microsoft Graph API Subscription
|
|
28
|
+
|
|
29
|
+
1. **Create a subscription** using Microsoft Graph API:
|
|
30
|
+
\`\`\`http
|
|
31
|
+
POST https://graph.microsoft.com/v1.0/subscriptions
|
|
32
|
+
Content-Type: application/json
|
|
33
|
+
Authorization: Bearer <your-access-token>
|
|
34
|
+
|
|
35
|
+
{
|
|
36
|
+
"changeType": "created",
|
|
37
|
+
"notificationUrl": "https://auxee-ca-workflows-qa-wus.orangerock-849186b3.westus.azurecontainerapps.io/api/v1/webhooks/meetings",
|
|
38
|
+
"resource": "communications/onlineMeetings/getAllTranscripts",
|
|
39
|
+
"expirationDateTime": "2026-01-20T00:00:00Z",
|
|
40
|
+
"clientState": "optional-secret-value"
|
|
41
|
+
}
|
|
42
|
+
\`\`\`
|
|
43
|
+
|
|
44
|
+
2. **Required Permissions**: Your Azure AD app needs:
|
|
45
|
+
- \`OnlineMeetingTranscript.Read.All\` (Application permission)
|
|
46
|
+
- \`OnlineMeetings.Read.All\` (Application permission)
|
|
47
|
+
|
|
48
|
+
### Important Notes
|
|
49
|
+
|
|
50
|
+
- This is a **shared endpoint** - one URL per environment, used by all users
|
|
51
|
+
- Multiple flows can use this trigger - all will receive the same webhook events
|
|
52
|
+
- You need to create the Graph API subscription separately
|
|
53
|
+
- The endpoint automatically handles Graph API validation tokens
|
|
54
|
+
`;
|
|
55
|
+
exports.meetingsWebhookTrigger = (0, pieces_framework_1.createTrigger)({
|
|
56
|
+
name: 'meetings_webhook',
|
|
57
|
+
displayName: 'Meetings Webhook',
|
|
58
|
+
description: 'Receives webhook events via a shared endpoint URL. Use this URL for Microsoft Graph API subscriptions.',
|
|
59
|
+
type: pieces_framework_1.TriggerStrategy.WEBHOOK,
|
|
60
|
+
sampleData: {
|
|
61
|
+
changeType: 'created',
|
|
62
|
+
resource: 'communications/onlineMeetings/19:meeting_xxxxx@thread.v2/transcripts/transcript-id-123',
|
|
63
|
+
resourceData: {
|
|
64
|
+
'@odata.type': '#Microsoft.Graph.onlineMeetingTranscript',
|
|
65
|
+
'@odata.id': 'communications/onlineMeetings/19:meeting_xxxxx@thread.v2/transcripts/transcript-id-123',
|
|
66
|
+
id: 'transcript-id-123',
|
|
67
|
+
},
|
|
68
|
+
subscriptionId: 'subscription-id-123',
|
|
69
|
+
tenantId: 'tenant-id-123',
|
|
70
|
+
meetingId: '19:meeting_xxxxx@thread.v2',
|
|
71
|
+
transcriptId: 'transcript-id-123',
|
|
72
|
+
},
|
|
73
|
+
props: {
|
|
74
|
+
instructions: pieces_framework_1.Property.MarkDown({
|
|
75
|
+
value: setupMarkdown,
|
|
76
|
+
variant: shared_1.MarkdownVariant.INFO,
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
onEnable() {
|
|
80
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
81
|
+
// No registration needed - the endpoint is stable and shared
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
onDisable() {
|
|
85
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
// No cleanup needed - the endpoint remains active for other flows
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
run(context) {
|
|
90
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
var _a;
|
|
92
|
+
const body = context.payload.body;
|
|
93
|
+
// Handle Microsoft Graph API validation token (for subscription setup)
|
|
94
|
+
if ((_a = context.payload.queryParams) === null || _a === void 0 ? void 0 : _a.validationToken) {
|
|
95
|
+
// Validation token is handled by the backend controller
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
// Handle Microsoft Graph API change notifications
|
|
99
|
+
// Graph API sends notifications in { value: [...] } format
|
|
100
|
+
if (body && Array.isArray(body.value)) {
|
|
101
|
+
// Extract and normalize transcript notifications
|
|
102
|
+
return body.value.map((notification) => {
|
|
103
|
+
var _a;
|
|
104
|
+
// Extract meeting ID and transcript ID from resource path
|
|
105
|
+
const resource = notification.resource || '';
|
|
106
|
+
const meetingMatch = resource.match(/onlineMeetings\/([^\/]+)/);
|
|
107
|
+
const transcriptMatch = resource.match(/transcripts\/([^\/]+)/);
|
|
108
|
+
return {
|
|
109
|
+
changeType: notification.changeType,
|
|
110
|
+
resource: notification.resource,
|
|
111
|
+
resourceData: notification.resourceData,
|
|
112
|
+
subscriptionId: notification.subscriptionId,
|
|
113
|
+
tenantId: notification.tenantId,
|
|
114
|
+
clientState: notification.clientState,
|
|
115
|
+
subscriptionExpirationDateTime: notification.subscriptionExpirationDateTime,
|
|
116
|
+
// Extracted fields for easier access
|
|
117
|
+
meetingId: meetingMatch ? meetingMatch[1] : null,
|
|
118
|
+
transcriptId: transcriptMatch ? transcriptMatch[1] : (((_a = notification.resourceData) === null || _a === void 0 ? void 0 : _a.id) || null),
|
|
119
|
+
// Raw notification for full access
|
|
120
|
+
rawNotification: notification,
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// Return body as-is for any other payload format
|
|
125
|
+
return [body];
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=meetings-webhook.trigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meetings-webhook.trigger.js","sourceRoot":"","sources":["../../../../../../../packages/pieces/custom/ms-teams-transcripts/src/triggers/meetings-webhook.trigger.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;AAEH,qEAIwC;AACxC,iDAAuD;AAEvD,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCrB,CAAC;AAEW,QAAA,sBAAsB,GAAG,IAAA,gCAAa,EAAC;IAClD,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,kBAAkB;IAC/B,WAAW,EAAE,wGAAwG;IACrH,IAAI,EAAE,kCAAe,CAAC,OAAO;IAC7B,UAAU,EAAE;QACV,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,wFAAwF;QAClG,YAAY,EAAE;YACZ,aAAa,EAAE,0CAA0C;YACzD,WAAW,EAAE,wFAAwF;YACrG,EAAE,EAAE,mBAAmB;SACxB;QACD,cAAc,EAAE,qBAAqB;QACrC,QAAQ,EAAE,eAAe;QACzB,SAAS,EAAE,4BAA4B;QACvC,YAAY,EAAE,mBAAmB;KAClC;IACD,KAAK,EAAE;QACL,YAAY,EAAE,2BAAQ,CAAC,QAAQ,CAAC;YAC9B,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,wBAAe,CAAC,IAAI;SAC9B,CAAC;KACH;IACK,QAAQ;;YACZ,6DAA6D;QAC/D,CAAC;KAAA;IACK,SAAS;;YACb,kEAAkE;QACpE,CAAC;KAAA;IACK,GAAG,CAAC,OAAO;;;YACf,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,IAAW,CAAC;YAEzC,uEAAuE;YACvE,IAAI,MAAA,OAAO,CAAC,OAAO,CAAC,WAAW,0CAAE,eAAe,EAAE,CAAC;gBACjD,wDAAwD;gBACxD,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,kDAAkD;YAClD,2DAA2D;YAC3D,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtC,iDAAiD;gBACjD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,YAAiB,EAAE,EAAE;;oBAC1C,0DAA0D;oBAC1D,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,IAAI,EAAE,CAAC;oBAC7C,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;oBAChE,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;oBAEhE,OAAO;wBACL,UAAU,EAAE,YAAY,CAAC,UAAU;wBACnC,QAAQ,EAAE,YAAY,CAAC,QAAQ;wBAC/B,YAAY,EAAE,YAAY,CAAC,YAAY;wBACvC,cAAc,EAAE,YAAY,CAAC,cAAc;wBAC3C,QAAQ,EAAE,YAAY,CAAC,QAAQ;wBAC/B,WAAW,EAAE,YAAY,CAAC,WAAW;wBACrC,8BAA8B,EAAE,YAAY,CAAC,8BAA8B;wBAC3E,qCAAqC;wBACrC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;wBAChD,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA,MAAA,YAAY,CAAC,YAAY,0CAAE,EAAE,KAAI,IAAI,CAAC;wBAC5F,mCAAmC;wBACnC,eAAe,EAAE,YAAY;qBAC9B,CAAC;gBACJ,CAAC,CAAC,CAAC;YACL,CAAC;YAED,iDAAiD;YACjD,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;KAAA;CACF,CAAC,CAAC"}
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Transcript Generated Trigger
|
|
2
|
+
* Transcript Generated Trigger (Meeting Link Based)
|
|
3
3
|
*
|
|
4
|
-
* This
|
|
4
|
+
* This trigger polls a Microsoft Teams meeting (provided via meeting link)
|
|
5
|
+
* and fires when a transcript is generated.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* 4. Extracts onlineMeeting.id from calendar events
|
|
11
|
-
* 5. Fetches transcripts for each meeting
|
|
12
|
-
* 6. Triggers when a new transcript is detected (not seen before)
|
|
7
|
+
* IMPORTANT:
|
|
8
|
+
* - Uses APPLICATION-ONLY Microsoft Graph permissions
|
|
9
|
+
* - Does NOT discover meetings
|
|
10
|
+
* - Does NOT scan users or calendars
|
|
13
11
|
*
|
|
14
|
-
*
|
|
15
|
-
* The /communications/onlineMeetings endpoint does NOT reliably return
|
|
16
|
-
* scheduled calendar meetings. Calendar events are the only reliable
|
|
17
|
-
* anchor for discovering Teams meetings with transcripts.
|
|
18
|
-
*
|
|
19
|
-
* NO USER INPUT REQUIRED:
|
|
20
|
-
* - Meeting IDs are discovered automatically from calendar
|
|
21
|
-
* - Transcript IDs are discovered automatically
|
|
22
|
-
*
|
|
23
|
-
* Required Permissions (Application):
|
|
12
|
+
* Required Application Permissions:
|
|
24
13
|
* - OnlineMeetingTranscript.Read.All
|
|
25
|
-
*
|
|
26
|
-
*
|
|
14
|
+
*
|
|
15
|
+
* Application Access Policy:
|
|
16
|
+
* - App must be allowed via Teams Application Access Policy
|
|
27
17
|
*/
|
|
28
18
|
import { TriggerStrategy } from '@activepieces/pieces-framework';
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
export declare const transcriptGeneratedTrigger: import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.WEBHOOK, import("@activepieces/pieces-framework").PieceAuthProperty, {
|
|
20
|
+
meetingLink: import("@activepieces/pieces-framework").ShortTextProperty<true>;
|
|
21
|
+
}> | import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.POLLING, import("@activepieces/pieces-framework").PieceAuthProperty, {
|
|
22
|
+
meetingLink: import("@activepieces/pieces-framework").ShortTextProperty<true>;
|
|
23
|
+
}> | import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.APP_WEBHOOK, import("@activepieces/pieces-framework").PieceAuthProperty, {
|
|
24
|
+
meetingLink: import("@activepieces/pieces-framework").ShortTextProperty<true>;
|
|
25
|
+
}>;
|
|
@@ -1,30 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Transcript Generated Trigger
|
|
3
|
+
* Transcript Generated Trigger (Meeting Link Based)
|
|
4
4
|
*
|
|
5
|
-
* This
|
|
5
|
+
* This trigger polls a Microsoft Teams meeting (provided via meeting link)
|
|
6
|
+
* and fires when a transcript is generated.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* 4. Extracts onlineMeeting.id from calendar events
|
|
12
|
-
* 5. Fetches transcripts for each meeting
|
|
13
|
-
* 6. Triggers when a new transcript is detected (not seen before)
|
|
8
|
+
* IMPORTANT:
|
|
9
|
+
* - Uses APPLICATION-ONLY Microsoft Graph permissions
|
|
10
|
+
* - Does NOT discover meetings
|
|
11
|
+
* - Does NOT scan users or calendars
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
* The /communications/onlineMeetings endpoint does NOT reliably return
|
|
17
|
-
* scheduled calendar meetings. Calendar events are the only reliable
|
|
18
|
-
* anchor for discovering Teams meetings with transcripts.
|
|
19
|
-
*
|
|
20
|
-
* NO USER INPUT REQUIRED:
|
|
21
|
-
* - Meeting IDs are discovered automatically from calendar
|
|
22
|
-
* - Transcript IDs are discovered automatically
|
|
23
|
-
*
|
|
24
|
-
* Required Permissions (Application):
|
|
13
|
+
* Required Application Permissions:
|
|
25
14
|
* - OnlineMeetingTranscript.Read.All
|
|
26
|
-
*
|
|
27
|
-
*
|
|
15
|
+
*
|
|
16
|
+
* Application Access Policy:
|
|
17
|
+
* - App must be allowed via Teams Application Access Policy
|
|
28
18
|
*/
|
|
29
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
20
|
exports.transcriptGeneratedTrigger = void 0;
|
|
@@ -33,270 +23,137 @@ const pieces_framework_1 = require("@activepieces/pieces-framework");
|
|
|
33
23
|
const pieces_common_1 = require("@activepieces/pieces-common");
|
|
34
24
|
const graph_token_1 = require("../utils/graph-token");
|
|
35
25
|
const ms_teams_app_auth_1 = require("../auth/ms-teams-app-auth");
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
/* -------------------------------------------------------------------------- */
|
|
27
|
+
/* Meeting Link → Meeting ID */
|
|
28
|
+
/* -------------------------------------------------------------------------- */
|
|
38
29
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const users = [];
|
|
44
|
-
let nextLink = `/users?$top=${limit}&$select=id,displayName,mail,userPrincipalName&$filter=accountEnabled eq true`;
|
|
45
|
-
try {
|
|
46
|
-
while (nextLink) {
|
|
47
|
-
const response = yield (0, graph_token_1.graphGet)(nextLink);
|
|
48
|
-
users.push(...(response.value || []));
|
|
49
|
-
nextLink = response['@odata.nextLink'];
|
|
50
|
-
// Safety limit to prevent infinite loops
|
|
51
|
-
if (users.length > 500)
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
catch (error) {
|
|
56
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
57
|
-
console.error('Error fetching users:', errorMessage);
|
|
58
|
-
}
|
|
59
|
-
return users;
|
|
60
|
-
});
|
|
61
|
-
/**
|
|
62
|
-
* Fetches calendar events for a specific user
|
|
63
|
-
* Filters for Teams online meetings only
|
|
30
|
+
* Extracts meetingId from a Microsoft Teams meeting link.
|
|
31
|
+
*
|
|
32
|
+
* Example link contains:
|
|
33
|
+
* 19:meeting_xxxxx@thread.v2
|
|
64
34
|
*/
|
|
65
|
-
const
|
|
66
|
-
const events = [];
|
|
67
|
-
// Calculate date range - look back N days
|
|
68
|
-
const startDate = new Date();
|
|
69
|
-
startDate.setDate(startDate.getDate() - LOOKBACK_DAYS);
|
|
70
|
-
const startDateStr = startDate.toISOString();
|
|
71
|
-
const endDate = new Date();
|
|
72
|
-
const endDateStr = endDate.toISOString();
|
|
35
|
+
const extractMeetingIdFromLink = (link) => {
|
|
73
36
|
try {
|
|
74
|
-
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
`&$top=50`;
|
|
81
|
-
while (nextLink) {
|
|
82
|
-
try {
|
|
83
|
-
const response = yield (0, graph_token_1.graphGet)(nextLink);
|
|
84
|
-
// Filter for online meetings only
|
|
85
|
-
const onlineMeetings = (response.value || []).filter(event => event.isOnlineMeeting === true && event.onlineMeetingId);
|
|
86
|
-
events.push(...onlineMeetings);
|
|
87
|
-
nextLink = response['@odata.nextLink'];
|
|
88
|
-
// Safety limit
|
|
89
|
-
if (events.length > 200)
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
94
|
-
// 403 or 404 means no access to this user's calendar - skip
|
|
95
|
-
if (errorMessage.includes('403') || errorMessage.includes('404')) {
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
throw error;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
catch (error) {
|
|
103
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
104
|
-
// Silently skip users we can't access
|
|
105
|
-
if (!errorMessage.includes('403') && !errorMessage.includes('404')) {
|
|
106
|
-
console.error(`Error fetching calendar for user ${userId}:`, errorMessage);
|
|
37
|
+
const decoded = decodeURIComponent(link);
|
|
38
|
+
// Case 1: threadId in query params (meeting recap link)
|
|
39
|
+
const url = new URL(decoded);
|
|
40
|
+
const threadId = url.searchParams.get('threadId');
|
|
41
|
+
if (threadId === null || threadId === void 0 ? void 0 : threadId.startsWith('19:meeting_')) {
|
|
42
|
+
return threadId;
|
|
107
43
|
}
|
|
44
|
+
// Case 2: meetup-join link
|
|
45
|
+
const match = decoded.match(/19:meeting_[^@]+@thread\.v2/);
|
|
46
|
+
return match ? match[0] : null;
|
|
108
47
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Discovers Teams meetings from calendar events across all users
|
|
113
|
-
* This is the CORRECT way to find meetings with transcripts
|
|
114
|
-
*/
|
|
115
|
-
const discoverTeamsMeetingsFromCalendar = () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
116
|
-
var _a, _b;
|
|
117
|
-
const meetings = [];
|
|
118
|
-
const seenMeetingIds = new Set();
|
|
119
|
-
// Step 1: Get all users in the tenant
|
|
120
|
-
const users = yield fetchUsers(100);
|
|
121
|
-
if (users.length === 0) {
|
|
122
|
-
console.log('No users found in the tenant');
|
|
123
|
-
return [];
|
|
48
|
+
catch (_a) {
|
|
49
|
+
return null;
|
|
124
50
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const calendarEvents = yield fetchUserCalendarEvents(user.id);
|
|
130
|
-
// Step 3: Extract meeting info from events with onlineMeetingId
|
|
131
|
-
for (const event of calendarEvents) {
|
|
132
|
-
// The onlineMeetingId is the key - this is what we need for transcript API
|
|
133
|
-
const meetingId = event.onlineMeetingId;
|
|
134
|
-
if (meetingId && !seenMeetingIds.has(meetingId)) {
|
|
135
|
-
seenMeetingIds.add(meetingId);
|
|
136
|
-
meetings.push({
|
|
137
|
-
onlineMeetingId: meetingId,
|
|
138
|
-
subject: event.subject,
|
|
139
|
-
startDateTime: (_a = event.start) === null || _a === void 0 ? void 0 : _a.dateTime,
|
|
140
|
-
endDateTime: (_b = event.end) === null || _b === void 0 ? void 0 : _b.dateTime,
|
|
141
|
-
organizerId: user.id,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
// Continue with other users
|
|
148
|
-
console.error(`Error processing user ${user.id}:`, error);
|
|
149
|
-
}
|
|
150
|
-
// Limit total meetings to prevent long polling times
|
|
151
|
-
if (meetings.length > 500)
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
console.log(`Discovered ${meetings.length} Teams meetings from calendars`);
|
|
155
|
-
return meetings;
|
|
156
|
-
});
|
|
157
|
-
/**
|
|
158
|
-
* Fetches transcripts for a specific meeting using app-level access
|
|
159
|
-
* Uses /communications/onlineMeetings/{meetingId}/transcripts endpoint
|
|
160
|
-
*/
|
|
51
|
+
};
|
|
52
|
+
/* -------------------------------------------------------------------------- */
|
|
53
|
+
/* Fetch Transcripts for a Meeting */
|
|
54
|
+
/* -------------------------------------------------------------------------- */
|
|
161
55
|
const fetchMeetingTranscripts = (meetingId) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
162
56
|
try {
|
|
163
|
-
const response = yield (0, graph_token_1.graphGet)(`/communications/onlineMeetings/${meetingId}/transcripts`);
|
|
57
|
+
const response = yield (0, graph_token_1.graphGet)(`/communications/onlineMeetings/${encodeURIComponent(meetingId)}/transcripts`);
|
|
164
58
|
return response.value || [];
|
|
165
59
|
}
|
|
166
60
|
catch (error) {
|
|
167
|
-
const
|
|
168
|
-
//
|
|
169
|
-
if (
|
|
61
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
62
|
+
// Normal / expected cases
|
|
63
|
+
if (message.includes('404'))
|
|
170
64
|
return [];
|
|
171
|
-
|
|
172
|
-
// 403 means permission denied - meeting may not have transcripts enabled
|
|
173
|
-
if (errorMessage.includes('403')) {
|
|
65
|
+
if (message.includes('403'))
|
|
174
66
|
return [];
|
|
175
|
-
}
|
|
176
|
-
// Log other errors but don't fail
|
|
177
|
-
console.error(`Error fetching transcripts for meeting ${meetingId}:`, errorMessage);
|
|
67
|
+
console.error(`Error fetching transcripts for meeting ${meetingId}:`, message);
|
|
178
68
|
return [];
|
|
179
69
|
}
|
|
180
70
|
});
|
|
181
|
-
/**
|
|
182
|
-
* The polling configuration for detecting new transcripts.
|
|
183
|
-
* Uses LAST_ITEM strategy for deduplication.
|
|
184
|
-
*/
|
|
185
71
|
const polling = {
|
|
186
72
|
strategy: pieces_common_1.DedupeStrategy.LAST_ITEM,
|
|
187
|
-
items: () => tslib_1.__awaiter(void 0,
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (meetings.length === 0) {
|
|
192
|
-
console.log('No Teams meetings found in calendars');
|
|
73
|
+
items: (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ propsValue }) {
|
|
74
|
+
const { meetingLink } = propsValue;
|
|
75
|
+
if (!meetingLink) {
|
|
76
|
+
console.log('Meeting link not provided');
|
|
193
77
|
return [];
|
|
194
78
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// Step 3: Create output for each transcript found
|
|
200
|
-
for (const transcript of transcripts) {
|
|
201
|
-
transcriptOutputs.push({
|
|
202
|
-
meetingId: meeting.onlineMeetingId,
|
|
203
|
-
transcriptId: transcript.id,
|
|
204
|
-
meetingSubject: meeting.subject,
|
|
205
|
-
startDateTime: meeting.startDateTime,
|
|
206
|
-
endDateTime: meeting.endDateTime,
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
catch (error) {
|
|
211
|
-
console.error(`Error processing meeting ${meeting.onlineMeetingId}:`, error);
|
|
212
|
-
// Continue with other meetings
|
|
213
|
-
}
|
|
79
|
+
const meetingId = extractMeetingIdFromLink(meetingLink);
|
|
80
|
+
if (!meetingId) {
|
|
81
|
+
console.log('Invalid Microsoft Teams meeting link');
|
|
82
|
+
return [];
|
|
214
83
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
84
|
+
const transcripts = yield fetchMeetingTranscripts(meetingId);
|
|
85
|
+
if (transcripts.length === 0) {
|
|
86
|
+
console.log(`No transcripts generated yet for meeting ${meetingId}`);
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
const sorted = [...transcripts].sort((a, b) => new Date(b.createdDateTime).getTime() -
|
|
90
|
+
new Date(a.createdDateTime).getTime());
|
|
91
|
+
return sorted.map((t) => ({
|
|
92
|
+
id: `${meetingId}:${t.id}`,
|
|
93
|
+
data: {
|
|
94
|
+
meetingId,
|
|
95
|
+
transcriptId: t.id,
|
|
96
|
+
createdDateTime: t.createdDateTime,
|
|
97
|
+
},
|
|
227
98
|
}));
|
|
228
99
|
}),
|
|
229
100
|
};
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
*/
|
|
101
|
+
/* -------------------------------------------------------------------------- */
|
|
102
|
+
/* Trigger */
|
|
103
|
+
/* -------------------------------------------------------------------------- */
|
|
233
104
|
exports.transcriptGeneratedTrigger = (0, pieces_framework_1.createTrigger)({
|
|
234
105
|
name: 'transcript_generated',
|
|
235
|
-
displayName: 'Transcript Generated',
|
|
236
|
-
description: '
|
|
237
|
-
'Discovers meetings from calendar events and fetches transcripts automatically.',
|
|
106
|
+
displayName: 'Transcript Generated (Meeting Link)',
|
|
107
|
+
description: 'Triggers when a transcript is generated for a Microsoft Teams meeting provided via meeting link.',
|
|
238
108
|
type: pieces_framework_1.TriggerStrategy.POLLING,
|
|
239
|
-
// Sample data shown in the UI when testing
|
|
240
109
|
sampleData: {
|
|
241
|
-
meetingId: '
|
|
242
|
-
transcriptId: '
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
110
|
+
meetingId: '19:meeting_xxxxx@thread.v2',
|
|
111
|
+
transcriptId: 'sampleTranscriptId',
|
|
112
|
+
createdDateTime: '2026-01-06T09:00:00Z',
|
|
113
|
+
},
|
|
114
|
+
props: {
|
|
115
|
+
meetingLink: pieces_framework_1.Property.ShortText({
|
|
116
|
+
displayName: 'Meeting Link',
|
|
117
|
+
description: 'Paste the Microsoft Teams meeting link',
|
|
118
|
+
required: true,
|
|
119
|
+
}),
|
|
246
120
|
},
|
|
247
|
-
// NO user-configurable properties - everything is automatic
|
|
248
|
-
props: {},
|
|
249
|
-
/**
|
|
250
|
-
* Called when the flow is first enabled.
|
|
251
|
-
* Validates environment and records current transcripts as "seen".
|
|
252
|
-
*/
|
|
253
121
|
onEnable(ctx) {
|
|
254
122
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
255
|
-
// Validate environment variables first
|
|
256
123
|
(0, ms_teams_app_auth_1.validateMSTeamsEnv)();
|
|
257
124
|
yield pieces_common_1.pollingHelper.onEnable(polling, {
|
|
258
125
|
store: ctx.store,
|
|
259
126
|
auth: null,
|
|
260
|
-
propsValue:
|
|
127
|
+
propsValue: ctx.propsValue,
|
|
261
128
|
});
|
|
262
129
|
});
|
|
263
130
|
},
|
|
264
|
-
/**
|
|
265
|
-
* Called on each polling interval to check for new transcripts.
|
|
266
|
-
*/
|
|
267
131
|
run(ctx) {
|
|
268
132
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
269
|
-
return
|
|
133
|
+
return pieces_common_1.pollingHelper.poll(polling, {
|
|
270
134
|
store: ctx.store,
|
|
271
135
|
auth: null,
|
|
272
|
-
propsValue:
|
|
136
|
+
propsValue: ctx.propsValue,
|
|
273
137
|
files: ctx.files,
|
|
274
138
|
});
|
|
275
139
|
});
|
|
276
140
|
},
|
|
277
|
-
/**
|
|
278
|
-
* Called when the flow is disabled.
|
|
279
|
-
*/
|
|
280
141
|
onDisable(ctx) {
|
|
281
142
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
282
143
|
yield pieces_common_1.pollingHelper.onDisable(polling, {
|
|
283
144
|
store: ctx.store,
|
|
284
145
|
auth: null,
|
|
285
|
-
propsValue:
|
|
146
|
+
propsValue: ctx.propsValue,
|
|
286
147
|
});
|
|
287
148
|
});
|
|
288
149
|
},
|
|
289
|
-
/**
|
|
290
|
-
* Called when user clicks "Test" in the UI.
|
|
291
|
-
*/
|
|
292
150
|
test(ctx) {
|
|
293
151
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
294
|
-
// Validate environment variables first
|
|
295
152
|
(0, ms_teams_app_auth_1.validateMSTeamsEnv)();
|
|
296
|
-
return
|
|
153
|
+
return pieces_common_1.pollingHelper.test(polling, {
|
|
297
154
|
store: ctx.store,
|
|
298
155
|
auth: null,
|
|
299
|
-
propsValue:
|
|
156
|
+
propsValue: ctx.propsValue,
|
|
300
157
|
files: ctx.files,
|
|
301
158
|
});
|
|
302
159
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-generated.trigger.js","sourceRoot":"","sources":["../../../../../../../packages/pieces/custom/ms-teams-transcripts/src/triggers/transcript-generated.trigger.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"transcript-generated.trigger.js","sourceRoot":"","sources":["../../../../../../../packages/pieces/custom/ms-teams-transcripts/src/triggers/transcript-generated.trigger.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;AAEH,qEAIwC;AACxC,+DAIqC;AACrC,sDAAgD;AAChD,iEAA+D;AAe/D,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAEhF;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,CAAC,IAAY,EAAiB,EAAE;IAC/D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAEzC,wDAAwD;QACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACxC,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,2BAA2B;QAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjC,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAGF,gFAAgF;AAChF,iFAAiF;AACjF,gFAAgF;AAEhF,MAAM,uBAAuB,GAAG,CAC9B,SAAiB,EACW,EAAE;IAC9B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAA,sBAAQ,EAC7B,kCAAkC,kBAAkB,CAAC,SAAS,CAAC,cAAc,CAC9E,CAAC;QAEF,OAAO,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEvE,0BAA0B;QAC1B,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEvC,OAAO,CAAC,KAAK,CAAC,0CAA0C,SAAS,GAAG,EAAE,OAAO,CAAC,CAAC;QAC/E,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAA,CAAC;AAUF,MAAM,OAAO,GAAgC;IAC3C,QAAQ,EAAE,8BAAc,CAAC,SAAS;IAElC,KAAK,EAAE,KAAuB,EAAE,oDAAlB,EAAE,UAAU,EAAE;QAC1B,MAAM,EAAE,WAAW,EAAE,GAAG,UAAU,CAAC;QAEnC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACzC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,SAAS,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;QAExD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;YACpD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,uBAAuB,CAAC,SAAS,CAAC,CAAC;QAE7D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,4CAA4C,SAAS,EAAE,CAAC,CAAC;YACrE,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAClC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,IAAI,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE;YACrC,IAAI,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CACxC,CAAC;QAEF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxB,EAAE,EAAE,GAAG,SAAS,IAAI,CAAC,CAAC,EAAE,EAAE;YAC1B,IAAI,EAAE;gBACJ,SAAS;gBACT,YAAY,EAAE,CAAC,CAAC,EAAE;gBAClB,eAAe,EAAE,CAAC,CAAC,eAAe;aACnC;SACF,CAAC,CAAC,CAAC;IACN,CAAC,CAAA;CACF,CAAC;AAEF,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAEnE,QAAA,0BAA0B,GAAG,IAAA,gCAAa,EAAC;IACtD,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EAAE,qCAAqC;IAClD,WAAW,EACT,kGAAkG;IACpG,IAAI,EAAE,kCAAe,CAAC,OAAO;IAE7B,UAAU,EAAE;QACV,SAAS,EAAE,4BAA4B;QACvC,YAAY,EAAE,oBAAoB;QAClC,eAAe,EAAE,sBAAsB;KACxC;IAED,KAAK,EAAE;QACL,WAAW,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAC9B,WAAW,EAAE,cAAc;YAC3B,WAAW,EAAE,wCAAwC;YACrD,QAAQ,EAAE,IAAI;SACf,CAAC;KACH;IAEK,QAAQ,CAAC,GAAG;;YAChB,IAAA,sCAAkB,GAAE,CAAC;YACrB,MAAM,6BAAa,CAAC,QAAQ,CAAC,OAAO,EAAE;gBACpC,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,GAAG,CAAC,UAAU;aAC3B,CAAC,CAAC;QACL,CAAC;KAAA;IAEK,GAAG,CAAC,GAAG;;YACX,OAAO,6BAAa,CAAC,IAAI,CAAC,OAAO,EAAE;gBACjC,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;QACL,CAAC;KAAA;IAEK,SAAS,CAAC,GAAG;;YACjB,MAAM,6BAAa,CAAC,SAAS,CAAC,OAAO,EAAE;gBACrC,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,GAAG,CAAC,UAAU;aAC3B,CAAC,CAAC;QACL,CAAC;KAAA;IAEK,IAAI,CAAC,GAAG;;YACZ,IAAA,sCAAkB,GAAE,CAAC;YACrB,OAAO,6BAAa,CAAC,IAAI,CAAC,OAAO,EAAE;gBACjC,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;QACL,CAAC;KAAA;CACF,CAAC,CAAC"}
|