n8n-nodes-redactor 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +42 -0
- package/README.dev.md +153 -0
- package/README.md +443 -0
- package/README.npm.md +443 -0
- package/dist/nodes/PiiRedactor/PiiRedactor.node.d.ts +5 -0
- package/dist/nodes/PiiRedactor/PiiRedactor.node.js +1093 -0
- package/dist/nodes/PiiRedactor/__tests__/encryption.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/encryption.test.js +200 -0
- package/dist/nodes/PiiRedactor/__tests__/engine.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/engine.test.js +524 -0
- package/dist/nodes/PiiRedactor/__tests__/operations.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/operations.test.js +316 -0
- package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.js +427 -0
- package/dist/nodes/PiiRedactor/__tests__/patterns.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/patterns.test.js +481 -0
- package/dist/nodes/PiiRedactor/__tests__/phase1.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/phase1.test.js +343 -0
- package/dist/nodes/PiiRedactor/__tests__/phase3.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/phase3.test.js +275 -0
- package/dist/nodes/PiiRedactor/__tests__/phase4.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/phase4.test.js +184 -0
- package/dist/nodes/PiiRedactor/__tests__/presidio.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/presidio.test.js +170 -0
- package/dist/nodes/PiiRedactor/__tests__/security.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/security.test.js +178 -0
- package/dist/nodes/PiiRedactor/__tests__/semantic.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/semantic.test.js +319 -0
- package/dist/nodes/PiiRedactor/__tests__/vault.test.d.ts +1 -0
- package/dist/nodes/PiiRedactor/__tests__/vault.test.js +247 -0
- package/dist/nodes/PiiRedactor/audit.d.ts +48 -0
- package/dist/nodes/PiiRedactor/audit.js +192 -0
- package/dist/nodes/PiiRedactor/classification.d.ts +33 -0
- package/dist/nodes/PiiRedactor/classification.js +118 -0
- package/dist/nodes/PiiRedactor/context.d.ts +57 -0
- package/dist/nodes/PiiRedactor/context.js +260 -0
- package/dist/nodes/PiiRedactor/encryption.d.ts +45 -0
- package/dist/nodes/PiiRedactor/encryption.js +158 -0
- package/dist/nodes/PiiRedactor/engine.d.ts +23 -0
- package/dist/nodes/PiiRedactor/engine.js +888 -0
- package/dist/nodes/PiiRedactor/injection.d.ts +46 -0
- package/dist/nodes/PiiRedactor/injection.js +425 -0
- package/dist/nodes/PiiRedactor/names.d.ts +25 -0
- package/dist/nodes/PiiRedactor/names.js +188 -0
- package/dist/nodes/PiiRedactor/patterns.d.ts +17 -0
- package/dist/nodes/PiiRedactor/patterns.js +1742 -0
- package/dist/nodes/PiiRedactor/presidio.d.ts +77 -0
- package/dist/nodes/PiiRedactor/presidio.js +264 -0
- package/dist/nodes/PiiRedactor/profiles.d.ts +47 -0
- package/dist/nodes/PiiRedactor/profiles.js +139 -0
- package/dist/nodes/PiiRedactor/pseudonymize.d.ts +20 -0
- package/dist/nodes/PiiRedactor/pseudonymize.js +203 -0
- package/dist/nodes/PiiRedactor/redact.png +0 -0
- package/dist/nodes/PiiRedactor/redact.svg +3 -0
- package/dist/nodes/PiiRedactor/ropa.d.ts +63 -0
- package/dist/nodes/PiiRedactor/ropa.js +70 -0
- package/dist/nodes/PiiRedactor/types.d.ts +82 -0
- package/dist/nodes/PiiRedactor/types.js +3 -0
- package/dist/nodes/PiiRedactor/vault.d.ts +61 -0
- package/dist/nodes/PiiRedactor/vault.js +352 -0
- package/package.json +87 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FileVault = exports.MemoryVault = void 0;
|
|
37
|
+
exports.createVault = createVault;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const crypto = __importStar(require("crypto"));
|
|
41
|
+
const encryption_1 = require("./encryption");
|
|
42
|
+
// ═══════════════════════════════════════════════════════════
|
|
43
|
+
// In-memory vault
|
|
44
|
+
// ═══════════════════════════════════════════════════════════
|
|
45
|
+
const memoryStore = new Map();
|
|
46
|
+
const reverseIndex = new Map();
|
|
47
|
+
const MAX_SESSIONS = 1000; // Prevent unbounded memory growth
|
|
48
|
+
class MemoryVault {
|
|
49
|
+
getOrCreateSession(sessionId, ttl) {
|
|
50
|
+
// Auto-cleanup expired sessions on every create to prevent memory leak
|
|
51
|
+
this.cleanup();
|
|
52
|
+
// Enforce max session limit
|
|
53
|
+
if (memoryStore.size >= MAX_SESSIONS && !memoryStore.has(sessionId)) {
|
|
54
|
+
// Evict oldest session
|
|
55
|
+
const oldest = memoryStore.keys().next().value;
|
|
56
|
+
if (oldest !== undefined) {
|
|
57
|
+
memoryStore.delete(oldest);
|
|
58
|
+
reverseIndex.delete(oldest);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!memoryStore.has(sessionId)) {
|
|
62
|
+
memoryStore.set(sessionId, {
|
|
63
|
+
sessionId,
|
|
64
|
+
entries: {},
|
|
65
|
+
createdAt: new Date().toISOString(),
|
|
66
|
+
ttl,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return memoryStore.get(sessionId);
|
|
70
|
+
}
|
|
71
|
+
getSession(sessionId) {
|
|
72
|
+
const session = memoryStore.get(sessionId);
|
|
73
|
+
if (!session)
|
|
74
|
+
return null;
|
|
75
|
+
// Check expiry
|
|
76
|
+
if (session.ttl > 0) {
|
|
77
|
+
const created = new Date(session.createdAt).getTime();
|
|
78
|
+
if (Date.now() - created > session.ttl) {
|
|
79
|
+
memoryStore.delete(sessionId);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return session;
|
|
84
|
+
}
|
|
85
|
+
addEntry(sessionId, entry) {
|
|
86
|
+
const session = memoryStore.get(sessionId);
|
|
87
|
+
if (session) {
|
|
88
|
+
session.entries[entry.token] = entry;
|
|
89
|
+
// Maintain reverse lookup index for O(1) dedup
|
|
90
|
+
if (!reverseIndex.has(sessionId))
|
|
91
|
+
reverseIndex.set(sessionId, new Map());
|
|
92
|
+
reverseIndex.get(sessionId).set(entry.original, entry);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
findByOriginal(sessionId, original) {
|
|
96
|
+
// O(1) lookup via reverse index instead of O(n) scan
|
|
97
|
+
const index = reverseIndex.get(sessionId);
|
|
98
|
+
if (index) {
|
|
99
|
+
const entry = index.get(original);
|
|
100
|
+
if (entry)
|
|
101
|
+
return entry;
|
|
102
|
+
}
|
|
103
|
+
// Fallback to linear scan (for sessions loaded without index)
|
|
104
|
+
const session = memoryStore.get(sessionId);
|
|
105
|
+
if (!session)
|
|
106
|
+
return undefined;
|
|
107
|
+
return Object.values(session.entries).find((e) => e.original === original);
|
|
108
|
+
}
|
|
109
|
+
deleteSession(sessionId) {
|
|
110
|
+
memoryStore.delete(sessionId);
|
|
111
|
+
reverseIndex.delete(sessionId);
|
|
112
|
+
}
|
|
113
|
+
listSessions() {
|
|
114
|
+
return Array.from(memoryStore.values()).map((s) => ({
|
|
115
|
+
sessionId: s.sessionId,
|
|
116
|
+
entryCount: Object.keys(s.entries).length,
|
|
117
|
+
createdAt: s.createdAt,
|
|
118
|
+
ttl: s.ttl,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
save() {
|
|
122
|
+
// No-op for memory vault
|
|
123
|
+
}
|
|
124
|
+
cleanup() {
|
|
125
|
+
let removed = 0;
|
|
126
|
+
const now = Date.now();
|
|
127
|
+
for (const [id, session] of memoryStore.entries()) {
|
|
128
|
+
if (session.ttl > 0) {
|
|
129
|
+
const created = new Date(session.createdAt).getTime();
|
|
130
|
+
if (now - created > session.ttl) {
|
|
131
|
+
memoryStore.delete(id);
|
|
132
|
+
reverseIndex.delete(id);
|
|
133
|
+
removed++;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return removed;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.MemoryVault = MemoryVault;
|
|
141
|
+
// ═══════════════════════════════════════════════════════════
|
|
142
|
+
// File-based vault (JSON files in a directory)
|
|
143
|
+
// ═══════════════════════════════════════════════════════════
|
|
144
|
+
class FileVault {
|
|
145
|
+
constructor(dir, passphrase) {
|
|
146
|
+
this.cache = new Map();
|
|
147
|
+
this.passphrase = passphrase || '';
|
|
148
|
+
this.dir = dir || path.join(process.env.HOME || '/tmp', '.n8n', 'pii-vault');
|
|
149
|
+
if (!fs.existsSync(this.dir)) {
|
|
150
|
+
fs.mkdirSync(this.dir, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
// Auto-cleanup expired files on every instantiation
|
|
153
|
+
this.cleanup();
|
|
154
|
+
}
|
|
155
|
+
filePath(sessionId) {
|
|
156
|
+
// Hash session ID for safe filenames — use 32 hex chars (128 bits) to avoid collisions
|
|
157
|
+
const hash = crypto.createHash('sha256').update(sessionId).digest('hex').slice(0, 32);
|
|
158
|
+
return path.join(this.dir, `vault_${hash}.json`);
|
|
159
|
+
}
|
|
160
|
+
load(sessionId) {
|
|
161
|
+
if (this.cache.has(sessionId)) {
|
|
162
|
+
return this.cache.get(sessionId);
|
|
163
|
+
}
|
|
164
|
+
const fp = this.filePath(sessionId);
|
|
165
|
+
if (!fs.existsSync(fp))
|
|
166
|
+
return null;
|
|
167
|
+
try {
|
|
168
|
+
const raw = fs.readFileSync(fp);
|
|
169
|
+
let jsonStr;
|
|
170
|
+
if ((0, encryption_1.isEncryptedVault)(raw)) {
|
|
171
|
+
// Encrypted file — decrypt with passphrase
|
|
172
|
+
if (!this.passphrase) {
|
|
173
|
+
// Encrypted but no passphrase — cannot read
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
jsonStr = (0, encryption_1.decryptVaultData)(raw, this.passphrase);
|
|
177
|
+
}
|
|
178
|
+
else if ((0, encryption_1.isPlaintextVault)(raw)) {
|
|
179
|
+
// Plaintext JSON — read directly
|
|
180
|
+
jsonStr = raw.toString('utf-8');
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// Unknown format
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const data = JSON.parse(jsonStr);
|
|
187
|
+
// Check expiry
|
|
188
|
+
if (data.ttl > 0) {
|
|
189
|
+
const created = new Date(data.createdAt).getTime();
|
|
190
|
+
if (Date.now() - created > data.ttl) {
|
|
191
|
+
try {
|
|
192
|
+
fs.unlinkSync(fp);
|
|
193
|
+
}
|
|
194
|
+
catch { /* ignore */ }
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
this.cache.set(sessionId, data);
|
|
199
|
+
return data;
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
getOrCreateSession(sessionId, ttl) {
|
|
206
|
+
// Auto-cleanup expired files before creating new sessions
|
|
207
|
+
this.cleanup();
|
|
208
|
+
const existing = this.load(sessionId);
|
|
209
|
+
if (existing)
|
|
210
|
+
return existing;
|
|
211
|
+
const session = {
|
|
212
|
+
sessionId,
|
|
213
|
+
entries: {},
|
|
214
|
+
createdAt: new Date().toISOString(),
|
|
215
|
+
ttl,
|
|
216
|
+
};
|
|
217
|
+
this.cache.set(sessionId, session);
|
|
218
|
+
return session;
|
|
219
|
+
}
|
|
220
|
+
getSession(sessionId) {
|
|
221
|
+
return this.load(sessionId);
|
|
222
|
+
}
|
|
223
|
+
addEntry(sessionId, entry) {
|
|
224
|
+
const session = this.cache.get(sessionId);
|
|
225
|
+
if (session) {
|
|
226
|
+
session.entries[entry.token] = entry;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
findByOriginal(sessionId, original) {
|
|
230
|
+
const session = this.cache.get(sessionId);
|
|
231
|
+
if (!session)
|
|
232
|
+
return undefined;
|
|
233
|
+
return Object.values(session.entries).find((e) => e.original === original);
|
|
234
|
+
}
|
|
235
|
+
deleteSession(sessionId) {
|
|
236
|
+
this.cache.delete(sessionId);
|
|
237
|
+
try {
|
|
238
|
+
const fp = this.filePath(sessionId);
|
|
239
|
+
if (fs.existsSync(fp)) {
|
|
240
|
+
fs.unlinkSync(fp);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Ignore file deletion errors (read-only FS, already deleted, etc.)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
listSessions() {
|
|
248
|
+
// List all vault files
|
|
249
|
+
const files = fs.readdirSync(this.dir).filter((f) => f.startsWith('vault_') && f.endsWith('.json'));
|
|
250
|
+
const sessions = [];
|
|
251
|
+
for (const file of files) {
|
|
252
|
+
try {
|
|
253
|
+
const fp = path.join(this.dir, file);
|
|
254
|
+
const raw = fs.readFileSync(fp);
|
|
255
|
+
let jsonStr;
|
|
256
|
+
if ((0, encryption_1.isEncryptedVault)(raw)) {
|
|
257
|
+
if (!this.passphrase)
|
|
258
|
+
continue; // Can't read without passphrase
|
|
259
|
+
try {
|
|
260
|
+
jsonStr = (0, encryption_1.decryptVaultData)(raw, this.passphrase);
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
continue; // Wrong passphrase or corrupted
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if ((0, encryption_1.isPlaintextVault)(raw)) {
|
|
267
|
+
jsonStr = raw.toString('utf-8');
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const data = JSON.parse(jsonStr);
|
|
273
|
+
sessions.push({
|
|
274
|
+
sessionId: data.sessionId,
|
|
275
|
+
entryCount: Object.keys(data.entries).length,
|
|
276
|
+
createdAt: data.createdAt,
|
|
277
|
+
ttl: data.ttl,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
// Skip corrupt files
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return sessions;
|
|
285
|
+
}
|
|
286
|
+
save(sessionId) {
|
|
287
|
+
const session = this.cache.get(sessionId);
|
|
288
|
+
if (session) {
|
|
289
|
+
try {
|
|
290
|
+
const fp = this.filePath(sessionId);
|
|
291
|
+
const tmpFp = fp + '.tmp';
|
|
292
|
+
const jsonData = JSON.stringify(session, null, 2);
|
|
293
|
+
if (this.passphrase) {
|
|
294
|
+
// Encrypt vault data before writing
|
|
295
|
+
const encrypted = (0, encryption_1.encryptVaultData)(jsonData, this.passphrase);
|
|
296
|
+
fs.writeFileSync(tmpFp, encrypted);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// Write plaintext JSON
|
|
300
|
+
fs.writeFileSync(tmpFp, jsonData, 'utf-8');
|
|
301
|
+
}
|
|
302
|
+
fs.renameSync(tmpFp, fp);
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// Write failed (read-only FS, permissions, disk full).
|
|
306
|
+
// Session stays in memory cache — restore will still work
|
|
307
|
+
// for this execution, just won't persist across restarts.
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
cleanup() {
|
|
312
|
+
let removed = 0;
|
|
313
|
+
const now = Date.now();
|
|
314
|
+
const files = fs.readdirSync(this.dir).filter((f) => f.startsWith('vault_') && f.endsWith('.json'));
|
|
315
|
+
for (const file of files) {
|
|
316
|
+
try {
|
|
317
|
+
const fp = path.join(this.dir, file);
|
|
318
|
+
const data = JSON.parse(fs.readFileSync(fp, 'utf-8'));
|
|
319
|
+
if (data.ttl > 0) {
|
|
320
|
+
const created = new Date(data.createdAt).getTime();
|
|
321
|
+
if (now - created > data.ttl) {
|
|
322
|
+
fs.unlinkSync(fp);
|
|
323
|
+
this.cache.delete(data.sessionId);
|
|
324
|
+
removed++;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// Skip
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return removed;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
exports.FileVault = FileVault;
|
|
336
|
+
/**
|
|
337
|
+
* Factory to get the right vault implementation.
|
|
338
|
+
* If file vault fails (read-only filesystem, no permissions, Docker, cloud),
|
|
339
|
+
* automatically falls back to memory vault so the node never crashes.
|
|
340
|
+
*/
|
|
341
|
+
function createVault(storage, vaultDir, passphrase) {
|
|
342
|
+
if (storage === 'file') {
|
|
343
|
+
try {
|
|
344
|
+
return new FileVault(vaultDir, passphrase);
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
// Filesystem not writable — fall back to memory vault silently
|
|
348
|
+
return new MemoryVault();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return new MemoryVault();
|
|
352
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-redactor",
|
|
3
|
+
"version": "3.0.1",
|
|
4
|
+
"description": "Redact, remove, mask and anonymize sensitive data before LLMs. Detect PII, personal information, emails, phones, addresses, IBAN, credit cards, names, SSN, passport, tax ID. Reversible vault restore. GDPR HIPAA CCPA DACH EU compliant. 50+ patterns. 100% local. Built by next8n.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"redactor",
|
|
9
|
+
"redact",
|
|
10
|
+
"pii",
|
|
11
|
+
"remove-data",
|
|
12
|
+
"remove-pii",
|
|
13
|
+
"data-masking",
|
|
14
|
+
"data-privacy",
|
|
15
|
+
"data-protection",
|
|
16
|
+
"anonymize",
|
|
17
|
+
"anonymization",
|
|
18
|
+
"sanitize",
|
|
19
|
+
"scrub",
|
|
20
|
+
"mask",
|
|
21
|
+
"gdpr",
|
|
22
|
+
"hipaa",
|
|
23
|
+
"ccpa",
|
|
24
|
+
"dsgvo",
|
|
25
|
+
"compliance",
|
|
26
|
+
"privacy",
|
|
27
|
+
"personal-data",
|
|
28
|
+
"sensitive-data",
|
|
29
|
+
"iban",
|
|
30
|
+
"credit-card",
|
|
31
|
+
"ssn",
|
|
32
|
+
"email",
|
|
33
|
+
"phone",
|
|
34
|
+
"address",
|
|
35
|
+
"passport",
|
|
36
|
+
"tax-id",
|
|
37
|
+
"eu",
|
|
38
|
+
"dach",
|
|
39
|
+
"european",
|
|
40
|
+
"llm",
|
|
41
|
+
"openai",
|
|
42
|
+
"claude",
|
|
43
|
+
"ai",
|
|
44
|
+
"next8n",
|
|
45
|
+
"workflow",
|
|
46
|
+
"automation"
|
|
47
|
+
],
|
|
48
|
+
"author": "Mirza Iqbal / next8n (https://next8n.com)",
|
|
49
|
+
"license": "FUCL",
|
|
50
|
+
"homepage": "https://next8n.com",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/mjmirza/n8n-nodes-redactor.git"
|
|
54
|
+
},
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/mjmirza/n8n-nodes-redactor/issues"
|
|
57
|
+
},
|
|
58
|
+
"main": "dist/nodes/PiiRedactor/PiiRedactor.node.js",
|
|
59
|
+
"types": "dist/nodes/PiiRedactor/PiiRedactor.node.d.ts",
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsc -p tsconfig.json && cp src/nodes/PiiRedactor/redact.png dist/nodes/PiiRedactor/redact.png",
|
|
62
|
+
"dev": "tsc -w -p tsconfig.json",
|
|
63
|
+
"test": "jest --no-cache",
|
|
64
|
+
"lint": "eslint src/ --ext .ts",
|
|
65
|
+
"prepublishOnly": "cp README.md README.dev.md && cp README.npm.md README.md && npm run build",
|
|
66
|
+
"postpublish": "mv README.dev.md README.md"
|
|
67
|
+
},
|
|
68
|
+
"files": [
|
|
69
|
+
"dist"
|
|
70
|
+
],
|
|
71
|
+
"n8n": {
|
|
72
|
+
"n8nNodesApiVersion": 1,
|
|
73
|
+
"nodes": [
|
|
74
|
+
"dist/nodes/PiiRedactor/PiiRedactor.node.js"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@types/jest": "^30.0.0",
|
|
79
|
+
"@types/node": "^20.0.0",
|
|
80
|
+
"jest": "^29.7.0",
|
|
81
|
+
"ts-jest": "^29.4.6",
|
|
82
|
+
"typescript": "^5.4.0"
|
|
83
|
+
},
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"n8n-workflow": "*"
|
|
86
|
+
}
|
|
87
|
+
}
|