n8n-nodes-onedrive-business-sp 1.0.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 ADDED
@@ -0,0 +1,272 @@
1
+ # Microsoft OneDrive (Business) Node for n8n
2
+
3
+ This is a complete implementation of a Microsoft OneDrive for Business node for n8n, built on SharePoint Document Library with Microsoft Graph API.
4
+
5
+ ## 🚀 Features
6
+
7
+ ### Resources & Operations
8
+
9
+ #### File Operations
10
+ - ✅ **Delete** - Remove files from OneDrive
11
+ - ✅ **Download** - Download file content as binary data
12
+ - ✅ **Get** - Retrieve file metadata
13
+ - ✅ **Rename** - Change file names
14
+ - ✅ **Search** - Find files by query
15
+ - ✅ **Share** - Create sharing links with configurable permissions
16
+ - ✅ **Upload** - Upload files from binary data
17
+
18
+ #### Folder Operations
19
+ - ✅ **Create** - Create new folders
20
+ - ✅ **Delete** - Remove folders
21
+ - ✅ **Get Items** - List contents of a folder
22
+ - ✅ **Rename** - Change folder names
23
+ - ✅ **Search** - Find folders by query
24
+ - ✅ **Share** - Create sharing links with configurable permissions
25
+
26
+ ### Triggers (Webhook-based)
27
+ - ⚡ **On File Created** - Triggers when a new file is created
28
+ - ⚡ **On File Updated** - Triggers when a file is modified
29
+ - ⚡ **On Folder Created** - Triggers when a new folder is created
30
+ - ⚡ **On Folder Updated** - Triggers when a folder is modified
31
+
32
+ ## 📋 Prerequisites
33
+
34
+ ### Microsoft Azure App Registration
35
+
36
+ 1. Go to [Azure Portal](https://portal.azure.com/)
37
+ 2. Navigate to **Azure Active Directory** > **App registrations** > **New registration**
38
+ 3. Configure:
39
+ - Name: `n8n OneDrive Business Integration`
40
+ - Supported account types: **Accounts in any organizational directory**
41
+ - Redirect URI: `https://your-n8n-instance.com/rest/oauth2-credential/callback`
42
+
43
+ 4. After creation, note down:
44
+ - **Application (client) ID**
45
+ - **Directory (tenant) ID**
46
+
47
+ 5. Go to **Certificates & secrets** > **New client secret**
48
+ - Note down the **Client secret value** (shown only once!)
49
+
50
+ 6. Go to **API permissions** > **Add a permission** > **Microsoft Graph** > **Delegated permissions**
51
+ - Add these permissions:
52
+ - `Files.ReadWrite.All`
53
+ - `Sites.Read.All`
54
+ - `Sites.ReadWrite.All`
55
+ - `offline_access`
56
+ - Click **Grant admin consent**
57
+
58
+ ## 🔧 Installation
59
+
60
+ ### For n8n Community Nodes
61
+
62
+ 1. **Copy Files to n8n Custom Nodes Directory:**
63
+
64
+ ```bash
65
+ # Navigate to your n8n installation
66
+ cd ~/.n8n/custom
67
+
68
+ # Create directory structure
69
+ mkdir -p nodes/MicrosoftOneDriveBusiness
70
+ mkdir -p credentials
71
+
72
+ # Copy credential file
73
+ cp credentials/MicrosoftOneDriveBusinessOAuth2Api.credentials.ts ~/.n8n/custom/credentials/
74
+
75
+ # Copy node files
76
+ cp nodes/MicrosoftOneDriveBusiness/* ~/.n8n/custom/nodes/MicrosoftOneDriveBusiness/
77
+ ```
78
+
79
+ 2. **Install as Community Node (Alternative):**
80
+
81
+ If published as an npm package:
82
+
83
+ ```bash
84
+ # In n8n UI: Settings > Community Nodes > Install
85
+ # Package name: n8n-nodes-microsoft-onedrive-business
86
+ ```
87
+
88
+ ### For Development
89
+
90
+ ```bash
91
+ # Clone repository
92
+ git clone <repository-url>
93
+ cd n8n-onedrive-business
94
+
95
+ # Install dependencies
96
+ npm install
97
+
98
+ # Link to n8n
99
+ npm link
100
+
101
+ # In your n8n directory
102
+ npm link n8n-nodes-microsoft-onedrive-business
103
+ ```
104
+
105
+ ## ⚙️ Configuration
106
+
107
+ ### 1. Add Credentials in n8n
108
+
109
+ 1. Go to **Credentials** > **New** > **Microsoft OneDrive (Business) OAuth2 API**
110
+ 2. Enter:
111
+ - **Client ID**: Your Azure App's Application (client) ID
112
+ - **Client Secret**: Your Azure App's client secret
113
+ 3. Click **Connect my account** and authorize
114
+
115
+ ### 2. Get Site ID and Drive ID
116
+
117
+ To use the node, you need your SharePoint site ID:
118
+
119
+ **Get Site ID:**
120
+ ```bash
121
+ GET https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}
122
+ ```
123
+
124
+ Example:
125
+ ```bash
126
+ GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/TeamSite
127
+ ```
128
+
129
+ **Get Drive ID** (optional - will auto-fetch if not provided):
130
+ ```bash
131
+ GET https://graph.microsoft.com/v1.0/sites/{site-id}/drive
132
+ ```
133
+
134
+ ## 📖 Usage Examples
135
+
136
+ ### Example 1: Upload a File
137
+
138
+ ```typescript
139
+ {
140
+ "nodes": [
141
+ {
142
+ "parameters": {
143
+ "resource": "file",
144
+ "operation": "upload",
145
+ "siteId": "contoso.sharepoint.com,abc123,def456",
146
+ "parentFolderId": "root",
147
+ "fileName": "report.pdf",
148
+ "binaryPropertyName": "data"
149
+ },
150
+ "name": "Upload to OneDrive",
151
+ "type": "n8n-nodes-microsoftOneDriveBusiness.microsoftOneDriveBusiness",
152
+ "credentials": {
153
+ "microsoftOneDriveBusinessOAuth2Api": "OneDrive Business Credentials"
154
+ }
155
+ }
156
+ ]
157
+ }
158
+ ```
159
+
160
+ ### Example 2: Search and Download Files
161
+
162
+ ```typescript
163
+ {
164
+ "nodes": [
165
+ {
166
+ "parameters": {
167
+ "resource": "file",
168
+ "operation": "search",
169
+ "siteId": "contoso.sharepoint.com,abc123,def456",
170
+ "query": "quarterly report"
171
+ },
172
+ "name": "Search Files"
173
+ },
174
+ {
175
+ "parameters": {
176
+ "resource": "file",
177
+ "operation": "download",
178
+ "fileId": "={{ $json.id }}",
179
+ "binaryProperty": "data"
180
+ },
181
+ "name": "Download File"
182
+ }
183
+ ]
184
+ }
185
+ ```
186
+
187
+ ### Example 3: Trigger on New Files
188
+
189
+ ```typescript
190
+ {
191
+ "nodes": [
192
+ {
193
+ "parameters": {
194
+ "siteId": "contoso.sharepoint.com,abc123,def456",
195
+ "event": "fileCreated",
196
+ "watchFolderId": "root"
197
+ },
198
+ "name": "OneDrive Trigger",
199
+ "type": "n8n-nodes-microsoftOneDriveBusiness.microsoftOneDriveBusinessTrigger"
200
+ }
201
+ ]
202
+ }
203
+ ```
204
+
205
+ ## 🔑 Key Differences from OneDrive Personal
206
+
207
+ | Feature | OneDrive Personal | OneDrive Business |
208
+ |---------|-------------------|-------------------|
209
+ | Backend | Consumer OneDrive | SharePoint |
210
+ | Drive Type | `personal` | `business` |
211
+ | API Base | `/me/drive` | `/sites/{id}/drive` |
212
+ | Authentication | Personal Microsoft Account | Azure AD (Work/School) |
213
+ | Organization Features | ❌ | ✅ (Sharing policies, DLP, etc.) |
214
+
215
+ ## 🛠️ API Endpoints Used
216
+
217
+ - `GET /sites/{site-id}/drive` - Get drive information
218
+ - `PUT /drives/{drive-id}/items/{parent-id}:/{filename}:/content` - Upload file
219
+ - `GET /drives/{drive-id}/items/{item-id}/content` - Download file
220
+ - `GET /drives/{drive-id}/items/{item-id}` - Get metadata
221
+ - `DELETE /drives/{drive-id}/items/{item-id}` - Delete item
222
+ - `PATCH /drives/{drive-id}/items/{item-id}` - Update item
223
+ - `GET /drives/{drive-id}/root/search(q='{query}')` - Search
224
+ - `POST /drives/{drive-id}/items/{item-id}/createLink` - Create sharing link
225
+ - `POST /subscriptions` - Create webhook subscription (triggers)
226
+ - `GET /drives/{drive-id}/root/delta` - Get delta changes (triggers)
227
+
228
+ ## 🐛 Troubleshooting
229
+
230
+ ### "Drive not found" error
231
+ - Verify your Site ID is correct
232
+ - Ensure user has access to the SharePoint site
233
+ - Check that the drive exists for the site
234
+
235
+ ### "Insufficient privileges" error
236
+ - Verify all required Graph API permissions are granted
237
+ - Ensure admin consent is given for tenant-wide permissions
238
+ - Check that the user has appropriate SharePoint permissions
239
+
240
+ ### Webhook/Trigger not working
241
+ - Ensure your n8n instance is publicly accessible
242
+ - Verify the webhook URL is correct
243
+ - Check that subscriptions are being created (they expire after 72 hours)
244
+ - Microsoft Graph webhook delivery can have delays
245
+
246
+ ### File upload fails
247
+ - Check file size (large files >4MB need resumable upload session)
248
+ - Verify binary data property name is correct
249
+ - Ensure mime type is set correctly
250
+
251
+ ## 📚 Resources
252
+
253
+ - [Microsoft Graph API Documentation](https://docs.microsoft.com/en-us/graph/api/resources/onedrive)
254
+ - [SharePoint API Documentation](https://docs.microsoft.com/en-us/graph/api/resources/sharepoint)
255
+ - [n8n Node Development](https://docs.n8n.io/integrations/creating-nodes/)
256
+ - [Azure App Registration](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)
257
+
258
+ ## 📄 License
259
+
260
+ MIT License - Feel free to use and modify as needed.
261
+
262
+ ## 🤝 Contributing
263
+
264
+ Contributions are welcome! Please:
265
+ 1. Fork the repository
266
+ 2. Create a feature branch
267
+ 3. Submit a pull request
268
+
269
+ ## ✨ Credits
270
+
271
+ Built for n8n following official node development guidelines.
272
+ Implements OneDrive for Business (SharePoint) only - does not support OneDrive Personal.
@@ -0,0 +1,10 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class MicrosoftOneDriveBusinessOAuth2Api implements ICredentialType {
3
+ name: string;
4
+ extends: string[];
5
+ displayName: string;
6
+ documentationUrl: string;
7
+ properties: INodeProperties[];
8
+ authenticate: IAuthenticateGeneric;
9
+ test: ICredentialTestRequest;
10
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MicrosoftOneDriveBusinessOAuth2Api = void 0;
4
+ class MicrosoftOneDriveBusinessOAuth2Api {
5
+ constructor() {
6
+ this.name = 'microsoftOneDriveBusinessOAuth2Api';
7
+ this.extends = ['oAuth2Api'];
8
+ this.displayName = 'Microsoft OneDrive (Business) OAuth2 API';
9
+ this.documentationUrl = 'microsoft';
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://login.microsoftonline.com/common/oauth2/v2.0/authorize',
22
+ },
23
+ {
24
+ displayName: 'Access Token URL',
25
+ name: 'accessTokenUrl',
26
+ type: 'hidden',
27
+ default: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
28
+ },
29
+ {
30
+ displayName: 'Scope',
31
+ name: 'scope',
32
+ type: 'hidden',
33
+ default: 'Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All offline_access',
34
+ },
35
+ {
36
+ displayName: 'Auth URI Query Parameters',
37
+ name: 'authQueryParameters',
38
+ type: 'hidden',
39
+ default: 'response_mode=query',
40
+ },
41
+ {
42
+ displayName: 'Authentication',
43
+ name: 'authentication',
44
+ type: 'hidden',
45
+ default: 'body',
46
+ },
47
+ ];
48
+ this.authenticate = {
49
+ type: 'generic',
50
+ properties: {
51
+ headers: {
52
+ Authorization: '={{"Bearer " + $credentials.oauthTokenData.access_token}}',
53
+ },
54
+ },
55
+ };
56
+ this.test = {
57
+ request: {
58
+ baseURL: 'https://graph.microsoft.com/v1.0',
59
+ url: '/me',
60
+ },
61
+ };
62
+ }
63
+ }
64
+ exports.MicrosoftOneDriveBusinessOAuth2Api = MicrosoftOneDriveBusinessOAuth2Api;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class MicrosoftOneDriveBusiness implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,583 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MicrosoftOneDriveBusiness = void 0;
4
+ class MicrosoftOneDriveBusiness {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: 'Microsoft OneDrive (Business)',
8
+ name: 'microsoftOneDriveBusiness',
9
+ icon: 'file:onedrive.svg',
10
+ group: ['input', 'output'],
11
+ version: 1,
12
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
13
+ description: 'Work with OneDrive for Business (SharePoint)',
14
+ defaults: {
15
+ name: 'Microsoft OneDrive (Business)',
16
+ },
17
+ inputs: ['main'],
18
+ outputs: ['main'],
19
+ credentials: [
20
+ {
21
+ name: 'microsoftOneDriveBusinessOAuth2Api',
22
+ required: true,
23
+ },
24
+ ],
25
+ properties: [
26
+ {
27
+ displayName: 'Resource',
28
+ name: 'resource',
29
+ type: 'options',
30
+ noDataExpression: true,
31
+ options: [
32
+ {
33
+ name: 'File',
34
+ value: 'file',
35
+ },
36
+ {
37
+ name: 'Folder',
38
+ value: 'folder',
39
+ },
40
+ ],
41
+ default: 'file',
42
+ },
43
+ // File Operations
44
+ {
45
+ displayName: 'Operation',
46
+ name: 'operation',
47
+ type: 'options',
48
+ noDataExpression: true,
49
+ displayOptions: {
50
+ show: {
51
+ resource: ['file'],
52
+ },
53
+ },
54
+ options: [
55
+ {
56
+ name: 'Delete',
57
+ value: 'delete',
58
+ description: 'Delete a file',
59
+ action: 'Delete a file',
60
+ },
61
+ {
62
+ name: 'Download',
63
+ value: 'download',
64
+ description: 'Download a file',
65
+ action: 'Download a file',
66
+ },
67
+ {
68
+ name: 'Get',
69
+ value: 'get',
70
+ description: 'Get file metadata',
71
+ action: 'Get a file',
72
+ },
73
+ {
74
+ name: 'Rename',
75
+ value: 'rename',
76
+ description: 'Rename a file',
77
+ action: 'Rename a file',
78
+ },
79
+ {
80
+ name: 'Search',
81
+ value: 'search',
82
+ description: 'Search for files',
83
+ action: 'Search files',
84
+ },
85
+ {
86
+ name: 'Share',
87
+ value: 'share',
88
+ description: 'Share a file',
89
+ action: 'Share a file',
90
+ },
91
+ {
92
+ name: 'Upload',
93
+ value: 'upload',
94
+ description: 'Upload a file',
95
+ action: 'Upload a file',
96
+ },
97
+ ],
98
+ default: 'upload',
99
+ },
100
+ // Folder Operations
101
+ {
102
+ displayName: 'Operation',
103
+ name: 'operation',
104
+ type: 'options',
105
+ noDataExpression: true,
106
+ displayOptions: {
107
+ show: {
108
+ resource: ['folder'],
109
+ },
110
+ },
111
+ options: [
112
+ {
113
+ name: 'Create',
114
+ value: 'create',
115
+ description: 'Create a folder',
116
+ action: 'Create a folder',
117
+ },
118
+ {
119
+ name: 'Delete',
120
+ value: 'delete',
121
+ description: 'Delete a folder',
122
+ action: 'Delete a folder',
123
+ },
124
+ {
125
+ name: 'Get Items',
126
+ value: 'getItems',
127
+ description: 'Get items in a folder',
128
+ action: 'Get items in a folder',
129
+ },
130
+ {
131
+ name: 'Rename',
132
+ value: 'rename',
133
+ description: 'Rename a folder',
134
+ action: 'Rename a folder',
135
+ },
136
+ {
137
+ name: 'Search',
138
+ value: 'search',
139
+ description: 'Search for folders',
140
+ action: 'Search folders',
141
+ },
142
+ {
143
+ name: 'Share',
144
+ value: 'share',
145
+ description: 'Share a folder',
146
+ action: 'Share a folder',
147
+ },
148
+ ],
149
+ default: 'create',
150
+ },
151
+ // Common Fields
152
+ {
153
+ displayName: 'Site ID',
154
+ name: 'siteId',
155
+ type: 'string',
156
+ default: '',
157
+ required: true,
158
+ description: 'The SharePoint site ID',
159
+ },
160
+ {
161
+ displayName: 'Drive ID',
162
+ name: 'driveId',
163
+ type: 'string',
164
+ default: '',
165
+ description: 'The drive ID. If not specified, the default drive for the site will be used.',
166
+ },
167
+ // File: Delete
168
+ {
169
+ displayName: 'File ID',
170
+ name: 'fileId',
171
+ type: 'string',
172
+ displayOptions: {
173
+ show: {
174
+ resource: ['file'],
175
+ operation: ['delete', 'get', 'download', 'rename', 'share'],
176
+ },
177
+ },
178
+ default: '',
179
+ required: true,
180
+ description: 'The ID of the file',
181
+ },
182
+ // File: Upload
183
+ {
184
+ displayName: 'Parent Folder ID',
185
+ name: 'parentFolderId',
186
+ type: 'string',
187
+ displayOptions: {
188
+ show: {
189
+ resource: ['file'],
190
+ operation: ['upload'],
191
+ },
192
+ },
193
+ default: 'root',
194
+ description: 'The ID of the parent folder. Use "root" for the root folder.',
195
+ },
196
+ {
197
+ displayName: 'File Name',
198
+ name: 'fileName',
199
+ type: 'string',
200
+ displayOptions: {
201
+ show: {
202
+ resource: ['file'],
203
+ operation: ['upload'],
204
+ },
205
+ },
206
+ default: '',
207
+ required: true,
208
+ description: 'The name of the file to upload',
209
+ },
210
+ {
211
+ displayName: 'Binary Property',
212
+ name: 'binaryPropertyName',
213
+ type: 'string',
214
+ displayOptions: {
215
+ show: {
216
+ resource: ['file'],
217
+ operation: ['upload'],
218
+ },
219
+ },
220
+ default: 'data',
221
+ required: true,
222
+ description: 'Name of the binary property containing the file data',
223
+ },
224
+ // File: Rename
225
+ {
226
+ displayName: 'New Name',
227
+ name: 'newName',
228
+ type: 'string',
229
+ displayOptions: {
230
+ show: {
231
+ resource: ['file', 'folder'],
232
+ operation: ['rename'],
233
+ },
234
+ },
235
+ default: '',
236
+ required: true,
237
+ description: 'The new name for the file or folder',
238
+ },
239
+ // File: Search
240
+ {
241
+ displayName: 'Query',
242
+ name: 'query',
243
+ type: 'string',
244
+ displayOptions: {
245
+ show: {
246
+ resource: ['file', 'folder'],
247
+ operation: ['search'],
248
+ },
249
+ },
250
+ default: '',
251
+ required: true,
252
+ description: 'The search query',
253
+ },
254
+ // File: Share
255
+ {
256
+ displayName: 'Link Type',
257
+ name: 'linkType',
258
+ type: 'options',
259
+ displayOptions: {
260
+ show: {
261
+ resource: ['file', 'folder'],
262
+ operation: ['share'],
263
+ },
264
+ },
265
+ options: [
266
+ {
267
+ name: 'View',
268
+ value: 'view',
269
+ description: 'View only',
270
+ },
271
+ {
272
+ name: 'Edit',
273
+ value: 'edit',
274
+ description: 'Edit access',
275
+ },
276
+ {
277
+ name: 'Embed',
278
+ value: 'embed',
279
+ description: 'Embed link',
280
+ },
281
+ ],
282
+ default: 'view',
283
+ description: 'The type of sharing link to create',
284
+ },
285
+ {
286
+ displayName: 'Link Scope',
287
+ name: 'linkScope',
288
+ type: 'options',
289
+ displayOptions: {
290
+ show: {
291
+ resource: ['file', 'folder'],
292
+ operation: ['share'],
293
+ },
294
+ },
295
+ options: [
296
+ {
297
+ name: 'Anonymous',
298
+ value: 'anonymous',
299
+ description: 'Anyone with the link',
300
+ },
301
+ {
302
+ name: 'Organization',
303
+ value: 'organization',
304
+ description: 'People in your organization',
305
+ },
306
+ ],
307
+ default: 'organization',
308
+ description: 'The scope of the sharing link',
309
+ },
310
+ // Folder: Create
311
+ {
312
+ displayName: 'Folder Name',
313
+ name: 'folderName',
314
+ type: 'string',
315
+ displayOptions: {
316
+ show: {
317
+ resource: ['folder'],
318
+ operation: ['create'],
319
+ },
320
+ },
321
+ default: '',
322
+ required: true,
323
+ description: 'The name of the folder to create',
324
+ },
325
+ {
326
+ displayName: 'Parent Folder ID',
327
+ name: 'parentFolderId',
328
+ type: 'string',
329
+ displayOptions: {
330
+ show: {
331
+ resource: ['folder'],
332
+ operation: ['create', 'getItems'],
333
+ },
334
+ },
335
+ default: 'root',
336
+ description: 'The ID of the parent folder. Use "root" for the root folder.',
337
+ },
338
+ // Folder: Delete, Rename, Share
339
+ {
340
+ displayName: 'Folder ID',
341
+ name: 'folderId',
342
+ type: 'string',
343
+ displayOptions: {
344
+ show: {
345
+ resource: ['folder'],
346
+ operation: ['delete', 'rename', 'share'],
347
+ },
348
+ },
349
+ default: '',
350
+ required: true,
351
+ description: 'The ID of the folder',
352
+ },
353
+ // Download Options
354
+ {
355
+ displayName: 'Put Output in Field',
356
+ name: 'binaryProperty',
357
+ type: 'string',
358
+ displayOptions: {
359
+ show: {
360
+ resource: ['file'],
361
+ operation: ['download'],
362
+ },
363
+ },
364
+ default: 'data',
365
+ required: true,
366
+ description: 'The name of the output binary field to put the file in',
367
+ },
368
+ ],
369
+ };
370
+ }
371
+ async execute() {
372
+ const items = this.getInputData();
373
+ const returnData = [];
374
+ const resource = this.getNodeParameter('resource', 0);
375
+ const operation = this.getNodeParameter('operation', 0);
376
+ let responseData = {};
377
+ for (let i = 0; i < items.length; i++) {
378
+ try {
379
+ const siteId = this.getNodeParameter('siteId', i);
380
+ const driveId = this.getNodeParameter('driveId', i, '');
381
+ // Get drive ID if not provided
382
+ let actualDriveId = driveId;
383
+ if (!actualDriveId) {
384
+ const driveResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
385
+ method: 'GET',
386
+ url: `https://graph.microsoft.com/v1.0/sites/${siteId}/drive`,
387
+ json: true,
388
+ });
389
+ actualDriveId = driveResponse.id;
390
+ }
391
+ if (resource === 'file') {
392
+ // FILE OPERATIONS
393
+ if (operation === 'delete') {
394
+ const fileId = this.getNodeParameter('fileId', i);
395
+ await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
396
+ method: 'DELETE',
397
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
398
+ json: true,
399
+ });
400
+ responseData = { success: true, fileId };
401
+ }
402
+ else if (operation === 'download') {
403
+ const fileId = this.getNodeParameter('fileId', i);
404
+ const binaryProperty = this.getNodeParameter('binaryProperty', i);
405
+ // Get file metadata first
406
+ const fileMetadata = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
407
+ method: 'GET',
408
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
409
+ json: true,
410
+ });
411
+ // Download file content
412
+ const fileContent = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
413
+ method: 'GET',
414
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}/content`,
415
+ json: false,
416
+ encoding: null,
417
+ });
418
+ const fileName = fileMetadata.name || 'file';
419
+ const mimeType = fileMetadata.file?.mimeType || undefined;
420
+ const binaryData = await this.helpers.prepareBinaryData(fileContent, fileName, mimeType);
421
+ returnData.push({
422
+ json: fileMetadata,
423
+ binary: {
424
+ [binaryProperty]: binaryData,
425
+ },
426
+ });
427
+ continue;
428
+ }
429
+ else if (operation === 'get') {
430
+ const fileId = this.getNodeParameter('fileId', i);
431
+ responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
432
+ method: 'GET',
433
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
434
+ json: true,
435
+ });
436
+ }
437
+ else if (operation === 'rename') {
438
+ const fileId = this.getNodeParameter('fileId', i);
439
+ const newName = this.getNodeParameter('newName', i);
440
+ responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
441
+ method: 'PATCH',
442
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
443
+ body: {
444
+ name: newName,
445
+ },
446
+ json: true,
447
+ });
448
+ }
449
+ else if (operation === 'search') {
450
+ const query = this.getNodeParameter('query', i);
451
+ const result = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
452
+ method: 'GET',
453
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/root/search(q='${encodeURIComponent(query)}')`,
454
+ json: true,
455
+ });
456
+ const items = result.value || [];
457
+ responseData = items.filter((item) => item.file !== undefined);
458
+ }
459
+ else if (operation === 'share') {
460
+ const fileId = this.getNodeParameter('fileId', i);
461
+ const linkType = this.getNodeParameter('linkType', i);
462
+ const linkScope = this.getNodeParameter('linkScope', i);
463
+ responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
464
+ method: 'POST',
465
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}/createLink`,
466
+ body: {
467
+ type: linkType,
468
+ scope: linkScope,
469
+ },
470
+ json: true,
471
+ });
472
+ }
473
+ else if (operation === 'upload') {
474
+ const parentFolderId = this.getNodeParameter('parentFolderId', i);
475
+ const fileName = this.getNodeParameter('fileName', i);
476
+ const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
477
+ const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
478
+ const fileBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
479
+ const parentPath = parentFolderId === 'root' ? 'root' : `items/${parentFolderId}`;
480
+ responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
481
+ method: 'PUT',
482
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/${parentPath}:/${fileName}:/content`,
483
+ body: fileBuffer,
484
+ headers: {
485
+ 'Content-Type': binaryData.mimeType || 'application/octet-stream',
486
+ },
487
+ json: true,
488
+ });
489
+ }
490
+ }
491
+ else if (resource === 'folder') {
492
+ // FOLDER OPERATIONS
493
+ if (operation === 'create') {
494
+ const folderName = this.getNodeParameter('folderName', i);
495
+ const parentFolderId = this.getNodeParameter('parentFolderId', i);
496
+ const parentPath = parentFolderId === 'root' ? 'root' : `items/${parentFolderId}`;
497
+ responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
498
+ method: 'POST',
499
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/${parentPath}/children`,
500
+ body: {
501
+ name: folderName,
502
+ folder: {},
503
+ '@microsoft.graph.conflictBehavior': 'rename',
504
+ },
505
+ json: true,
506
+ });
507
+ }
508
+ else if (operation === 'delete') {
509
+ const folderId = this.getNodeParameter('folderId', i);
510
+ await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
511
+ method: 'DELETE',
512
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${folderId}`,
513
+ json: true,
514
+ });
515
+ responseData = { success: true, folderId };
516
+ }
517
+ else if (operation === 'getItems') {
518
+ const parentFolderId = this.getNodeParameter('parentFolderId', i);
519
+ const parentPath = parentFolderId === 'root' ? 'root' : `items/${parentFolderId}`;
520
+ const result = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
521
+ method: 'GET',
522
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/${parentPath}/children`,
523
+ json: true,
524
+ });
525
+ responseData = result.value || [];
526
+ }
527
+ else if (operation === 'rename') {
528
+ const folderId = this.getNodeParameter('folderId', i);
529
+ const newName = this.getNodeParameter('newName', i);
530
+ responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
531
+ method: 'PATCH',
532
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${folderId}`,
533
+ body: {
534
+ name: newName,
535
+ },
536
+ json: true,
537
+ });
538
+ }
539
+ else if (operation === 'search') {
540
+ const query = this.getNodeParameter('query', i);
541
+ const result = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
542
+ method: 'GET',
543
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/root/search(q='${encodeURIComponent(query)}')`,
544
+ json: true,
545
+ });
546
+ const items = result.value || [];
547
+ responseData = items.filter((item) => item.folder !== undefined);
548
+ }
549
+ else if (operation === 'share') {
550
+ const folderId = this.getNodeParameter('folderId', i);
551
+ const linkType = this.getNodeParameter('linkType', i);
552
+ const linkScope = this.getNodeParameter('linkScope', i);
553
+ responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
554
+ method: 'POST',
555
+ url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${folderId}/createLink`,
556
+ body: {
557
+ type: linkType,
558
+ scope: linkScope,
559
+ },
560
+ json: true,
561
+ });
562
+ }
563
+ }
564
+ if (Array.isArray(responseData)) {
565
+ returnData.push(...responseData.map((item) => ({ json: item })));
566
+ }
567
+ else {
568
+ returnData.push({ json: responseData });
569
+ }
570
+ }
571
+ catch (error) {
572
+ if (this.continueOnFail()) {
573
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
574
+ returnData.push({ json: { error: errorMessage } });
575
+ continue;
576
+ }
577
+ throw error;
578
+ }
579
+ }
580
+ return [returnData];
581
+ }
582
+ }
583
+ exports.MicrosoftOneDriveBusiness = MicrosoftOneDriveBusiness;
@@ -0,0 +1,12 @@
1
+ import { IHookFunctions, IWebhookFunctions, INodeType, INodeTypeDescription, IWebhookResponseData } from 'n8n-workflow';
2
+ export declare class MicrosoftOneDriveBusinessTrigger implements INodeType {
3
+ description: INodeTypeDescription;
4
+ webhookMethods: {
5
+ default: {
6
+ checkExists(this: IHookFunctions): Promise<boolean>;
7
+ create(this: IHookFunctions): Promise<boolean>;
8
+ delete(this: IHookFunctions): Promise<boolean>;
9
+ };
10
+ };
11
+ webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
12
+ }
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MicrosoftOneDriveBusinessTrigger = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ class MicrosoftOneDriveBusinessTrigger {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: 'Microsoft OneDrive (Business) Trigger',
9
+ name: 'microsoftOneDriveBusinessTrigger',
10
+ icon: 'file:onedrive.svg',
11
+ group: ['trigger'],
12
+ version: 1,
13
+ subtitle: '={{$parameter["event"]}}',
14
+ description: 'Triggers when OneDrive for Business events occur',
15
+ defaults: {
16
+ name: 'OneDrive (Business) Trigger',
17
+ },
18
+ inputs: [],
19
+ outputs: ['main'],
20
+ credentials: [
21
+ {
22
+ name: 'microsoftOneDriveBusinessOAuth2Api',
23
+ required: true,
24
+ },
25
+ ],
26
+ webhooks: [
27
+ {
28
+ name: 'default',
29
+ httpMethod: 'POST',
30
+ responseMode: 'onReceived',
31
+ path: 'webhook',
32
+ },
33
+ ],
34
+ properties: [
35
+ {
36
+ displayName: 'Site ID',
37
+ name: 'siteId',
38
+ type: 'string',
39
+ default: '',
40
+ required: true,
41
+ description: 'The SharePoint site ID',
42
+ },
43
+ {
44
+ displayName: 'Drive ID',
45
+ name: 'driveId',
46
+ type: 'string',
47
+ default: '',
48
+ description: 'The drive ID. If not specified, the default drive for the site will be used.',
49
+ },
50
+ {
51
+ displayName: 'Event',
52
+ name: 'event',
53
+ type: 'options',
54
+ options: [
55
+ {
56
+ name: '⚡ On File Created',
57
+ value: 'fileCreated',
58
+ description: 'Trigger when a file is created',
59
+ },
60
+ {
61
+ name: '⚡ On File Updated',
62
+ value: 'fileUpdated',
63
+ description: 'Trigger when a file is updated',
64
+ },
65
+ {
66
+ name: '⚡ On Folder Created',
67
+ value: 'folderCreated',
68
+ description: 'Trigger when a folder is created',
69
+ },
70
+ {
71
+ name: '⚡ On Folder Updated',
72
+ value: 'folderUpdated',
73
+ description: 'Trigger when a folder is updated',
74
+ },
75
+ ],
76
+ default: 'fileCreated',
77
+ description: 'The event to trigger on',
78
+ },
79
+ {
80
+ displayName: 'Watch Folder ID',
81
+ name: 'watchFolderId',
82
+ type: 'string',
83
+ default: 'root',
84
+ description: 'The ID of the folder to watch. Use "root" to watch the entire drive.',
85
+ },
86
+ {
87
+ displayName: 'Options',
88
+ name: 'options',
89
+ type: 'collection',
90
+ placeholder: 'Add Option',
91
+ default: {},
92
+ options: [
93
+ {
94
+ displayName: 'Poll Interval (minutes)',
95
+ name: 'pollInterval',
96
+ type: 'number',
97
+ default: 5,
98
+ description: 'How often to poll for changes (in minutes)',
99
+ },
100
+ ],
101
+ },
102
+ ],
103
+ };
104
+ this.webhookMethods = {
105
+ default: {
106
+ async checkExists() {
107
+ const webhookData = this.getWorkflowStaticData('node');
108
+ if (webhookData.subscriptionId === undefined) {
109
+ return false;
110
+ }
111
+ const siteId = this.getNodeParameter('siteId');
112
+ const driveId = this.getNodeParameter('driveId', '');
113
+ // Get drive ID if not provided
114
+ let actualDriveId = driveId;
115
+ if (!actualDriveId) {
116
+ const driveResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
117
+ method: 'GET',
118
+ url: `https://graph.microsoft.com/v1.0/sites/${siteId}/drive`,
119
+ json: true,
120
+ });
121
+ actualDriveId = driveResponse.id;
122
+ }
123
+ try {
124
+ await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
125
+ method: 'GET',
126
+ url: `https://graph.microsoft.com/v1.0/subscriptions/${webhookData.subscriptionId}`,
127
+ json: true,
128
+ });
129
+ return true;
130
+ }
131
+ catch (error) {
132
+ return false;
133
+ }
134
+ },
135
+ async create() {
136
+ const webhookUrl = this.getNodeWebhookUrl('default');
137
+ const webhookData = this.getWorkflowStaticData('node');
138
+ const siteId = this.getNodeParameter('siteId');
139
+ const driveId = this.getNodeParameter('driveId', '');
140
+ const watchFolderId = this.getNodeParameter('watchFolderId');
141
+ // Get drive ID if not provided
142
+ let actualDriveId = driveId;
143
+ if (!actualDriveId) {
144
+ const driveResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
145
+ method: 'GET',
146
+ url: `https://graph.microsoft.com/v1.0/sites/${siteId}/drive`,
147
+ json: true,
148
+ });
149
+ actualDriveId = driveResponse.id;
150
+ }
151
+ const watchPath = watchFolderId === 'root' ? 'root' : `items/${watchFolderId}`;
152
+ const resource = `/drives/${actualDriveId}/${watchPath}`;
153
+ // Create subscription
154
+ const expirationDateTime = new Date();
155
+ expirationDateTime.setHours(expirationDateTime.getHours() + 72); // 72 hours max
156
+ const body = {
157
+ changeType: 'updated',
158
+ notificationUrl: webhookUrl,
159
+ resource,
160
+ expirationDateTime: expirationDateTime.toISOString(),
161
+ clientState: 'n8n-secret-token',
162
+ };
163
+ try {
164
+ const responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
165
+ method: 'POST',
166
+ url: 'https://graph.microsoft.com/v1.0/subscriptions',
167
+ body,
168
+ json: true,
169
+ });
170
+ webhookData.subscriptionId = responseData.id;
171
+ webhookData.driveId = actualDriveId;
172
+ webhookData.deltaLink = null;
173
+ }
174
+ catch (error) {
175
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
176
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Microsoft Graph subscription creation failed: ${errorMessage}`);
177
+ }
178
+ return true;
179
+ },
180
+ async delete() {
181
+ const webhookData = this.getWorkflowStaticData('node');
182
+ if (webhookData.subscriptionId !== undefined) {
183
+ try {
184
+ await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
185
+ method: 'DELETE',
186
+ url: `https://graph.microsoft.com/v1.0/subscriptions/${webhookData.subscriptionId}`,
187
+ json: true,
188
+ });
189
+ }
190
+ catch (error) {
191
+ return false;
192
+ }
193
+ delete webhookData.subscriptionId;
194
+ delete webhookData.driveId;
195
+ delete webhookData.deltaLink;
196
+ }
197
+ return true;
198
+ },
199
+ },
200
+ };
201
+ }
202
+ async webhook() {
203
+ const bodyData = this.getBodyData();
204
+ const query = this.getQueryData();
205
+ const webhookData = this.getWorkflowStaticData('node');
206
+ // Handle validation request
207
+ if (query.validationToken) {
208
+ return {
209
+ webhookResponse: query.validationToken,
210
+ };
211
+ }
212
+ // Verify client state
213
+ const notification = bodyData.value?.[0];
214
+ if (notification?.clientState !== 'n8n-secret-token') {
215
+ return {
216
+ webhookResponse: 'Invalid client state',
217
+ };
218
+ }
219
+ const event = this.getNodeParameter('event');
220
+ const watchFolderId = this.getNodeParameter('watchFolderId');
221
+ const driveId = webhookData.driveId;
222
+ // Use delta query to get changes
223
+ let deltaUrl = webhookData.deltaLink;
224
+ if (!deltaUrl) {
225
+ const watchPath = watchFolderId === 'root' ? 'root' : `items/${watchFolderId}`;
226
+ deltaUrl = `https://graph.microsoft.com/v1.0/drives/${driveId}/${watchPath}/delta`;
227
+ }
228
+ try {
229
+ const deltaResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
230
+ method: 'GET',
231
+ url: deltaUrl,
232
+ json: true,
233
+ });
234
+ // Store the new delta link
235
+ webhookData.deltaLink = deltaResponse['@odata.deltaLink'];
236
+ const changes = deltaResponse.value;
237
+ const filteredChanges = changes.filter((change) => {
238
+ const isFile = change.file !== undefined;
239
+ const isFolder = change.folder !== undefined;
240
+ const isDeleted = change.deleted !== undefined;
241
+ if (isDeleted)
242
+ return false;
243
+ if (event === 'fileCreated' && isFile) {
244
+ return change.createdDateTime === change.lastModifiedDateTime;
245
+ }
246
+ else if (event === 'fileUpdated' && isFile) {
247
+ return change.createdDateTime !== change.lastModifiedDateTime;
248
+ }
249
+ else if (event === 'folderCreated' && isFolder) {
250
+ return change.createdDateTime === change.lastModifiedDateTime;
251
+ }
252
+ else if (event === 'folderUpdated' && isFolder) {
253
+ return change.createdDateTime !== change.lastModifiedDateTime;
254
+ }
255
+ return false;
256
+ });
257
+ if (filteredChanges.length === 0) {
258
+ return {
259
+ webhookResponse: 'No matching changes',
260
+ workflowData: [],
261
+ };
262
+ }
263
+ return {
264
+ workflowData: [filteredChanges.map((change) => ({ json: change }))],
265
+ };
266
+ }
267
+ catch (error) {
268
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
269
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to fetch delta changes: ${errorMessage}`);
270
+ }
271
+ }
272
+ }
273
+ exports.MicrosoftOneDriveBusinessTrigger = MicrosoftOneDriveBusinessTrigger;
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
2
+ <path fill="#0364B8" d="M154.4 90.93A66.31 66.31 0 0 0 92.38 56C64.25 56 41 78.55 40 106.64A63.67 63.67 0 0 0 0 167.68C0 198.16 24.73 223 55.21 223h98.11c36.51 0 66.16-29.65 66.16-66.16a66.37 66.37 0 0 0-65.08-65.91Z"/>
3
+ <path fill="#0078D4" d="M154.4 90.93A66.28 66.28 0 0 0 92.38 56a66.84 66.84 0 0 0-15.61 1.84a66.33 66.33 0 0 1 77.63 99.33a66.18 66.18 0 0 1 65.08 65.91c0 2.4-.13 4.77-.39 7.1A66.13 66.13 0 0 0 256 156.84a66.37 66.37 0 0 0-101.6-65.91Z"/>
4
+ <path fill="#1490DF" d="M154.4 90.93a66.54 66.54 0 0 0-3.65-1.52A66.36 66.36 0 0 0 92.38 56a66.84 66.84 0 0 0-15.61 1.84a67 67 0 0 1 9.09 1.16a66.32 66.32 0 0 1 53.48 83.45A63.67 63.67 0 0 0 99.85 120a63.87 63.87 0 0 0-59.85 40.71a63.87 63.87 0 0 1 15.21-54.07A63.67 63.67 0 0 1 95 81.24a66.36 66.36 0 0 1 59.4 9.69Z"/>
5
+ <path fill="#28A8EA" d="M154.4 90.93a63.67 63.67 0 0 1 44 66.63a66.18 66.18 0 0 1 21.08 65.91H153.32a66.16 66.16 0 0 0 66.16-66.63a66.36 66.36 0 0 0-65.08-65.91Z"/>
6
+ </svg>
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "n8n-nodes-onedrive-business-sp",
3
+ "version": "1.0.0",
4
+ "description": "n8n node for Microsoft OneDrive for Business (SharePoint)",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "onedrive",
9
+ "sharepoint",
10
+ "microsoft",
11
+ "graph",
12
+ "business"
13
+ ],
14
+ "license": "MIT",
15
+ "author": {
16
+ "name": "Your Name",
17
+ "email": "your.email@example.com"
18
+ },
19
+ "main": "dist/index.js",
20
+ "scripts": {
21
+ "build": "tsc && node copy-icons.js",
22
+ "dev": "tsc --watch",
23
+ "format": "prettier nodes credentials --write",
24
+ "lint": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\" package.json",
25
+ "lintfix": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\" package.json --fix",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "n8n": {
32
+ "n8nNodesApiVersion": 1,
33
+ "credentials": [
34
+ "dist/credentials/MicrosoftOneDriveBusinessOAuth2Api.credentials.js"
35
+ ],
36
+ "nodes": [
37
+ "dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusiness.node.js",
38
+ "dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusinessTrigger.node.js"
39
+ ]
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^25.0.3",
43
+ "@typescript-eslint/parser": "^6.0.0",
44
+ "eslint": "^8.0.0",
45
+ "eslint-plugin-n8n-nodes-base": "^1.11.0",
46
+ "gulp": "^4.0.2",
47
+ "n8n-workflow": "*",
48
+ "prettier": "^3.0.0",
49
+ "typescript": "^5.3.3"
50
+ },
51
+ "peerDependencies": {
52
+ "n8n-workflow": "*"
53
+ }
54
+ }