@n8n-as-code/sync 0.5.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 +22 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/services/directory-utils.d.ts +35 -0
- package/dist/services/directory-utils.d.ts.map +1 -0
- package/dist/services/directory-utils.js +75 -0
- package/dist/services/directory-utils.js.map +1 -0
- package/dist/services/hash-utils.d.ts +22 -0
- package/dist/services/hash-utils.d.ts.map +1 -0
- package/dist/services/hash-utils.js +31 -0
- package/dist/services/hash-utils.js.map +1 -0
- package/dist/services/n8n-api-client.d.ts +23 -0
- package/dist/services/n8n-api-client.d.ts.map +1 -0
- package/dist/services/n8n-api-client.js +193 -0
- package/dist/services/n8n-api-client.js.map +1 -0
- package/dist/services/resolution-manager.d.ts +73 -0
- package/dist/services/resolution-manager.d.ts.map +1 -0
- package/dist/services/resolution-manager.js +149 -0
- package/dist/services/resolution-manager.js.map +1 -0
- package/dist/services/state-manager.d.ts +43 -0
- package/dist/services/state-manager.d.ts.map +1 -0
- package/dist/services/state-manager.js +68 -0
- package/dist/services/state-manager.js.map +1 -0
- package/dist/services/sync-engine.d.ts +56 -0
- package/dist/services/sync-engine.d.ts.map +1 -0
- package/dist/services/sync-engine.js +312 -0
- package/dist/services/sync-engine.js.map +1 -0
- package/dist/services/sync-manager.d.ts +37 -0
- package/dist/services/sync-manager.d.ts.map +1 -0
- package/dist/services/sync-manager.js +280 -0
- package/dist/services/sync-manager.js.map +1 -0
- package/dist/services/trash-service.d.ts +17 -0
- package/dist/services/trash-service.d.ts.map +1 -0
- package/dist/services/trash-service.js +41 -0
- package/dist/services/trash-service.js.map +1 -0
- package/dist/services/watcher.d.ts +135 -0
- package/dist/services/watcher.d.ts.map +1 -0
- package/dist/services/watcher.js +655 -0
- package/dist/services/watcher.js.map +1 -0
- package/dist/services/workflow-sanitizer.d.ts +23 -0
- package/dist/services/workflow-sanitizer.d.ts.map +1 -0
- package/dist/services/workflow-sanitizer.js +100 -0
- package/dist/services/workflow-sanitizer.js.map +1 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @n8n-as-code/sync
|
|
2
|
+
|
|
3
|
+
The logical sync of the **n8n-as-code** ecosystem.
|
|
4
|
+
|
|
5
|
+
## 🛠Purpose
|
|
6
|
+
|
|
7
|
+
This package contains the shared logic used by the CLI, the Skills CLI, and the VS Code extension:
|
|
8
|
+
- **API Client**: Communication with the n8n REST API.
|
|
9
|
+
- **Synchronization**: Logic for pulling, pushing, and detecting changes.
|
|
10
|
+
- **Sanitization**: Cleaning up n8n JSONs for better Git versioning (removing IDs, timestamps, etc.).
|
|
11
|
+
- **State Management**: Tracking local vs. remote state to detect conflicts.
|
|
12
|
+
|
|
13
|
+
## 🚀 Usage
|
|
14
|
+
|
|
15
|
+
This is internal tooling primarily intended to be consumed by other `@n8n-as-code` packages.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @n8n-as-code/sync
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 📄 License
|
|
22
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './services/n8n-api-client.js';
|
|
3
|
+
export * from './services/workflow-sanitizer.js';
|
|
4
|
+
export * from './services/sync-manager.js';
|
|
5
|
+
export * from './services/sync-engine.js';
|
|
6
|
+
export * from './services/watcher.js';
|
|
7
|
+
export * from './services/resolution-manager.js';
|
|
8
|
+
export * from './services/state-manager.js';
|
|
9
|
+
export * from './services/directory-utils.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './services/n8n-api-client.js';
|
|
3
|
+
export * from './services/workflow-sanitizer.js';
|
|
4
|
+
export * from './services/sync-manager.js';
|
|
5
|
+
export * from './services/sync-engine.js';
|
|
6
|
+
export * from './services/watcher.js';
|
|
7
|
+
export * from './services/resolution-manager.js';
|
|
8
|
+
export * from './services/state-manager.js';
|
|
9
|
+
export * from './services/directory-utils.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a user-friendly host slug for directory naming
|
|
3
|
+
* @param host The host URL
|
|
4
|
+
* @returns Cleaned host slug (e.g., "local_5678", "etiennel_cloud")
|
|
5
|
+
*/
|
|
6
|
+
export declare function createHostSlug(host: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Creates a user-friendly slug from user information
|
|
9
|
+
* @param user User object with email, firstName, lastName
|
|
10
|
+
* @returns User slug (e.g., "etienne_l", "john_d")
|
|
11
|
+
*/
|
|
12
|
+
export declare function createUserSlug(user: {
|
|
13
|
+
email?: string;
|
|
14
|
+
firstName?: string;
|
|
15
|
+
lastName?: string;
|
|
16
|
+
}): string;
|
|
17
|
+
/**
|
|
18
|
+
* Creates an instance identifier for directory naming
|
|
19
|
+
* @param host The host URL
|
|
20
|
+
* @param user User information (optional)
|
|
21
|
+
* @returns Instance identifier (e.g., "local_5678_etienne_l")
|
|
22
|
+
*/
|
|
23
|
+
export declare function createInstanceIdentifier(host: string, user?: {
|
|
24
|
+
email?: string;
|
|
25
|
+
firstName?: string;
|
|
26
|
+
lastName?: string;
|
|
27
|
+
}): string;
|
|
28
|
+
/**
|
|
29
|
+
* Creates a fallback instance identifier using API key hash when user info is unavailable
|
|
30
|
+
* @param host The host URL
|
|
31
|
+
* @param apiKey The API key for uniqueness
|
|
32
|
+
* @returns Fallback instance identifier (e.g., "local_5678_abc123")
|
|
33
|
+
*/
|
|
34
|
+
export declare function createFallbackInstanceIdentifier(host: string, apiKey: string): string;
|
|
35
|
+
//# sourceMappingURL=directory-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-utils.d.ts","sourceRoot":"","sources":["../../src/services/directory-utils.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBnD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAoBtG;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAK/H;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKrF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a user-friendly host slug for directory naming
|
|
4
|
+
* @param host The host URL
|
|
5
|
+
* @returns Cleaned host slug (e.g., "local_5678", "etiennel_cloud")
|
|
6
|
+
*/
|
|
7
|
+
export function createHostSlug(host) {
|
|
8
|
+
// Remove protocol and trailing slashes
|
|
9
|
+
let cleanHost = host.replace(/^https?:\/\//, '').replace(/\/$/, '');
|
|
10
|
+
// Handle localhost with port
|
|
11
|
+
if (cleanHost.startsWith('localhost:')) {
|
|
12
|
+
const port = cleanHost.split(':')[1];
|
|
13
|
+
return `local_${port}`;
|
|
14
|
+
}
|
|
15
|
+
// For domains, extract main parts
|
|
16
|
+
// etiennel.app.n8n.cloud -> etiennel_cloud
|
|
17
|
+
// prod.example.com -> prod_example
|
|
18
|
+
cleanHost = cleanHost
|
|
19
|
+
.replace(/\.app\.n8n\.cloud$/, '_cloud')
|
|
20
|
+
.replace(/\.example\.com$/, '_example')
|
|
21
|
+
.replace(/\.com$/, '')
|
|
22
|
+
.replace(/\.io$/, '')
|
|
23
|
+
.replace(/\.net$/, '')
|
|
24
|
+
.replace(/\.org$/, '');
|
|
25
|
+
// Replace remaining dots and hyphens with underscores
|
|
26
|
+
return cleanHost
|
|
27
|
+
.replace(/[.-]/g, '_')
|
|
28
|
+
.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a user-friendly slug from user information
|
|
32
|
+
* @param user User object with email, firstName, lastName
|
|
33
|
+
* @returns User slug (e.g., "etienne_l", "john_d")
|
|
34
|
+
*/
|
|
35
|
+
export function createUserSlug(user) {
|
|
36
|
+
// Prefer first name + last name initial if available
|
|
37
|
+
if (user.firstName && user.lastName) {
|
|
38
|
+
return `${user.firstName.toLowerCase()}_${user.lastName.charAt(0).toLowerCase()}`;
|
|
39
|
+
}
|
|
40
|
+
// Fallback to first name only
|
|
41
|
+
if (user.firstName) {
|
|
42
|
+
return user.firstName.toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
// Fallback to email username part
|
|
45
|
+
if (user.email) {
|
|
46
|
+
return user.email.split('@')[0]
|
|
47
|
+
.replace(/[^a-zA-Z0-9]/g, '_')
|
|
48
|
+
.toLowerCase();
|
|
49
|
+
}
|
|
50
|
+
// Final fallback
|
|
51
|
+
return 'user';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates an instance identifier for directory naming
|
|
55
|
+
* @param host The host URL
|
|
56
|
+
* @param user User information (optional)
|
|
57
|
+
* @returns Instance identifier (e.g., "local_5678_etienne_l")
|
|
58
|
+
*/
|
|
59
|
+
export function createInstanceIdentifier(host, user) {
|
|
60
|
+
const hostSlug = createHostSlug(host);
|
|
61
|
+
const userSlug = user ? createUserSlug(user) : 'user';
|
|
62
|
+
return `${hostSlug}_${userSlug}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates a fallback instance identifier using API key hash when user info is unavailable
|
|
66
|
+
* @param host The host URL
|
|
67
|
+
* @param apiKey The API key for uniqueness
|
|
68
|
+
* @returns Fallback instance identifier (e.g., "local_5678_abc123")
|
|
69
|
+
*/
|
|
70
|
+
export function createFallbackInstanceIdentifier(host, apiKey) {
|
|
71
|
+
const hostSlug = createHostSlug(host);
|
|
72
|
+
const apiKeyHash = crypto.createHash('sha256').update(apiKey).digest('hex').substring(0, 6);
|
|
73
|
+
return `${hostSlug}_${apiKeyHash}`;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=directory-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-utils.js","sourceRoot":"","sources":["../../src/services/directory-utils.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,uCAAuC;IACvC,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEpE,6BAA6B;IAC7B,IAAI,SAAS,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,OAAO,SAAS,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,kCAAkC;IAClC,2CAA2C;IAC3C,mCAAmC;IACnC,SAAS,GAAG,SAAS;SAChB,OAAO,CAAC,oBAAoB,EAAE,QAAQ,CAAC;SACvC,OAAO,CAAC,iBAAiB,EAAE,UAAU,CAAC;SACtC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAE3B,sDAAsD;IACtD,OAAO,SAAS;SACX,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,WAAW,EAAE,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAA+D;IAC1F,qDAAqD;IACrD,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IACtF,CAAC;IAED,8BAA8B;IAC9B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IACxC,CAAC;IAED,kCAAkC;IAClC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;aAC1B,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;aAC7B,WAAW,EAAE,CAAC;IACvB,CAAC;IAED,iBAAiB;IACjB,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY,EAAE,IAAgE;IACnH,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEtD,OAAO,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gCAAgC,CAAC,IAAY,EAAE,MAAc;IACzE,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5F,OAAO,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash Utilities for canonical hashing
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent SHA-256 hashing of JSON content with stable stringification.
|
|
5
|
+
* Used by all components to ensure hash consistency.
|
|
6
|
+
*/
|
|
7
|
+
export declare class HashUtils {
|
|
8
|
+
/**
|
|
9
|
+
* Computes a stable, canonical hash for any object (usually a workflow).
|
|
10
|
+
* Non-functional metadata should be removed before calling this.
|
|
11
|
+
*/
|
|
12
|
+
static computeHash(content: any): string;
|
|
13
|
+
/**
|
|
14
|
+
* Compares two objects by computing their canonical hashes
|
|
15
|
+
*/
|
|
16
|
+
static areEqual(obj1: any, obj2: any): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Short hash for display purposes
|
|
19
|
+
*/
|
|
20
|
+
static shortHash(hash: string, length?: number): string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=hash-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-utils.d.ts","sourceRoot":"","sources":["../../src/services/hash-utils.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,qBAAa,SAAS;IAClB;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM;IAKxC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO;IAI9C;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,GAAG,MAAM;CAG7D"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import stringify from 'json-stable-stringify';
|
|
3
|
+
/**
|
|
4
|
+
* Hash Utilities for canonical hashing
|
|
5
|
+
*
|
|
6
|
+
* Provides consistent SHA-256 hashing of JSON content with stable stringification.
|
|
7
|
+
* Used by all components to ensure hash consistency.
|
|
8
|
+
*/
|
|
9
|
+
export class HashUtils {
|
|
10
|
+
/**
|
|
11
|
+
* Computes a stable, canonical hash for any object (usually a workflow).
|
|
12
|
+
* Non-functional metadata should be removed before calling this.
|
|
13
|
+
*/
|
|
14
|
+
static computeHash(content) {
|
|
15
|
+
const canonicalString = stringify(content) || '';
|
|
16
|
+
return crypto.createHash('sha256').update(canonicalString).digest('hex');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Compares two objects by computing their canonical hashes
|
|
20
|
+
*/
|
|
21
|
+
static areEqual(obj1, obj2) {
|
|
22
|
+
return this.computeHash(obj1) === this.computeHash(obj2);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Short hash for display purposes
|
|
26
|
+
*/
|
|
27
|
+
static shortHash(hash, length = 8) {
|
|
28
|
+
return hash.substring(0, length);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=hash-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-utils.js","sourceRoot":"","sources":["../../src/services/hash-utils.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,SAAS,MAAM,uBAAuB,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,OAAO,SAAS;IAClB;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,OAAY;QAC3B,MAAM,eAAe,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACjD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAS,EAAE,IAAS;QAChC,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,IAAY,EAAE,SAAiB,CAAC;QAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;CACJ"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IN8nCredentials, IWorkflow } from '../types.js';
|
|
2
|
+
export declare class N8nApiClient {
|
|
3
|
+
private client;
|
|
4
|
+
constructor(credentials: IN8nCredentials);
|
|
5
|
+
testConnection(): Promise<boolean>;
|
|
6
|
+
getCurrentUser(): Promise<{
|
|
7
|
+
id: string;
|
|
8
|
+
email: string;
|
|
9
|
+
firstName?: string;
|
|
10
|
+
lastName?: string;
|
|
11
|
+
} | null>;
|
|
12
|
+
getAllWorkflows(): Promise<IWorkflow[]>;
|
|
13
|
+
getWorkflow(id: string): Promise<IWorkflow | null>;
|
|
14
|
+
createWorkflow(payload: Partial<IWorkflow>): Promise<IWorkflow>;
|
|
15
|
+
updateWorkflow(id: string, payload: Partial<IWorkflow>): Promise<IWorkflow>;
|
|
16
|
+
deleteWorkflow(id: string): Promise<boolean>;
|
|
17
|
+
activateWorkflow(id: string, active: boolean): Promise<boolean>;
|
|
18
|
+
getHealth(): Promise<{
|
|
19
|
+
version: string;
|
|
20
|
+
}>;
|
|
21
|
+
getNodeTypes(): Promise<any[]>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=n8n-api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"n8n-api-client.d.ts","sourceRoot":"","sources":["../../src/services/n8n-api-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEzD,qBAAa,YAAY;IACrB,OAAO,CAAC,MAAM,CAAgB;gBAElB,WAAW,EAAE,eAAe;IAoBlC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAUlC,cAAc,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;KAAE,GAAG,IAAI,CAAC;IA2CvG,eAAe,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAWvC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAclD,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IAK/D,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IAoB3E,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU5C,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAS/D,SAAS,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAsCzC,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;CAUvC"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import * as https from 'https';
|
|
3
|
+
export class N8nApiClient {
|
|
4
|
+
client;
|
|
5
|
+
constructor(credentials) {
|
|
6
|
+
let host = credentials.host;
|
|
7
|
+
if (host.endsWith('/')) {
|
|
8
|
+
host = host.slice(0, -1);
|
|
9
|
+
}
|
|
10
|
+
this.client = axios.create({
|
|
11
|
+
baseURL: host,
|
|
12
|
+
headers: {
|
|
13
|
+
'X-N8N-API-KEY': credentials.apiKey,
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
'User-Agent': 'n8n-as-code'
|
|
16
|
+
},
|
|
17
|
+
// Allow self-signed certificates by default to avoid issues in local environments
|
|
18
|
+
httpsAgent: new https.Agent({
|
|
19
|
+
rejectUnauthorized: false
|
|
20
|
+
})
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async testConnection() {
|
|
24
|
+
try {
|
|
25
|
+
await this.client.get('/api/v1/users'); // Simple endpoint to test auth
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('Connection test failed:', error);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async getCurrentUser() {
|
|
34
|
+
// Try /me first (modern n8n)
|
|
35
|
+
try {
|
|
36
|
+
const res = await this.client.get('/api/v1/users/me');
|
|
37
|
+
console.debug('[N8nApiClient] getCurrentUser: Successfully retrieved user from /me endpoint');
|
|
38
|
+
if (res.data && res.data.id) {
|
|
39
|
+
return {
|
|
40
|
+
id: res.data.id,
|
|
41
|
+
email: res.data.email,
|
|
42
|
+
firstName: res.data.firstName,
|
|
43
|
+
lastName: res.data.lastName
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.debug('[N8nApiClient] getCurrentUser: /me endpoint failed:', error.message);
|
|
49
|
+
// If it's a connection error, throw immediately
|
|
50
|
+
if (!error.response)
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
// Fallback: get all users and take the first one (assuming the API key belongs to an admin or the only user)
|
|
54
|
+
console.debug('[N8nApiClient] getCurrentUser: Trying /api/v1/users endpoint');
|
|
55
|
+
try {
|
|
56
|
+
const res = await this.client.get('/api/v1/users');
|
|
57
|
+
if (res.data && res.data.data && res.data.data.length > 0) {
|
|
58
|
+
console.debug('[N8nApiClient] getCurrentUser: Found', res.data.data.length, 'users');
|
|
59
|
+
const user = res.data.data[0];
|
|
60
|
+
return {
|
|
61
|
+
id: user.id,
|
|
62
|
+
email: user.email,
|
|
63
|
+
firstName: user.firstName,
|
|
64
|
+
lastName: user.lastName
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.debug('[N8nApiClient] getCurrentUser: /api/v1/users endpoint failed:', error.message);
|
|
70
|
+
// If it's a connection error, throw immediately
|
|
71
|
+
if (!error.response)
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
console.debug('[N8nApiClient] getCurrentUser: All attempts failed, returning null');
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
async getAllWorkflows() {
|
|
78
|
+
try {
|
|
79
|
+
const res = await this.client.get('/api/v1/workflows');
|
|
80
|
+
return res.data.data;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error('Failed to get workflows:', error.message);
|
|
84
|
+
// Re-throw so the caller (Watcher) can distinguish between "no workflows" and "connection error"
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async getWorkflow(id) {
|
|
89
|
+
try {
|
|
90
|
+
const res = await this.client.get(`/api/v1/workflows/${id}`);
|
|
91
|
+
return res.data;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
// 404 is expected if workflow deleted remotely
|
|
95
|
+
if (error.response && error.response.status === 404) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
// Re-throw other errors (connection, 500, etc.)
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async createWorkflow(payload) {
|
|
103
|
+
const res = await this.client.post('/api/v1/workflows', payload);
|
|
104
|
+
return res.data;
|
|
105
|
+
}
|
|
106
|
+
async updateWorkflow(id, payload) {
|
|
107
|
+
// Use console.warn to be more visible in some environments
|
|
108
|
+
console.warn(`[N8nApiClient] Starting PUT /api/v1/workflows/${id}`);
|
|
109
|
+
const startTime = Date.now();
|
|
110
|
+
try {
|
|
111
|
+
const res = await this.client.put(`/api/v1/workflows/${id}`, payload);
|
|
112
|
+
const duration = Date.now() - startTime;
|
|
113
|
+
console.warn(`[N8nApiClient] PUT finished in ${duration}ms. Status: ${res.status}`);
|
|
114
|
+
return res.data;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const duration = Date.now() - startTime;
|
|
118
|
+
console.error(`[N8nApiClient] PUT failed after ${duration}ms: ${error.message}`);
|
|
119
|
+
if (error.response) {
|
|
120
|
+
console.error(`[N8nApiClient] Error data:`, error.response.data);
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async deleteWorkflow(id) {
|
|
126
|
+
try {
|
|
127
|
+
await this.client.delete(`/api/v1/workflows/${id}`);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error(`Failed to delete workflow ${id}:`, error);
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async activateWorkflow(id, active) {
|
|
136
|
+
try {
|
|
137
|
+
await this.client.post(`/api/v1/workflows/${id}/activate`, { active });
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async getHealth() {
|
|
145
|
+
try {
|
|
146
|
+
// 1. Try public endpoint if available (some versions)
|
|
147
|
+
try {
|
|
148
|
+
const res = await this.client.get('/healthz');
|
|
149
|
+
if (res.data && res.data.version)
|
|
150
|
+
return { version: res.data.version };
|
|
151
|
+
}
|
|
152
|
+
catch { }
|
|
153
|
+
// 2. Scraping Root Page as fallback (Using raw axios to avoid API headers)
|
|
154
|
+
const baseURL = this.client.defaults.baseURL;
|
|
155
|
+
const res = await axios.get(`${baseURL}/`);
|
|
156
|
+
const html = res.data;
|
|
157
|
+
// Look for "release":"n8n@X.Y.Z" probably inside n8n:config:sentry meta (Base64 encoded)
|
|
158
|
+
const sentryMatch = html.match(/name="n8n:config:sentry"\s+content="([^"]+)"/);
|
|
159
|
+
if (sentryMatch && sentryMatch[1]) {
|
|
160
|
+
const decoded = Buffer.from(sentryMatch[1], 'base64').toString('utf-8');
|
|
161
|
+
const releaseMatch = decoded.match(/"release":"n8n@([^"]+)"/);
|
|
162
|
+
if (releaseMatch && releaseMatch[1]) {
|
|
163
|
+
return { version: releaseMatch[1] };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Fallback: Check plain text just in case
|
|
167
|
+
const releaseRegex = /"release":"n8n@([^"]+)"/;
|
|
168
|
+
const plainMatch = html.match(releaseRegex);
|
|
169
|
+
if (plainMatch && plainMatch[1])
|
|
170
|
+
return { version: plainMatch[1] };
|
|
171
|
+
// Look for other common patterns
|
|
172
|
+
const metaMatch = html.match(/n8n version: ([0-9.]+)/i);
|
|
173
|
+
if (metaMatch && metaMatch[1])
|
|
174
|
+
return { version: metaMatch[1] };
|
|
175
|
+
return { version: '1.0+' };
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return { version: 'Unknown' };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async getNodeTypes() {
|
|
182
|
+
try {
|
|
183
|
+
// Unofficial/Internal endpoint often used by frontend
|
|
184
|
+
const res = await this.client.get('/rest/node-types');
|
|
185
|
+
return res.data;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Fallback: If REST API not accessible, return empty
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=n8n-api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"n8n-api-client.js","sourceRoot":"","sources":["../../src/services/n8n-api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SyncEngine } from './sync-engine.js';
|
|
2
|
+
import { Watcher } from './watcher.js';
|
|
3
|
+
import { WorkflowSyncStatus } from '../types.js';
|
|
4
|
+
import { N8nApiClient } from './n8n-api-client.js';
|
|
5
|
+
/**
|
|
6
|
+
* Resolution & Validation Manager
|
|
7
|
+
*
|
|
8
|
+
* Responsibilities:
|
|
9
|
+
* 1. Conflict Resolution (6.1 from spec)
|
|
10
|
+
* 2. Deletion Validation (6.2 from spec)
|
|
11
|
+
*
|
|
12
|
+
* Bridges user intent with Sync Engine operations
|
|
13
|
+
*/
|
|
14
|
+
export declare class ResolutionManager {
|
|
15
|
+
private syncEngine;
|
|
16
|
+
private watcher;
|
|
17
|
+
private client;
|
|
18
|
+
private directory;
|
|
19
|
+
constructor(syncEngine: SyncEngine, watcher: Watcher, client: N8nApiClient);
|
|
20
|
+
/**
|
|
21
|
+
* 6.1 Conflict Resolution - KEEP LOCAL
|
|
22
|
+
*
|
|
23
|
+
* Action: Force PUSH (Overwrite Remote with Local)
|
|
24
|
+
* Commit: Update lastSyncedHash = LocalHash. Status becomes IN_SYNC.
|
|
25
|
+
*/
|
|
26
|
+
keepLocal(workflowId: string, filename: string): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* 6.1 Conflict Resolution - KEEP REMOTE
|
|
29
|
+
*
|
|
30
|
+
* Action: Force PULL (Overwrite Local with Remote)
|
|
31
|
+
* Commit: Update lastSyncedHash = RemoteHash. Status becomes IN_SYNC.
|
|
32
|
+
*/
|
|
33
|
+
keepRemote(workflowId: string, filename: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* 6.1 Conflict Resolution - SHOW DIFF
|
|
36
|
+
*
|
|
37
|
+
* Opens diff editor (implementation depends on UI layer)
|
|
38
|
+
* Returns diff data for UI to display
|
|
39
|
+
*/
|
|
40
|
+
showDiff(workflowId: string, filename: string): Promise<{
|
|
41
|
+
localContent: any;
|
|
42
|
+
remoteContent: any;
|
|
43
|
+
localHash: string;
|
|
44
|
+
remoteHash: string;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* 6.2 Deletion Validation - CONFIRM DELETION
|
|
48
|
+
*
|
|
49
|
+
* Case Deleted Locally: Send DELETE to API -> Remove from state
|
|
50
|
+
* Case Deleted Remotely: Move local file to _archive/ -> Remove from state
|
|
51
|
+
*/
|
|
52
|
+
confirmDeletion(workflowId: string, filename: string, deletionType: 'local' | 'remote'): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* 6.2 Deletion Validation - RESTORE WORKFLOW
|
|
55
|
+
*
|
|
56
|
+
* Case Deleted Locally: Move file from _archive/ to workflows/
|
|
57
|
+
* Case Deleted Remotely: Force PUSH (Re-create on Remote)
|
|
58
|
+
*/
|
|
59
|
+
restoreWorkflow(workflowId: string, filename: string, deletionType: 'local' | 'remote'): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Get current status for a workflow
|
|
62
|
+
*/
|
|
63
|
+
getWorkflowStatus(workflowId: string, filename: string): Promise<{
|
|
64
|
+
status: WorkflowSyncStatus;
|
|
65
|
+
localExists: boolean;
|
|
66
|
+
remoteExists: boolean;
|
|
67
|
+
lastSyncedHash?: string;
|
|
68
|
+
localHash?: string;
|
|
69
|
+
remoteHash?: string;
|
|
70
|
+
}>;
|
|
71
|
+
private readJsonFile;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=resolution-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolution-manager.d.ts","sourceRoot":"","sources":["../../src/services/resolution-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAEd,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY;IAQ1E;;;;;OAKG;IACU,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAM7E;;;;;OAKG;IACU,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5E;;;;;OAKG;IACU,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QACjE,YAAY,EAAE,GAAG,CAAC;QAClB,aAAa,EAAE,GAAG,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IA4BF;;;;;OAKG;IACU,eAAe,CACxB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,OAAO,GAAG,QAAQ,GACjC,OAAO,CAAC,IAAI,CAAC;IAchB;;;;;OAKG;IACU,eAAe,CACxB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,OAAO,GAAG,QAAQ,GACjC,OAAO,CAAC,MAAM,CAAC;IAgBlB;;OAEG;IACU,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAC1E,MAAM,EAAE,kBAAkB,CAAC;QAC3B,WAAW,EAAE,OAAO,CAAC;QACrB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IAwBF,OAAO,CAAC,YAAY;CAOvB"}
|