@n8n-as-code/core 0.2.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 (38) hide show
  1. package/README.md +22 -0
  2. package/dist/index.d.ts +11 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +11 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/services/directory-utils.d.ts +35 -0
  7. package/dist/services/directory-utils.d.ts.map +1 -0
  8. package/dist/services/directory-utils.js +75 -0
  9. package/dist/services/directory-utils.js.map +1 -0
  10. package/dist/services/n8n-api-client.d.ts +23 -0
  11. package/dist/services/n8n-api-client.d.ts.map +1 -0
  12. package/dist/services/n8n-api-client.js +199 -0
  13. package/dist/services/n8n-api-client.js.map +1 -0
  14. package/dist/services/schema-generator.d.ts +9 -0
  15. package/dist/services/schema-generator.d.ts.map +1 -0
  16. package/dist/services/schema-generator.js +79 -0
  17. package/dist/services/schema-generator.js.map +1 -0
  18. package/dist/services/state-manager.d.ts +42 -0
  19. package/dist/services/state-manager.d.ts.map +1 -0
  20. package/dist/services/state-manager.js +99 -0
  21. package/dist/services/state-manager.js.map +1 -0
  22. package/dist/services/sync-manager.d.ts +101 -0
  23. package/dist/services/sync-manager.d.ts.map +1 -0
  24. package/dist/services/sync-manager.js +692 -0
  25. package/dist/services/sync-manager.js.map +1 -0
  26. package/dist/services/trash-service.d.ts +17 -0
  27. package/dist/services/trash-service.d.ts.map +1 -0
  28. package/dist/services/trash-service.js +41 -0
  29. package/dist/services/trash-service.js.map +1 -0
  30. package/dist/services/workflow-sanitizer.d.ts +18 -0
  31. package/dist/services/workflow-sanitizer.d.ts.map +1 -0
  32. package/dist/services/workflow-sanitizer.js +80 -0
  33. package/dist/services/workflow-sanitizer.js.map +1 -0
  34. package/dist/types.d.ts +41 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +9 -0
  37. package/dist/types.js.map +1 -0
  38. package/package.json +41 -0
