@pakoor/n8n-nodes-instagram 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +271 -0
- package/dist/__tests__/helpers/index.d.ts +2 -0
- package/dist/__tests__/helpers/index.d.ts.map +1 -0
- package/dist/__tests__/helpers/index.js +18 -0
- package/dist/__tests__/helpers/index.js.map +1 -0
- package/dist/__tests__/helpers/testUtils.d.ts +104 -0
- package/dist/__tests__/helpers/testUtils.d.ts.map +1 -0
- package/dist/__tests__/helpers/testUtils.js +175 -0
- package/dist/__tests__/helpers/testUtils.js.map +1 -0
- package/dist/credentials/InstagramAccessTokenApi.credentials.d.ts +19 -0
- package/dist/credentials/InstagramAccessTokenApi.credentials.d.ts.map +1 -0
- package/dist/credentials/InstagramAccessTokenApi.credentials.js +130 -0
- package/dist/credentials/InstagramAccessTokenApi.credentials.js.map +1 -0
- package/dist/credentials/InstagramOAuth2Api.credentials.d.ts +20 -0
- package/dist/credentials/InstagramOAuth2Api.credentials.d.ts.map +1 -0
- package/dist/credentials/InstagramOAuth2Api.credentials.js +177 -0
- package/dist/credentials/InstagramOAuth2Api.credentials.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/Instagram/Instagram.node.d.ts +10 -0
- package/dist/nodes/Instagram/Instagram.node.d.ts.map +1 -0
- package/dist/nodes/Instagram/Instagram.node.js +1152 -0
- package/dist/nodes/Instagram/Instagram.node.js.map +1 -0
- package/dist/nodes/Instagram/InstagramTrigger.node.d.ts +61 -0
- package/dist/nodes/Instagram/InstagramTrigger.node.d.ts.map +1 -0
- package/dist/nodes/Instagram/InstagramTrigger.node.js +315 -0
- package/dist/nodes/Instagram/InstagramTrigger.node.js.map +1 -0
- package/dist/nodes/Instagram/instagram.svg +15 -0
- package/dist/services/InstagramApiClient.d.ts +261 -0
- package/dist/services/InstagramApiClient.d.ts.map +1 -0
- package/dist/services/InstagramApiClient.js +548 -0
- package/dist/services/InstagramApiClient.js.map +1 -0
- package/dist/services/TokenManager.d.ts +73 -0
- package/dist/services/TokenManager.d.ts.map +1 -0
- package/dist/services/TokenManager.js +150 -0
- package/dist/services/TokenManager.js.map +1 -0
- package/dist/services/ValidationUtils.d.ts +44 -0
- package/dist/services/ValidationUtils.d.ts.map +1 -0
- package/dist/services/ValidationUtils.js +203 -0
- package/dist/services/ValidationUtils.js.map +1 -0
- package/dist/services/WebhookHandler.d.ts +206 -0
- package/dist/services/WebhookHandler.d.ts.map +1 -0
- package/dist/services/WebhookHandler.js +261 -0
- package/dist/services/WebhookHandler.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +21 -0
- package/dist/services/index.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InstagramAccessTokenApi = void 0;
|
|
4
|
+
class InstagramAccessTokenApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'instagramAccessTokenApi';
|
|
7
|
+
this.displayName = 'Instagram Access Token API';
|
|
8
|
+
this.documentationUrl = 'https://developers.facebook.com/docs/instagram-api/';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'Access Token',
|
|
12
|
+
name: 'accessToken',
|
|
13
|
+
type: 'string',
|
|
14
|
+
typeOptions: {
|
|
15
|
+
password: true,
|
|
16
|
+
},
|
|
17
|
+
default: '',
|
|
18
|
+
required: true,
|
|
19
|
+
description: 'Long-lived access token from Meta Developer Console',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
displayName: 'Instagram Account ID',
|
|
23
|
+
name: 'instagramAccountId',
|
|
24
|
+
type: 'string',
|
|
25
|
+
default: '',
|
|
26
|
+
description: 'Auto-discovered after validation. Leave empty for auto-discovery.',
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
this.authenticate = {
|
|
30
|
+
type: 'generic',
|
|
31
|
+
properties: {
|
|
32
|
+
qs: {
|
|
33
|
+
access_token: '={{$credentials.accessToken}}',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
this.test = {
|
|
38
|
+
request: {
|
|
39
|
+
baseURL: 'https://graph.facebook.com/v18.0',
|
|
40
|
+
url: '/me',
|
|
41
|
+
qs: {
|
|
42
|
+
fields: 'id,name',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Pre-authentication hook to validate token and auto-discover Instagram Business Account ID
|
|
49
|
+
*
|
|
50
|
+
* Requirements:
|
|
51
|
+
* - 2.1: Validate token against Instagram Graph API
|
|
52
|
+
* - 2.2: Auto-discover Instagram Business Account ID
|
|
53
|
+
* - 2.3: Return descriptive error for invalid tokens
|
|
54
|
+
*/
|
|
55
|
+
async preAuthentication(credentials) {
|
|
56
|
+
const accessToken = credentials.accessToken;
|
|
57
|
+
if (!accessToken) {
|
|
58
|
+
throw new Error('Access token is required');
|
|
59
|
+
}
|
|
60
|
+
const updatedCredentials = { ...credentials };
|
|
61
|
+
try {
|
|
62
|
+
// Step 1: Validate token (Requirement 2.1)
|
|
63
|
+
// First, try a simple API call to validate the token
|
|
64
|
+
await this.helpers.httpRequest({
|
|
65
|
+
method: 'GET',
|
|
66
|
+
url: 'https://graph.facebook.com/v18.0/me',
|
|
67
|
+
qs: {
|
|
68
|
+
fields: 'id,name',
|
|
69
|
+
access_token: accessToken,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
// Step 2: Auto-discover Instagram Business Account ID (Requirement 2.2)
|
|
73
|
+
// Only if not already set
|
|
74
|
+
if (!credentials.instagramAccountId) {
|
|
75
|
+
try {
|
|
76
|
+
// Get pages connected to the user
|
|
77
|
+
const pagesResponse = await this.helpers.httpRequest({
|
|
78
|
+
method: 'GET',
|
|
79
|
+
url: 'https://graph.facebook.com/v18.0/me/accounts',
|
|
80
|
+
qs: {
|
|
81
|
+
fields: 'instagram_business_account,id,name',
|
|
82
|
+
access_token: accessToken,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
// Find the first page with an Instagram Business Account
|
|
86
|
+
if (pagesResponse.data && pagesResponse.data.length > 0) {
|
|
87
|
+
for (const page of pagesResponse.data) {
|
|
88
|
+
if (page.instagram_business_account?.id) {
|
|
89
|
+
updatedCredentials.instagramAccountId = page.instagram_business_account.id;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// If no Instagram Business Account found, provide helpful message
|
|
95
|
+
if (!updatedCredentials.instagramAccountId) {
|
|
96
|
+
console.warn('No Instagram Business Account found. Make sure your Facebook Page is connected to an Instagram Business or Creator account.');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (accountError) {
|
|
100
|
+
// Account discovery failed but token is valid
|
|
101
|
+
console.warn('Could not auto-discover Instagram Account ID. You may need to set it manually.');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// Requirement 2.3: Return descriptive error for invalid tokens
|
|
107
|
+
const errorResponse = error;
|
|
108
|
+
const errorMessage = errorResponse?.error?.message ?? 'Unknown error';
|
|
109
|
+
const errorCode = errorResponse?.error?.code;
|
|
110
|
+
let descriptiveError = `Invalid access token: ${errorMessage}`;
|
|
111
|
+
// Provide more specific error messages based on error code
|
|
112
|
+
if (errorCode === 190) {
|
|
113
|
+
descriptiveError =
|
|
114
|
+
'Access token has expired or is invalid. Please generate a new token from Meta Developer Console.';
|
|
115
|
+
}
|
|
116
|
+
else if (errorCode === 102) {
|
|
117
|
+
descriptiveError =
|
|
118
|
+
'Session has expired. Please generate a new access token from Meta Developer Console.';
|
|
119
|
+
}
|
|
120
|
+
else if (errorCode === 10) {
|
|
121
|
+
descriptiveError =
|
|
122
|
+
'Permission denied. Make sure your token has the required permissions: instagram_basic, instagram_manage_messages.';
|
|
123
|
+
}
|
|
124
|
+
throw new Error(descriptiveError);
|
|
125
|
+
}
|
|
126
|
+
return updatedCredentials;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.InstagramAccessTokenApi = InstagramAccessTokenApi;
|
|
130
|
+
//# sourceMappingURL=InstagramAccessTokenApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InstagramAccessTokenApi.credentials.js","sourceRoot":"","sources":["../../src/credentials/InstagramAccessTokenApi.credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IAuthenticateGeneric, ICredentialDataDecryptedObject, ICredentialTestRequest, ICredentialType, IHttpRequestHelper, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class InstagramOAuth2Api implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
extends: string[];
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
authenticate: IAuthenticateGeneric;
|
|
9
|
+
test: ICredentialTestRequest;
|
|
10
|
+
/**
|
|
11
|
+
* Pre-authentication hook to exchange short-lived token for long-lived token
|
|
12
|
+
* and auto-discover Instagram Business Account ID
|
|
13
|
+
*
|
|
14
|
+
* Requirements:
|
|
15
|
+
* - 1.3: Exchange short-lived token for long-lived token
|
|
16
|
+
* - 1.6: Auto-discover Instagram Business Account ID
|
|
17
|
+
*/
|
|
18
|
+
preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject): Promise<ICredentialDataDecryptedObject>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=InstagramOAuth2Api.credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InstagramOAuth2Api.credentials.d.ts","sourceRoot":"","sources":["../../src/credentials/InstagramOAuth2Api.credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EAChB,MAAM,cAAc,CAAC;AAuCtB,qBAAa,kBAAmB,YAAW,eAAe;IACxD,IAAI,SAAwB;IAC5B,WAAW,SAA0B;IACrC,gBAAgB,SAAyD;IACzE,OAAO,WAAiB;IAExB,UAAU,EAAE,eAAe,EAAE,CAqF3B;IAEF,YAAY,EAAE,oBAAoB,CAOhC;IAEF,IAAI,EAAE,sBAAsB,CAQ1B;IAEF;;;;;;;OAOG;IACG,iBAAiB,CACrB,IAAI,EAAE,kBAAkB,EACxB,WAAW,EAAE,8BAA8B,GAC1C,OAAO,CAAC,8BAA8B,CAAC;CAiE3C"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InstagramOAuth2Api = void 0;
|
|
4
|
+
class InstagramOAuth2Api {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'instagramOAuth2Api';
|
|
7
|
+
this.displayName = 'Instagram OAuth2 API';
|
|
8
|
+
this.documentationUrl = 'https://developers.facebook.com/docs/instagram-api/';
|
|
9
|
+
this.extends = ['oAuth2Api'];
|
|
10
|
+
this.properties = [
|
|
11
|
+
{
|
|
12
|
+
displayName: 'Grant Type',
|
|
13
|
+
name: 'grantType',
|
|
14
|
+
type: 'hidden',
|
|
15
|
+
default: 'authorizationCode',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
displayName: 'Authorization URL',
|
|
19
|
+
name: 'authUrl',
|
|
20
|
+
type: 'hidden',
|
|
21
|
+
default: 'https://www.facebook.com/v18.0/dialog/oauth',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
displayName: 'Access Token URL',
|
|
25
|
+
name: 'accessTokenUrl',
|
|
26
|
+
type: 'hidden',
|
|
27
|
+
default: 'https://graph.facebook.com/v18.0/oauth/access_token',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
displayName: 'Scope',
|
|
31
|
+
name: 'scope',
|
|
32
|
+
type: 'hidden',
|
|
33
|
+
default: 'instagram_basic,instagram_manage_messages,instagram_manage_comments,instagram_content_publish,pages_show_list,pages_manage_metadata',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
displayName: 'Auth URI Query Parameters',
|
|
37
|
+
name: 'authQueryParameters',
|
|
38
|
+
type: 'hidden',
|
|
39
|
+
default: '',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
displayName: 'Authentication',
|
|
43
|
+
name: 'authentication',
|
|
44
|
+
type: 'hidden',
|
|
45
|
+
default: 'body',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
displayName: 'Client ID',
|
|
49
|
+
name: 'clientId',
|
|
50
|
+
type: 'string',
|
|
51
|
+
default: '',
|
|
52
|
+
required: true,
|
|
53
|
+
description: 'Facebook App ID from Meta Developer Console',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
displayName: 'Client Secret',
|
|
57
|
+
name: 'clientSecret',
|
|
58
|
+
type: 'string',
|
|
59
|
+
typeOptions: {
|
|
60
|
+
password: true,
|
|
61
|
+
},
|
|
62
|
+
default: '',
|
|
63
|
+
required: true,
|
|
64
|
+
description: 'Facebook App Secret from Meta Developer Console',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
displayName: 'Instagram Account ID',
|
|
68
|
+
name: 'instagramAccountId',
|
|
69
|
+
type: 'string',
|
|
70
|
+
default: '',
|
|
71
|
+
description: 'Auto-discovered after authentication. Leave empty for auto-discovery.',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
displayName: 'Long-Lived Token',
|
|
75
|
+
name: 'longLivedToken',
|
|
76
|
+
type: 'hidden',
|
|
77
|
+
typeOptions: {
|
|
78
|
+
password: true,
|
|
79
|
+
},
|
|
80
|
+
default: '',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
displayName: 'Long-Lived Token Expires At',
|
|
84
|
+
name: 'longLivedTokenExpiresAt',
|
|
85
|
+
type: 'hidden',
|
|
86
|
+
default: 0,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
displayName: 'Long-Lived Token Created At',
|
|
90
|
+
name: 'longLivedTokenCreatedAt',
|
|
91
|
+
type: 'hidden',
|
|
92
|
+
default: 0,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
this.authenticate = {
|
|
96
|
+
type: 'generic',
|
|
97
|
+
properties: {
|
|
98
|
+
qs: {
|
|
99
|
+
access_token: '={{$credentials.longLivedToken || $credentials.accessToken}}',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
this.test = {
|
|
104
|
+
request: {
|
|
105
|
+
baseURL: 'https://graph.facebook.com/v18.0',
|
|
106
|
+
url: '/me',
|
|
107
|
+
qs: {
|
|
108
|
+
fields: 'id,name',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Pre-authentication hook to exchange short-lived token for long-lived token
|
|
115
|
+
* and auto-discover Instagram Business Account ID
|
|
116
|
+
*
|
|
117
|
+
* Requirements:
|
|
118
|
+
* - 1.3: Exchange short-lived token for long-lived token
|
|
119
|
+
* - 1.6: Auto-discover Instagram Business Account ID
|
|
120
|
+
*/
|
|
121
|
+
async preAuthentication(credentials) {
|
|
122
|
+
const accessToken = credentials.accessToken;
|
|
123
|
+
const clientSecret = credentials.clientSecret;
|
|
124
|
+
if (!accessToken || !clientSecret) {
|
|
125
|
+
return credentials;
|
|
126
|
+
}
|
|
127
|
+
const updatedCredentials = { ...credentials };
|
|
128
|
+
try {
|
|
129
|
+
// Step 1: Exchange short-lived token for long-lived token (Requirement 1.3)
|
|
130
|
+
const longLivedTokenResponse = await this.helpers.httpRequest({
|
|
131
|
+
method: 'GET',
|
|
132
|
+
url: 'https://graph.facebook.com/v18.0/oauth/access_token',
|
|
133
|
+
qs: {
|
|
134
|
+
grant_type: 'fb_exchange_token',
|
|
135
|
+
client_id: credentials.clientId,
|
|
136
|
+
client_secret: clientSecret,
|
|
137
|
+
fb_exchange_token: accessToken,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
if (longLivedTokenResponse.access_token) {
|
|
141
|
+
const now = Date.now();
|
|
142
|
+
const expiresIn = longLivedTokenResponse.expires_in ?? 5184000; // Default 60 days
|
|
143
|
+
updatedCredentials.longLivedToken = longLivedTokenResponse.access_token;
|
|
144
|
+
updatedCredentials.longLivedTokenExpiresAt = now + expiresIn * 1000;
|
|
145
|
+
updatedCredentials.longLivedTokenCreatedAt = now;
|
|
146
|
+
}
|
|
147
|
+
// Step 2: Auto-discover Instagram Business Account ID (Requirement 1.6)
|
|
148
|
+
const tokenToUse = updatedCredentials.longLivedToken || accessToken;
|
|
149
|
+
// Get pages connected to the user
|
|
150
|
+
const pagesResponse = await this.helpers.httpRequest({
|
|
151
|
+
method: 'GET',
|
|
152
|
+
url: 'https://graph.facebook.com/v18.0/me/accounts',
|
|
153
|
+
qs: {
|
|
154
|
+
fields: 'instagram_business_account,id,name',
|
|
155
|
+
access_token: tokenToUse,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
// Find the first page with an Instagram Business Account
|
|
159
|
+
if (pagesResponse.data && pagesResponse.data.length > 0) {
|
|
160
|
+
for (const page of pagesResponse.data) {
|
|
161
|
+
if (page.instagram_business_account?.id) {
|
|
162
|
+
updatedCredentials.instagramAccountId = page.instagram_business_account.id;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
// Log error but don't fail - credentials might still work
|
|
170
|
+
const errorResponse = error;
|
|
171
|
+
console.warn('Instagram OAuth2 pre-authentication warning:', errorResponse?.error?.message ?? 'Unknown error');
|
|
172
|
+
}
|
|
173
|
+
return updatedCredentials;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.InstagramOAuth2Api = InstagramOAuth2Api;
|
|
177
|
+
//# sourceMappingURL=InstagramOAuth2Api.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InstagramOAuth2Api.credentials.js","sourceRoot":"","sources":["../../src/credentials/InstagramOAuth2Api.credentials.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './credentials/InstagramOAuth2Api.credentials';
|
|
2
|
+
export * from './credentials/InstagramAccessTokenApi.credentials';
|
|
3
|
+
export * from './nodes/Instagram/Instagram.node';
|
|
4
|
+
export * from './nodes/Instagram/InstagramTrigger.node';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mDAAmD,CAAC;AAClE,cAAc,kCAAkC,CAAC;AACjD,cAAc,yCAAyC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// n8n Instagram Node Package
|
|
3
|
+
// Main entry point - exports are configured in package.json n8n section
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
16
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
__exportStar(require("./credentials/InstagramOAuth2Api.credentials"), exports);
|
|
20
|
+
__exportStar(require("./credentials/InstagramAccessTokenApi.credentials"), exports);
|
|
21
|
+
__exportStar(require("./nodes/Instagram/Instagram.node"), exports);
|
|
22
|
+
__exportStar(require("./nodes/Instagram/InstagramTrigger.node"), exports);
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,wEAAwE;;;;;;;;;;;;;;;;AAExE,+EAA6D;AAC7D,oFAAkE;AAClE,mEAAiD;AACjD,0EAAwD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class Instagram implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
/**
|
|
5
|
+
* Execute method - wires up all operations to InstagramApiClient
|
|
6
|
+
* Requirements: All node operations, 14.4 (continueOnFail support)
|
|
7
|
+
*/
|
|
8
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=Instagram.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Instagram.node.d.ts","sourceRoot":"","sources":["../../../src/nodes/Instagram/Instagram.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,oBAAoB,EAGrB,MAAM,cAAc,CAAC;AA4atB,qBAAa,SAAU,YAAW,SAAS;IACzC,WAAW,EAAE,oBAAoB,CAswB/B;IAEF;;;OAGG;IACG,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CAmFxE"}
|