@n8n-as-code/sync 0.6.0 → 0.8.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.
Files changed (47) hide show
  1. package/dist/helpers/index.d.ts +8 -0
  2. package/dist/helpers/index.d.ts.map +1 -0
  3. package/dist/helpers/index.js +8 -0
  4. package/dist/helpers/index.js.map +1 -0
  5. package/dist/helpers/project-helpers.d.ts +93 -0
  6. package/dist/helpers/project-helpers.d.ts.map +1 -0
  7. package/dist/helpers/project-helpers.js +168 -0
  8. package/dist/helpers/project-helpers.js.map +1 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/services/directory-utils.d.ts +6 -0
  14. package/dist/services/directory-utils.d.ts.map +1 -1
  15. package/dist/services/directory-utils.js +12 -0
  16. package/dist/services/directory-utils.js.map +1 -1
  17. package/dist/services/n8n-api-client.d.ts +28 -2
  18. package/dist/services/n8n-api-client.d.ts.map +1 -1
  19. package/dist/services/n8n-api-client.js +197 -3
  20. package/dist/services/n8n-api-client.js.map +1 -1
  21. package/dist/services/resolution-manager.d.ts +2 -2
  22. package/dist/services/resolution-manager.js +7 -7
  23. package/dist/services/resolution-manager.js.map +1 -1
  24. package/dist/services/sync-engine.d.ts +1 -1
  25. package/dist/services/sync-engine.d.ts.map +1 -1
  26. package/dist/services/sync-engine.js +10 -10
  27. package/dist/services/sync-engine.js.map +1 -1
  28. package/dist/services/sync-manager.d.ts +6 -1
  29. package/dist/services/sync-manager.d.ts.map +1 -1
  30. package/dist/services/sync-manager.js +18 -12
  31. package/dist/services/sync-manager.js.map +1 -1
  32. package/dist/services/trash-service.d.ts +1 -1
  33. package/dist/services/trash-service.d.ts.map +1 -1
  34. package/dist/services/trash-service.js +8 -8
  35. package/dist/services/trash-service.js.map +1 -1
  36. package/dist/services/watcher.d.ts +9 -1
  37. package/dist/services/watcher.d.ts.map +1 -1
  38. package/dist/services/watcher.js +93 -22
  39. package/dist/services/watcher.js.map +1 -1
  40. package/dist/services/workflow-sanitizer.d.ts +11 -0
  41. package/dist/services/workflow-sanitizer.d.ts.map +1 -1
  42. package/dist/services/workflow-sanitizer.js +31 -1
  43. package/dist/services/workflow-sanitizer.js.map +1 -1
  44. package/dist/types.d.ts +17 -0
  45. package/dist/types.d.ts.map +1 -1
  46. package/dist/types.js.map +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Helper utilities for workflow and project management