@@ -0,0 +1,99 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import crypto from 'crypto';
4
+ export class StateManager {
5
+ stateFilePath;
6
+ constructor(directory) {
7
+ this.stateFilePath = path.join(directory, '.n8n-state.json');
8
+ }
9
+ load() {
10
+ if (fs.existsSync(this.stateFilePath)) {
11
+ try {
12
+ const data = JSON.parse(fs.readFileSync(this.stateFilePath, 'utf-8'));
13
+ // Ensure workflows object exists
14
+ if (!data.workflows) {
15
+ data.workflows = {};
16
+ }
17
+ return data;
18
+ }
19
+ catch (e) {
20
+ console.warn('Could not read state file, using empty state');
21
+ }
22
+ }
23
+ return { workflows: {} };
24
+ }
25
+ save(state) {
26
+ fs.writeFileSync(this.stateFilePath, JSON.stringify(state, null, 2));
27
+ }
28
+ /**
29
+ * Computes a stable hash for a workflow object.
30
+ */
31
+ static computeHash(workflow) {
32
+ // We use the cleaned version to ensure stable hashing (no dynamic IDs or timestamps)
33
+ const content = typeof workflow === 'string' ? workflow : JSON.stringify(workflow);
34
+ return crypto.createHash('sha256').update(content).digest('hex');
35
+ }
36
+ /**
37
+ * Gets the last known state for a workflow.
38
+ */
39
+ getWorkflowState(id) {
40
+ const state = this.load();
41
+ return state.workflows[id];
42
+ }
43
+ /**
44
+ * Updates the last known state for a workflow.
45
+ */
46
+ updateWorkflowState(id, workflow) {
47
+ const state = this.load();
48
+ const hash = StateManager.computeHash(workflow);
49
+ state.workflows[id] = {
50
+ lastSyncedHash: hash,
51
+ lastSyncedAt: new Date().toISOString()
52
+ };
53
+ this.save(state);
54
+ }
55
+ /**
56
+ * Removes a workflow from state.
57
+ */
58
+ removeWorkflowState(id) {
59
+ const state = this.load();
60
+ delete state.workflows[id];
61
+ this.save(state);
62
+ }
63
+ /**
64
+ * Gets all tracked workflow IDs.
65
+ */
66
+ getTrackedWorkflowIds() {
67
+ const state = this.load();
68
+ return Object.keys(state.workflows);
69
+ }
70
+ /**
71
+ * Checks if a local content matches the last synced state.
72
+ */
73
+ isLocalSynced(id, localContent) {
74
+ const state = this.getWorkflowState(id);
75
+ if (!state)
76
+ return true; // If no state, we assume it's new
77
+ const currentHash = StateManager.computeHash(localContent);
78
+ const result = state.lastSyncedHash === currentHash;
79
+ if (!result) {
80
+ // Changed from console.log to silent for production
81
+ }
82
+ return result;
83
+ }
84
+ /**
85
+ * Checks if a remote workflow matches the last synced state.
86
+ */
87
+ isRemoteSynced(id, remoteWorkflow) {
88
+ const state = this.getWorkflowState(id);
89
+ if (!state)
90
+ return true;
91
+ const remoteHash = StateManager.computeHash(remoteWorkflow);
92
+ const result = state.lastSyncedHash === remoteHash;
93
+ if (!result) {
94
+ // Changed from console.log to silent for production
95
+ }
96
+ return result;
97
+ }
98
+ }
99
+ //# sourceMappingURL=state-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-manager.js","sourceRoot":"","sources":["../../src/services/state-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import EventEmitter from 'events';
2
+ import { N8nApiClient } from './n8n-api-client.js';
3
+ import { ISyncConfig, IWorkflowStatus } from '../types.js';
4
+ export declare class SyncManager extends EventEmitter {
5
+ private client;
6
+ private config;
7
+ private fileToIdMap;
8
+ private selfWrittenCache;
9
+ private isWriting;
10
+ private pendingDeletions;
11
+ private watcher;
12
+ private pollInterval;
13
+ private stateManager;
14
+ private trashService;
15
+ constructor(client: N8nApiClient, config: ISyncConfig);
16
+ /**
17
+ * Get the path to the instance configuration file
18
+ */
19
+ private getInstanceConfigPath;
20
+ /**
21
+ * Load instance configuration from disk
22
+ */
23
+ private loadInstanceConfig;
24
+ /**
25
+ * Save instance configuration to disk
26
+ */
27
+ private saveInstanceConfig;
28
+ /**
29
+ * Ensure instance identifier is set and persistent
30
+ */
31
+ private ensureInstanceIdentifier;
32
+ private initializeInstanceIdentifier;
33
+ getInstanceDirectory(): string;
34
+ private getFilePath;
35
+ private safeName;
36
+ private normalizeContent;
37
+ private markAsSelfWritten;
38
+ private isSelfWritten;
39
+ loadRemoteState(): Promise<void>;
40
+ /**
41
+ * Retrieves the status of all workflows (local and remote)
42
+ */
43
+ getWorkflowsStatus(): Promise<IWorkflowStatus[]>;
44
+ private formatSummary;
45
+ /**
46
+ * Scans n8n instance and updates local files (Downstream Sync)
47
+ */
48
+ syncDown(): Promise<void>;
49
+ /**
50
+ * Identifies and handles workflows deleted on n8n but still present locally and tracked in state
51
+ */
52
+ private processRemoteDeletions;
53
+ /**
54
+ * Scans n8n instance and updates local files with conflict resolution
55
+ */
56
+ syncDownWithConflictResolution(): Promise<void>;
57
+ /**
58
+ * Pulls a single workflow by ID and writes to filename
59
+ * @param force If true, overwrites local changes without checking for conflicts
60
+ */
61
+ pullWorkflow(filename: string, id: string, force?: boolean): Promise<void>;
62
+ /**
63
+ * Pulls a single workflow with conflict resolution
64
+ * @returns 'updated' if file was updated, 'skipped' if no change or conflict, 'new' if file was created
65
+ */
66
+ pullWorkflowWithConflictResolution(filename: string, id: string, remoteUpdatedAt?: string): Promise<'updated' | 'skipped' | 'new' | 'up-to-date' | 'conflict'>;
67
+ /**
68
+ * Writes file to disk only if changed
69
+ */
70
+ private writeLocalFile;
71
+ private shouldIgnore;
72
+ /**
73
+ * Uploads local files that don't exist remotely (Upstream Sync - Init)
74
+ */
75
+ syncUpMissing(): Promise<void>;
76
+ /**
77
+ * Full Upstream Sync: Updates existing and Creates new.
78
+ */
79
+ syncUp(): Promise<void>;
80
+ /**
81
+ * Handles local file deletion (detected by watcher)
82
+ */
83
+ handleLocalFileDeletion(filePath: string): Promise<void>;
84
+ /**
85
+ * Actually deletes the remote workflow and cleans up local state
86
+ */
87
+ deleteRemoteWorkflow(id: string, filename: string): Promise<boolean>;
88
+ /**
89
+ * Restore a deleted local file from remote
90
+ */
91
+ restoreLocalFile(id: string, filename: string): Promise<boolean>;
92
+ /**
93
+ * Handle FS watcher events
94
+ */
95
+ handleLocalFileChange(filePath: string, silent?: boolean): Promise<'updated' | 'created' | 'up-to-date' | 'conflict' | 'skipped'>;
96
+ private readLocalFile;
97
+ private readRawFile;
98
+ startWatch(): Promise<void>;
99
+ stopWatch(): void;
100
+ }
101
+ //# sourceMappingURL=sync-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-manager.d.ts","sourceRoot":"","sources":["../../src/services/sync-manager.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAGlC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKnD,OAAO,EAAE,WAAW,EAAiC,eAAe,EAAE,MAAM,aAAa,CAAC;AAO1F,qBAAa,WAAY,SAAQ,YAAY;IACzC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAAc;IAG5B,OAAO,CAAC,WAAW,CAAkC;IAErD,OAAO,CAAC,gBAAgB,CAAkC;IAE1D,OAAO,CAAC,SAAS,CAAqB;IAEtC,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,YAAY,CAA6B;gBAErC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW;IAWrD;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;OAEG;YACW,wBAAwB;YA+BxB,4BAA4B;IAkBnC,oBAAoB,IAAI,MAAM;IAarC,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,aAAa;IAOf,eAAe;IAarB;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IA8DtD,OAAO,CAAC,aAAa;IASrB;;OAEG;IACG,QAAQ;IAmCd;;OAEG;YACW,sBAAsB;IAoCpC;;OAEG;IACG,8BAA8B;IAkCpC;;;OAGG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,OAAe;IA4BvE;;;OAGG;IACG,kCAAkC,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,GAAG,KAAK,GAAG,YAAY,GAAG,UAAU,CAAC;IA8CpK;;OAEG;YACW,cAAc;IAqC5B,OAAO,CAAC,YAAY;IASpB;;OAEG;IACG,aAAa;IAenB;;OAEG;IACG,MAAM;IAqBZ;;OAEG;IACG,uBAAuB,CAAC,QAAQ,EAAE,MAAM;IAiB9C;;OAEG;IACG,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAuB1E;;OAEG;IACG,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBtE;;OAEG;IACG,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,OAAe,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;IA0F9I,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,WAAW;IAIb,UAAU;IAwChB,SAAS;CAWZ"}