@skillful-ai/piece-skai-instagram-business 0.0.1

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/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # pieces-skai-instagram-business
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build pieces-skai-instagram-business` to build the library.
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@skillful-ai/piece-skai-instagram-business",
3
+ "version": "0.0.1",
4
+ "type": "commonjs",
5
+ "main": "./src/index.js",
6
+ "types": "./src/index.d.ts",
7
+ "dependencies": {
8
+ "@activepieces/pieces-framework": "^0.20.1",
9
+ "@sinclair/typebox": "0.34.11",
10
+ "axios": "1.8.3",
11
+ "axios-retry": "4.4.1",
12
+ "deepmerge-ts": "7.1.0",
13
+ "mime-types": "2.1.35",
14
+ "nanoid": "3.3.8",
15
+ "semver": "7.6.0",
16
+ "tslib": "^2.3.0",
17
+ "zod": "3.25.76",
18
+ "@activepieces/pieces-common": "0.7.0",
19
+ "@activepieces/shared": "0.22.0"
20
+ },
21
+ "overrides": {
22
+ "@tryfabric/martian": {
23
+ "@notionhq/client": "$@notionhq/client"
24
+ },
25
+ "vite": {
26
+ "rollup": "npm:@rollup/wasm-node"
27
+ },
28
+ "undici": "6.19.8"
29
+ },
30
+ "resolutions": {
31
+ "rollup": "npm:@rollup/wasm-node",
32
+ "undici": "6.19.8"
33
+ }
34
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export declare const skaiInstagramBusiness: import("@activepieces/pieces-framework").Piece<import("@activepieces/pieces-framework").CustomAuthProperty<{
2
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
3
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
4
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
5
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
6
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
7
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
8
+ }>>;
package/src/index.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.skaiInstagramBusiness = void 0;
4
+ const pieces_framework_1 = require("@activepieces/pieces-framework");
5
+ const shared_1 = require("@activepieces/shared");
6
+ const instagram_business_auth_1 = require("./lib/auth/instagram-business.auth");
7
+ // Actions
8
+ const send_message_1 = require("./lib/actions/send-message");
9
+ const upload_photo_1 = require("./lib/actions/upload-photo");
10
+ const upload_reel_1 = require("./lib/actions/upload-reel");
11
+ // Triggers
12
+ const new_message_1 = require("./lib/triggers/new-message");
13
+ exports.skaiInstagramBusiness = (0, pieces_framework_1.createPiece)({
14
+ displayName: 'Instagram Business',
15
+ description: 'Send and receive messages on Instagram Business accounts with SKAI Adapters support',
16
+ auth: instagram_business_auth_1.instagramBusinessAuth,
17
+ minimumSupportedRelease: '0.36.1',
18
+ logoUrl: 'https://cdn.activepieces.com/pieces/instagram.png',
19
+ authors: ['Haider Shabbir Hamid', 'Skillful AI'],
20
+ categories: [shared_1.PieceCategory.COMMUNICATION, shared_1.PieceCategory.MARKETING],
21
+ events: {
22
+ parseAndReply: ({ payload }) => {
23
+ var _a, _b, _c;
24
+ const body = payload.body;
25
+ const recipientId = ((_a = body === null || body === void 0 ? void 0 : body.recipient) === null || _a === void 0 ? void 0 : _a.id) || ((_c = (_b = body === null || body === void 0 ? void 0 : body.entry) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.id);
26
+ return {
27
+ event: 'new_instagram_message',
28
+ identifierValue: recipientId,
29
+ };
30
+ },
31
+ verify: () => {
32
+ return true;
33
+ },
34
+ },
35
+ actions: [
36
+ send_message_1.sendMessage,
37
+ upload_photo_1.uploadPhoto,
38
+ upload_reel_1.uploadReel,
39
+ ],
40
+ triggers: [
41
+ new_message_1.newInstagramMessage,
42
+ ],
43
+ });
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/pieces/custom/skai-instagram-business/src/index.ts"],"names":[],"mappings":";;;AAAA,qEAA6D;AAC7D,iDAAqD;AACrD,gFAA2E;AAE3E,UAAU;AACV,6DAAyD;AACzD,6DAAyD;AACzD,2DAAuD;AAEvD,WAAW;AACX,4DAAiE;AAEpD,QAAA,qBAAqB,GAAG,IAAA,8BAAW,EAAC;IAC7C,WAAW,EAAE,oBAAoB;IACjC,WAAW,EAAE,qFAAqF;IAClG,IAAI,EAAE,+CAAqB;IAC3B,uBAAuB,EAAE,QAAQ;IACjC,OAAO,EAAE,mDAAmD;IAC5D,OAAO,EAAE,CAAC,sBAAsB,EAAE,aAAa,CAAC;IAChD,UAAU,EAAE,CAAC,sBAAa,CAAC,aAAa,EAAE,sBAAa,CAAC,SAAS,CAAC;IAClE,MAAM,EAAE;QACJ,aAAa,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;;YAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAW,CAAC;YACjC,MAAM,WAAW,GAAG,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,SAAS,0CAAE,EAAE,MAAI,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,KAAK,0CAAG,CAAC,CAAC,0CAAE,EAAE,CAAA,CAAC;YAChE,OAAO;gBACH,KAAK,EAAE,uBAAuB;gBAC9B,eAAe,EAAE,WAAW;aAC/B,CAAC;QACN,CAAC;QACD,MAAM,EAAE,GAAG,EAAE;YACT,OAAO,IAAI,CAAC;QAChB,CAAC;KACJ;IACD,OAAO,EAAE;QACL,0BAAW;QACX,0BAAW;QACX,wBAAU;KACb;IACD,QAAQ,EAAE;QACN,iCAAmB;KACtB;CACJ,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ export declare const sendMessage: import("@activepieces/pieces-framework").IAction<import("@activepieces/pieces-framework").CustomAuthProperty<{
2
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
3
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
4
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
5
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
6
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
7
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
8
+ }>, {
9
+ recipientId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
10
+ text: import("@activepieces/pieces-framework").LongTextProperty<false>;
11
+ mediaUrl: import("@activepieces/pieces-framework").ShortTextProperty<false>;
12
+ mediaType: import("@activepieces/pieces-framework").StaticDropdownProperty<"image" | "video" | "audio" | "file", false>;
13
+ replyToMessageId: import("@activepieces/pieces-framework").ShortTextProperty<false>;
14
+ reactionEmoji: import("@activepieces/pieces-framework").ShortTextProperty<false>;
15
+ }>;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendMessage = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const pieces_framework_1 = require("@activepieces/pieces-framework");
6
+ const instagram_business_auth_1 = require("../auth/instagram-business.auth");
7
+ const common_1 = require("../common");
8
+ exports.sendMessage = (0, pieces_framework_1.createAction)({
9
+ auth: instagram_business_auth_1.instagramBusinessAuth,
10
+ name: 'sendMessage',
11
+ displayName: 'Send Message',
12
+ description: 'Send a text message, media, or reaction through Instagram',
13
+ props: {
14
+ recipientId: pieces_framework_1.Property.ShortText({
15
+ displayName: 'Recipient ID',
16
+ description: 'The Instagram-scoped ID (IGSID) of the message recipient',
17
+ required: true,
18
+ }),
19
+ text: pieces_framework_1.Property.LongText({
20
+ displayName: 'Message / Caption',
21
+ description: 'The text message to send (or caption if media is provided)',
22
+ required: false,
23
+ }),
24
+ mediaUrl: pieces_framework_1.Property.ShortText({
25
+ displayName: 'Media URL',
26
+ description: 'URL of the media file to send (image, video, audio, file). If provided with text, text will be sent separately.',
27
+ required: false,
28
+ }),
29
+ mediaType: pieces_framework_1.Property.StaticDropdown({
30
+ displayName: 'Media Type',
31
+ description: 'Type of media to send (required when Media URL is provided)',
32
+ required: false,
33
+ options: {
34
+ disabled: false,
35
+ options: common_1.supportedMediaTypes.map((type) => ({
36
+ label: type.charAt(0).toUpperCase() + type.slice(1),
37
+ value: type,
38
+ })),
39
+ },
40
+ }),
41
+ replyToMessageId: pieces_framework_1.Property.ShortText({
42
+ displayName: 'Reply To Message ID',
43
+ description: 'Message ID to reply to (optional)',
44
+ required: false,
45
+ defaultValue: '',
46
+ }),
47
+ reactionEmoji: pieces_framework_1.Property.ShortText({
48
+ displayName: 'Reaction Emoji',
49
+ description: 'Emoji reaction to add to a message (leave empty to remove reaction). Requires Reply To Message ID.',
50
+ required: false,
51
+ })
52
+ },
53
+ run(context) {
54
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
55
+ var _a;
56
+ const { recipientId, text, mediaUrl, mediaType, replyToMessageId, reactionEmoji } = context.propsValue;
57
+ const auth = context.auth;
58
+ // Get valid token (may refresh if needed)
59
+ const { accessToken } = yield common_1.instagramTokenService.getValidToken({
60
+ auth,
61
+ server: context.server,
62
+ project: context.project,
63
+ });
64
+ // Normalize inputs
65
+ const normalizedText = (text === null || text === void 0 ? void 0 : text.trim()) || '';
66
+ const normalizedMediaUrl = (mediaUrl === null || mediaUrl === void 0 ? void 0 : mediaUrl.trim()) || '';
67
+ const normalizedReaction = (_a = reactionEmoji === null || reactionEmoji === void 0 ? void 0 : reactionEmoji.trim()) !== null && _a !== void 0 ? _a : '';
68
+ const normalizedReplyTo = (replyToMessageId === null || replyToMessageId === void 0 ? void 0 : replyToMessageId.trim()) || '';
69
+ // Handle reaction messages first
70
+ const hasTextOrMedia = normalizedText || normalizedMediaUrl;
71
+ const isReactionRequest = normalizedReaction || (normalizedReplyTo && !hasTextOrMedia);
72
+ if (isReactionRequest) {
73
+ if (!normalizedReplyTo) {
74
+ throw new Error('Reply To Message ID is required when sending a reaction');
75
+ }
76
+ const response = yield common_1.instagramApi.sendReaction(auth.instagramAccountId, accessToken, recipientId, normalizedReplyTo, normalizedReaction);
77
+ return {
78
+ success: true,
79
+ reaction: normalizedReaction || '(removed)',
80
+ };
81
+ }
82
+ // Validate that either text or media is provided
83
+ if (!normalizedText && !normalizedMediaUrl) {
84
+ throw new Error('Either message text or media URL must be provided');
85
+ }
86
+ if (normalizedText && normalizedMediaUrl) {
87
+ throw new Error('Either message text or media URL must be provided, not both');
88
+ }
89
+ let result = null;
90
+ // Send media message if media URL is provided
91
+ if (normalizedMediaUrl) {
92
+ const normalizedMediaType = ((mediaType === null || mediaType === void 0 ? void 0 : mediaType.trim()) || '');
93
+ if (!normalizedMediaType) {
94
+ throw new Error('Media Type is required when Media URL is provided');
95
+ }
96
+ if (!common_1.supportedMediaTypes.includes(normalizedMediaType)) {
97
+ throw new Error(`Invalid media type: ${mediaType}. Valid types are: ${common_1.supportedMediaTypes.join(', ')}`);
98
+ }
99
+ result = yield common_1.instagramApi.sendMediaMessage(auth.instagramAccountId, accessToken, recipientId, normalizedMediaType, normalizedMediaUrl);
100
+ }
101
+ else if (normalizedText) {
102
+ // Send text-only message
103
+ result = yield common_1.instagramApi.sendTextMessage(auth.instagramAccountId, accessToken, recipientId, normalizedText);
104
+ }
105
+ return {
106
+ success: true,
107
+ messageId: (result === null || result === void 0 ? void 0 : result.message_id) || null,
108
+ recipientId: recipientId,
109
+ };
110
+ });
111
+ },
112
+ });
113
+ //# sourceMappingURL=send-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-message.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/skai-instagram-business/src/lib/actions/send-message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare const uploadPhoto: import("@activepieces/pieces-framework").IAction<import("@activepieces/pieces-framework").CustomAuthProperty<{
2
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
3
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
4
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
5
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
6
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
7
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
8
+ }>, {
9
+ photo: import("@activepieces/pieces-framework").ShortTextProperty<true>;
10
+ caption: import("@activepieces/pieces-framework").LongTextProperty<false>;
11
+ }>;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadPhoto = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const pieces_framework_1 = require("@activepieces/pieces-framework");
6
+ const pieces_common_1 = require("@activepieces/pieces-common");
7
+ const instagram_business_auth_1 = require("../auth/instagram-business.auth");
8
+ const common_1 = require("../common");
9
+ const description = `
10
+ ## Upload Photo
11
+
12
+ Upload a photo to your Instagram Business Account as a feed post.
13
+
14
+ ### Input Parameters
15
+ - **Photo URL** (required): A publicly accessible URL to the image (JPG/PNG)
16
+ - **Caption**: Optional caption for the post
17
+
18
+ ### Requirements
19
+ - The image URL must be publicly accessible
20
+ - Your Instagram account must be connected to a Facebook Page
21
+ - Requires \`instagram_business_content_publish\` permission
22
+
23
+ ### Output
24
+ Returns the created media ID on success.
25
+ `;
26
+ exports.uploadPhoto = (0, pieces_framework_1.createAction)({
27
+ auth: instagram_business_auth_1.instagramBusinessAuth,
28
+ name: 'upload_photo',
29
+ displayName: 'Upload Photo',
30
+ description: 'Upload a photo to your Instagram Business Account',
31
+ props: {
32
+ photo: pieces_framework_1.Property.ShortText({
33
+ displayName: 'Photo URL',
34
+ description: 'A publicly accessible URL to the image (JPG/PNG)',
35
+ required: true,
36
+ }),
37
+ caption: pieces_framework_1.Property.LongText({
38
+ displayName: 'Caption',
39
+ description: 'Caption for the post',
40
+ required: false,
41
+ }),
42
+ },
43
+ run(context) {
44
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
45
+ const auth = context.auth;
46
+ const { photo, caption } = context.propsValue;
47
+ const { accessToken } = yield common_1.instagramTokenService.getValidToken({
48
+ auth,
49
+ server: context.server,
50
+ project: context.project,
51
+ });
52
+ // Step 1: Create media container
53
+ const createContainerResponse = yield pieces_common_1.httpClient.sendRequest({
54
+ method: pieces_common_1.HttpMethod.POST,
55
+ url: `${common_1.INSTAGRAM_GRAPH_API_BASE}/${auth.instagramAccountId}/media`,
56
+ queryParams: {
57
+ access_token: accessToken,
58
+ image_url: photo,
59
+ caption: caption || '',
60
+ },
61
+ });
62
+ if (!createContainerResponse.body.id) {
63
+ throw new Error(`Failed to create media container: ${JSON.stringify(createContainerResponse.body)}`);
64
+ }
65
+ const containerId = createContainerResponse.body.id;
66
+ // Step 2: Publish the container
67
+ const publishResponse = yield pieces_common_1.httpClient.sendRequest({
68
+ method: pieces_common_1.HttpMethod.POST,
69
+ url: `${common_1.INSTAGRAM_GRAPH_API_BASE}/${auth.instagramAccountId}/media_publish`,
70
+ queryParams: {
71
+ access_token: accessToken,
72
+ creation_id: containerId,
73
+ },
74
+ });
75
+ return {
76
+ success: true,
77
+ mediaId: publishResponse.body.id,
78
+ containerId,
79
+ };
80
+ });
81
+ },
82
+ });
83
+ //# sourceMappingURL=upload-photo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-photo.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/skai-instagram-business/src/lib/actions/upload-photo.ts"],"names":[],"mappings":";;;;AAAA,qEAAwE;AACxE,+DAAqE;AACrE,6EAAoG;AACpG,sCAA4E;AAE5E,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;CAgBnB,CAAC;AAEW,QAAA,WAAW,GAAG,IAAA,+BAAY,EAAC;IACpC,IAAI,EAAE,+CAAqB;IAC3B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,cAAc;IAC3B,WAAW,EAAE,mDAAmD;IAChE,KAAK,EAAE;QACH,KAAK,EAAE,2BAAQ,CAAC,SAAS,CAAC;YACtB,WAAW,EAAE,WAAW;YACxB,WAAW,EAAE,kDAAkD;YAC/D,QAAQ,EAAE,IAAI;SACjB,CAAC;QACF,OAAO,EAAE,2BAAQ,CAAC,QAAQ,CAAC;YACvB,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,sBAAsB;YACnC,QAAQ,EAAE,KAAK;SAClB,CAAC;KACL;IACK,GAAG,CAAC,OAAO;;YACb,MAAM,IAAI,GAAG,OAAO,CAAC,IAAkC,CAAC;YACxD,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YAE9C,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,8BAAqB,CAAC,aAAa,CAAC;gBAC9D,IAAI;gBACJ,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,OAAO,EAAE,OAAO,CAAC,OAAO;aAC3B,CAAC,CAAC;YAGH,iCAAiC;YACjC,MAAM,uBAAuB,GAAG,MAAM,0BAAU,CAAC,WAAW,CAAC;gBACzD,MAAM,EAAE,0BAAU,CAAC,IAAI;gBACvB,GAAG,EAAE,GAAG,iCAAwB,IAAI,IAAI,CAAC,kBAAkB,QAAQ;gBACnE,WAAW,EAAE;oBACT,YAAY,EAAE,WAAW;oBACzB,SAAS,EAAE,KAAK;oBAChB,OAAO,EAAE,OAAO,IAAI,EAAE;iBACzB;aACJ,CAAC,CAAC;YAEH,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACzG,CAAC;YAED,MAAM,WAAW,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC;YAEpD,gCAAgC;YAChC,MAAM,eAAe,GAAG,MAAM,0BAAU,CAAC,WAAW,CAAC;gBACjD,MAAM,EAAE,0BAAU,CAAC,IAAI;gBACvB,GAAG,EAAE,GAAG,iCAAwB,IAAI,IAAI,CAAC,kBAAkB,gBAAgB;gBAC3E,WAAW,EAAE;oBACT,YAAY,EAAE,WAAW;oBACzB,WAAW,EAAE,WAAW;iBAC3B;aACJ,CAAC,CAAC;YAEH,OAAO;gBACH,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE;gBAChC,WAAW;aACd,CAAC;QACN,CAAC;KAAA;CACJ,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const uploadReel: import("@activepieces/pieces-framework").IAction<import("@activepieces/pieces-framework").CustomAuthProperty<{
2
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
3
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
4
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
5
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
6
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
7
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
8
+ }>, {
9
+ video: import("@activepieces/pieces-framework").ShortTextProperty<true>;
10
+ caption: import("@activepieces/pieces-framework").LongTextProperty<false>;
11
+ }>;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadReel = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const pieces_framework_1 = require("@activepieces/pieces-framework");
6
+ const pieces_common_1 = require("@activepieces/pieces-common");
7
+ const instagram_business_auth_1 = require("../auth/instagram-business.auth");
8
+ const common_1 = require("../common");
9
+ const description = `
10
+ ## Upload Reel
11
+
12
+ Upload a video reel to your Instagram Business Account.
13
+
14
+ ### Input Parameters
15
+ - **Video URL** (required): A publicly accessible URL to the video
16
+ - **Caption**: Optional caption for the reel
17
+
18
+ ### Requirements
19
+ - The video URL must be publicly accessible
20
+ - Video must be between 3-90 seconds
21
+ - Maximum file size: 1GB
22
+ - Your Instagram account must be connected to a Facebook Page
23
+ - Requires \`instagram_business_content_publish\` permission
24
+
25
+ ### Output
26
+ Returns the created media ID on success.
27
+ `;
28
+ // Helper to wait for video processing
29
+ function waitForVideoProcessing(instagramAccountId_1, containerId_1, accessToken_1) {
30
+ return tslib_1.__awaiter(this, arguments, void 0, function* (instagramAccountId, containerId, accessToken, maxRetries = 30, delayMs = 5000) {
31
+ for (let i = 0; i < maxRetries; i++) {
32
+ const response = yield pieces_common_1.httpClient.sendRequest({
33
+ method: pieces_common_1.HttpMethod.GET,
34
+ url: `${common_1.INSTAGRAM_GRAPH_API_BASE}/${containerId}`,
35
+ queryParams: {
36
+ access_token: accessToken,
37
+ fields: 'status_code',
38
+ },
39
+ });
40
+ const status = response.body.status_code;
41
+ if (status === 'FINISHED') {
42
+ return true;
43
+ }
44
+ if (status === 'ERROR') {
45
+ throw new Error('Video processing failed');
46
+ }
47
+ // Wait before checking again
48
+ yield new Promise(resolve => setTimeout(resolve, delayMs));
49
+ }
50
+ return false;
51
+ });
52
+ }
53
+ exports.uploadReel = (0, pieces_framework_1.createAction)({
54
+ auth: instagram_business_auth_1.instagramBusinessAuth,
55
+ name: 'upload_reel',
56
+ displayName: 'Upload Reel',
57
+ description: 'Upload a video reel to your Instagram Business Account',
58
+ props: {
59
+ video: pieces_framework_1.Property.ShortText({
60
+ displayName: 'Video URL',
61
+ description: 'A publicly accessible URL to the video (3-90 seconds, max 1GB)',
62
+ required: true,
63
+ }),
64
+ caption: pieces_framework_1.Property.LongText({
65
+ displayName: 'Caption',
66
+ description: 'Caption for the reel',
67
+ required: false,
68
+ }),
69
+ },
70
+ run(context) {
71
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
72
+ const auth = context.auth;
73
+ const { video, caption } = context.propsValue;
74
+ const { accessToken } = yield common_1.instagramTokenService.getValidToken({
75
+ auth,
76
+ server: context.server,
77
+ project: context.project,
78
+ });
79
+ // Step 1: Create media container for reel
80
+ const createContainerResponse = yield pieces_common_1.httpClient.sendRequest({
81
+ method: pieces_common_1.HttpMethod.POST,
82
+ url: `${common_1.INSTAGRAM_GRAPH_API_BASE}/${auth.instagramAccountId}/media`,
83
+ queryParams: {
84
+ access_token: accessToken,
85
+ video_url: video,
86
+ caption: caption || '',
87
+ media_type: 'REELS',
88
+ },
89
+ });
90
+ if (!createContainerResponse.body.id) {
91
+ throw new Error(`Failed to create media container: ${JSON.stringify(createContainerResponse.body)}`);
92
+ }
93
+ const containerId = createContainerResponse.body.id;
94
+ // Step 2: Wait for video processing
95
+ const isProcessed = yield waitForVideoProcessing(auth.instagramAccountId, containerId, accessToken);
96
+ if (!isProcessed) {
97
+ throw new Error('Video processing timed out. Please try again with a smaller video.');
98
+ }
99
+ // Step 3: Publish the container
100
+ const publishResponse = yield pieces_common_1.httpClient.sendRequest({
101
+ method: pieces_common_1.HttpMethod.POST,
102
+ url: `${common_1.INSTAGRAM_GRAPH_API_BASE}/${auth.instagramAccountId}/media_publish`,
103
+ queryParams: {
104
+ access_token: accessToken,
105
+ creation_id: containerId,
106
+ },
107
+ });
108
+ return {
109
+ success: true,
110
+ mediaId: publishResponse.body.id,
111
+ containerId,
112
+ };
113
+ });
114
+ },
115
+ });
116
+ //# sourceMappingURL=upload-reel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-reel.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/skai-instagram-business/src/lib/actions/upload-reel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare const instagramBusinessAuth: import("@activepieces/pieces-framework").CustomAuthProperty<{
2
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
3
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
4
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
5
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
6
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
7
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
8
+ }>;
9
+ export type InstagramBusinessAuthValue = {
10
+ accessToken: string;
11
+ instagramAccountId: string;
12
+ instagramUsername: string;
13
+ userId: string;
14
+ tokenExpiresAt?: string;
15
+ refreshThresholdDays?: number;
16
+ };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.instagramBusinessAuth = void 0;
4
+ const pieces_framework_1 = require("@activepieces/pieces-framework");
5
+ const markdown = `
6
+ ## Authentication
7
+
8
+ ### Embedded Signup (Recommended)
9
+ Click "Connect" to authenticate via Instagram Business Login. This will automatically:
10
+ 1. Redirect to Instagram for authorization
11
+ 2. Exchange the authorization code for tokens (server-side)
12
+ 3. Fetch your Instagram Account ID and username
13
+ 4. Set the token expiration date
14
+
15
+ ### Manual Setup
16
+ To manually obtain credentials:
17
+ 1. Go to https://developers.facebook.com/
18
+ 2. Create app → Select **Other** → Choose **Business** type
19
+ 3. Add Product → **Instagram**
20
+ 4. Configure **Instagram Business Login** settings
21
+ 5. Generate User Access Token with scopes:
22
+ - instagram_business_basic
23
+ - instagram_business_manage_messages
24
+ - instagram_business_content_publish
25
+ 6. Exchange for long-lived token (60 days)
26
+ 7. Get Instagram Account ID from /me endpoint
27
+
28
+ ### Token Refresh
29
+ Tokens are automatically refreshed when nearing expiration (within 10 days).
30
+ `;
31
+ exports.instagramBusinessAuth = pieces_framework_1.PieceAuth.CustomAuth({
32
+ required: true,
33
+ description: markdown,
34
+ props: {
35
+ accessToken: pieces_framework_1.PieceAuth.SecretText({
36
+ displayName: 'Access Token',
37
+ description: 'Instagram long-lived access token. Populated automatically via Embedded Signup.',
38
+ required: true,
39
+ }),
40
+ instagramAccountId: pieces_framework_1.Property.ShortText({
41
+ displayName: 'Instagram Account ID',
42
+ description: 'The Instagram Business Account ID. Populated automatically via Embedded Signup.',
43
+ required: true,
44
+ }),
45
+ instagramUsername: pieces_framework_1.Property.ShortText({
46
+ displayName: 'Instagram Username',
47
+ description: 'Your Instagram username (without @). Populated automatically via Embedded Signup.',
48
+ required: true,
49
+ }),
50
+ userId: pieces_framework_1.Property.ShortText({
51
+ displayName: 'User ID',
52
+ description: 'Instagram-scoped User ID (for connection identification). Populated automatically via Embedded Signup.',
53
+ required: true,
54
+ }),
55
+ tokenExpiresAt: pieces_framework_1.Property.ShortText({
56
+ displayName: 'Token Expires At',
57
+ description: 'ISO date string when the token expires. Populated automatically via Embedded Signup.',
58
+ required: false,
59
+ }),
60
+ refreshThresholdDays: pieces_framework_1.Property.Number({
61
+ displayName: 'Refresh Threshold (Days)',
62
+ description: 'Refresh token when this many days remain until expiration. Default: 10 days.',
63
+ required: false,
64
+ defaultValue: 10,
65
+ }),
66
+ },
67
+ });
68
+ //# sourceMappingURL=instagram-business.auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instagram-business.auth.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/skai-instagram-business/src/lib/auth/instagram-business.auth.ts"],"names":[],"mappings":";;;AAAA,qEAAqE;AAErE,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyBhB,CAAC;AAEW,QAAA,qBAAqB,GAAG,4BAAS,CAAC,UAAU,CAAC;IACtD,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,QAAQ;IACrB,KAAK,EAAE;QACH,WAAW,EAAE,4BAAS,CAAC,UAAU,CAAC;YAC9B,WAAW,EAAE,cAAc;YAC3B,WAAW,EAAE,iFAAiF;YAC9F,QAAQ,EAAE,IAAI;SACjB,CAAC;QACF,kBAAkB,EAAE,2BAAQ,CAAC,SAAS,CAAC;YACnC,WAAW,EAAE,sBAAsB;YACnC,WAAW,EAAE,iFAAiF;YAC9F,QAAQ,EAAE,IAAI;SACjB,CAAC;QACF,iBAAiB,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAClC,WAAW,EAAE,oBAAoB;YACjC,WAAW,EAAE,mFAAmF;YAChG,QAAQ,EAAE,IAAI;SACjB,CAAC;QACF,MAAM,EAAE,2BAAQ,CAAC,SAAS,CAAC;YACvB,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,wGAAwG;YACrH,QAAQ,EAAE,IAAI;SACjB,CAAC;QACF,cAAc,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAC/B,WAAW,EAAE,kBAAkB;YAC/B,WAAW,EAAE,sFAAsF;YACnG,QAAQ,EAAE,KAAK;SAClB,CAAC;QACF,oBAAoB,EAAE,2BAAQ,CAAC,MAAM,CAAC;YAClC,WAAW,EAAE,0BAA0B;YACvC,WAAW,EAAE,8EAA8E;YAC3F,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,EAAE;SACnB,CAAC;KACL;CACJ,CAAC,CAAC"}
@@ -0,0 +1,72 @@
1
+ export declare const INSTAGRAM_GRAPH_API_BASE = "https://graph.instagram.com/v24.0";
2
+ export declare const supportedMediaTypes: readonly ["image", "video", "audio", "file"];
3
+ export type MediaType = typeof supportedMediaTypes[number];
4
+ export declare const instagramApi: {
5
+ /**
6
+ * Send a text message
7
+ */
8
+ sendTextMessage(instagramAccountId: string, accessToken: string, recipientId: string, text: string, replyToMessageId?: string): Promise<any>;
9
+ /**
10
+ * Send a media message (image, video, audio, file)
11
+ */
12
+ sendMediaMessage(instagramAccountId: string, accessToken: string, recipientId: string, mediaType: MediaType, mediaUrl: string, replyToMessageId?: string): Promise<any>;
13
+ /**
14
+ * Send a reaction to a message
15
+ */
16
+ sendReaction(instagramAccountId: string, accessToken: string, recipientId: string, messageId: string, emoji: string): Promise<any>;
17
+ /**
18
+ * Get user profile information
19
+ */
20
+ getUserProfile(accessToken: string, userId: string): Promise<any>;
21
+ /**
22
+ * Download media from Instagram CDN
23
+ */
24
+ downloadMedia(accessToken: string, mediaId: string): Promise<any>;
25
+ };
26
+ export interface NormalizedInstagramMessage {
27
+ senderId: string;
28
+ recipientId: string;
29
+ timestamp: number;
30
+ type: 'text' | 'media' | 'reaction' | 'unsupported';
31
+ messageId: string;
32
+ text?: string;
33
+ attachments?: Array<{
34
+ type: string;
35
+ url?: string;
36
+ }>;
37
+ reaction?: {
38
+ emoji: string;
39
+ action: 'react' | 'unreact';
40
+ };
41
+ }
42
+ export interface InstagramMessaging {
43
+ sender?: {
44
+ id: string;
45
+ };
46
+ recipient?: {
47
+ id: string;
48
+ };
49
+ timestamp: number;
50
+ message?: InstagramMessage;
51
+ reaction?: InstagramReaction;
52
+ }
53
+ export interface InstagramMessage {
54
+ mid: string;
55
+ text?: string;
56
+ attachments?: InstagramAttachment[];
57
+ }
58
+ export interface InstagramAttachment {
59
+ type: string;
60
+ payload: {
61
+ url?: string;
62
+ reel_url?: string;
63
+ };
64
+ }
65
+ export interface InstagramReaction {
66
+ mid: string;
67
+ action: 'react' | 'unreact';
68
+ emoji?: string;
69
+ reaction?: string;
70
+ }
71
+ export declare function normalizeMessagingEvent(messaging: InstagramMessaging): NormalizedInstagramMessage | undefined;
72
+ export { instagramTokenService, TokenServiceContext, TokenRefreshResult } from './token-service';
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.instagramTokenService = exports.instagramApi = exports.supportedMediaTypes = exports.INSTAGRAM_GRAPH_API_BASE = void 0;
4
+ exports.normalizeMessagingEvent = normalizeMessagingEvent;
5
+ const tslib_1 = require("tslib");
6
+ const pieces_common_1 = require("@activepieces/pieces-common");
7
+ // Instagram Graph API base URL
8
+ exports.INSTAGRAM_GRAPH_API_BASE = 'https://graph.instagram.com/v24.0';
9
+ // Supported media types for messaging
10
+ exports.supportedMediaTypes = ['image', 'video', 'audio', 'file'];
11
+ // Instagram API helper functions
12
+ exports.instagramApi = {
13
+ /**
14
+ * Send a text message
15
+ */
16
+ sendTextMessage(instagramAccountId, accessToken, recipientId, text, replyToMessageId) {
17
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
18
+ const body = {
19
+ recipient: { id: recipientId },
20
+ message: { text },
21
+ };
22
+ if (replyToMessageId) {
23
+ body.reply_to = { mid: replyToMessageId };
24
+ }
25
+ const response = yield pieces_common_1.httpClient.sendRequest({
26
+ method: pieces_common_1.HttpMethod.POST,
27
+ url: `${exports.INSTAGRAM_GRAPH_API_BASE}/${instagramAccountId}/messages`,
28
+ queryParams: { access_token: accessToken },
29
+ body,
30
+ });
31
+ return response.body;
32
+ });
33
+ },
34
+ /**
35
+ * Send a media message (image, video, audio, file)
36
+ */
37
+ sendMediaMessage(instagramAccountId, accessToken, recipientId, mediaType, mediaUrl, replyToMessageId) {
38
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
39
+ const body = {
40
+ recipient: { id: recipientId },
41
+ message: {
42
+ attachment: {
43
+ type: mediaType,
44
+ payload: { url: mediaUrl },
45
+ },
46
+ },
47
+ };
48
+ if (replyToMessageId) {
49
+ body.reply_to = { mid: replyToMessageId };
50
+ }
51
+ const response = yield pieces_common_1.httpClient.sendRequest({
52
+ method: pieces_common_1.HttpMethod.POST,
53
+ url: `${exports.INSTAGRAM_GRAPH_API_BASE}/${instagramAccountId}/messages`,
54
+ queryParams: { access_token: accessToken },
55
+ body,
56
+ });
57
+ return response.body;
58
+ });
59
+ },
60
+ /**
61
+ * Send a reaction to a message
62
+ */
63
+ sendReaction(instagramAccountId, accessToken, recipientId, messageId, emoji // Empty string to remove reaction
64
+ ) {
65
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
66
+ const body = {
67
+ recipient: { id: recipientId },
68
+ sender_action: emoji ? 'react' : 'unreact',
69
+ payload: Object.assign({ message_id: messageId }, (emoji ? { reaction: emoji } : {})),
70
+ };
71
+ const response = yield pieces_common_1.httpClient.sendRequest({
72
+ method: pieces_common_1.HttpMethod.POST,
73
+ url: `${exports.INSTAGRAM_GRAPH_API_BASE}/${instagramAccountId}/messages`,
74
+ queryParams: { access_token: accessToken },
75
+ body,
76
+ });
77
+ return response.body;
78
+ });
79
+ },
80
+ /**
81
+ * Get user profile information
82
+ */
83
+ getUserProfile(accessToken, userId) {
84
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
85
+ const response = yield pieces_common_1.httpClient.sendRequest({
86
+ method: pieces_common_1.HttpMethod.GET,
87
+ url: `${exports.INSTAGRAM_GRAPH_API_BASE}/${userId}`,
88
+ queryParams: {
89
+ access_token: accessToken,
90
+ fields: 'id,username,name,profile_picture_url',
91
+ },
92
+ });
93
+ return response.body;
94
+ });
95
+ },
96
+ /**
97
+ * Download media from Instagram CDN
98
+ */
99
+ downloadMedia(accessToken, mediaId) {
100
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
101
+ const response = yield pieces_common_1.httpClient.sendRequest({
102
+ method: pieces_common_1.HttpMethod.GET,
103
+ url: `${exports.INSTAGRAM_GRAPH_API_BASE}/${mediaId}`,
104
+ queryParams: {
105
+ access_token: accessToken,
106
+ fields: 'id,media_type,media_url',
107
+ },
108
+ });
109
+ return response.body;
110
+ });
111
+ },
112
+ };
113
+ // Normalize messaging event to consistent format
114
+ function normalizeMessagingEvent(messaging) {
115
+ var _a, _b, _c, _d;
116
+ const base = {
117
+ senderId: ((_a = messaging.sender) === null || _a === void 0 ? void 0 : _a.id) || '',
118
+ recipientId: ((_b = messaging.recipient) === null || _b === void 0 ? void 0 : _b.id) || '',
119
+ timestamp: messaging.timestamp,
120
+ };
121
+ // Handle reaction events
122
+ if (messaging.reaction) {
123
+ return Object.assign(Object.assign({}, base), { type: 'reaction', messageId: messaging.reaction.mid, reaction: {
124
+ emoji: messaging.reaction.emoji || '',
125
+ action: messaging.reaction.action,
126
+ } });
127
+ }
128
+ // Handle media attachments
129
+ if (((_c = messaging.message) === null || _c === void 0 ? void 0 : _c.attachments) && ((_d = messaging.message) === null || _d === void 0 ? void 0 : _d.attachments.length) > 0) {
130
+ return Object.assign(Object.assign({}, base), { type: 'media', messageId: messaging.message.mid, attachments: messaging.message.attachments.map(att => ({
131
+ type: att.type,
132
+ url: att.payload.url || att.payload.reel_url,
133
+ })) });
134
+ }
135
+ // Handle message events
136
+ if (messaging.message) {
137
+ return Object.assign(Object.assign({}, base), { type: 'text', messageId: messaging.message.mid, text: messaging.message.text });
138
+ }
139
+ return undefined;
140
+ }
141
+ // Re-export token service
142
+ var token_service_1 = require("./token-service");
143
+ Object.defineProperty(exports, "instagramTokenService", { enumerable: true, get: function () { return token_service_1.instagramTokenService; } });
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/skai-instagram-business/src/lib/common/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { InstagramBusinessAuthValue } from '../auth/instagram-business.auth';
2
+ export interface TokenRefreshResult {
3
+ accessToken: string;
4
+ expiresIn: number;
5
+ expiresAt: Date;
6
+ }
7
+ export interface TokenServiceContext {
8
+ auth: InstagramBusinessAuthValue;
9
+ server: {
10
+ apiUrl: string;
11
+ publicUrl: string;
12
+ token: string;
13
+ };
14
+ project: {
15
+ id: string;
16
+ };
17
+ }
18
+ export declare const instagramTokenService: {
19
+ /**
20
+ * Get valid access token, refreshing if necessary and updating the connection in DB
21
+ * This is the main entry point - call this before every API request
22
+ */
23
+ getValidToken(context: TokenServiceContext): Promise<{
24
+ accessToken: string;
25
+ wasRefreshed: boolean;
26
+ }>;
27
+ /**
28
+ * Refresh long-lived access token via Instagram API
29
+ * Tokens are valid for 60 days, can refresh when at least 24 hours old
30
+ */
31
+ refreshToken(currentToken: string): Promise<TokenRefreshResult>;
32
+ /**
33
+ * Fetch the full connection from the database via worker API
34
+ * Returns the complete AppConnection including displayName
35
+ */
36
+ fetchConnection(server: TokenServiceContext["server"], projectId: string, externalId: string): Promise<{
37
+ displayName: string;
38
+ }>;
39
+ /**
40
+ * Update the connection in the database via server API
41
+ * Uses upsert endpoint which matches by externalId and updates existing connection
42
+ */
43
+ updateConnectionInDatabase(context: TokenServiceContext, refreshedToken: TokenRefreshResult): Promise<void>;
44
+ };
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.instagramTokenService = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const pieces_common_1 = require("@activepieces/pieces-common");
6
+ const shared_1 = require("@activepieces/shared");
7
+ const DEFAULT_REFRESH_THRESHOLD_DAYS = 10;
8
+ const PIECE_NAME = '@skillful-ai/piece-skai-instagram-business';
9
+ exports.instagramTokenService = {
10
+ /**
11
+ * Get valid access token, refreshing if necessary and updating the connection in DB
12
+ * This is the main entry point - call this before every API request
13
+ */
14
+ getValidToken(context) {
15
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
16
+ var _a;
17
+ const { auth } = context;
18
+ const thresholdDays = (_a = auth.refreshThresholdDays) !== null && _a !== void 0 ? _a : DEFAULT_REFRESH_THRESHOLD_DAYS;
19
+ // Check if token has expiration info
20
+ if (!auth.tokenExpiresAt) {
21
+ console.log('[Instagram Token Service] No token expiration info, using current token');
22
+ return { accessToken: auth.accessToken, wasRefreshed: false };
23
+ }
24
+ const expiresAt = new Date(auth.tokenExpiresAt);
25
+ const daysUntilExpiry = (expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24);
26
+ // Check if expired
27
+ if (daysUntilExpiry <= 0) {
28
+ throw new Error(`Instagram token has expired (expired ${Math.abs(Math.round(daysUntilExpiry))} days ago). ` +
29
+ `Please reconnect your Instagram account.`);
30
+ }
31
+ // Check if refresh needed
32
+ if (daysUntilExpiry > thresholdDays) {
33
+ console.log(`[Instagram Token Service] Token valid, expires in ${Math.round(daysUntilExpiry)} days`);
34
+ return { accessToken: auth.accessToken, wasRefreshed: false };
35
+ }
36
+ // Token needs refresh
37
+ console.log(`[Instagram Token Service] Token expires in ${Math.round(daysUntilExpiry)} days, attempting refresh...`);
38
+ try {
39
+ const refreshed = yield this.refreshToken(auth.accessToken);
40
+ // Update the connection in the database via server API
41
+ yield this.updateConnectionInDatabase(context, refreshed);
42
+ console.log(`[Instagram Token Service] Token refreshed, new expiration: ${refreshed.expiresAt.toISOString()}`);
43
+ return { accessToken: refreshed.accessToken, wasRefreshed: true };
44
+ }
45
+ catch (error) {
46
+ console.error('[Instagram Token Service] Failed to refresh token:', error.message);
47
+ // If refresh fails but token not yet expired, continue with current token
48
+ if (daysUntilExpiry > 0) {
49
+ console.log('[Instagram Token Service] Using current token despite refresh failure');
50
+ return { accessToken: auth.accessToken, wasRefreshed: false };
51
+ }
52
+ throw error;
53
+ }
54
+ });
55
+ },
56
+ /**
57
+ * Refresh long-lived access token via Instagram API
58
+ * Tokens are valid for 60 days, can refresh when at least 24 hours old
59
+ */
60
+ refreshToken(currentToken) {
61
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
62
+ var _a, _b;
63
+ const response = yield pieces_common_1.httpClient.sendRequest({
64
+ method: pieces_common_1.HttpMethod.GET,
65
+ url: 'https://graph.instagram.com/refresh_access_token',
66
+ queryParams: {
67
+ grant_type: 'ig_refresh_token',
68
+ access_token: currentToken,
69
+ },
70
+ });
71
+ if (response.status !== 200) {
72
+ throw new Error(`Failed to refresh token: ${((_b = (_a = response.body) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.message) || 'Unknown error'}`);
73
+ }
74
+ return {
75
+ accessToken: response.body.access_token,
76
+ expiresIn: response.body.expires_in, // seconds (5184000 = 60 days)
77
+ expiresAt: new Date(Date.now() + response.body.expires_in * 1000),
78
+ };
79
+ });
80
+ },
81
+ /**
82
+ * Fetch the full connection from the database via worker API
83
+ * Returns the complete AppConnection including displayName
84
+ */
85
+ fetchConnection(server, projectId, externalId) {
86
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
87
+ var _a, _b;
88
+ const response = yield pieces_common_1.httpClient.sendRequest({
89
+ method: pieces_common_1.HttpMethod.GET,
90
+ url: `${server.apiUrl}v1/worker/app-connections/${encodeURIComponent(externalId)}`,
91
+ queryParams: {
92
+ projectId,
93
+ },
94
+ authentication: {
95
+ type: pieces_common_1.AuthenticationType.BEARER_TOKEN,
96
+ token: server.token,
97
+ },
98
+ });
99
+ if (response.status !== 200) {
100
+ throw new Error(`Failed to fetch connection: ${((_b = (_a = response.body) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.message) || response.status}`);
101
+ }
102
+ return response.body;
103
+ });
104
+ },
105
+ /**
106
+ * Update the connection in the database via server API
107
+ * Uses upsert endpoint which matches by externalId and updates existing connection
108
+ */
109
+ updateConnectionInDatabase(context, refreshedToken) {
110
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
111
+ var _a, _b, _c;
112
+ const { auth, server, project } = context;
113
+ const externalId = `instagram_user_${auth.userId}`;
114
+ // Fetch the full connection to get displayName
115
+ const existingConnection = yield this.fetchConnection(server, project.id, externalId);
116
+ const requestBody = {
117
+ externalId,
118
+ displayName: existingConnection.displayName,
119
+ pieceName: PIECE_NAME,
120
+ projectId: project.id,
121
+ type: shared_1.AppConnectionType.CUSTOM_AUTH,
122
+ value: {
123
+ type: shared_1.AppConnectionType.CUSTOM_AUTH,
124
+ props: {
125
+ accessToken: refreshedToken.accessToken,
126
+ instagramAccountId: auth.instagramAccountId,
127
+ instagramUsername: auth.instagramUsername,
128
+ userId: auth.userId,
129
+ tokenExpiresAt: refreshedToken.expiresAt.toISOString(),
130
+ refreshThresholdDays: (_a = auth.refreshThresholdDays) !== null && _a !== void 0 ? _a : DEFAULT_REFRESH_THRESHOLD_DAYS,
131
+ },
132
+ },
133
+ };
134
+ const response = yield pieces_common_1.httpClient.sendRequest({
135
+ method: pieces_common_1.HttpMethod.POST,
136
+ url: `${server.apiUrl}v1/app-connections`,
137
+ authentication: {
138
+ type: pieces_common_1.AuthenticationType.BEARER_TOKEN,
139
+ token: server.token,
140
+ },
141
+ body: requestBody,
142
+ });
143
+ if (response.status !== 201 && response.status !== 200) {
144
+ throw new Error(`Failed to update connection in database: ${((_c = (_b = response.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.message) || response.status}`);
145
+ }
146
+ console.log('[Instagram Token Service] Connection updated in database with refreshed token');
147
+ });
148
+ },
149
+ };
150
+ //# sourceMappingURL=token-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-service.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/skai-instagram-business/src/lib/common/token-service.ts"],"names":[],"mappings":";;;;AAAA,+DAAyF;AACzF,iDAAyD;AAqBzD,MAAM,8BAA8B,GAAG,EAAE,CAAC;AAC1C,MAAM,UAAU,GAAG,4CAA4C,CAAC;AAEnD,QAAA,qBAAqB,GAAG;IACjC;;;OAGG;IACG,aAAa,CAAC,OAA4B;;;YAC5C,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;YACzB,MAAM,aAAa,GAAG,MAAA,IAAI,CAAC,oBAAoB,mCAAI,8BAA8B,CAAC;YAElF,qCAAqC;YACrC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;gBACvF,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;YAClE,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAChD,MAAM,eAAe,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YAEnF,mBAAmB;YACnB,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CACX,wCAAwC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,cAAc;oBAC3F,0CAA0C,CAC7C,CAAC;YACN,CAAC;YAED,0BAA0B;YAC1B,IAAI,eAAe,GAAG,aAAa,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,qDAAqD,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;gBACrG,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;YAClE,CAAC;YAED,sBAAsB;YACtB,OAAO,CAAC,GAAG,CAAC,8CAA8C,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,8BAA8B,CAAC,CAAC;YAErH,IAAI,CAAC;gBACD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAE5D,uDAAuD;gBACvD,MAAM,IAAI,CAAC,0BAA0B,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBAE1D,OAAO,CAAC,GAAG,CAAC,8DAA8D,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;gBAC/G,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;YACtE,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAEnF,0EAA0E;gBAC1E,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;oBACtB,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;oBACrF,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;gBAClE,CAAC;gBAED,MAAM,KAAK,CAAC;YAChB,CAAC;QACL,CAAC;KAAA;IAED;;;OAGG;IACG,YAAY,CAAC,YAAoB;;;YACnC,MAAM,QAAQ,GAAG,MAAM,0BAAU,CAAC,WAAW,CAAC;gBAC1C,MAAM,EAAE,0BAAU,CAAC,GAAG;gBACtB,GAAG,EAAE,kDAAkD;gBACvD,WAAW,EAAE;oBACT,UAAU,EAAE,kBAAkB;oBAC9B,YAAY,EAAE,YAAY;iBAC7B;aACJ,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAA,MAAA,MAAA,QAAQ,CAAC,IAAI,0CAAE,KAAK,0CAAE,OAAO,KAAI,eAAe,EAAE,CAAC,CAAC;YACpG,CAAC;YAED,OAAO;gBACH,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,YAAY;gBACvC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,8BAA8B;gBACnE,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;aACpE,CAAC;QACN,CAAC;KAAA;IAED;;;OAGG;IACG,eAAe,CACjB,MAAqC,EACrC,SAAiB,EACjB,UAAkB;;;YAElB,MAAM,QAAQ,GAAG,MAAM,0BAAU,CAAC,WAAW,CAAC;gBAC1C,MAAM,EAAE,0BAAU,CAAC,GAAG;gBACtB,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,6BAA6B,kBAAkB,CAAC,UAAU,CAAC,EAAE;gBAClF,WAAW,EAAE;oBACT,SAAS;iBACZ;gBACD,cAAc,EAAE;oBACZ,IAAI,EAAE,kCAAkB,CAAC,YAAY;oBACrC,KAAK,EAAE,MAAM,CAAC,KAAK;iBACtB;aACJ,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAA,MAAA,MAAA,QAAQ,CAAC,IAAI,0CAAE,KAAK,0CAAE,OAAO,KAAI,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACvG,CAAC;YAED,OAAO,QAAQ,CAAC,IAAI,CAAC;QACzB,CAAC;KAAA;IAED;;;OAGG;IACG,0BAA0B,CAC5B,OAA4B,EAC5B,cAAkC;;;YAElC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;YAC1C,MAAM,UAAU,GAAG,kBAAkB,IAAI,CAAC,MAAM,EAAE,CAAC;YAEnD,+CAA+C;YAC/C,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YAEtF,MAAM,WAAW,GAAG;gBAChB,UAAU;gBACV,WAAW,EAAE,kBAAkB,CAAC,WAAW;gBAC3C,SAAS,EAAE,UAAU;gBACrB,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,IAAI,EAAE,0BAAiB,CAAC,WAAW;gBACnC,KAAK,EAAE;oBACH,IAAI,EAAE,0BAAiB,CAAC,WAAW;oBACnC,KAAK,EAAE;wBACH,WAAW,EAAE,cAAc,CAAC,WAAW;wBACvC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;wBAC3C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;wBACzC,MAAM,EAAE,IAAI,CAAC,MAAM;wBACnB,cAAc,EAAE,cAAc,CAAC,SAAS,CAAC,WAAW,EAAE;wBACtD,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,8BAA8B;qBACpF;iBACJ;aACJ,CAAC;YAEF,MAAM,QAAQ,GAAG,MAAM,0BAAU,CAAC,WAAW,CAAC;gBAC1C,MAAM,EAAE,0BAAU,CAAC,IAAI;gBACvB,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,oBAAoB;gBACzC,cAAc,EAAE;oBACZ,IAAI,EAAE,kCAAkB,CAAC,YAAY;oBACrC,KAAK,EAAE,MAAM,CAAC,KAAK;iBACtB;gBACD,IAAI,EAAE,WAAW;aACpB,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CACX,4CAA4C,CAAA,MAAA,MAAA,QAAQ,CAAC,IAAI,0CAAE,KAAK,0CAAE,OAAO,KAAI,QAAQ,CAAC,MAAM,EAAE,CACjG,CAAC;YACN,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,+EAA+E,CAAC,CAAC;QACjG,CAAC;KAAA;CACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { TriggerStrategy } from '@activepieces/pieces-framework';
2
+ export declare const newInstagramMessage: import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.WEBHOOK, import("@activepieces/pieces-framework").CustomAuthProperty<{
3
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
4
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
5
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
6
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
7
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
8
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
9
+ }>, {}> | import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.POLLING, import("@activepieces/pieces-framework").CustomAuthProperty<{
10
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
11
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
12
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
13
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
14
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
15
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
16
+ }>, {}> | import("@activepieces/pieces-framework").ITrigger<TriggerStrategy.APP_WEBHOOK, import("@activepieces/pieces-framework").CustomAuthProperty<{
17
+ accessToken: import("@activepieces/pieces-framework").SecretTextProperty<true>;
18
+ instagramAccountId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
19
+ instagramUsername: import("@activepieces/pieces-framework").ShortTextProperty<true>;
20
+ userId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
21
+ tokenExpiresAt: import("@activepieces/pieces-framework").ShortTextProperty<false>;
22
+ refreshThresholdDays: import("@activepieces/pieces-framework").NumberProperty<false>;
23
+ }>, {}>;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.newInstagramMessage = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const pieces_framework_1 = require("@activepieces/pieces-framework");
6
+ const pieces_common_1 = require("@activepieces/pieces-common");
7
+ const instagram_business_auth_1 = require("../auth/instagram-business.auth");
8
+ const common_1 = require("../common");
9
+ exports.newInstagramMessage = (0, pieces_framework_1.createTrigger)({
10
+ auth: instagram_business_auth_1.instagramBusinessAuth,
11
+ name: 'new_instagram_message',
12
+ displayName: 'New Message',
13
+ description: 'Triggers on new Instagram messages, reactions, and events',
14
+ type: pieces_framework_1.TriggerStrategy.APP_WEBHOOK,
15
+ props: {},
16
+ sampleData: {
17
+ senderId: '1234567890123456',
18
+ recipientId: '9876543210987654',
19
+ timestamp: 1703865600000,
20
+ type: 'text',
21
+ messageId: 'aWdGZAA...',
22
+ text: 'Hello! This is a sample message.',
23
+ attachments: null,
24
+ reaction: null,
25
+ },
26
+ onEnable(context) {
27
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
28
+ const auth = context.auth;
29
+ // Register this flow to receive events for this Instagram account
30
+ // The server's webhook controller routes events by recipient.id (Instagram Account ID)
31
+ context.app.createListeners({
32
+ events: ['new_instagram_message'],
33
+ identifierValue: auth.instagramAccountId,
34
+ });
35
+ // Subscribe to webhook fields via Instagram API
36
+ // This tells Instagram to send webhooks to your configured URL
37
+ try {
38
+ yield pieces_common_1.httpClient.sendRequest({
39
+ method: pieces_common_1.HttpMethod.POST,
40
+ url: `${common_1.INSTAGRAM_GRAPH_API_BASE}/${auth.instagramAccountId}/subscribed_apps`,
41
+ queryParams: {
42
+ access_token: auth.accessToken,
43
+ subscribed_fields: 'messages,message_reactions',
44
+ },
45
+ });
46
+ console.log(`[Instagram Trigger] Subscribed to webhooks for account ${auth.instagramAccountId}`);
47
+ }
48
+ catch (error) {
49
+ console.error(`[Instagram Trigger] Failed to subscribe to webhooks: ${error.message}`);
50
+ // Don't fail the trigger enable - the subscription might already exist
51
+ }
52
+ });
53
+ },
54
+ onDisable(context) {
55
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
56
+ const auth = context.auth;
57
+ // Unsubscribe from webhook fields
58
+ try {
59
+ yield pieces_common_1.httpClient.sendRequest({
60
+ method: pieces_common_1.HttpMethod.DELETE,
61
+ url: `${common_1.INSTAGRAM_GRAPH_API_BASE}/${auth.instagramAccountId}/subscribed_apps`,
62
+ queryParams: {
63
+ access_token: auth.accessToken,
64
+ },
65
+ });
66
+ console.log(`[Instagram Trigger] Unsubscribed from webhooks for account ${auth.instagramAccountId}`);
67
+ }
68
+ catch (error) {
69
+ console.error(`[Instagram Trigger] Failed to unsubscribe from webhooks: ${error.message}`);
70
+ }
71
+ });
72
+ },
73
+ run(context) {
74
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
75
+ const payload = context.payload;
76
+ const messaging = payload === null || payload === void 0 ? void 0 : payload.body;
77
+ if (!messaging) {
78
+ return [];
79
+ }
80
+ const normalizedMessage = (0, common_1.normalizeMessagingEvent)(messaging);
81
+ if (!normalizedMessage) {
82
+ return [];
83
+ }
84
+ return [normalizedMessage];
85
+ });
86
+ },
87
+ });
88
+ //# sourceMappingURL=new-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new-message.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/skai-instagram-business/src/lib/triggers/new-message.ts"],"names":[],"mappings":";;;;AAAA,qEAAgF;AAChF,+DAAqE;AACrE,6EAAoG;AACpG,sCAAkG;AAGrF,QAAA,mBAAmB,GAAG,IAAA,gCAAa,EAAC;IAC7C,IAAI,EAAE,+CAAqB;IAC3B,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,2DAA2D;IACxE,IAAI,EAAE,kCAAe,CAAC,WAAW;IACjC,KAAK,EAAE,EAAE;IACT,UAAU,EAAE;QACR,QAAQ,EAAE,kBAAkB;QAC5B,WAAW,EAAE,kBAAkB;QAC/B,SAAS,EAAE,aAAa;QACxB,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,YAAY;QACvB,IAAI,EAAE,kCAAkC;QACxC,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,IAAI;KACjB;IACK,QAAQ,CAAC,OAAO;;YAClB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAkC,CAAC;YAExD,kEAAkE;YAClE,uFAAuF;YACvF,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;gBACxB,MAAM,EAAE,CAAC,uBAAuB,CAAC;gBACjC,eAAe,EAAE,IAAI,CAAC,kBAAkB;aAC3C,CAAC,CAAC;YAEH,gDAAgD;YAChD,+DAA+D;YAC/D,IAAI,CAAC;gBACD,MAAM,0BAAU,CAAC,WAAW,CAAC;oBACzB,MAAM,EAAE,0BAAU,CAAC,IAAI;oBACvB,GAAG,EAAE,GAAG,iCAAwB,IAAI,IAAI,CAAC,kBAAkB,kBAAkB;oBAC7E,WAAW,EAAE;wBACT,YAAY,EAAE,IAAI,CAAC,WAAW;wBAC9B,iBAAiB,EAAE,4BAA4B;qBAClD;iBACJ,CAAC,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,0DAA0D,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC;YACrG,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,wDAAwD,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvF,uEAAuE;YAC3E,CAAC;QACL,CAAC;KAAA;IACK,SAAS,CAAC,OAAO;;YACnB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAkC,CAAC;YAExD,kCAAkC;YAClC,IAAI,CAAC;gBACD,MAAM,0BAAU,CAAC,WAAW,CAAC;oBACzB,MAAM,EAAE,0BAAU,CAAC,MAAM;oBACzB,GAAG,EAAE,GAAG,iCAAwB,IAAI,IAAI,CAAC,kBAAkB,kBAAkB;oBAC7E,WAAW,EAAE;wBACT,YAAY,EAAE,IAAI,CAAC,WAAW;qBACjC;iBACJ,CAAC,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,8DAA8D,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC;YACzG,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,4DAA4D,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC/F,CAAC;QACL,CAAC;KAAA;IACK,GAAG,CAAC,OAAO;;YACb,MAAM,OAAO,GAAG,OAAO,CAAC,OAAc,CAAC;YACvC,MAAM,SAAS,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAA0B,CAAC;YACtD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACb,OAAO,EAAE,CAAC;YACd,CAAC;YACD,MAAM,iBAAiB,GAAG,IAAA,gCAAuB,EAAC,SAAS,CAAC,CAAC;YAC7D,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACrB,OAAO,EAAE,CAAC;YACd,CAAC;YACD,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC/B,CAAC;KAAA;CACJ,CAAC,CAAC"}