3
+ *
4
+ * This module exports reusable helper functions that can be used
5
+ * across different interfaces (CLI, VS Code extension, etc.)
6
+ */
7
+ export { getDisplayProjectName, getWorkflowProjectName, getProjectDisplayName, groupWorkflowsByProject, sortWorkflowsInGroups, buildProjectGroups, formatWorkflowNameWithBadges, type IProjectGroup } from './project-helpers.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,aAAa,EACrB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Helper utilities for workflow and project management
3
+ *
4
+ * This module exports reusable helper functions that can be used
5
+ * across different interfaces (CLI, VS Code extension, etc.)
6
+ */
7
+ export { getDisplayProjectName, getWorkflowProjectName, getProjectDisplayName, groupWorkflowsByProject, sortWorkflowsInGroups, buildProjectGroups, formatWorkflowNameWithBadges } from './project-helpers.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,EAE/B,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Project-related helper functions for workflow organization
3
+ *
4
+ * These helpers provide reusable utilities for working with projects
5
+ * across different interfaces (CLI, VS Code extension, etc.)
6
+ */
7
+ import { IProject, IWorkflow } from '../types.js';
8
+ /**
9
+ * Gets a user-friendly display name for a project.
10
+ *
11
+ * Personal projects (type === 'personal') are displayed as "Personal"
12
+ * regardless of their actual name (which often includes user email).
13
+ *
14
+ * @param project The project to get a display name for
15
+ * @returns A user-friendly display name
16
+ */
17
+ export declare function getDisplayProjectName(project: IProject): string;
18
+ /**
19
+ * Gets a user-friendly display name for a workflow's project.
20
+ *
21
+ * If the workflow has no project assignment, returns the fallback.
22
+ *
23
+ * @param workflow The workflow to get a project name for
24
+ * @param fallback The name to use if the workflow has no project (default: "Personal")
25
+ * @returns A user-friendly display name
26
+ */
27
+ export declare function getWorkflowProjectName(workflow: IWorkflow, fallback?: string): string;
28
+ /**
29
+ * Gets a display name for a project from an object with project metadata.
30
+ * Works with IWorkflow, IWorkflowStatus, or any object with projectName and homeProject.
31
+ *
32
+ * @param obj Object containing project metadata
33
+ * @param fallback The name to use if no project (default: "Personal")
34
+ * @returns A user-friendly display name
35
+ */
36
+ export declare function getProjectDisplayName(obj: {
37
+ projectName?: string;
38
+ homeProject?: IProject;
39
+ }, fallback?: string): string;
40
+ /**
41
+ * Groups workflows by their project assignment.
42
+ *
43
+ * @param workflows Array of workflows to group
44
+ * @returns Map of projectId -> workflows array
45
+ */
46
+ export declare function groupWorkflowsByProject(workflows: IWorkflow[]): Map<string, IWorkflow[]>;
47
+ /**
48
+ * Sorts workflows within each project group.
49
+ *
50
+ * Default sort order: active workflows first, then by name alphabetically.
51
+ *
52
+ * @param groups Map of projectId -> workflows to sort in-place
53
+ * @param compareFn Optional custom comparison function
54
+ */
55
+ export declare function sortWorkflowsInGroups(groups: Map<string, IWorkflow[]>, compareFn?: (a: IWorkflow, b: IWorkflow) => number): void;
56
+ /**
57
+ * Interface for a project with its workflows
58
+ */
59
+ export interface IProjectGroup {
60
+ id: string;
61
+ name: string;
62
+ displayName: string;
63
+ project: IProject | null;
64
+ workflows: IWorkflow[];
65
+ }
66
+ /**
67
+ * Converts grouped workflows into structured project groups with metadata.
68
+ *
69
+ * @param groupedWorkflows Map of projectId -> workflows
70
+ * @param sortProjects Whether to sort projects (no-project last)
71
+ * @returns Array of project groups with display information
72
+ */
73
+ export declare function buildProjectGroups(groupedWorkflows: Map<string, IWorkflow[]>, sortProjects?: boolean): IProjectGroup[];
74
+ /**
75
+ * Format workflow name with project and archived badges
76
+ *
77
+ * @param workflow The workflow object (must have name, projectName/homeProject, isArchived)
78
+ * @param options Optional formatting options
79
+ * @returns Workflow name with badges
80
+ */
81
+ export declare function formatWorkflowNameWithBadges(workflow: {
82
+ name: string;
83
+ projectName?: string;
84
+ homeProject?: IProject;
85
+ isArchived?: boolean;
86
+ }, options?: {
87
+ showProjectBadge?: boolean;
88
+ showArchivedBadge?: boolean;
89
+ maxLength?: number;
90
+ projectBadgeStyle?: (text: string) => string;
91
+ archivedBadgeStyle?: (text: string) => string;
92
+ }): string;
93
+ //# sourceMappingURL=project-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-helpers.d.ts","sourceRoot":"","sources":["../../src/helpers/project-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAE/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAE,MAAmB,GAAG,MAAM,CAKjG;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,GAAG,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,CAAA;CAAE,EACrD,QAAQ,GAAE,MAAmB,GAC9B,MAAM,CAKR;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAexF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAChC,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,KAAK,MAAM,GACnD,IAAI,CAcN;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,SAAS,EAAE,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAC9B,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAC1C,YAAY,GAAE,OAAc,GAC7B,aAAa,EAAE,CAqCjB;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CACxC,QAAQ,EAAE;IACN,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAA;CACvB,EACD,OAAO,CAAC,EAAE;IACN,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACjD,GACF,MAAM,CAoCR"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Project-related helper functions for workflow organization
3
+ *
4
+ * These helpers provide reusable utilities for working with projects
5
+ * across different interfaces (CLI, VS Code extension, etc.)
6
+ */
7
+ /**
8
+ * Gets a user-friendly display name for a project.
9
+ *
10
+ * Personal projects (type === 'personal') are displayed as "Personal"
11
+ * regardless of their actual name (which often includes user email).
12
+ *
13
+ * @param project The project to get a display name for
14
+ * @returns A user-friendly display name
15
+ */
16
+ export function getDisplayProjectName(project) {
17
+ return project.type === 'personal' ? 'Personal' : project.name;
18
+ }
19
+ /**
20
+ * Gets a user-friendly display name for a workflow's project.
21
+ *
22
+ * If the workflow has no project assignment, returns the fallback.
23
+ *
24
+ * @param workflow The workflow to get a project name for
25
+ * @param fallback The name to use if the workflow has no project (default: "Personal")
26
+ * @returns A user-friendly display name
27
+ */
28
+ export function getWorkflowProjectName(workflow, fallback = 'Personal') {
29
+ if (!workflow.homeProject) {
30
+ return fallback;
31
+ }
32
+ return getDisplayProjectName(workflow.homeProject);
33
+ }
34
+ /**
35
+ * Gets a display name for a project from an object with project metadata.
36
+ * Works with IWorkflow, IWorkflowStatus, or any object with projectName and homeProject.
37
+ *
38
+ * @param obj Object containing project metadata
39
+ * @param fallback The name to use if no project (default: "Personal")
40
+ * @returns A user-friendly display name
41
+ */
42
+ export function getProjectDisplayName(obj, fallback = 'Personal') {
43
+ if (obj.homeProject) {
44
+ return getDisplayProjectName(obj.homeProject);
45
+ }
46
+ return obj.projectName || fallback;
47
+ }
48
+ /**
49
+ * Groups workflows by their project assignment.
50
+ *
51
+ * @param workflows Array of workflows to group
52
+ * @returns Map of projectId -> workflows array
53
+ */
54
+ export function groupWorkflowsByProject(workflows) {
55
+ const NO_PROJECT_KEY = '__NO_PROJECT__';
56
+ const groups = new Map();
57
+ for (const workflow of workflows) {
58
+ const projectId = workflow.projectId || NO_PROJECT_KEY;
59
+ if (!groups.has(projectId)) {
60
+ groups.set(projectId, []);
61
+ }
62
+ groups.get(projectId).push(workflow);
63
+ }
64
+ return groups;
65
+ }
66
+ /**
67
+ * Sorts workflows within each project group.
68
+ *
69
+ * Default sort order: active workflows first, then by name alphabetically.
70
+ *
71
+ * @param groups Map of projectId -> workflows to sort in-place
72
+ * @param compareFn Optional custom comparison function
73
+ */
74
+ export function sortWorkflowsInGroups(groups, compareFn) {
75
+ const defaultCompare = (a, b) => {
76
+ // Active workflows first
77
+ if (a.active && !b.active)
78
+ return -1;
79
+ if (!a.active && b.active)
80
+ return 1;
81
+ // Then by name
82
+ return a.name.localeCompare(b.name);
83
+ };
84
+ const compare = compareFn || defaultCompare;
85
+ for (const [, workflows] of groups) {
86
+ workflows.sort(compare);
87
+ }
88
+ }
89
+ /**
90
+ * Converts grouped workflows into structured project groups with metadata.
91
+ *
92
+ * @param groupedWorkflows Map of projectId -> workflows
93
+ * @param sortProjects Whether to sort projects (no-project last)
94
+ * @returns Array of project groups with display information
95
+ */
96
+ export function buildProjectGroups(groupedWorkflows, sortProjects = true) {
97
+ const NO_PROJECT_KEY = '__NO_PROJECT__';
98
+ const groups = [];
99
+ for (const [projectId, workflows] of groupedWorkflows) {
100
+ const isNoProject = projectId === NO_PROJECT_KEY;
101
+ const firstWorkflow = workflows[0];
102
+ const project = firstWorkflow?.homeProject || null;
103
+ const name = isNoProject
104
+ ? 'Personal'
105
+ : project?.name || 'Unknown Project';
106
+ const displayName = project
107
+ ? getDisplayProjectName(project)
108
+ : 'Personal';
109
+ groups.push({
110
+ id: projectId,
111
+ name,
112
+ displayName,
113
+ project,
114
+ workflows
115
+ });
116
+ }
117
+ if (sortProjects) {
118
+ groups.sort((a, b) => {
119
+ // No-project (Personal) last
120
+ if (a.id === NO_PROJECT_KEY)
121
+ return 1;
122
+ if (b.id === NO_PROJECT_KEY)
123
+ return -1;
124
+ // Others alphabetically by display name
125
+ return a.displayName.localeCompare(b.displayName);
126
+ });
127
+ }
128
+ return groups;
129
+ }
130
+ /**
131
+ * Format workflow name with project and archived badges
132
+ *
133
+ * @param workflow The workflow object (must have name, projectName/homeProject, isArchived)
134
+ * @param options Optional formatting options
135
+ * @returns Workflow name with badges
136
+ */
137
+ export function formatWorkflowNameWithBadges(workflow, options) {
138
+ const opts = {
139
+ showProjectBadge: true,
140
+ showArchivedBadge: true,
141
+ projectBadgeStyle: (text) => text,
142
+ archivedBadgeStyle: (text) => text,
143
+ ...options
144
+ };
145
+ let name = workflow.name;
146
+ const badges = [];
147
+ // Add project badge (only if not Personal)
148
+ if (opts.showProjectBadge) {
149
+ const projectName = getProjectDisplayName(workflow, '');
150
+ if (projectName && projectName !== 'Personal' && projectName !== '-') {
151
+ badges.push(opts.projectBadgeStyle(`[${projectName}]`));
152
+ }
153
+ }
154
+ // Add archived badge
155
+ if (opts.showArchivedBadge && workflow.isArchived) {
156
+ badges.push(opts.archivedBadgeStyle('[archived]'));
157
+ }
158
+ // Truncate name if needed (before adding badges)
159
+ if (opts.maxLength && name.length > opts.maxLength) {
160
+ name = name.substring(0, opts.maxLength - 3) + '...';
161
+ }
162
+ // Combine name and badges
163
+ if (badges.length > 0) {
164
+ return `${name} ${badges.join(' ')}`;
165
+ }
166
+ return name;
167
+ }
168
+ //# sourceMappingURL=project-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-helpers.js","sourceRoot":"","sources":["../../src/helpers/project-helpers.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,4 +7,5 @@ export * from './services/watcher.js';
7
7
  export * from './services/resolution-manager.js';
