n8n-nodes-mautic-advanced 1.3.7 → 1.3.9
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.
|
@@ -3,6 +3,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runtimeZod = exports.RuntimeDynamicStructuredTool = void 0;
|
|
4
4
|
// nodes/MauticAdvanced/ai-tools/runtime.ts
|
|
5
5
|
const module_1 = require("module");
|
|
6
|
+
/**
|
|
7
|
+
* Anchor candidates — packages in n8n's dependency tree that can serve as a
|
|
8
|
+
* createRequire() anchor to resolve @langchain/core/tools and zod from n8n's
|
|
9
|
+
* own module tree (not this package's bundled devDependency copies).
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT: resolution must NEVER run at module-import time. n8n's
|
|
12
|
+
* node-directory-loader requires every node file in this package (including
|
|
13
|
+
* this one) purely to register node metadata, long before any workflow
|
|
14
|
+
* executes — and it aborts loading the ENTIRE package if any one file throws
|
|
15
|
+
* while being required. That used to be exactly what happened here: under
|
|
16
|
+
* pnpm-strict-isolated n8n installs (v2.29.x+) this package is installed
|
|
17
|
+
* outside n8n's own node_modules tree (e.g. ~/.n8n/nodes/), so neither
|
|
18
|
+
* anchor below resolves at all — @langchain/classic/@langchain/core are only
|
|
19
|
+
* reachable from inside @n8n/n8n-nodes-langchain's own isolated pnpm
|
|
20
|
+
* subtree, which no filesystem-based require.resolve() from here can walk
|
|
21
|
+
* into. The resulting throw took down the plain, non-AI `mauticAdvanced`
|
|
22
|
+
* node and its trigger too, not just this AI-tools node.
|
|
23
|
+
*
|
|
24
|
+
* Resolution is therefore deferred to first actual use, inside the Proxy
|
|
25
|
+
* traps below (which only fire when a connected AI tool is invoked at
|
|
26
|
+
* workflow-execution time via supplyData()). By then, n8n's own Agent/MCP
|
|
27
|
+
* Trigger machinery has already loaded @langchain/core/tools itself (to run
|
|
28
|
+
* its own tool-calling logic), so if the anchors still don't resolve, a
|
|
29
|
+
* require.cache scan finds the exact module instance n8n itself loaded —
|
|
30
|
+
* which works regardless of install layout.
|
|
31
|
+
*/
|
|
6
32
|
const ANCHOR_CANDIDATES = [
|
|
7
33
|
// primary: @langchain/classic is a direct dep of @n8n/nodes-langchain, stable since n8n 2.4.x.
|
|
8
34
|
// Its @langchain/core peerDep resolves to n8n's hoisted @langchain/core.
|
|
@@ -10,25 +36,224 @@ const ANCHOR_CANDIDATES = [
|
|
|
10
36
|
// secondary: langchain package is in the n8n catalog and also has @langchain/core as peerDep.
|
|
11
37
|
'langchain/agents',
|
|
12
38
|
];
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
39
|
+
// Memoized ONLY on success — a failed attempt must not permanently disable
|
|
40
|
+
// retries (e.g. the require.cache scan fallback below may only succeed on a
|
|
41
|
+
// later call, once n8n has finished loading its own langchain-dependent
|
|
42
|
+
// nodes).
|
|
43
|
+
let _runtimeReq;
|
|
44
|
+
let _anchorDiagnostic = null;
|
|
45
|
+
function getRuntimeRequire() {
|
|
46
|
+
if (_runtimeReq)
|
|
47
|
+
return _runtimeReq;
|
|
48
|
+
const tried = [];
|
|
49
|
+
for (const candidate of ANCHOR_CANDIDATES) {
|
|
50
|
+
try {
|
|
51
|
+
const resolved = require.resolve(candidate);
|
|
52
|
+
_runtimeReq = (0, module_1.createRequire)(resolved);
|
|
53
|
+
_anchorDiagnostic = `resolved via anchor: ${candidate}`;
|
|
54
|
+
return _runtimeReq;
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
tried.push(`${candidate}: ${e.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
_anchorDiagnostic = `Could not resolve LangChain anchor. Tried:\n${tried.join('\n')}`;
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Scans Node's process-global module cache (shared across every node_modules
|
|
65
|
+
* tree in this process, regardless of who loaded what) for an already-loaded
|
|
66
|
+
* module whose resolved path matches `pathPattern`, returning the first
|
|
67
|
+
* match whose exports satisfy `validate`. Must be called lazily (not at
|
|
68
|
+
* module load) — n8n requires node files for registration before any
|
|
69
|
+
* workflow runs, i.e. before langchain/zod are necessarily loaded into cache.
|
|
70
|
+
*/
|
|
71
|
+
function findCachedExports(pathPattern, validate, excludeKey) {
|
|
19
72
|
try {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
73
|
+
// require.cache is the public, documented CommonJS alias that points at the exact
|
|
74
|
+
// same underlying object as the internal Module._cache. It is available directly in
|
|
75
|
+
// CJS module scope (this file compiles to CJS via tsc), so no require('module') needed.
|
|
76
|
+
const cache = require.cache;
|
|
77
|
+
if (!cache)
|
|
78
|
+
return undefined;
|
|
79
|
+
for (const key of Object.keys(cache)) {
|
|
80
|
+
if (!pathPattern.test(key))
|
|
81
|
+
continue;
|
|
82
|
+
if (excludeKey && excludeKey(key))
|
|
83
|
+
continue;
|
|
84
|
+
const entry = cache[key];
|
|
85
|
+
if (!entry)
|
|
86
|
+
continue;
|
|
87
|
+
const result = validate(entry.exports);
|
|
88
|
+
if (result !== undefined)
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (_e) {
|
|
93
|
+
// best-effort — require.cache introspection is not guaranteed across Node versions
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
let _RuntimeDynamicStructuredTool;
|
|
98
|
+
let _runtimeZod;
|
|
99
|
+
let _langchainLoadError = null;
|
|
100
|
+
let _zodLoadError = null;
|
|
101
|
+
let _zodDiagnostic = null;
|
|
102
|
+
function resolveDynamicStructuredTool() {
|
|
103
|
+
if (_RuntimeDynamicStructuredTool)
|
|
104
|
+
return _RuntimeDynamicStructuredTool;
|
|
105
|
+
const runtimeReq = getRuntimeRequire();
|
|
106
|
+
if (runtimeReq) {
|
|
107
|
+
try {
|
|
108
|
+
const coreTools = runtimeReq('@langchain/core/tools');
|
|
109
|
+
if (typeof coreTools?.['DynamicStructuredTool'] === 'function') {
|
|
110
|
+
_RuntimeDynamicStructuredTool = coreTools['DynamicStructuredTool'];
|
|
111
|
+
return _RuntimeDynamicStructuredTool;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
_langchainLoadError = e.message;
|
|
116
|
+
}
|
|
23
117
|
}
|
|
24
|
-
|
|
25
|
-
|
|
118
|
+
// Fallback for pnpm-isolated installs where no filesystem anchor reaches
|
|
119
|
+
// @langchain/core at all: it is loaded by n8n's own Agent/MCP Trigger
|
|
120
|
+
// machinery before our supplyData() ever runs, so grab it straight out of
|
|
121
|
+
// require.cache once it is resident.
|
|
122
|
+
const cached = findCachedExports(/[\\/]@langchain[\\/]core[\\/]/, (exports) => typeof exports['DynamicStructuredTool'] === 'function'
|
|
123
|
+
? exports['DynamicStructuredTool']
|
|
124
|
+
: undefined);
|
|
125
|
+
if (cached) {
|
|
126
|
+
_RuntimeDynamicStructuredTool = cached;
|
|
127
|
+
_langchainLoadError = null;
|
|
26
128
|
}
|
|
129
|
+
return _RuntimeDynamicStructuredTool;
|
|
27
130
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
131
|
+
function resolveZod() {
|
|
132
|
+
if (_runtimeZod)
|
|
133
|
+
return _runtimeZod;
|
|
134
|
+
// Three-step resolution, in priority order: require.main → anchor → require.cache scan.
|
|
135
|
+
//
|
|
136
|
+
// Primary path: resolve zod starting from n8n's own main entry point's module tree
|
|
137
|
+
// (require.main). For a correctly-installed (non-isolated) setup this lands on n8n's
|
|
138
|
+
// top-level zod — the exact copy n8n's own normalizeToolSchema does `instanceof ZodType`
|
|
139
|
+
// against. Even under pnpm-strict isolation this is a DIFFERENT resolution path than this
|
|
140
|
+
// package's own local require('zod'), so it is far more likely to reach n8n's real copy
|
|
141
|
+
// (or fail cleanly) than to silently return this package's OWN bundled zod. Resolved
|
|
142
|
+
// lazily here (NOT at module top level) so node registration never triggers it — that
|
|
143
|
+
// laziness is the entire point of this fix (#2).
|
|
144
|
+
//
|
|
145
|
+
// Only anchor at require.main when it is actually defined. When it is undefined (ESM-
|
|
146
|
+
// launched n8n, worker_threads / queue-mode workers — exactly the deployment mode #2 was
|
|
147
|
+
// filed against), there is NO useful main to anchor at: falling back to `__filename` would
|
|
148
|
+
// anchor at THIS file (mautic's own runtime.js), whose `require.resolve('zod')` lands on
|
|
149
|
+
// this package's OWN bundled zod — the copy that fails n8n's `instanceof ZodType` check.
|
|
150
|
+
// So resolve-then-check the path and skip it if it points into this package's own tree,
|
|
151
|
+
// reusing the same exclusion substring as the cache-scan path below.
|
|
152
|
+
if (require.main?.filename) {
|
|
153
|
+
try {
|
|
154
|
+
const mainReq = (0, module_1.createRequire)(require.main.filename);
|
|
155
|
+
const resolvedPath = mainReq.resolve('zod');
|
|
156
|
+
if (!resolvedPath.includes('n8n-nodes-mautic-advanced')) {
|
|
157
|
+
_runtimeZod = mainReq('zod');
|
|
158
|
+
if (_runtimeZod) {
|
|
159
|
+
_zodDiagnostic = 'resolved zod via require.main';
|
|
160
|
+
_zodLoadError = null;
|
|
161
|
+
return _runtimeZod;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
_zodLoadError = e.message;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Secondary path: the existing @langchain/classic / langchain anchor. Same resolve-then-
|
|
170
|
+
// check exclusion for defense-in-depth consistency — very unlikely to ever resolve into
|
|
171
|
+
// this package's own tree, but structurally guarded identically to the other two paths.
|
|
172
|
+
const runtimeReq = getRuntimeRequire();
|
|
173
|
+
if (runtimeReq) {
|
|
174
|
+
try {
|
|
175
|
+
const resolvedPath = runtimeReq.resolve('zod');
|
|
176
|
+
if (!resolvedPath.includes('n8n-nodes-mautic-advanced')) {
|
|
177
|
+
_runtimeZod = runtimeReq('zod');
|
|
178
|
+
if (_runtimeZod) {
|
|
179
|
+
_zodDiagnostic = 'resolved zod via anchor';
|
|
180
|
+
_zodLoadError = null;
|
|
181
|
+
return _runtimeZod;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
_zodLoadError = e.message;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Tertiary path: scan require.cache for an already-resident zod once neither
|
|
190
|
+
// filesystem resolution reaches it (pnpm-strict-isolated installs). The path regex is
|
|
191
|
+
// narrowed to zod's own entry-point directories (lib/dist/index/v3/v4) so it never
|
|
192
|
+
// matches zod-adjacent package names (e.g. zod-to-json-schema). Validate the exports
|
|
193
|
+
// look like zod via `ZodType` (the class n8n's normalizeToolSchema does `instanceof`
|
|
194
|
+
// against — the meaningful correctness signal) plus the `object` factory our
|
|
195
|
+
// schema-generator calls.
|
|
196
|
+
//
|
|
197
|
+
// Exclusion guard: this package declares zod as a REAL dependency and imports it at
|
|
198
|
+
// node-registration time (schema-generator.ts), so this package's OWN bundled zod is
|
|
199
|
+
// ALWAYS resident in require.cache — potentially earlier in iteration order than n8n's.
|
|
200
|
+
// We specifically want a DIFFERENT copy (n8n's), because a self-bundled copy would fail
|
|
201
|
+
// n8n's `instanceof ZodType` class-identity check. So skip any cache key belonging to
|
|
202
|
+
// this package's own bundled zod. (The pathPattern has already matched the zod segment,
|
|
203
|
+
// so a package-name match on the key is sufficient and robust to both nested
|
|
204
|
+
// `.../n8n-nodes-mautic-advanced/node_modules/zod/...` and flatter install layouts.)
|
|
205
|
+
const cached = findCachedExports(/[\\/]zod[\\/](lib|dist|index|v3|v4)/, (exports) => typeof exports['ZodType'] === 'function' && typeof exports['object'] === 'function'
|
|
206
|
+
? exports
|
|
207
|
+
: undefined, (key) => key.includes('n8n-nodes-mautic-advanced'));
|
|
208
|
+
if (cached) {
|
|
209
|
+
_runtimeZod = cached;
|
|
210
|
+
_zodLoadError = null;
|
|
211
|
+
_zodDiagnostic = 'resolved zod via require.cache scan (pnpm-isolated install)';
|
|
212
|
+
}
|
|
213
|
+
return _runtimeZod;
|
|
31
214
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
215
|
+
// IMPORTANT: Proxy target MUST be `function () {}`, not `{}`.
|
|
216
|
+
// ECMAScript spec §10.5.13: a Proxy only has [[Construct]] if its target does.
|
|
217
|
+
// Plain objects lack [[Construct]], so `new Proxy({}, ...)` throws
|
|
218
|
+
// "is not a constructor" before the construct trap ever fires.
|
|
219
|
+
exports.RuntimeDynamicStructuredTool = new Proxy(function () { }, {
|
|
220
|
+
construct(_target, args) {
|
|
221
|
+
const ctor = resolveDynamicStructuredTool();
|
|
222
|
+
if (!ctor) {
|
|
223
|
+
throw new Error(`[MauticAdvancedAiTools] Could not resolve LangChain's DynamicStructuredTool. ` +
|
|
224
|
+
`Ensure @n8n/nodes-langchain is installed in n8n's node_modules.` +
|
|
225
|
+
(_anchorDiagnostic ? ` Diagnostic: ${_anchorDiagnostic}` : '') +
|
|
226
|
+
(_langchainLoadError ? ` Load error: ${_langchainLoadError}` : ''));
|
|
227
|
+
}
|
|
228
|
+
return new ctor(...args);
|
|
229
|
+
},
|
|
230
|
+
get(_target, prop) {
|
|
231
|
+
const ctor = resolveDynamicStructuredTool();
|
|
232
|
+
if (ctor) {
|
|
233
|
+
return ctor[prop];
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
exports.runtimeZod = new Proxy({}, {
|
|
239
|
+
get(_target, prop) {
|
|
240
|
+
// Guard: frameworks probe Symbol.toPrimitive, Symbol.toStringTag, .then
|
|
241
|
+
// (Promise thenable), and .constructor. Throwing on these causes
|
|
242
|
+
// misleading errors during structural inspection.
|
|
243
|
+
if (typeof prop === 'symbol' || prop === 'then' || prop === 'constructor')
|
|
244
|
+
return undefined;
|
|
245
|
+
const z = resolveZod();
|
|
246
|
+
if (!z) {
|
|
247
|
+
throw new Error(`[MauticAdvancedAiTools] Could not resolve zod (accessing .${String(prop)}) ` +
|
|
248
|
+
`via require.main, LangChain anchor, or require.cache scan. ` +
|
|
249
|
+
`Ensure @n8n/nodes-langchain is installed in n8n's node_modules.` +
|
|
250
|
+
(_zodDiagnostic
|
|
251
|
+
? ` Diagnostic: ${_zodDiagnostic}`
|
|
252
|
+
: _anchorDiagnostic
|
|
253
|
+
? ` Diagnostic: ${_anchorDiagnostic}`
|
|
254
|
+
: '') +
|
|
255
|
+
(_zodLoadError ? ` Load error: ${_zodLoadError}` : ''));
|
|
256
|
+
}
|
|
257
|
+
return z[prop];
|
|
258
|
+
},
|
|
259
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-mautic-advanced",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.9",
|
|
4
4
|
"description": "Enhanced n8n node for Mautic with comprehensive API coverage including tags, campaigns, categories, and advanced contact management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n",
|
|
@@ -72,5 +72,13 @@
|
|
|
72
72
|
"@types/change-case": "^0.0.30",
|
|
73
73
|
"change-case": "^5.4.4",
|
|
74
74
|
"zod": "^3.22.0"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"@langchain/core": "*"
|
|
78
|
+
},
|
|
79
|
+
"peerDependenciesMeta": {
|
|
80
|
+
"@langchain/core": {
|
|
81
|
+
"optional": true
|
|
82
|
+
}
|
|
75
83
|
}
|
|
76
84
|
}
|