@brainfish-ai/web-tracker 0.0.4-alpha.9 → 0.0.4-beta.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/dist/index.cjs.js +30 -0
- package/dist/index.cjs.js.gz +0 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3816 -0
- package/dist/index.js.gz +0 -0
- package/dist/index.js.map +1 -0
- package/dist/src/common/isLocal.d.ts +1 -0
- package/dist/src/index.d.ts +24 -0
- package/dist/src/record/eventBuffer.d.ts +7 -0
- package/dist/src/record/index.d.ts +16 -0
- package/dist/src/record/recorder.d.ts +41 -0
- package/dist/src/record/recordingManager.d.ts +17 -0
- package/dist/src/record/sender.d.ts +11 -0
- package/dist/src/record/stasher.d.ts +23 -0
- package/dist/src/record/timer.d.ts +11 -0
- package/dist/src/redact/built-ins/NameRedactor.d.ts +6 -0
- package/dist/src/redact/built-ins/SimpleRegexpRedactor.d.ts +10 -0
- package/dist/src/redact/built-ins/simple-regexp-patterns.d.ts +12 -0
- package/dist/src/redact/built-ins/well-known-names.d.ts +2 -0
- package/dist/src/redact/composition.d.ts +2 -0
- package/dist/src/redact/index.d.ts +10 -0
- package/dist/src/redact/types.d.ts +27 -0
- package/dist/src/redact/utils.d.ts +4 -0
- package/dist/src/screenshot/capture.d.ts +2 -0
- package/dist/src/screenshot/redact.d.ts +3 -0
- package/dist/src/screenshot/snapshot.d.ts +2 -0
- package/dist/src/setupTests.d.ts +0 -0
- package/dist/src/tracker.d.ts +9 -0
- package/dist/tracker.cjs.js +2 -0
- package/dist/tracker.cjs.js.map +1 -0
- package/dist/tracker.d.ts +1 -0
- package/dist/tracker.js +15 -0
- package/dist/tracker.js.map +1 -0
- package/package.json +14 -11
- package/index.ts +0 -2
- package/postcss.config.cjs +0 -6
- package/src/index.ts +0 -193
- package/src/setupTests.ts +0 -1
- package/src/tracker.ts +0 -31
- package/src/types.d.ts +0 -31
- package/src/utils/capture.test.ts +0 -83
- package/src/utils/capture.ts +0 -51
- package/src/utils/redact.test.ts +0 -74
- package/src/utils/redact.ts +0 -57
- package/src/utils/snapshot.ts +0 -35
- package/src/vite-env.d.ts +0 -7
- package/tailwind.config.cjs +0 -9
- package/tsconfig.json +0 -15
- package/vite.config.ts +0 -50
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { captureScreenshot } from './capture';
|
|
3
|
-
import { toPng } from 'html-to-image';
|
|
4
|
-
|
|
5
|
-
// Mock the html-to-image module
|
|
6
|
-
vi.mock('html-to-image', () => ({
|
|
7
|
-
toPng: vi.fn(),
|
|
8
|
-
}));
|
|
9
|
-
|
|
10
|
-
describe('captureScreenshot', () => {
|
|
11
|
-
let mockDomBody: HTMLElement;
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
// Create a mock DOM body
|
|
15
|
-
mockDomBody = document.createElement('div');
|
|
16
|
-
document.body.appendChild(mockDomBody);
|
|
17
|
-
|
|
18
|
-
// Mock document properties
|
|
19
|
-
vi.spyOn(document.documentElement, 'scrollHeight', 'get').mockReturnValue(1000);
|
|
20
|
-
vi.spyOn(document.documentElement, 'scrollWidth', 'get').mockReturnValue(800);
|
|
21
|
-
|
|
22
|
-
// Mock styleSheets
|
|
23
|
-
Object.defineProperty(document, 'styleSheets', {
|
|
24
|
-
value: [
|
|
25
|
-
{
|
|
26
|
-
cssRules: [
|
|
27
|
-
{ cssText: 'body { background-color: white; }' },
|
|
28
|
-
{ cssText: 'h1 { color: black; }' },
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
configurable: true,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Mock toPng function
|
|
36
|
-
vi.mocked(toPng).mockResolvedValue('mock-image-data');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
afterEach(() => {
|
|
40
|
-
document.body.removeChild(mockDomBody);
|
|
41
|
-
vi.restoreAllMocks();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should capture a screenshot of the entire page', async () => {
|
|
45
|
-
const result = await captureScreenshot(mockDomBody);
|
|
46
|
-
|
|
47
|
-
expect(result).toBe('mock-image-data');
|
|
48
|
-
expect(toPng).toHaveBeenCalledWith(mockDomBody, expect.objectContaining({
|
|
49
|
-
quality: 0.7,
|
|
50
|
-
width: 800,
|
|
51
|
-
height: 1000,
|
|
52
|
-
style: { transform: 'scale(1)' },
|
|
53
|
-
skipFonts: true,
|
|
54
|
-
cacheBust: true,
|
|
55
|
-
backgroundColor: 'white',
|
|
56
|
-
fetchRequestInit: { mode: 'cors' },
|
|
57
|
-
}));
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should handle errors when accessing stylesheet rules', async () => {
|
|
61
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
62
|
-
|
|
63
|
-
// Mock styleSheets to throw an error
|
|
64
|
-
Object.defineProperty(document, 'styleSheets', {
|
|
65
|
-
get: () => ({
|
|
66
|
-
[Symbol.iterator]: function* () {
|
|
67
|
-
yield {
|
|
68
|
-
cssRules: {
|
|
69
|
-
[Symbol.iterator]: function* () {
|
|
70
|
-
throw new Error('Access denied');
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
},
|
|
75
|
-
}),
|
|
76
|
-
configurable: true,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
await captureScreenshot(mockDomBody);
|
|
80
|
-
|
|
81
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('Error accessing stylesheet rules:', expect.any(Error));
|
|
82
|
-
});
|
|
83
|
-
});
|
package/src/utils/capture.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { toPng } from 'html-to-image';
|
|
2
|
-
|
|
3
|
-
// Function to capture a screenshot of the entire page
|
|
4
|
-
async function captureScreenshot(domBody: HTMLElement): Promise<string> {
|
|
5
|
-
const height = document.documentElement.scrollHeight;
|
|
6
|
-
const width = document.documentElement.scrollWidth;
|
|
7
|
-
|
|
8
|
-
// Collect all stylesheet rules
|
|
9
|
-
const styles = Array.from(document.styleSheets)
|
|
10
|
-
.map(styleSheet => {
|
|
11
|
-
try {
|
|
12
|
-
return Array.from(styleSheet.cssRules)
|
|
13
|
-
.map(rule => rule.cssText)
|
|
14
|
-
.join('');
|
|
15
|
-
} catch (e) {
|
|
16
|
-
console.log('Error accessing stylesheet rules:', e);
|
|
17
|
-
return '';
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
.join('\n');
|
|
21
|
-
|
|
22
|
-
// Create a new style element with all the rules
|
|
23
|
-
const styleElement = document.createElement('style');
|
|
24
|
-
styleElement.textContent = styles;
|
|
25
|
-
domBody.appendChild(styleElement);
|
|
26
|
-
|
|
27
|
-
// Capture the screenshot
|
|
28
|
-
const image = await toPng(domBody, {
|
|
29
|
-
quality: 0.7, // Set quality to 0.7
|
|
30
|
-
width, // Set width to the scroll width
|
|
31
|
-
height, // Set height to the scroll height
|
|
32
|
-
style: {
|
|
33
|
-
transform: 'scale(1)', // Set scale to 1 to avoid scaling
|
|
34
|
-
},
|
|
35
|
-
skipFonts: true, // Avoid embedding web fonts to bypass SecurityError
|
|
36
|
-
cacheBust: true, // Prevent caching
|
|
37
|
-
backgroundColor: 'white', // Set background color to white
|
|
38
|
-
fetchRequestInit: {
|
|
39
|
-
mode: 'cors', // Enable CORS
|
|
40
|
-
},
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
// Remove the style element
|
|
44
|
-
domBody.removeChild(styleElement);
|
|
45
|
-
|
|
46
|
-
return image;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export { captureScreenshot };
|
|
50
|
-
|
|
51
|
-
|
package/src/utils/redact.test.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { redactTextContent, redactPIIInDOM } from './redact';
|
|
2
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
3
|
-
|
|
4
|
-
describe('redactTextContent', () => {
|
|
5
|
-
it('should redact email addresses', () => {
|
|
6
|
-
const text = 'Contact me at john.doe@example.com';
|
|
7
|
-
const redacted = redactTextContent(text);
|
|
8
|
-
expect(redacted).toBe('Contact me at EMAIL_ADDRESS');
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should redact phone numbers', () => {
|
|
12
|
-
const text = 'My phone number is 123-456-7890';
|
|
13
|
-
const redacted = redactTextContent(text);
|
|
14
|
-
expect(redacted).toBe('My phone number is PHONE_NUMBER');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should redact SSNs', () => {
|
|
18
|
-
const text = 'SSN: 123-45-6789';
|
|
19
|
-
const redacted = redactTextContent(text);
|
|
20
|
-
expect(redacted).toBe('SSN: US_SOCIAL_SECURITY_NUMBER');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should redact passport numbers', () => {
|
|
24
|
-
const text = 'Passport number: A1234567';
|
|
25
|
-
const redacted = redactTextContent(text);
|
|
26
|
-
expect(redacted).toBe('Passport number: PASSPORT_NUMBER');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should return the original text if no PII is found', () => {
|
|
30
|
-
const text = 'No PII here';
|
|
31
|
-
const redacted = redactTextContent(text);
|
|
32
|
-
expect(redacted).toBe(text);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should redact credit card numbers', () => {
|
|
36
|
-
const text = 'Credit Card: 1234-5678-1234-5678';
|
|
37
|
-
const redacted = redactTextContent(text);
|
|
38
|
-
expect(redacted).toBe('Credit Card: CREDIT_CARD_NUMBER');
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('redactPIIInDOM', () => {
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
document.body.innerHTML = `
|
|
45
|
-
<div id="content">
|
|
46
|
-
<p>Email: john.doe@example.com</p>
|
|
47
|
-
<p>Phone: 123-456-7890</p>
|
|
48
|
-
<p>SSN: 123-45-6789</p>
|
|
49
|
-
<p>Passport: A1234567</p>
|
|
50
|
-
<p>No PII here</p>
|
|
51
|
-
</div>
|
|
52
|
-
`;
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should redact PII in text nodes', () => {
|
|
56
|
-
const element = document.getElementById('content') as Element;
|
|
57
|
-
redactPIIInDOM(element);
|
|
58
|
-
|
|
59
|
-
expect(element.innerHTML).toContain('Email: EMAIL_ADDRESS');
|
|
60
|
-
expect(element.innerHTML).toContain('Phone: PHONE_NUMBER');
|
|
61
|
-
expect(element.innerHTML).toContain('SSN: US_SOCIAL_SECURITY_NUMBER');
|
|
62
|
-
expect(element.innerHTML).toContain('Passport: PASSPORT_NUMBER');
|
|
63
|
-
expect(element.innerHTML).toContain('No PII here');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should not change text content without PII', () => {
|
|
67
|
-
const element = document.querySelector('p:last-child') as Element;
|
|
68
|
-
const originalText = element.textContent;
|
|
69
|
-
|
|
70
|
-
redactPIIInDOM(element);
|
|
71
|
-
|
|
72
|
-
expect(element.textContent).toBe(originalText);
|
|
73
|
-
});
|
|
74
|
-
});
|
package/src/utils/redact.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { SyncRedactor } from "redact-pii";
|
|
2
|
-
|
|
3
|
-
const customRedactors = {
|
|
4
|
-
before: [
|
|
5
|
-
{
|
|
6
|
-
regexpPattern: /\b[A-Z]\d{7}\b/g,
|
|
7
|
-
replaceWith: 'PASSPORT_NUMBER'
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
regexpPattern: /(?<=password: )(.*)/gi,
|
|
11
|
-
replaceWith: '[REDACTED]'
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// Function to redact PII in text content
|
|
17
|
-
function redactTextContent(text: string): string {
|
|
18
|
-
const redactor = new SyncRedactor({
|
|
19
|
-
builtInRedactors: {
|
|
20
|
-
names: {
|
|
21
|
-
replaceWith: 'ANONYMOUS_PERSON'
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
customRedactors
|
|
25
|
-
});
|
|
26
|
-
return redactor.redact(text);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Function to recursively find and redact PII in text nodes
|
|
30
|
-
function redactPIIInDOM(element: Element) {
|
|
31
|
-
const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null);
|
|
32
|
-
let currentNode;
|
|
33
|
-
|
|
34
|
-
while ((currentNode = treeWalker.nextNode())) {
|
|
35
|
-
const originalText = currentNode.nodeValue as string;
|
|
36
|
-
const redactedText = redactTextContent(originalText);
|
|
37
|
-
|
|
38
|
-
if (originalText !== redactedText) {
|
|
39
|
-
currentNode.nodeValue = redactedText;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Redact PII in input fields
|
|
44
|
-
redactPIIInInputs(element);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Function to redact PII from passwords in input fields
|
|
48
|
-
function redactPIIInInputs(element: Element) {
|
|
49
|
-
const inputs = Array.from(element.querySelectorAll('input[type="password"]'));
|
|
50
|
-
inputs.forEach(input => {
|
|
51
|
-
const passwordInput = input as HTMLInputElement;
|
|
52
|
-
passwordInput.value = '[REDACTED]';
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export { redactPIIInDOM, redactTextContent };
|
|
57
|
-
|
package/src/utils/snapshot.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { captureScreenshot } from "./capture";
|
|
2
|
-
import { redactPIIInDOM } from "./redact";
|
|
3
|
-
|
|
4
|
-
async function screenshot() {
|
|
5
|
-
try {
|
|
6
|
-
// Wait for page to load
|
|
7
|
-
await new Promise((resolve) => {
|
|
8
|
-
if (document.readyState === 'complete') {
|
|
9
|
-
resolve(null);
|
|
10
|
-
} else {
|
|
11
|
-
window.addEventListener('load', resolve);
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
// Clone the document body to avoid modifying the original
|
|
16
|
-
const clonedBody = document.body.cloneNode(true) as HTMLElement;
|
|
17
|
-
|
|
18
|
-
// Redact PII in text content
|
|
19
|
-
redactPIIInDOM(clonedBody);
|
|
20
|
-
|
|
21
|
-
// Capture the screenshot
|
|
22
|
-
const imageDataUrl = await captureScreenshot(clonedBody);
|
|
23
|
-
|
|
24
|
-
// if local env, print the imageDataUrl to the console
|
|
25
|
-
if (window.location.hostname === 'localhost') {
|
|
26
|
-
console.log(imageDataUrl);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return imageDataUrl;
|
|
30
|
-
} catch (error) {
|
|
31
|
-
console.error('An error occurred:', error);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export { screenshot };
|
package/src/vite-env.d.ts
DELETED
package/tailwind.config.cjs
DELETED
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"strict": true,
|
|
4
|
-
"target": "ESNext",
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"moduleResolution": "node",
|
|
7
|
-
"allowSyntheticDefaultImports": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"types": ["vite/client", "jest"],
|
|
10
|
-
"baseUrl": ".",
|
|
11
|
-
"declaration": true
|
|
12
|
-
},
|
|
13
|
-
"include": ["src"],
|
|
14
|
-
"exclude": ["src/**/*.test.ts", "src/**/*.spec.ts", "src/**/tests/**"]
|
|
15
|
-
}
|
package/vite.config.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import { terser } from 'rollup-plugin-terser';
|
|
3
|
-
import dts from 'vite-plugin-dts';
|
|
4
|
-
import compression from 'vite-plugin-compression';
|
|
5
|
-
import { visualizer } from 'rollup-plugin-visualizer';
|
|
6
|
-
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
7
|
-
import { version } from './package.json';
|
|
8
|
-
|
|
9
|
-
export default defineConfig({
|
|
10
|
-
plugins: [
|
|
11
|
-
tsconfigPaths(),
|
|
12
|
-
dts({
|
|
13
|
-
tsconfigPath: './tsconfig.json',
|
|
14
|
-
insertTypesEntry: true,
|
|
15
|
-
include: ['src'],
|
|
16
|
-
}),
|
|
17
|
-
compression(),
|
|
18
|
-
visualizer(),
|
|
19
|
-
],
|
|
20
|
-
build: {
|
|
21
|
-
target: 'esnext',
|
|
22
|
-
sourcemap: false,
|
|
23
|
-
lib: {
|
|
24
|
-
entry: ['index.ts', 'src/tracker.ts'],
|
|
25
|
-
formats: ['es'],
|
|
26
|
-
fileName: (format, entryName) => `${entryName}.js`,
|
|
27
|
-
},
|
|
28
|
-
minify: false,
|
|
29
|
-
terserOptions: {
|
|
30
|
-
compress: {
|
|
31
|
-
drop_console: true,
|
|
32
|
-
drop_debugger: true,
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
rollupOptions: {
|
|
36
|
-
treeshake: true,
|
|
37
|
-
plugins: [terser()],
|
|
38
|
-
external: ['@google-cloud/dlp'],
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
test: {
|
|
42
|
-
environment: 'jsdom',
|
|
43
|
-
},
|
|
44
|
-
define: {
|
|
45
|
-
'import.meta.env.PACKAGE_VERSION': JSON.stringify(version)
|
|
46
|
-
},
|
|
47
|
-
optimizeDeps: {
|
|
48
|
-
include: ['@brainfish-ai/tracker-sdk'],
|
|
49
|
-
}
|
|
50
|
-
});
|