n8nac 2.4.0 → 2.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.
Files changed (64) hide show
  1. package/README.md +9 -0
  2. package/dist/commands/base.d.ts +39 -0
  3. package/dist/commands/base.d.ts.map +1 -1
  4. package/dist/commands/base.js +84 -36
  5. package/dist/commands/base.js.map +1 -1
  6. package/dist/commands/list.d.ts.map +1 -1
  7. package/dist/commands/list.js +2 -2
  8. package/dist/commands/list.js.map +1 -1
  9. package/dist/commands/sync.d.ts.map +1 -1
  10. package/dist/commands/sync.js +28 -6
  11. package/dist/commands/sync.js.map +1 -1
  12. package/dist/commands/test.d.ts.map +1 -1
  13. package/dist/commands/test.js +2 -2
  14. package/dist/commands/test.js.map +1 -1
  15. package/dist/core/index.d.ts +3 -0
  16. package/dist/core/index.d.ts.map +1 -1
  17. package/dist/core/index.js +3 -0
  18. package/dist/core/index.js.map +1 -1
  19. package/dist/core/services/folder-path-resolver.d.ts +51 -0
  20. package/dist/core/services/folder-path-resolver.d.ts.map +1 -0
  21. package/dist/core/services/folder-path-resolver.js +123 -0
  22. package/dist/core/services/folder-path-resolver.js.map +1 -0
  23. package/dist/core/services/n8n-api-client.d.ts +53 -1
  24. package/dist/core/services/n8n-api-client.d.ts.map +1 -1
  25. package/dist/core/services/n8n-api-client.js +184 -2
  26. package/dist/core/services/n8n-api-client.js.map +1 -1
  27. package/dist/core/services/resolution-manager.d.ts.map +1 -1
  28. package/dist/core/services/resolution-manager.js +4 -4
  29. package/dist/core/services/resolution-manager.js.map +1 -1
  30. package/dist/core/services/state-manager.d.ts +1 -1
  31. package/dist/core/services/state-manager.d.ts.map +1 -1
  32. package/dist/core/services/sync-engine.d.ts +48 -1
  33. package/dist/core/services/sync-engine.d.ts.map +1 -1
  34. package/dist/core/services/sync-engine.js +200 -6
  35. package/dist/core/services/sync-engine.js.map +1 -1
  36. package/dist/core/services/sync-manager.d.ts.map +1 -1
  37. package/dist/core/services/sync-manager.js +10 -8
  38. package/dist/core/services/sync-manager.js.map +1 -1
  39. package/dist/core/services/tls-certificates.d.ts +105 -0
  40. package/dist/core/services/tls-certificates.d.ts.map +1 -0
  41. package/dist/core/services/tls-certificates.js +329 -0
  42. package/dist/core/services/tls-certificates.js.map +1 -0
  43. package/dist/core/services/workflow-path-utils.d.ts +56 -0
  44. package/dist/core/services/workflow-path-utils.d.ts.map +1 -0
  45. package/dist/core/services/workflow-path-utils.js +102 -0
  46. package/dist/core/services/workflow-path-utils.js.map +1 -0
  47. package/dist/core/services/workflow-state-tracker.d.ts +56 -0
  48. package/dist/core/services/workflow-state-tracker.d.ts.map +1 -1
  49. package/dist/core/services/workflow-state-tracker.js +225 -32
  50. package/dist/core/services/workflow-state-tracker.js.map +1 -1
  51. package/dist/core/services/workflow-transformer-adapter.d.ts +7 -1
  52. package/dist/core/services/workflow-transformer-adapter.d.ts.map +1 -1
  53. package/dist/core/services/workflow-transformer-adapter.js +8 -2
  54. package/dist/core/services/workflow-transformer-adapter.js.map +1 -1
  55. package/dist/core/types.d.ts +84 -0
  56. package/dist/core/types.d.ts.map +1 -1
  57. package/dist/core/types.js.map +1 -1
  58. package/dist/index.js +46 -10
  59. package/dist/index.js.map +1 -1
  60. package/dist/services/config-service.d.ts +33 -6
  61. package/dist/services/config-service.d.ts.map +1 -1
  62. package/dist/services/config-service.js +54 -3
  63. package/dist/services/config-service.js.map +1 -1
  64. package/package.json +3 -3