8
8
  export * from './services/state-manager.js';
9
9
  export * from './services/directory-utils.js';
10
+ export * from './helpers/index.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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"}
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;AAC9C,cAAc,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -7,4 +7,5 @@ export * from './services/watcher.js';
7
7
  export * from './services/resolution-manager.js';
8
8
  export * from './services/state-manager.js';
9
9
  export * from './services/directory-utils.js';
10
+ export * from './helpers/index.js';
10
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +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"}
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;AAC9C,cAAc,oBAAoB,CAAC"}
@@ -32,4 +32,10 @@ export declare function createInstanceIdentifier(host: string, user?: {
32
32
  * @returns Fallback instance identifier (e.g., "local_5678_abc123")
33
33
  */
34
34
  export declare function createFallbackInstanceIdentifier(host: string, apiKey: string): string;
35
+ /**
36
+ * Creates a project slug for directory naming
37
+ * @param projectName The project name or type
38
+ * @returns Project slug (e.g., "personal", "marketing_project")
39
+ */
40
+ export declare function createProjectSlug(projectName: string): string;
35
41
  //# sourceMappingURL=directory-utils.d.ts.map
@@ -1 +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"}
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;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAO7D"}
@@ -72,4 +72,16 @@ export function createFallbackInstanceIdentifier(host, apiKey) {
72
72
  const apiKeyHash = crypto.createHash('sha256').update(apiKey).digest('hex').substring(0, 6);
73
73
  return `${hostSlug}_${apiKeyHash}`;
74
74
  }
75
+ /**
76
+ * Creates a project slug for directory naming
77
+ * @param projectName The project name or type
78
+ * @returns Project slug (e.g., "personal", "marketing_project")
79
+ */
80
+ export function createProjectSlug(projectName) {
81
+ const slug = projectName
82
+ .toLowerCase()
83
+ .replace(/[^a-z0-9]+/g, '_')
84
+ .replace(/^_+|_+$/g, '');
85
+ return slug || 'project';
86
+ }
75
87
  //# sourceMappingURL=directory-utils.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"directory-utils.js","sourceRoot":"","sources":["../../src/services/directory-utils.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
- import { IN8nCredentials, IWorkflow } from '../types.js';
1
+ import { IN8nCredentials, IWorkflow, IProject } from '../types.js';
2
2
  export declare class N8nApiClient {
3
3
  private client;
4
+ private projectsCache;
4
5
  constructor(credentials: IN8nCredentials);
5
6
  testConnection(): Promise<boolean>;
6
7
  getCurrentUser(): Promise<{
@@ -9,8 +10,33 @@ export declare class N8nApiClient {
9
10
  firstName?: string;
10
11
  lastName?: string;
11
12
  } | null>;
12
- getAllWorkflows(): Promise<IWorkflow[]>;
13
+ /**
14
+ * Fetches all projects from n8n.
15
+ * Public method for CLI/UI to show project selection.
16
+ *
17
+ * @returns Array of IProject
18
+ */
19
+ getProjects(): Promise<IProject[]>;
20
+ /**
21
+ * Fetches all projects from n8n and caches them.
22
+ * Returns a Map of projectId -> IProject for quick lookups.
23
+ *
24
+ * The cache is populated on first call and reused for subsequent calls.
25
+ * If the API call fails, returns an empty cache to allow graceful degradation.
26
+ *
27
+ * @returns Map of projectId to IProject
28
+ */
29
+ private getProjectsCache;
30
+ getAllWorkflows(projectId?: string): Promise<IWorkflow[]>;
13
31
  getWorkflow(id: string): Promise<IWorkflow | null>;
32
+ /**
33
+ * Enriches a workflow with organization metadata extracted from the API response.
34
+ * This metadata includes project information and archived status.
35
+ *
36
+ * @param workflow Raw workflow from n8n API
37
+ * @returns Workflow with organization metadata
38
+ */
39
+ private enrichWorkflowMetadata;
14
40
  createWorkflow(payload: Partial<IWorkflow>): Promise<IWorkflow>;
15
41
  updateWorkflow(id: string, payload: Partial<IWorkflow>): Promise<IWorkflow>;
16
42
  deleteWorkflow(id: string): Promise<boolean>;
@@ -1 +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"}
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,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEnE,qBAAa,YAAY;IACrB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,aAAa,CAAsC;gBAE/C,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;IA2C7G;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IA6DxC;;;;;;;;OAQG;YACW,gBAAgB;IAiFxB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA4BzD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAexD;;;;;;OAMG;YACW,sBAAsB;IAiC9B,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"}
@@ -2,6 +2,7 @@ import axios from 'axios';
2
2
  import * as https from 'https';
3
3
  export class N8nApiClient {
4
4
  client;
5
+ projectsCache = null;
5
6
  constructor(credentials) {
6
7
  let host = credentials.host;
7
8
  if (host.endsWith('/')) {
@@ -74,10 +75,168 @@ export class N8nApiClient {
74
75
  console.debug('[N8nApiClient] getCurrentUser: All attempts failed, returning null');
75
76
  return null;
76
77
  }
77
- async getAllWorkflows() {
78
+ /**
79
+ * Fetches all projects from n8n.
80
+ * Public method for CLI/UI to show project selection.
81
+ *
82
+ * @returns Array of IProject
83
+ */
84
+ async getProjects() {
85
+ try {
86
+ const res = await this.client.get('/api/v1/projects');
87
+ const projects = res.data.data || [];
88
+ return projects.map((p) => ({
89
+ id: p.id,
90
+ name: p.name,
91
+ type: p.type,
92
+ createdAt: p.createdAt,
93
+ updatedAt: p.updatedAt
94
+ }));
95
+ }
96
+ catch (error) {
97
+ // Check if this is a license restriction error (common on local n8n instances)
98
+ const isLicenseError = error.response?.status === 403 &&
99
+ error.response?.data?.message?.includes('license') ||
100
+ error.response?.data?.message?.includes('feat:projectRole:admin');
101
+ if (isLicenseError) {
102
+ console.warn(`[N8nApiClient] Projects API requires license upgrade. Using personal project fallback.`);
103
+ // Try to get the personal project ID from existing workflows
104
+ try {
105
+ const workflowsRes = await this.client.get('/api/v1/workflows');
106
+ const workflows = workflowsRes.data.data || [];
107
+ // Find a project ID from workflow shared data
108
+ for (const wf of workflows) {
109
+ if (wf.shared && Array.isArray(wf.shared) && wf.shared.length > 0) {
110
+ const projectId = wf.shared[0].projectId;
111
+ if (projectId) {
112
+ console.debug(`[N8nApiClient] Found personal project ID from workflows: ${projectId}`);
113
+ return [{
114
+ id: projectId,
115
+ name: 'Personal',
116
+ type: 'personal',
117
+ createdAt: new Date().toISOString(),
118
+ updatedAt: new Date().toISOString()
119
+ }];
120
+ }
121
+ }
122
+ }
123
+ }
124
+ catch (innerError) {
125
+ console.debug(`[N8nApiClient] Could not fetch workflows to discover project ID: ${innerError.message}`);
126
+ }
127
+ // Fallback: return a placeholder personal project
128
+ console.warn(`[N8nApiClient] No workflows found, using placeholder personal project ID`);
129
+ return [{
130
+ id: 'personal',
131
+ name: 'Personal',
132
+ type: 'personal',
133
+ createdAt: new Date().toISOString(),
134
+ updatedAt: new Date().toISOString()
135
+ }];
136
+ }
137
+ console.error(`[N8nApiClient] Failed to fetch projects: ${error.message}`);
138
+ return [];
139
+ }
140
+ }
141
+ /**
142
+ * Fetches all projects from n8n and caches them.
143
+ * Returns a Map of projectId -> IProject for quick lookups.
144
+ *
145
+ * The cache is populated on first call and reused for subsequent calls.
146
+ * If the API call fails, returns an empty cache to allow graceful degradation.
147
+ *
148
+ * @returns Map of projectId to IProject
149
+ */
150
+ async getProjectsCache() {
151
+ if (this.projectsCache !== null) {
152
+ return this.projectsCache;
153
+ }
154
+ try {
155
+ const res = await this.client.get('/api/v1/projects');
156
+ const projects = res.data.data || [];
157
+ this.projectsCache = new Map();
158
+ for (const project of projects) {
159
+ this.projectsCache.set(project.id, {
160
+ id: project.id,
161
+ name: project.name,
162
+ type: project.type,
163
+ createdAt: project.createdAt,
164
+ updatedAt: project.updatedAt
165
+ });
166
+ }
167
+ // Only log in debug mode to avoid noise
168
+ if (process.env.DEBUG) {
169
+ console.debug(`[N8nApiClient] Cached ${this.projectsCache.size} projects`);
170
+ }
171
+ return this.projectsCache;
172
+ }
173
+ catch (error) {
174
+ // Check if this is a license restriction error (common on local n8n instances)
175
+ const isLicenseError = error.response?.status === 403 &&
176
+ error.response?.data?.message?.includes('license') ||
177
+ error.response?.data?.message?.includes('feat:projectRole:admin');
178
+ if (isLicenseError) {
179
+ console.warn(`[N8nApiClient] Projects API requires license upgrade. Using personal project fallback in cache.`);
180
+ // Try to get the personal project ID from existing workflows
181
+ try {
182
+ const workflowsRes = await this.client.get('/api/v1/workflows');
183
+ const workflows = workflowsRes.data.data || [];
184
+ // Find a project ID from workflow shared data
185
+ for (const wf of workflows) {
186
+ if (wf.shared && Array.isArray(wf.shared) && wf.shared.length > 0) {
187
+ const projectId = wf.shared[0].projectId;
188
+ if (projectId) {
189
+ console.debug(`[N8nApiClient] Found personal project ID from workflows for cache: ${projectId}`);
190
+ this.projectsCache = new Map();
191
+ this.projectsCache.set(projectId, {
192
+ id: projectId,
193
+ name: 'Personal',
194
+ type: 'personal',
195
+ createdAt: new Date().toISOString(),
196
+ updatedAt: new Date().toISOString()
197
+ });
198
+ return this.projectsCache;
199
+ }
200
+ }
201
+ }
202
+ }
203
+ catch (innerError) {
204
+ console.debug(`[N8nApiClient] Could not fetch workflows to discover project ID for cache: ${innerError.message}`);
205
+ }
206
+ // Fallback: create a placeholder personal project
207
+ console.warn(`[N8nApiClient] No workflows found, using placeholder personal project ID in cache`);
208
+ this.projectsCache = new Map();
209
+ this.projectsCache.set('personal', {
210
+ id: 'personal',
211
+ name: 'Personal',
212
+ type: 'personal',
213
+ createdAt: new Date().toISOString(),
214
+ updatedAt: new Date().toISOString()
215
+ });
216
+ return this.projectsCache;
217
+ }
218
+ // Graceful degradation: workflows will have projectId but no homeProject/projectName
219
+ console.warn(`[N8nApiClient] Failed to fetch projects: ${error.message}. Workflows will not have project names.`);
220
+ this.projectsCache = new Map();
221
+ return this.projectsCache;
222
+ }
223
+ }
224
+ async getAllWorkflows(projectId) {
78
225
  try {
79
226
  const res = await this.client.get('/api/v1/workflows');
80
- return res.data.data;
227
+ let workflows = res.data.data;
228
+ // Filter by project if specified
229
+ if (projectId) {
230
+ workflows = workflows.filter((wf) => {
231
+ if (!wf.shared || !Array.isArray(wf.shared) || wf.shared.length === 0) {
232
+ return false;
233
+ }
234
+ return wf.shared[0].projectId === projectId;
235
+ });
236
+ }
237
+ // Enrich workflows with organization metadata
238
+ const enriched = await Promise.all(workflows.map((wf) => this.enrichWorkflowMetadata(wf)));
239
+ return enriched;
81
240
  }
82
241
  catch (error) {
83
242
  console.error('Failed to get workflows:', error.message);
@@ -88,7 +247,8 @@ export class N8nApiClient {
88
247
  async getWorkflow(id) {
89
248
  try {
90
249
  const res = await this.client.get(`/api/v1/workflows/${id}`);
91
- return res.data;
250
+ // Enrich with organization metadata
251
+ return await this.enrichWorkflowMetadata(res.data);
92
252
  }
93
253
  catch (error) {
94
254
  // 404 is expected if workflow deleted remotely
@@ -99,6 +259,40 @@ export class N8nApiClient {
99
259
  throw error;
100
260
  }
101
261
  }
262
+ /**
263
+ * Enriches a workflow with organization metadata extracted from the API response.
264
+ * This metadata includes project information and archived status.
265
+ *
266
+ * @param workflow Raw workflow from n8n API
267
+ * @returns Workflow with organization metadata
268
+ */
269
+ async enrichWorkflowMetadata(workflow) {
270
+ const enriched = { ...workflow };
271
+ // Get projects cache
272
+ const projectsCache = await this.getProjectsCache();
273
+ // Extract project information from shared array
274
+ // n8n stores projectId in workflow.shared[0].projectId
275
+ if (workflow.shared && Array.isArray(workflow.shared) && workflow.shared.length > 0) {
276
+ const firstShare = workflow.shared[0];
277
+ if (firstShare.projectId) {
278
+ enriched.projectId = firstShare.projectId;
279
+ // Look up project details in cache
280
+ const project = projectsCache.get(firstShare.projectId);
281
+ if (project) {
282
+ enriched.homeProject = project;
283
+ enriched.projectName = project.name;
284
+ }
285
+ else {
286
+ console.debug(`[N8nApiClient] Project ${firstShare.projectId} not found in cache`);
287
+ }
288
+ }
289
+ }
290
+ // Extract archived status (direct property)
291
+ if (workflow.isArchived !== undefined) {
292
+ enriched.isArchived = workflow.isArchived;
293
+ }
294
+ return enriched;
295
+ }
102
296
  async createWorkflow(payload) {
103
297
  const res = await this.client.post('/api/v1/workflows', payload);
104
298
  return res.data;