n8n-nodes-cloudbridge 0.0.0-stage → 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CloudBridge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,53 @@
1
- # Temporary Holding Version
1
+ # n8n-nodes-cloudbridge
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ n8n community node for [CloudBridge](https://cloud-bridge.ru) — a SaaS that
4
+ transfers and syncs files between 19 cloud storages: Yandex Disk, Google
5
+ Drive, VK Cloud (Mail.ru), Dropbox, OneDrive, Telegram channels, MEGA,
6
+ pCloud, TeraBox, S3-compatible, WebDAV, FTP/FTPS, Google Photos, Kinescope.
7
+
8
+ Move files cloud-to-cloud without downloading — straight from your n8n
9
+ workflows.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install n8n-nodes-cloudbridge
15
+ ```
16
+
17
+ Or in n8n: **Settings → Community Nodes → Install** → `n8n-nodes-cloudbridge`.
18
+
19
+ ## Credentials
20
+
21
+ Create a CloudBridge API key (`cb_live_…`) in your CloudBridge dashboard →
22
+ **API** (requires the API access add-on), then add it as a **CloudBridge
23
+ API** credential in n8n.
24
+
25
+ ## Operations
26
+
27
+ | Resource | Operations |
28
+ |---|---|
29
+ | Cloud | Get Many — list connected storage accounts (id, provider, quota) |
30
+ | File | Get Many — list files/folders inside a cloud directory |
31
+ | Transfer | Create, Get, Get Many, Cancel — cloud-to-cloud file transfers |
32
+ | Remote Upload | Create, Get, Get Many, Cancel — fetch a URL straight into a cloud |
33
+ | Share Link | Create, Get Many, Revoke — public download / inbox / archive links |
34
+ | Sync | Create, Get, Get Many, Update, Delete, Run Now — scheduled one-way/two-way syncs |
35
+ | Usage | Get — current plan and monthly quota consumption |
36
+
37
+ ## Example workflows
38
+
39
+ - **Nightly backup**: Cron → Sync → Run Now (or let the scheduler handle it)
40
+ - **Mirror a folder**: Webhook → Transfer → Create (paths = folder)
41
+ - **Inbound file pipeline**: HTTP trigger → Remote Upload → Create →
42
+ Share Link → Create → notify Telegram
43
+ - **Quota watchdog**: Cron → Usage → Get → alert when `used_gb` > 80%
44
+
45
+ ## Docs & links
46
+
47
+ - API key / dashboard: https://cloud-bridge.ru
48
+ - MCP server (same API surface for AI agents): https://cloud-bridge.ru/mcp
49
+ - Registry: `ru.cloud-bridge/cloudbridge`
50
+
51
+ ## License
52
+
53
+ MIT
@@ -0,0 +1,9 @@
1
+ import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class CloudBridgeApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CloudBridgeApi = void 0;
4
+ class CloudBridgeApi {
5
+ name = 'cloudBridgeApi';
6
+ displayName = 'CloudBridge API';
7
+ documentationUrl = 'https://cloud-bridge.ru/mcp';
8
+ properties = [
9
+ {
10
+ displayName: 'API Key',
11
+ name: 'apiKey',
12
+ type: 'string',
13
+ typeOptions: { password: true },
14
+ default: '',
15
+ required: true,
16
+ description: 'cb_live_… key — create it in the CloudBridge dashboard → API ' +
17
+ '(requires the API access add-on)',
18
+ },
19
+ ];
20
+ authenticate = {
21
+ type: 'generic',
22
+ properties: {
23
+ headers: {
24
+ 'X-API-Key': '={{$credentials.apiKey}}',
25
+ },
26
+ },
27
+ };
28
+ test = {
29
+ request: {
30
+ baseURL: 'https://cloud-bridge.ru',
31
+ url: '/api/v1/usage',
32
+ method: 'GET',
33
+ },
34
+ };
35
+ }
36
+ exports.CloudBridgeApi = CloudBridgeApi;
@@ -0,0 +1,4 @@
1
+ import type { INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class CloudBridge implements INodeType {
3
+ description: INodeTypeDescription;
4
+ }
@@ -0,0 +1,811 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CloudBridge = void 0;
4
+ const CLOUDS_NOTE = 'Cloud connection IDs come from the CloudBridge dashboard or ' +
5
+ 'CloudBridge → Cloud → Get Many.';
6
+ class CloudBridge {
7
+ description = {
8
+ displayName: 'CloudBridge',
9
+ name: 'cloudBridge',
10
+ icon: 'file:cloudbridge.svg',
11
+ group: ['transform'],
12
+ version: 1,
13
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
14
+ description: 'Transfer and sync files between 19 cloud storages — Yandex Disk, ' +
15
+ 'Google Drive, VK Cloud, Dropbox, OneDrive, Telegram, S3, WebDAV, FTP',
16
+ defaults: { name: 'CloudBridge' },
17
+ inputs: ['main'],
18
+ outputs: ['main'],
19
+ credentials: [{ name: 'cloudBridgeApi', required: true }],
20
+ requestDefaults: {
21
+ baseURL: 'https://cloud-bridge.ru',
22
+ headers: {
23
+ Accept: 'application/json',
24
+ 'Content-Type': 'application/json',
25
+ },
26
+ },
27
+ properties: [
28
+ {
29
+ displayName: 'Resource',
30
+ name: 'resource',
31
+ type: 'options',
32
+ noDataExpression: true,
33
+ options: [
34
+ { name: 'Cloud', value: 'cloud' },
35
+ { name: 'File', value: 'file' },
36
+ { name: 'Remote Upload', value: 'remoteUpload' },
37
+ { name: 'Share Link', value: 'shareLink' },
38
+ { name: 'Sync', value: 'sync' },
39
+ { name: 'Transfer', value: 'transfer' },
40
+ { name: 'Usage', value: 'usage' },
41
+ ],
42
+ default: 'transfer',
43
+ },
44
+ {
45
+ displayName: 'Operation',
46
+ name: 'operation',
47
+ type: 'options',
48
+ noDataExpression: true,
49
+ displayOptions: { show: { resource: ['cloud'] } },
50
+ options: [
51
+ {
52
+ name: 'Get Many',
53
+ value: 'getAll',
54
+ action: 'List connected clouds',
55
+ description: 'Connected storage accounts: ID, provider, quota',
56
+ routing: {
57
+ request: { method: 'GET', url: '/api/v1/connections' },
58
+ },
59
+ },
60
+ ],
61
+ default: 'getAll',
62
+ },
63
+ {
64
+ displayName: 'Operation',
65
+ name: 'operation',
66
+ type: 'options',
67
+ noDataExpression: true,
68
+ displayOptions: { show: { resource: ['file'] } },
69
+ options: [
70
+ {
71
+ name: 'Get Many',
72
+ value: 'getAll',
73
+ action: 'List files in a folder',
74
+ description: 'Direct children of a folder in a cloud',
75
+ routing: {
76
+ request: {
77
+ method: 'GET',
78
+ url: '/api/v1/files',
79
+ qs: {
80
+ connection_id: '={{$parameter.connectionId}}',
81
+ path: '={{$parameter.path || ""}}',
82
+ key: '={{$parameter.key || undefined}}',
83
+ },
84
+ },
85
+ },
86
+ },
87
+ ],
88
+ default: 'getAll',
89
+ },
90
+ {
91
+ displayName: 'Connection ID',
92
+ name: 'connectionId',
93
+ type: 'number',
94
+ required: true,
95
+ default: 0,
96
+ description: CLOUDS_NOTE,
97
+ displayOptions: { show: { resource: ['file'], operation: ['getAll'] } },
98
+ },
99
+ {
100
+ displayName: 'Path',
101
+ name: 'path',
102
+ type: 'string',
103
+ default: '',
104
+ description: 'Relative folder path — empty = cloud root',
105
+ displayOptions: { show: { resource: ['file'], operation: ['getAll'] } },
106
+ },
107
+ {
108
+ displayName: 'Folder Key',
109
+ name: 'key',
110
+ type: 'string',
111
+ default: '',
112
+ description: 'Provider folder id — needed for key-based clouds (Google ' +
113
+ 'Drive, OneDrive); take `key` from a previous File → Get Many',
114
+ displayOptions: { show: { resource: ['file'], operation: ['getAll'] } },
115
+ },
116
+ {
117
+ displayName: 'Operation',
118
+ name: 'operation',
119
+ type: 'options',
120
+ noDataExpression: true,
121
+ displayOptions: { show: { resource: ['transfer'] } },
122
+ options: [
123
+ {
124
+ name: 'Cancel',
125
+ value: 'cancel',
126
+ action: 'Cancel a transfer',
127
+ routing: {
128
+ request: {
129
+ method: 'DELETE',
130
+ url: '=/api/v1/transfers/{{$parameter.transferId}}',
131
+ },
132
+ },
133
+ },
134
+ {
135
+ name: 'Create',
136
+ value: 'create',
137
+ action: 'Create a transfer',
138
+ description: 'Start a cloud-to-cloud file transfer (background job)',
139
+ routing: {
140
+ request: {
141
+ method: 'POST',
142
+ url: '/api/v1/transfers',
143
+ body: '={{ (() => { const a = $parameter.additionalFields || {}; const f = {}; if (a.paths) f.paths = String(a.paths).split(",").map((s) => s.trim()).filter(Boolean); if (a.exclude) f.exclude = String(a.exclude).split(",").map((s) => s.trim()).filter(Boolean); if (a.targetPath) f.target_path = a.targetPath; if (a.syncMode && a.syncMode !== "copy") f.sync_mode = a.syncMode; if (a.autoRetry) f.auto_retry = true; const b = { source_connection_id: $parameter.sourceConnectionId, target_connection_id: $parameter.targetConnectionId }; if (Object.keys(f).length) b.filters = f; return b; })() }}',
144
+ },
145
+ },
146
+ },
147
+ {
148
+ name: 'Get',
149
+ value: 'get',
150
+ action: 'Get a transfer',
151
+ routing: {
152
+ request: {
153
+ method: 'GET',
154
+ url: '=/api/v1/transfers/{{$parameter.transferId}}',
155
+ },
156
+ },
157
+ },
158
+ {
159
+ name: 'Get Many',
160
+ value: 'getAll',
161
+ action: 'List transfers',
162
+ routing: {
163
+ request: {
164
+ method: 'GET',
165
+ url: '/api/v1/transfers',
166
+ qs: {
167
+ limit: '={{$parameter.limit || 20}}',
168
+ offset: '={{$parameter.offset || 0}}',
169
+ },
170
+ },
171
+ },
172
+ },
173
+ ],
174
+ default: 'getAll',
175
+ },
176
+ {
177
+ displayName: 'Transfer ID',
178
+ name: 'transferId',
179
+ type: 'number',
180
+ required: true,
181
+ default: 0,
182
+ displayOptions: {
183
+ show: { resource: ['transfer'], operation: ['get', 'cancel'] },
184
+ },
185
+ },
186
+ {
187
+ displayName: 'Source Connection ID',
188
+ name: 'sourceConnectionId',
189
+ type: 'number',
190
+ required: true,
191
+ default: 0,
192
+ description: CLOUDS_NOTE,
193
+ displayOptions: {
194
+ show: { resource: ['transfer'], operation: ['create'] },
195
+ },
196
+ },
197
+ {
198
+ displayName: 'Target Connection ID',
199
+ name: 'targetConnectionId',
200
+ type: 'number',
201
+ required: true,
202
+ default: 0,
203
+ displayOptions: {
204
+ show: { resource: ['transfer'], operation: ['create'] },
205
+ },
206
+ },
207
+ {
208
+ displayName: 'Additional Fields',
209
+ name: 'additionalFields',
210
+ type: 'collection',
211
+ placeholder: 'Add Field',
212
+ default: {},
213
+ displayOptions: {
214
+ show: { resource: ['transfer'], operation: ['create'] },
215
+ },
216
+ options: [
217
+ {
218
+ displayName: 'Auto Retry',
219
+ name: 'autoRetry',
220
+ type: 'boolean',
221
+ default: false,
222
+ description: 'Whether to restart on transient failures (paid plans)',
223
+ },
224
+ {
225
+ displayName: 'Exclude Paths',
226
+ name: 'exclude',
227
+ type: 'string',
228
+ default: '',
229
+ },
230
+ {
231
+ displayName: 'Paths',
232
+ name: 'paths',
233
+ type: 'string',
234
+ default: '',
235
+ description: 'Comma-separated relative source paths — empty = whole cloud',
236
+ },
237
+ {
238
+ displayName: 'Sync Mode',
239
+ name: 'syncMode',
240
+ type: 'options',
241
+ options: [
242
+ { name: 'Copy (New Files Only)', value: 'copy' },
243
+ { name: 'Mirror (Deletes Extras!)', value: 'mirror' },
244
+ { name: 'New Only (Skip Existing)', value: 'new' },
245
+ { name: 'Update Changed', value: 'update' },
246
+ ],
247
+ default: 'copy',
248
+ },
249
+ {
250
+ displayName: 'Target Path',
251
+ name: 'targetPath',
252
+ type: 'string',
253
+ default: '',
254
+ description: 'Destination folder — empty = cloud root',
255
+ },
256
+ ],
257
+ },
258
+ {
259
+ displayName: 'Limit',
260
+ name: 'limit',
261
+ type: 'number',
262
+ description: 'Max number of results to return',
263
+ typeOptions: { minValue: 1 },
264
+ default: 50,
265
+ displayOptions: {
266
+ show: { resource: ['transfer'], operation: ['getAll'] },
267
+ },
268
+ },
269
+ {
270
+ displayName: 'Offset',
271
+ name: 'offset',
272
+ type: 'number',
273
+ default: 0,
274
+ displayOptions: {
275
+ show: { resource: ['transfer'], operation: ['getAll'] },
276
+ },
277
+ },
278
+ {
279
+ displayName: 'Operation',
280
+ name: 'operation',
281
+ type: 'options',
282
+ noDataExpression: true,
283
+ displayOptions: { show: { resource: ['remoteUpload'] } },
284
+ options: [
285
+ {
286
+ name: 'Cancel',
287
+ value: 'cancel',
288
+ action: 'Cancel a remote upload',
289
+ routing: {
290
+ request: {
291
+ method: 'DELETE',
292
+ url: '=/api/v1/remote/{{$parameter.jobId}}',
293
+ },
294
+ },
295
+ },
296
+ {
297
+ name: 'Create',
298
+ value: 'create',
299
+ action: 'Upload a file by URL',
300
+ description: 'Server downloads a URL straight into the cloud — no local bandwidth',
301
+ routing: {
302
+ request: {
303
+ method: 'POST',
304
+ url: '/api/v1/remote',
305
+ body: '={{ (() => { const a = $parameter.additionalFields || {}; const b = { connection_id: $parameter.connectionId, url: $parameter.url }; if (a.targetPath) b.target_path = a.targetPath; if (a.fileName) b.file_name = a.fileName; if (a.extraConnectionIds) b.connection_ids = String(a.extraConnectionIds).split(",").map((s) => Number(s.trim())).filter((n) => n > 0); return b; })() }}',
306
+ },
307
+ },
308
+ },
309
+ {
310
+ name: 'Get',
311
+ value: 'get',
312
+ action: 'Get a remote upload',
313
+ routing: {
314
+ request: {
315
+ method: 'GET',
316
+ url: '=/api/v1/remote/{{$parameter.jobId}}',
317
+ },
318
+ },
319
+ },
320
+ {
321
+ name: 'Get Many',
322
+ value: 'getAll',
323
+ action: 'List remote uploads',
324
+ routing: {
325
+ request: { method: 'GET', url: '/api/v1/remote' },
326
+ },
327
+ },
328
+ ],
329
+ default: 'getAll',
330
+ },
331
+ {
332
+ displayName: 'Job ID',
333
+ name: 'jobId',
334
+ type: 'number',
335
+ required: true,
336
+ default: 0,
337
+ displayOptions: {
338
+ show: { resource: ['remoteUpload'], operation: ['get', 'cancel'] },
339
+ },
340
+ },
341
+ {
342
+ displayName: 'Connection ID',
343
+ name: 'connectionId',
344
+ type: 'number',
345
+ required: true,
346
+ default: 0,
347
+ description: CLOUDS_NOTE,
348
+ displayOptions: {
349
+ show: { resource: ['remoteUpload'], operation: ['create'] },
350
+ },
351
+ },
352
+ {
353
+ displayName: 'URL',
354
+ name: 'url',
355
+ type: 'string',
356
+ required: true,
357
+ default: '',
358
+ displayOptions: {
359
+ show: { resource: ['remoteUpload'], operation: ['create'] },
360
+ },
361
+ },
362
+ {
363
+ displayName: 'Additional Fields',
364
+ name: 'additionalFields',
365
+ type: 'collection',
366
+ placeholder: 'Add Field',
367
+ default: {},
368
+ displayOptions: {
369
+ show: { resource: ['remoteUpload'], operation: ['create'] },
370
+ },
371
+ options: [
372
+ {
373
+ displayName: 'Target Path',
374
+ name: 'targetPath',
375
+ type: 'string',
376
+ default: '',
377
+ description: 'Destination folder — empty = cloud root',
378
+ },
379
+ {
380
+ displayName: 'File Name',
381
+ name: 'fileName',
382
+ type: 'string',
383
+ default: '',
384
+ description: 'Empty = derived from the URL',
385
+ },
386
+ {
387
+ displayName: 'Extra Connection IDs',
388
+ name: 'extraConnectionIds',
389
+ type: 'string',
390
+ default: '',
391
+ description: 'Comma-separated — fan the upload out to several clouds (paid plans)',
392
+ },
393
+ ],
394
+ },
395
+ {
396
+ displayName: 'Operation',
397
+ name: 'operation',
398
+ type: 'options',
399
+ noDataExpression: true,
400
+ displayOptions: { show: { resource: ['shareLink'] } },
401
+ options: [
402
+ {
403
+ name: 'Create',
404
+ value: 'create',
405
+ action: 'Create a share link',
406
+ routing: {
407
+ request: {
408
+ method: 'POST',
409
+ url: '/api/v1/share-links',
410
+ body: '={{ (() => { const a = $parameter.additionalFields || {}; const b = { kind: $parameter.kind }; for (const [k, v] of Object.entries({ connection_id: a.connectionId, download_id: a.downloadId, key: a.key || undefined, path: a.path || undefined, name: a.name || undefined, mime_type: a.mimeType || undefined, size: a.size || undefined, password: a.password || undefined, ttl_days: a.ttlDays || undefined, title: a.title || undefined })) { if (v !== undefined && v !== "" && v !== 0) b[k] = v; } if (a.targetConnectionIds) b.target_connection_ids = String(a.targetConnectionIds).split(",").map((s) => Number(s.trim())).filter((n) => n > 0); return b; })() }}',
411
+ },
412
+ },
413
+ },
414
+ {
415
+ name: 'Get Many',
416
+ value: 'getAll',
417
+ action: 'List share links',
418
+ routing: {
419
+ request: { method: 'GET', url: '/api/v1/share-links' },
420
+ },
421
+ },
422
+ {
423
+ name: 'Revoke',
424
+ value: 'revoke',
425
+ action: 'Revoke a share link',
426
+ routing: {
427
+ request: {
428
+ method: 'DELETE',
429
+ url: '=/api/v1/share-links/{{$parameter.linkId}}',
430
+ },
431
+ },
432
+ },
433
+ ],
434
+ default: 'getAll',
435
+ },
436
+ {
437
+ displayName: 'Kind',
438
+ name: 'kind',
439
+ type: 'options',
440
+ required: true,
441
+ options: [
442
+ { name: 'File — Download Link', value: 'file' },
443
+ { name: 'Inbox — Receive Files', value: 'inbox' },
444
+ { name: 'Archive — Ready ZIP', value: 'archive' },
445
+ ],
446
+ default: 'file',
447
+ displayOptions: {
448
+ show: { resource: ['shareLink'], operation: ['create'] },
449
+ },
450
+ },
451
+ {
452
+ displayName: 'Additional Fields',
453
+ name: 'additionalFields',
454
+ type: 'collection',
455
+ placeholder: 'Add Field',
456
+ default: {},
457
+ displayOptions: {
458
+ show: { resource: ['shareLink'], operation: ['create'] },
459
+ },
460
+ options: [
461
+ {
462
+ displayName: 'Connection ID',
463
+ name: 'connectionId',
464
+ type: 'number',
465
+ default: 0,
466
+ description: 'Required for kind file/inbox. ' + CLOUDS_NOTE,
467
+ },
468
+ {
469
+ displayName: 'Download ID',
470
+ name: 'downloadId',
471
+ type: 'number',
472
+ default: 0,
473
+ description: 'Required for kind archive — ID of a finished ZIP job',
474
+ },
475
+ {
476
+ displayName: 'File Key',
477
+ name: 'key',
478
+ type: 'string',
479
+ default: '',
480
+ description: 'Provider file ID — from File → Get Many `key`',
481
+ },
482
+ {
483
+ displayName: 'File Name',
484
+ name: 'name',
485
+ type: 'string',
486
+ default: '',
487
+ },
488
+ {
489
+ displayName: 'File Path',
490
+ name: 'path',
491
+ type: 'string',
492
+ default: '',
493
+ description: 'Relative path — use Key or Path for file links',
494
+ },
495
+ {
496
+ displayName: 'Inbox Title',
497
+ name: 'title',
498
+ type: 'string',
499
+ default: '',
500
+ description: 'Public page heading for inbox links',
501
+ },
502
+ {
503
+ displayName: 'MIME Type',
504
+ name: 'mimeType',
505
+ type: 'string',
506
+ default: '',
507
+ },
508
+ {
509
+ displayName: 'Password',
510
+ name: 'password',
511
+ type: 'string',
512
+ typeOptions: { password: true },
513
+ default: '',
514
+ },
515
+ {
516
+ displayName: 'Size (Bytes)',
517
+ name: 'size',
518
+ type: 'number',
519
+ default: 0,
520
+ },
521
+ {
522
+ displayName: 'Target Connection IDs',
523
+ name: 'targetConnectionIds',
524
+ type: 'string',
525
+ default: '',
526
+ description: 'Comma-separated — inbox uploads fan out to several clouds',
527
+ },
528
+ {
529
+ displayName: 'TTL (Days)',
530
+ name: 'ttlDays',
531
+ type: 'number',
532
+ default: 0,
533
+ },
534
+ ],
535
+ },
536
+ {
537
+ displayName: 'Link ID',
538
+ name: 'linkId',
539
+ type: 'number',
540
+ required: true,
541
+ default: 0,
542
+ displayOptions: {
543
+ show: { resource: ['shareLink'], operation: ['revoke'] },
544
+ },
545
+ },
546
+ {
547
+ displayName: 'Operation',
548
+ name: 'operation',
549
+ type: 'options',
550
+ noDataExpression: true,
551
+ displayOptions: { show: { resource: ['sync'] } },
552
+ options: [
553
+ {
554
+ name: 'Create',
555
+ value: 'create',
556
+ action: 'Create a scheduled sync',
557
+ routing: {
558
+ request: {
559
+ method: 'POST',
560
+ url: '/api/v1/syncs',
561
+ body: '={{ (() => { const a = $parameter.additionalFields || {}; const b = { name: $parameter.name || ("Sync " + $parameter.sourceConnectionId + " → " + $parameter.targetConnectionId), source_connection_id: $parameter.sourceConnectionId, target_connection_id: $parameter.targetConnectionId, frequency: $parameter.frequency, direction: $parameter.direction }; if (a.scheduleTime) b.schedule_time = a.scheduleTime; if (a.scheduleDay !== undefined && a.scheduleDay !== "") b.schedule_day = Number(a.scheduleDay); if (a.filters) { try { b.filters = typeof a.filters === "string" ? JSON.parse(a.filters) : a.filters; } catch (e) { throw new Error("Filters must be valid JSON"); } } return b; })() }}',
562
+ },
563
+ },
564
+ },
565
+ {
566
+ name: 'Delete',
567
+ value: 'delete',
568
+ action: 'Delete a sync',
569
+ routing: {
570
+ request: {
571
+ method: 'DELETE',
572
+ url: '=/api/v1/syncs/{{$parameter.syncId}}',
573
+ },
574
+ },
575
+ },
576
+ {
577
+ name: 'Get',
578
+ value: 'get',
579
+ action: 'Get a sync',
580
+ routing: {
581
+ request: {
582
+ method: 'GET',
583
+ url: '=/api/v1/syncs/{{$parameter.syncId}}',
584
+ },
585
+ },
586
+ },
587
+ {
588
+ name: 'Get Many',
589
+ value: 'getAll',
590
+ action: 'List syncs',
591
+ routing: {
592
+ request: { method: 'GET', url: '/api/v1/syncs' },
593
+ },
594
+ },
595
+ {
596
+ name: 'Run Now',
597
+ value: 'runNow',
598
+ action: 'Run a sync immediately',
599
+ routing: {
600
+ request: {
601
+ method: 'POST',
602
+ url: '=/api/v1/syncs/{{$parameter.syncId}}/run',
603
+ },
604
+ },
605
+ },
606
+ {
607
+ name: 'Update',
608
+ value: 'update',
609
+ action: 'Update a sync',
610
+ routing: {
611
+ request: {
612
+ method: 'PUT',
613
+ url: '=/api/v1/syncs/{{$parameter.syncId}}',
614
+ body: '={{ (() => { const a = $parameter.updateFields || {}; const b = {}; if (a.name) b.name = a.name; if (a.frequency) b.frequency = a.frequency; if (a.isActive !== undefined && a.isActive !== "") b.is_active = a.isActive; if (a.direction) b.direction = a.direction; if (a.scheduleTime) b.schedule_time = a.scheduleTime; if (a.scheduleDay !== undefined && a.scheduleDay !== "") b.schedule_day = Number(a.scheduleDay); return b; })() }}',
615
+ },
616
+ },
617
+ },
618
+ ],
619
+ default: 'getAll',
620
+ },
621
+ {
622
+ displayName: 'Sync ID',
623
+ name: 'syncId',
624
+ type: 'number',
625
+ required: true,
626
+ default: 0,
627
+ displayOptions: {
628
+ show: {
629
+ resource: ['sync'],
630
+ operation: ['get', 'update', 'delete', 'runNow'],
631
+ },
632
+ },
633
+ },
634
+ {
635
+ displayName: 'Name',
636
+ name: 'name',
637
+ type: 'string',
638
+ default: '',
639
+ displayOptions: {
640
+ show: { resource: ['sync'], operation: ['create'] },
641
+ },
642
+ },
643
+ {
644
+ displayName: 'Source Connection ID',
645
+ name: 'sourceConnectionId',
646
+ type: 'number',
647
+ required: true,
648
+ default: 0,
649
+ description: CLOUDS_NOTE,
650
+ displayOptions: {
651
+ show: { resource: ['sync'], operation: ['create'] },
652
+ },
653
+ },
654
+ {
655
+ displayName: 'Target Connection ID',
656
+ name: 'targetConnectionId',
657
+ type: 'number',
658
+ required: true,
659
+ default: 0,
660
+ displayOptions: {
661
+ show: { resource: ['sync'], operation: ['create'] },
662
+ },
663
+ },
664
+ {
665
+ displayName: 'Frequency',
666
+ name: 'frequency',
667
+ type: 'options',
668
+ required: true,
669
+ options: [
670
+ { name: 'Daily', value: 'daily' },
671
+ { name: 'Every 5 Minutes (Pro)', value: 'every_5_min' },
672
+ { name: 'Hourly', value: 'hourly' },
673
+ { name: 'Monthly', value: 'monthly' },
674
+ { name: 'Once', value: 'once' },
675
+ { name: 'Weekly', value: 'weekly' },
676
+ ],
677
+ default: 'daily',
678
+ displayOptions: {
679
+ show: { resource: ['sync'], operation: ['create'] },
680
+ },
681
+ },
682
+ {
683
+ displayName: 'Direction',
684
+ name: 'direction',
685
+ type: 'options',
686
+ options: [
687
+ { name: 'One Way', value: 'one_way' },
688
+ { name: 'Two Way', value: 'two_way' },
689
+ ],
690
+ default: 'one_way',
691
+ displayOptions: {
692
+ show: { resource: ['sync'], operation: ['create'] },
693
+ },
694
+ },
695
+ {
696
+ displayName: 'Additional Fields',
697
+ name: 'additionalFields',
698
+ type: 'collection',
699
+ placeholder: 'Add Field',
700
+ default: {},
701
+ displayOptions: {
702
+ show: { resource: ['sync'], operation: ['create'] },
703
+ },
704
+ options: [
705
+ {
706
+ displayName: 'Schedule Time',
707
+ name: 'scheduleTime',
708
+ type: 'string',
709
+ default: '',
710
+ description: 'HH:MM',
711
+ },
712
+ {
713
+ displayName: 'Schedule Day',
714
+ name: 'scheduleDay',
715
+ type: 'number',
716
+ default: 0,
717
+ description: 'Day of week 0-6 for weekly, day of month for monthly',
718
+ },
719
+ {
720
+ displayName: 'Filters (JSON)',
721
+ name: 'filters',
722
+ type: 'json',
723
+ default: '',
724
+ description: '{"folders": ["Docs"], "exclude_folders": [...], ' +
725
+ '"file_types": ["jpg"], "min_size": 0, "max_size": 0}',
726
+ },
727
+ ],
728
+ },
729
+ {
730
+ displayName: 'Update Fields',
731
+ name: 'updateFields',
732
+ type: 'collection',
733
+ placeholder: 'Add Field',
734
+ default: {},
735
+ displayOptions: {
736
+ show: { resource: ['sync'], operation: ['update'] },
737
+ },
738
+ options: [
739
+ {
740
+ displayName: 'Active',
741
+ name: 'isActive',
742
+ type: 'boolean',
743
+ default: true,
744
+ description: 'Whether the schedule runs (false = paused)',
745
+ },
746
+ {
747
+ displayName: 'Direction',
748
+ name: 'direction',
749
+ type: 'options',
750
+ options: [
751
+ { name: 'One Way', value: 'one_way' },
752
+ { name: 'Two Way', value: 'two_way' },
753
+ ],
754
+ default: 'one_way',
755
+ },
756
+ {
757
+ displayName: 'Frequency',
758
+ name: 'frequency',
759
+ type: 'options',
760
+ options: [
761
+ { name: 'Daily', value: 'daily' },
762
+ { name: 'Every 5 Minutes (Pro)', value: 'every_5_min' },
763
+ { name: 'Hourly', value: 'hourly' },
764
+ { name: 'Monthly', value: 'monthly' },
765
+ { name: 'Once', value: 'once' },
766
+ { name: 'Weekly', value: 'weekly' },
767
+ ],
768
+ default: 'daily',
769
+ },
770
+ {
771
+ displayName: 'Name',
772
+ name: 'name',
773
+ type: 'string',
774
+ default: '',
775
+ },
776
+ {
777
+ displayName: 'Schedule Day',
778
+ name: 'scheduleDay',
779
+ type: 'number',
780
+ default: 0,
781
+ },
782
+ {
783
+ displayName: 'Schedule Time',
784
+ name: 'scheduleTime',
785
+ type: 'string',
786
+ default: '',
787
+ },
788
+ ],
789
+ },
790
+ {
791
+ displayName: 'Operation',
792
+ name: 'operation',
793
+ type: 'options',
794
+ noDataExpression: true,
795
+ displayOptions: { show: { resource: ['usage'] } },
796
+ options: [
797
+ {
798
+ name: 'Get',
799
+ value: 'get',
800
+ action: 'Get plan and quota usage',
801
+ routing: {
802
+ request: { method: 'GET', url: '/api/v1/usage' },
803
+ },
804
+ },
805
+ ],
806
+ default: 'get',
807
+ },
808
+ ],
809
+ };
810
+ }
811
+ exports.CloudBridge = CloudBridge;
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
2
+ <path d="M20 48h24a11 11 0 0 0 2.1-21.8 15 15 0 0 0-29.3-3.4A9.5 9.5 0 0 0 20 48z" fill="#0891b2"/>
3
+ <path d="M24 36h15m0 0-4.5-4.5M39 36l-4.5 4.5" stroke="#fff" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "n8n-nodes-cloudbridge",
3
+ "version": "0.1.0",
4
+ "description": "n8n community node for CloudBridge — transfer and sync files between 19 cloud storages",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "cloudbridge",
8
+ "cloud storage",
9
+ "file transfer",
10
+ "yandex disk",
11
+ "google drive",
12
+ "vk cloud",
13
+ "telegram"
14
+ ],
15
+ "license": "MIT",
16
+ "homepage": "https://cloud-bridge.ru",
17
+ "author": {
18
+ "name": "CloudBridge",
19
+ "email": "support@cloud-bridge.ru"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/nw-cd/n8n-nodes-cloudbridge"
24
+ },
25
+ "engines": {
26
+ "node": ">=20.15"
27
+ },
28
+ "n8n": {
29
+ "n8nNodesApiVersion": 1,
30
+ "credentials": [
31
+ "dist/credentials/CloudBridgeApi.credentials.js"
32
+ ],
33
+ "nodes": [
34
+ "dist/nodes/CloudBridge/CloudBridge.node.js"
35
+ ]
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "scripts": {
41
+ "build": "tsc && gulp build:icons",
42
+ "dev": "tsc --watch",
43
+ "lint": "eslint nodes credentials package.json",
44
+ "format": "prettier nodes credentials --write",
45
+ "prepublishOnly": "npm run build && npm run lint -s"
46
+ },
47
+ "devDependencies": {
48
+ "@typescript-eslint/parser": "^8.0.0",
49
+ "eslint": "^8.57.0",
50
+ "eslint-plugin-n8n-nodes-base": "^1.16.3",
51
+ "gulp": "^5.0.0",
52
+ "n8n-workflow": "^1.48.0",
53
+ "prettier": "^3.3.0",
54
+ "typescript": "^5.5.0"
55
+ },
56
+ "peerDependencies": {
57
+ "n8n-workflow": "*"
58
+ }
59
+ }
package/package.json CHANGED
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "name": "n8n-nodes-cloudbridge",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "n8n community node for CloudBridge — transfer and sync files between 19 cloud storages",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "cloudbridge",
8
+ "cloud storage",
9
+ "file transfer",
10
+ "yandex disk",
11
+ "google drive",
12
+ "vk cloud",
13
+ "telegram"
14
+ ],
15
+ "license": "MIT",
16
+ "homepage": "https://cloud-bridge.ru",
17
+ "author": {
18
+ "name": "CloudBridge",
19
+ "email": "support@cloud-bridge.ru"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/nw-cd/n8n-nodes-cloudbridge"
24
+ },
25
+ "engines": {
26
+ "node": ">=20.15"
27
+ },
28
+ "n8n": {
29
+ "n8nNodesApiVersion": 1,
30
+ "credentials": [
31
+ "dist/credentials/CloudBridgeApi.credentials.js"
32
+ ],
33
+ "nodes": [
34
+ "dist/nodes/CloudBridge/CloudBridge.node.js"
35
+ ]
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "scripts": {
41
+ "build": "tsc && gulp build:icons",
42
+ "dev": "tsc --watch",
43
+ "lint": "eslint nodes credentials package.json",
44
+ "format": "prettier nodes credentials --write",
45
+ "prepublishOnly": "npm run build && npm run lint -s"
46
+ },
47
+ "devDependencies": {
48
+ "@typescript-eslint/parser": "^8.0.0",
49
+ "eslint": "^8.57.0",
50
+ "eslint-plugin-n8n-nodes-base": "^1.16.3",
51
+ "gulp": "^5.0.0",
52
+ "n8n-workflow": "^1.48.0",
53
+ "prettier": "^3.3.0",
54
+ "typescript": "^5.5.0"
55
+ },
56
+ "peerDependencies": {
57
+ "n8n-workflow": "*"
58
+ }
59
+ }