@@ -0,0 +1,329 @@
1
+ import * as fs from 'fs';
2
+ import { createRequire } from 'module';
3
+ import * as path from 'path';
4
+ import * as tls from 'tls';
5
+ /**
6
+ * Additional trust anchors for outbound HTTPS.
7
+ *
8
+ * Node honours `NODE_EXTRA_CA_CERTS` and `--use-system-ca` when it builds the default
9
+ * TLS trust store, but only when the process is a stock Node build that is started with
10
+ * those settings. The VS Code extension host is neither: it is an Electron process
11
+ * (BoringSSL, no `NODE_EXTRA_CA_CERTS` support) that users cannot pass Node flags to.
12
+ * The same gap exists for anything reaching n8n through the global `fetch`
13
+ * (`@n8n-as-code/n8n-manager-core` health probes, project listing, credential REST calls),
14
+ * because `fetch` ignores `https.Agent` options entirely.
15
+ *
16
+ * So we read the certificates ourselves and append them to every secure context the
17
+ * process creates, which covers axios, `fetch`, `ws` and `http-proxy` in one place.
18
+ */
19
+ const PEM_CERTIFICATE_PATTERN = /-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g;
20
+ /** Read in addition to Node's own `NODE_EXTRA_CA_CERTS`; accepts several paths. */
21
+ export const N8NAC_EXTRA_CA_CERTS_ENV = 'N8NAC_EXTRA_CA_CERTS';
22
+ const patchedHosts = new WeakMap();
23
+ let defaultSecureContextHost;
24
+ /**
25
+ * The mutable `tls` module object.
26
+ *
27
+ * `import * as tls` yields a frozen module namespace, so the patch has to go through the
28
+ * CommonJS export object that `https`, `ws` and undici's `fetch` all read from.
29
+ */
30
+ function getDefaultSecureContextHost() {
31
+ defaultSecureContextHost ??= createRequire(import.meta.url)('tls');
32
+ return defaultSecureContextHost;
33
+ }
34
+ /**
35
+ * Split a path list. Accepts the platform delimiter, commas and newlines so a single
36
+ * setting works whether it was copied from a shell variable or typed by hand.
37
+ */
38
+ export function splitCertificatePathList(value) {
39
+ return value
40
+ .split(new RegExp(`[${escapeForCharacterClass(path.delimiter)},\\r\\n]`))
41
+ .map((entry) => entry.trim().replace(/^["']|["']$/g, ''))
42
+ .filter((entry) => entry.length > 0);
43
+ }
44
+ function escapeForCharacterClass(value) {
45
+ return value.replace(/[\\\]^-]/g, '\\$&');
46
+ }
47
+ /** Extract every PEM certificate block from a bundle, ignoring keys and comments. */
48
+ export function extractPemCertificates(contents) {
49
+ return contents.match(PEM_CERTIFICATE_PATTERN) ?? [];
50
+ }
51
+ function readCertificateFile(filePath, resolution, label) {
52
+ let contents;
53
+ try {
54
+ contents = fs.readFileSync(filePath, 'utf8');
55
+ }
56
+ catch (error) {
57
+ resolution.errors.push(`${label}: cannot read "${filePath}" (${error?.code || error?.message || error})`);
58
+ return;
59
+ }
60
+ const certificates = extractPemCertificates(contents);
61
+ if (!certificates.length) {
62
+ resolution.errors.push(`${label}: "${filePath}" does not contain any PEM certificate`);
63
+ return;
64
+ }
65
+ resolution.hasConfiguredAnchors = true;
66
+ addCertificates(resolution, certificates, `${label}: ${filePath}`);
67
+ }
68
+ function addCertificates(resolution, certificates, source) {
69
+ let added = 0;
70
+ for (const certificate of certificates) {
71
+ const normalized = certificate.trim();
72
+ if (!normalized || resolution.certificates.includes(normalized))
73
+ continue;
74
+ resolution.certificates.push(normalized);
75
+ added++;
76
+ }
77
+ if (added > 0) {
78
+ resolution.sources.push(`${source} (${added})`);
79
+ }
80
+ }
81
+ function readSystemCertificates(resolution) {
82
+ // Node 22.15+/24 only. Older hosts (and Electron) simply do not expose it, which is the
83
+ // expected state rather than a misconfiguration, so it is not reported as an error.
84
+ const getCACertificates = tls.getCACertificates;
85
+ if (typeof getCACertificates !== 'function') {
86
+ return;
87
+ }
88
+ try {
89
+ addCertificates(resolution, getCACertificates('system'), 'system trust store');
90
+ }
91
+ catch (error) {
92
+ resolution.errors.push(`system trust store: ${error?.message || error}`);
93
+ }
94
+ }
95
+ /**
96
+ * Collect the extra trust anchors from settings, `N8NAC_EXTRA_CA_CERTS`,
97
+ * `NODE_EXTRA_CA_CERTS` and — on request — the OS trust store.
98
+ */
99
+ export function resolveExtraCaCertificates(options = {}) {
100
+ const env = options.env ?? process.env;
101
+ const baseDir = options.baseDir ?? process.cwd();
102
+ const resolution = {
103
+ certificates: [],
104
+ sources: [],
105
+ errors: [],
106
+ hasConfiguredAnchors: false,
107
+ };
108
+ const resolvePath = (candidate) => (path.isAbsolute(candidate) ? candidate : path.resolve(baseDir, candidate));
109
+ for (const candidate of options.caFiles ?? []) {
110
+ for (const filePath of splitCertificatePathList(candidate)) {
111
+ readCertificateFile(resolvePath(filePath), resolution, 'setting');
112
+ }
113
+ }
114
+ for (const filePath of splitCertificatePathList(env[N8NAC_EXTRA_CA_CERTS_ENV] ?? '')) {
115
+ readCertificateFile(resolvePath(filePath), resolution, N8NAC_EXTRA_CA_CERTS_ENV);
116
+ }
117
+ for (const filePath of splitCertificatePathList(env.NODE_EXTRA_CA_CERTS ?? '')) {
118
+ readCertificateFile(resolvePath(filePath), resolution, 'NODE_EXTRA_CA_CERTS');
119
+ }
120
+ if (options.useSystemCertificateAuthorities) {
121
+ readSystemCertificates(resolution);
122
+ }
123
+ return resolution;
124
+ }
125
+ /**
126
+ * Append the resolved certificates to every secure context created from now on.
127
+ *
128
+ * Idempotent: calling it again replaces the certificate set instead of stacking another
129
+ * wrapper, so it is safe to re-run whenever the configuration changes.
130
+ */
131
+ export function installExtraCaCertificates(options = {}, host = getDefaultSecureContextHost()) {
132
+ const resolution = resolveExtraCaCertificates(options);
133
+ const existing = patchedHosts.get(host);
134
+ if (existing) {
135
+ existing.certificates = resolution.certificates;
136
+ return { ...resolution, installed: resolution.certificates.length > 0 };
137
+ }
138
+ if (!resolution.certificates.length) {
139
+ // Nothing to trust yet — leave the runtime untouched rather than wrapping it for nothing.
140
+ return { ...resolution, installed: false };
141
+ }
142
+ const state = {
143
+ original: host.createSecureContext,
144
+ certificates: resolution.certificates,
145
+ };
146
+ patchedHosts.set(host, state);
147
+ host.createSecureContext = (contextOptions) => {
148
+ const context = state.original.call(host, contextOptions);
149
+ const nativeContext = context.context;
150
+ if (typeof nativeContext?.addCACert !== 'function') {
151
+ return context;
152
+ }
153
+ for (const certificate of state.certificates) {
154
+ try {
155
+ nativeContext.addCACert(certificate);
156
+ }
157
+ catch {
158
+ // A malformed or duplicate anchor must not break the whole handshake.
159
+ }
160
+ }
161
+ return context;
162
+ };
163
+ return { ...resolution, installed: true };
164
+ }
165
+ /** Certificates currently appended by the installer, for diagnostics and tests. */
166
+ export function getInstalledExtraCaCertificates(host = getDefaultSecureContextHost()) {
167
+ return [...(patchedHosts.get(host)?.certificates ?? [])];
168
+ }
169
+ /** Restore the untouched `createSecureContext`. Intended for tests. */
170
+ export function uninstallExtraCaCertificates(host = getDefaultSecureContextHost()) {
171
+ const state = patchedHosts.get(host);
172
+ if (!state)
173
+ return;
174
+ host.createSecureContext = state.original;
175
+ patchedHosts.delete(host);
176
+ }
177
+ /** Set to 1/true/yes to skip certificate verification outright. Last resort, see below. */
178
+ export const N8NAC_INSECURE_TLS_ENV = 'N8NAC_INSECURE_TLS';
179
+ const PRIVATE_HOSTNAME_SUFFIXES = ['.localhost', '.local', '.internal', '.home.arpa'];
180
+ /** Pull the host out of a URL by hand, for the inputs `URL` refuses (an IPv6 zone id). */
181
+ function stripUrlDecorations(value) {
182
+ const bare = value
183
+ .replace(/^[a-z][a-z0-9+.-]*:\/\//i, '')
184
+ .replace(/^[^@/]*@/, '')
185
+ .replace(/[/?#].*$/, '');
186
+ const bracketed = /^\[([^\]]*)\]/.exec(bare);
187
+ if (bracketed)
188
+ return bracketed[1];
189
+ // A bare IPv6 literal holds several colons; a `host:port` pair holds exactly one.
190
+ return bare.split(':').length === 2 ? bare.replace(/:\d*$/, '') : bare;
191
+ }
192
+ /** Strip the scheme, port, brackets, IPv6 zone id and trailing dot from a configured host. */
193
+ function normalizeHostname(hostOrUrl) {
194
+ const value = hostOrUrl.trim();
195
+ if (!value)
196
+ return '';
197
+ let hostname;
198
+ try {
199
+ hostname = new URL(value.includes('://') ? value : `https://${value}`).hostname;
200
+ }
201
+ catch {
202
+ hostname = stripUrlDecorations(value);
203
+ }
204
+ return hostname
205
+ .toLowerCase()
206
+ .replace(/^\[|\]$/g, '')
207
+ .replace(/%.*$/, '')
208
+ .replace(/\.$/, '');
209
+ }
210
+ function isPrivateIpv4(hostname) {
211
+ const octets = hostname.split('.').map(Number);
212
+ if (octets.length !== 4 || octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
213
+ return false;
214
+ }
215
+ const [first, second] = octets;
216
+ if (first === 0)
217
+ return true; // "this host on this network"
218
+ if (first === 10)
219
+ return true; // RFC 1918
220
+ if (first === 127)
221
+ return true; // loopback
222
+ if (first === 169 && second === 254)
223
+ return true; // link-local
224
+ if (first === 172 && second >= 16 && second <= 31)
225
+ return true; // RFC 1918
226
+ if (first === 192 && second === 168)
227
+ return true; // RFC 1918
228
+ if (first === 100 && second >= 64 && second <= 127)
229
+ return true; // CGNAT, incl. Tailscale
230
+ return false;
231
+ }
232
+ function isPrivateIpv6(hostname) {
233
+ if (hostname === '::1' || hostname === '::')
234
+ return true;
235
+ const mapped = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/.exec(hostname);
236
+ if (mapped)
237
+ return isPrivateIpv4(mapped[1]);
238
+ // `URL` rewrites an IPv4-mapped address to its hex form (`::ffff:c0a8:10a`), so the
239
+ // embedded IPv4 address has to be read back out of the last two groups.
240
+ const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(hostname);
241
+ if (mappedHex) {
242
+ const high = parseInt(mappedHex[1], 16);
243
+ const low = parseInt(mappedHex[2], 16);
244
+ return isPrivateIpv4([high >> 8, high & 0xff, low >> 8, low & 0xff].join('.'));
245
+ }
246
+ if (/^f[cd][0-9a-f]{2}:/.test(hostname))
247
+ return true; // fc00::/7 unique local
248
+ if (/^fe[89ab][0-9a-f]:/.test(hostname))
249
+ return true; // fe80::/10 link-local
250
+ return false;
251
+ }
252
+ /**
253
+ * `true` when the host can only be reached from this machine or a private network.
254
+ *
255
+ * These are precisely the destinations a public CA will not issue a certificate for, so they
256
+ * are the ones where a self-signed certificate is the normal setup rather than an attack.
257
+ * Anything else — a real domain name — is treated as public, which is the safe default: an
258
+ * unrecognised host fails closed into verification.
259
+ */
260
+ export function isPrivateNetworkHost(hostOrUrl) {
261
+ const hostname = normalizeHostname(hostOrUrl);
262
+ if (!hostname)
263
+ return false;
264
+ if (hostname === 'localhost')
265
+ return true;
266
+ if (PRIVATE_HOSTNAME_SUFFIXES.some((suffix) => hostname.endsWith(suffix)))
267
+ return true;
268
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname))
269
+ return isPrivateIpv4(hostname);
270
+ if (hostname.includes(':'))
271
+ return isPrivateIpv6(hostname);
272
+ // A single-label name ("n8n-box") is an intranet name: it has no public DNS entry and no
273
+ // public CA will certify it.
274
+ return !hostname.includes('.');
275
+ }
276
+ /**
277
+ * Whether the server certificate has to verify for this destination.
278
+ *
279
+ * Verification is the default. It is relaxed only where the historical zero-configuration
280
+ * behaviour is actually needed — a private or loopback address, which cannot hold a publicly
281
+ * trusted certificate — and only while the user has not configured any anchor of their own.
282
+ * Configuring an anchor still means "verify everywhere", so a private host does not become a
283
+ * hole for someone who did set the certificates up.
284
+ *
285
+ * The remaining case, a self-signed certificate on a public host name, has to opt out through
286
+ * {@link N8NAC_INSECURE_TLS_ENV}, because it is indistinguishable from an interception.
287
+ */
288
+ export function shouldVerifyServerCertificate(policy) {
289
+ const env = policy.env ?? process.env;
290
+ if (/^(1|true|yes)$/i.test((env[N8NAC_INSECURE_TLS_ENV] ?? '').trim()))
291
+ return false;
292
+ if (policy.hasConfiguredAnchors)
293
+ return true;
294
+ return !isPrivateNetworkHost(policy.host);
295
+ }
296
+ /** `true` when the error is a TLS trust failure rather than a transport or HTTP error. */
297
+ export function isCertificateTrustError(error) {
298
+ const code = typeof error?.code === 'string' ? error.code : '';
299
+ if (code.startsWith('UNABLE_TO_') || code.startsWith('SELF_SIGNED') || code.startsWith('DEPTH_ZERO_')) {
300
+ return true;
301
+ }
302
+ if (code === 'CERT_HAS_EXPIRED' || code === 'ERR_TLS_CERT_ALTNAME_INVALID' || code === 'CERT_SIGNATURE_FAILURE') {
303
+ return true;
304
+ }
305
+ if (error?.cause && error.cause !== error && isCertificateTrustError(error.cause)) {
306
+ return true;
307
+ }
308
+ const message = String(error?.message ?? error ?? '');
309
+ return /unable to (get|verify)|self[- ]signed certificate|certificate has expired|CERT_/i.test(message);
310
+ }
311
+ /** Guidance appended to connection errors caused by an untrusted certificate. */
312
+ export const CERTIFICATE_TRUST_HINT = 'The certificate is not trusted by this process. Point "n8n.tls.certificateAuthorities" '
313
+ + '(or the NODE_EXTRA_CA_CERTS environment variable) at the PEM bundle holding your root CA, then retry. '
314
+ + 'The VS Code extension host cannot read Node\'s --use-system-ca flag, so the setting is the reliable path there.';
315
+ /**
316
+ * The same guidance for someone running `n8nac` in a terminal.
317
+ *
318
+ * Deliberately not {@link CERTIFICATE_TRUST_HINT}: that one points at the
319
+ * `n8n.tls.certificateAuthorities` VS Code setting and explains extension-host behaviour, and
320
+ * neither exists on the command line — following it would send a CLI user to a setting they
321
+ * have no way to set. The environment variables are the CLI's actual levers, and
322
+ * `N8NAC_EXTRA_CA_CERTS` is named first because it accepts several paths while Node's own
323
+ * variable takes exactly one.
324
+ */
325
+ export const CERTIFICATE_TRUST_HINT_CLI = 'The certificate presented by the n8n instance is not trusted by this process. Point '
326
+ + `${N8NAC_EXTRA_CA_CERTS_ENV} (accepts several paths) or NODE_EXTRA_CA_CERTS at the PEM bundle `
327
+ + 'holding your root CA, then retry. If the instance is genuinely only reachable over a '
328
+ + `self-signed certificate and you accept the risk, set ${N8NAC_INSECURE_TLS_ENV}=1 to skip verification.`;
329
+ //# sourceMappingURL=tls-certificates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls-certificates.js","sourceRoot":"","sources":["../../../src/core/services/tls-certificates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Rewrites a path to POSIX separators.
3
+ *
4
+ * Workflow paths are stored POSIX-style in `.n8n-state.json` so a repository
5
+ * checked out on Windows and on Linux produces the same state file.
6
+ */
7
+ export declare function toPosixRelativePath(value: string): string;
8
+ /**
9
+ * Normalises a workflow path relative to the workflows directory and rejects
10
+ * anything that could escape it.
11
+ *
12
+ * @param value Path as written by a user, a state file, or the CLI.
13
+ * @returns The normalised POSIX-relative path.
14
+ * @throws If the path is empty, absolute, climbs above the root, or contains a
15
+ * control character — all of which would let a crafted state file or filename
16
+ * write outside the sync scope.
17
+ */
18
+ export declare function normalizeWorkflowRelativePath(value: string): string;
19
+ /**
20
+ * Resolves a workflow-relative path against the workflows directory.
21
+ *
22
+ * Validates before joining, so this is the only sanctioned way to turn a stored
23
+ * filename into an absolute path.
24
+ *
25
+ * @param root Absolute path of the workflows directory.
26
+ * @param relativePath Workflow-relative path (nested paths allowed).
27
+ */
28
+ export declare function workflowRelativePathToAbsolute(root: string, relativePath: string): string;
29
+ /**
30
+ * Inverse of {@link workflowRelativePathToAbsolute}: expresses an absolute path
31
+ * as a validated workflow-relative one.
32
+ *
33
+ * @throws If the file lies outside `root`.
34
+ */
35
+ export declare function relativePathFromAbsolute(root: string, absolutePath: string): string;
36
+ /**
37
+ * Creates the parent directory of `filePath` if it is missing.
38
+ *
39
+ * Needed since workflows can live in nested folders: the first pull or push of
40
+ * `Reports/Weekly/summary.workflow.ts` has to create `Reports/Weekly` first.
41
+ */
42
+ export declare function ensureParentDirectory(filePath: string): void;
43
+ /**
44
+ * Lists every `*.workflow.ts` file under `root`, recursively.
45
+ *
46
+ * Dot-prefixed entries are skipped, so `.n8n-state.json` and `.git` never show
47
+ * up. Results are workflow-relative, normalised, and sorted for deterministic
48
+ * ordering across platforms.
49
+ *
50
+ * Synchronous by design — it runs inside the tracker's synchronous scan path.
51
+ * Fine for the hundreds of workflows a project realistically holds.
52
+ *
53
+ * @returns Sorted workflow-relative paths; empty when `root` does not exist.
54
+ */
55
+ export declare function listWorkflowFilesRecursive(root: string): string[];
56
+ //# sourceMappingURL=workflow-path-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-path-utils.d.ts","sourceRoot":"","sources":["../../../src/core/services/workflow-path-utils.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAanE;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAGzF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAGnF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBjE"}
@@ -0,0 +1,102 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Rewrites a path to POSIX separators.
5
+ *
6
+ * Workflow paths are stored POSIX-style in `.n8n-state.json` so a repository
7
+ * checked out on Windows and on Linux produces the same state file.
8
+ */
9
+ export function toPosixRelativePath(value) {
10
+ return value.split(path.sep).join('/').replace(/\\/g, '/');
11
+ }
12
+ /**
13
+ * Normalises a workflow path relative to the workflows directory and rejects
14
+ * anything that could escape it.
15
+ *
16
+ * @param value Path as written by a user, a state file, or the CLI.
17
+ * @returns The normalised POSIX-relative path.
18
+ * @throws If the path is empty, absolute, climbs above the root, or contains a
19
+ * control character — all of which would let a crafted state file or filename
20
+ * write outside the sync scope.
21
+ */
22
+ export function normalizeWorkflowRelativePath(value) {
23
+ const normalized = path.posix.normalize(toPosixRelativePath(value).trim());
24
+ if (!normalized || normalized === '.') {
25
+ throw new Error('Workflow path must not be empty');
26
+ }
27
+ if (normalized.startsWith('../') || normalized === '..' || path.posix.isAbsolute(normalized)) {
28
+ throw new Error(`Workflow path escapes the sync scope: ${value}`);
29
+ }
30
+ const parts = normalized.split('/');
31
+ if (parts.some((part) => !part || part === '.' || part === '..' || /[\u0000-\u001f\u007f]/.test(part))) {
32
+ throw new Error(`Workflow path contains an unsafe segment: ${value}`);
33
+ }
34
+ return normalized;
35
+ }
36
+ /**
37
+ * Resolves a workflow-relative path against the workflows directory.
38
+ *
39
+ * Validates before joining, so this is the only sanctioned way to turn a stored
40
+ * filename into an absolute path.
41
+ *
42
+ * @param root Absolute path of the workflows directory.
43
+ * @param relativePath Workflow-relative path (nested paths allowed).
44
+ */
45
+ export function workflowRelativePathToAbsolute(root, relativePath) {
46
+ const safeRelativePath = normalizeWorkflowRelativePath(relativePath);
47
+ return path.join(root, ...safeRelativePath.split('/'));
48
+ }
49
+ /**
50
+ * Inverse of {@link workflowRelativePathToAbsolute}: expresses an absolute path
51
+ * as a validated workflow-relative one.
52
+ *
53
+ * @throws If the file lies outside `root`.
54
+ */
55
+ export function relativePathFromAbsolute(root, absolutePath) {
56
+ const relative = path.relative(root, absolutePath);
57
+ return normalizeWorkflowRelativePath(toPosixRelativePath(relative));
58
+ }
59
+ /**
60
+ * Creates the parent directory of `filePath` if it is missing.
61
+ *
62
+ * Needed since workflows can live in nested folders: the first pull or push of
63
+ * `Reports/Weekly/summary.workflow.ts` has to create `Reports/Weekly` first.
64
+ */
65
+ export function ensureParentDirectory(filePath) {
66
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
67
+ }
68
+ /**
69
+ * Lists every `*.workflow.ts` file under `root`, recursively.
70
+ *
71
+ * Dot-prefixed entries are skipped, so `.n8n-state.json` and `.git` never show
72
+ * up. Results are workflow-relative, normalised, and sorted for deterministic
73
+ * ordering across platforms.
74
+ *
75
+ * Synchronous by design — it runs inside the tracker's synchronous scan path.
76
+ * Fine for the hundreds of workflows a project realistically holds.
77
+ *
78
+ * @returns Sorted workflow-relative paths; empty when `root` does not exist.
79
+ */
80
+ export function listWorkflowFilesRecursive(root) {
81
+ const results = [];
82
+ const visit = (dir, relativeDir = '') => {
83
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
84
+ for (const entry of entries) {
85
+ if (entry.name.startsWith('.'))
86
+ continue;
87
+ const childRelative = relativeDir ? `${relativeDir}/${entry.name}` : entry.name;
88
+ const childAbsolute = path.join(dir, entry.name);
89
+ if (entry.isDirectory()) {
90
+ visit(childAbsolute, childRelative);
91
+ continue;
92
+ }
93
+ if (entry.isFile() && entry.name.endsWith('.workflow.ts')) {
94
+ results.push(normalizeWorkflowRelativePath(childRelative));
95
+ }
96
+ }
97
+ };
98
+ if (fs.existsSync(root))
99
+ visit(root);
100
+ return results.sort();
101
+ }
102
+ //# sourceMappingURL=workflow-path-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-path-utils.js","sourceRoot":"","sources":["../../../src/core/services/workflow-path-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC7C,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAAC,KAAa;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3E,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,UAAU,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3F,MAAM,IAAI,KAAK,CAAC,yCAAyC,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACrG,MAAM,IAAI,KAAK,CAAC,6CAA6C,KAAK,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,UAAU,CAAC;AACtB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,8BAA8B,CAAC,IAAY,EAAE,YAAoB;IAC7E,MAAM,gBAAgB,GAAG,6BAA6B,CAAC,YAAY,CAAC,CAAC;IACrE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY,EAAE,YAAoB;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACnD,OAAO,6BAA6B,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IAClD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACnD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,CAAC,GAAW,EAAE,WAAW,GAAG,EAAE,EAAE,EAAE;QAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YACzC,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YAChF,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACtB,KAAK,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;gBACpC,SAAS;YACb,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,aAAa,CAAC,CAAC,CAAC;YAC/D,CAAC;QACL,CAAC;IACL,CAAC,CAAC;IACF,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC"}
@@ -20,6 +20,8 @@ export declare class WorkflowStateTracker extends EventEmitter {
20
20
  private ignoredTags;
21
21
  private projectId;
22
22
  private stateFilePath;
23
+ private folderSync;
24
+ private warnedFolderMetadataUnavailable;
23
25
  private isConnected;
24
26
  /** True during the first refreshRemoteState() call — suppresses status broadcasts */
25
27
  private isInitialRemoteLoad;
@@ -36,11 +38,14 @@ export declare class WorkflowStateTracker extends EventEmitter {
36
38
  private remoteActive;
37
39
  /** Remote archived flag per workflow (populated by refreshRemoteState / updateSingleRemoteState). */
38
40
  private remoteArchived;
41
+ private remoteParentFolderIds;
42
+ private remoteFolderPaths;
39
43
  constructor(client: N8nApiClient, options: {
40
44
  directory: string;
41
45
  syncInactive: boolean;
42
46
  ignoredTags: string[];
43
47
  projectId: string;
48
+ folderSync?: boolean;
44
49
  });
45
50
  getDirectory(): string;
46
51
  getFilenameForId(id: string): string | undefined;
@@ -89,6 +94,22 @@ export declare class WorkflowStateTracker extends EventEmitter {
89
94
  calculateStatus(filename: string, workflowId?: string): WorkflowSyncStatus;
90
95
  private shouldIgnore;
91
96
  private safeName;
97
+ /**
98
+ * Builds the resolver that turns a remote workflow's folder into local path
99
+ * segments — when n8n tells us what that folder is.
100
+ *
101
+ * As of n8n 2.32 it does not: `parentFolderId` is declared `writeOnly` in the
102
+ * public API spec, the read handlers never load the `parentFolder` relation,
103
+ * and no endpoint maps workflows to folders. This holds on every edition,
104
+ * Enterprise included, so pull lays workflows out flat and this returns null.
105
+ *
106
+ * The detection is deliberately based on the payload rather than a version
107
+ * check: the day a workflow read carries folder fields, nested pulls start
108
+ * working with no change here.
109
+ */
110
+ private createFolderResolver;
111
+ private warnFolderMetadataUnavailable;
112
+ private buildRelativeFilename;
92
113
  /**
93
114
  * Find local file that contains a specific workflow ID
94
115
  * Used when we have an ID but no filename mapping yet (e.g., after file rename)
@@ -115,6 +136,41 @@ export declare class WorkflowStateTracker extends EventEmitter {
115
136
  includeArchived?: boolean;
116
137
  onlyArchived?: boolean;
117
138
  }): Promise<IWorkflowStatus[]>;
139
+ /**
140
+ * Cheap drift computation for the lightweight `list` path.
141
+ *
142
+ * Single source of truth (SSOT) for the "did either side change since last sync?"
143
+ * question when a remote hash is not yet cached (i.e. before `n8nac fetch <id>`
144
+ * runs the expensive per-workflow hash roundtrip).
145
+ *
146
+ * Returns `undefined` when there is no reference state for the workflow
147
+ * (never pulled / first sync), so consumers can distinguish "no drift known"
148
+ * from "drift checked and nothing changed". Within the returned object each
149
+ * axis is likewise `undefined` when its input is missing, so an absent axis
150
+ * reads as "unknown" and never as "unchanged".
151
+ *
152
+ * Cost: O(1) Map lookups, one string compare and one timestamp parse. No AST,
153
+ * no I/O, no extra API calls.
154
+ * The data sources are already populated by the existing lightweight refresh:
155
+ * - `localHashes[filename]` - populated by `refreshLocalState`
156
+ * - `state.workflows[id]` - read from `.n8n-state.json`
157
+ * - `remoteTimestamp` - returned by `/api/v1/workflows` (now cached by
158
+ * `refreshRemoteState` into `remoteTimestamps`)
159
+ */
160
+ private computeDrift;
161
+ /**
162
+ * True when the remote `updatedAt` is strictly newer than the recorded `lastSyncedAt`.
163
+ *
164
+ * `lastSyncedAt` is normally a verbatim copy of the remote `updatedAt` (see
165
+ * `updateWorkflowState`), so both sides usually share the same representation and
166
+ * equality means "in sync". They can still diverge in format — the fallback in
167
+ * `updateWorkflowState` writes a client-side `new Date().toISOString()` when the API
168
+ * response carried no `updatedAt`, and n8n instances differ in how they serialise
169
+ * timestamps. A lexical compare across two formats misreports silently (`' '` < `'T'`
170
+ * makes a space-separated timestamp always look older), so compare parsed instants,
171
+ * consistent with the existing remote-change guard in `sync-engine.ts`.
172
+ */
173
+ private isNewerThan;
118
174
  /**
119
175
  * Get list of local workflow filenames (just checks file system, no parsing)
120
176
  */
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-state-tracker.d.ts","sourceRoot":"","sources":["../../../src/core/services/workflow-state-tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-state-tracker.d.ts","sourceRoot":"","sources":["../../../src/core/services/workflow-state-tracker.ts"],"names":[],"mappings":"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"}