healcode-client 1.0.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.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # @healcode/client
2
+
3
+ 🩺 **HealCode** - Automatic error detection and fix generation for your frontend projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @healcode/client
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### 1. Initialize in your project
14
+
15
+ ```bash
16
+ npx healcode init
17
+ ```
18
+
19
+ This will prompt you for your HealCode token and create a `healcode.config.json` file.
20
+
21
+ ### 2. Import in your app
22
+
23
+ ```typescript
24
+ // main.ts or index.js
25
+ import { initFromConfig } from '@healcode/client';
26
+
27
+ initFromConfig();
28
+ ```
29
+
30
+ Or with manual configuration:
31
+
32
+ ```typescript
33
+ import { HealCode } from '@healcode/client';
34
+
35
+ const healcode = new HealCode({
36
+ token: 'hc_your_token_here',
37
+ endpoint: 'https://api.healcode.io', // optional
38
+ enabled: true,
39
+ captureConsoleErrors: true,
40
+ captureUnhandledRejections: true,
41
+ maxBreadcrumbs: 20,
42
+ });
43
+ ```
44
+
45
+ ## Features
46
+
47
+ - 🔍 **Automatic Error Capture** - Catches window errors, console.error, and unhandled rejections
48
+ - 🍞 **Breadcrumbs** - Tracks user interactions leading up to errors
49
+ - 🔧 **Auto-Fix** - Generates and creates PRs with fixes automatically
50
+ - 🔒 **Secure** - Your repository tokens are encrypted
51
+ - 📊 **Dashboard** - View all errors and fixes at healcode.io
52
+
53
+ ## CLI Commands
54
+
55
+ ```bash
56
+ npx healcode init # Initialize HealCode in your project
57
+ npx healcode status # Check configuration status
58
+ npx healcode enable # Enable error tracking
59
+ npx healcode disable # Disable error tracking
60
+ ```
61
+
62
+ ## Manual Error Capture
63
+
64
+ ```typescript
65
+ import { captureError, addBreadcrumb } from '@healcode/client';
66
+
67
+ // Add custom breadcrumb
68
+ addBreadcrumb('user.action', 'User clicked checkout button', { cartItems: 3 });
69
+
70
+ // Manually capture an error
71
+ try {
72
+ riskyOperation();
73
+ } catch (error) {
74
+ captureError(error.message, error.stack);
75
+ }
76
+ ```
77
+
78
+ ## Configuration Options
79
+
80
+ | Option | Type | Default | Description |
81
+ |--------|------|---------|-------------|
82
+ | `token` | string | required | Your HealCode integration token |
83
+ | `endpoint` | string | `https://api.healcode.io` | API endpoint |
84
+ | `enabled` | boolean | `true` | Enable/disable tracking |
85
+ | `captureConsoleErrors` | boolean | `true` | Capture console.error calls |
86
+ | `captureUnhandledRejections` | boolean | `true` | Capture unhandled promise rejections |
87
+ | `maxBreadcrumbs` | number | `20` | Maximum breadcrumbs to store |
88
+ | `beforeSend` | function | - | Modify or filter errors before sending |
89
+
90
+ ## beforeSend Hook
91
+
92
+ ```typescript
93
+ const healcode = new HealCode({
94
+ token: 'hc_...',
95
+ beforeSend: (payload) => {
96
+ // Filter out specific errors
97
+ if (payload.message.includes('ResizeObserver')) {
98
+ return null; // Don't send
99
+ }
100
+
101
+ // Modify payload
102
+ payload.message = payload.message.replace(/secret/gi, '[REDACTED]');
103
+ return payload;
104
+ },
105
+ });
106
+ ```
107
+
108
+ ## License
109
+
110
+ MIT
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import inquirer from 'inquirer';
5
+ import chalk from 'chalk';
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+
9
+ const CONFIG_FILE_NAME = 'healcode.config.json';
10
+ const DEFAULT_ENDPOINT = 'https://api.healcode.io';
11
+
12
+ const program = new Command();
13
+
14
+ program
15
+ .name('healcode')
16
+ .description('HealCode CLI - Automatic error detection and fix generation')
17
+ .version('1.0.0');
18
+
19
+ program
20
+ .command('init')
21
+ .description('Initialize HealCode in your project')
22
+ .action(async () => {
23
+ console.log(chalk.green.bold('\n🩺 HealCode Setup\n'));
24
+
25
+ const initialAnswers = await inquirer.prompt([
26
+ {
27
+ type: 'input',
28
+ name: 'token',
29
+ message: 'Enter your HealCode token:',
30
+ validate: (input) => {
31
+ if (!input || input.trim().length === 0) {
32
+ return 'Token is required. Get one at https://healcode.io/dashboard';
33
+ }
34
+ if (!input.startsWith('hc_')) {
35
+ return 'Invalid token format. Token should start with "hc_"';
36
+ }
37
+ return true;
38
+ },
39
+ },
40
+ {
41
+ type: 'input',
42
+ name: 'endpoint',
43
+ message: 'API Endpoint (press Enter for default):',
44
+ default: DEFAULT_ENDPOINT,
45
+ },
46
+ ]);
47
+
48
+ // Validate token with API
49
+ console.log(chalk.yellow('\n⏳ Validating token...'));
50
+
51
+ let remoteConfig = null;
52
+
53
+ try {
54
+ const response = await fetch(`${initialAnswers.endpoint}/api/tokens/validate`, {
55
+ method: 'POST',
56
+ headers: { 'Content-Type': 'application/json' },
57
+ body: JSON.stringify({ token: initialAnswers.token }),
58
+ });
59
+
60
+ const result = await response.json();
61
+
62
+ if (!result.isValid) {
63
+ console.log(chalk.red(`\n❌ Token validation failed: ${result.errorMessage || 'Invalid token'}`));
64
+ console.log(chalk.gray('Get a valid token at https://healcode.io/dashboard\n'));
65
+ process.exit(1);
66
+ }
67
+
68
+ console.log(chalk.green('✅ Token validated successfully!'));
69
+ console.log(chalk.gray(` Project: ${result.projectId}`));
70
+
71
+ if (result.configuration) {
72
+ remoteConfig = result.configuration;
73
+ console.log(chalk.green('✅ Configuration loaded from Dashboard.'));
74
+ }
75
+
76
+ } catch (error) {
77
+ console.log(chalk.yellow('\n⚠️ Could not validate token (API unreachable). Proceeding with manual setup...'));
78
+ }
79
+
80
+ let options = {};
81
+
82
+ if (remoteConfig) {
83
+ options = remoteConfig;
84
+ } else {
85
+ options = await inquirer.prompt([
86
+ {
87
+ type: 'confirm',
88
+ name: 'captureConsoleErrors',
89
+ message: 'Capture console.error calls?',
90
+ default: true,
91
+ },
92
+ {
93
+ type: 'confirm',
94
+ name: 'captureUnhandledRejections',
95
+ message: 'Capture unhandled promise rejections?',
96
+ default: true,
97
+ },
98
+ ]);
99
+ }
100
+
101
+ // Create config file
102
+ const config = {
103
+ token: initialAnswers.token,
104
+ endpoint: initialAnswers.endpoint === DEFAULT_ENDPOINT ? undefined : initialAnswers.endpoint,
105
+ enabled: true,
106
+ options: {
107
+ captureConsoleErrors: options.captureConsoleErrors !== false,
108
+ captureUnhandledRejections: options.captureUnhandledRejections !== false,
109
+ maxBreadcrumbs: 20,
110
+ },
111
+ };
112
+
113
+ const configPath = path.join(process.cwd(), CONFIG_FILE_NAME);
114
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
115
+
116
+ console.log(chalk.green(`\n✅ Config saved to ${CONFIG_FILE_NAME}`));
117
+
118
+ // Show usage instructions
119
+ console.log(chalk.cyan('\n📖 Usage:\n'));
120
+ console.log(chalk.white(' // In your main entry file (e.g., main.ts, index.js)'));
121
+ console.log(chalk.gray(' import { initFromConfig } from \'@healcode/client\';'));
122
+ console.log(chalk.gray(' initFromConfig();\n'));
123
+
124
+ console.log(chalk.white(' // Or with manual configuration:'));
125
+ console.log(chalk.gray(' import { HealCode } from \'@healcode/client\';'));
126
+ console.log(chalk.gray(` const healcode = new HealCode({ token: '${answers.token.substring(0, 10)}...' });\n`));
127
+
128
+ // Add to .gitignore
129
+ const gitignorePath = path.join(process.cwd(), '.gitignore');
130
+ if (fs.existsSync(gitignorePath)) {
131
+ const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
132
+ if (!gitignore.includes(CONFIG_FILE_NAME)) {
133
+ fs.appendFileSync(gitignorePath, `\n# HealCode\n${CONFIG_FILE_NAME}\n`);
134
+ console.log(chalk.gray(`Added ${CONFIG_FILE_NAME} to .gitignore`));
135
+ }
136
+ }
137
+
138
+ console.log(chalk.green.bold('\n🎉 HealCode is ready! Errors will be automatically tracked and fixed.\n'));
139
+ });
140
+
141
+ program
142
+ .command('status')
143
+ .description('Check HealCode configuration status')
144
+ .action(() => {
145
+ const configPath = path.join(process.cwd(), CONFIG_FILE_NAME);
146
+
147
+ if (!fs.existsSync(configPath)) {
148
+ console.log(chalk.yellow('\n⚠️ No HealCode configuration found.'));
149
+ console.log(chalk.gray('Run `npx healcode init` to set up.\n'));
150
+ return;
151
+ }
152
+
153
+ try {
154
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
155
+ console.log(chalk.green.bold('\n🩺 HealCode Status\n'));
156
+ console.log(chalk.white(` Token: ${config.token.substring(0, 15)}...`));
157
+ console.log(chalk.white(` Endpoint: ${config.endpoint || DEFAULT_ENDPOINT}`));
158
+ console.log(chalk.white(` Enabled: ${config.enabled !== false ? '✅' : '❌'}`));
159
+ console.log('');
160
+ } catch (error) {
161
+ console.log(chalk.red('\n❌ Failed to read configuration file.\n'));
162
+ }
163
+ });
164
+
165
+ program
166
+ .command('disable')
167
+ .description('Disable HealCode error tracking')
168
+ .action(() => {
169
+ const configPath = path.join(process.cwd(), CONFIG_FILE_NAME);
170
+
171
+ if (!fs.existsSync(configPath)) {
172
+ console.log(chalk.yellow('\n⚠️ No HealCode configuration found.\n'));
173
+ return;
174
+ }
175
+
176
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
177
+ config.enabled = false;
178
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
179
+ console.log(chalk.yellow('\n⏸️ HealCode tracking disabled.\n'));
180
+ });
181
+
182
+ program
183
+ .command('enable')
184
+ .description('Enable HealCode error tracking')
185
+ .action(() => {
186
+ const configPath = path.join(process.cwd(), CONFIG_FILE_NAME);
187
+
188
+ if (!fs.existsSync(configPath)) {
189
+ console.log(chalk.yellow('\n⚠️ No HealCode configuration found.'));
190
+ console.log(chalk.gray('Run `npx healcode init` to set up.\n'));
191
+ return;
192
+ }
193
+
194
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
195
+ config.enabled = true;
196
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
197
+ console.log(chalk.green('\n▶️ HealCode tracking enabled.\n'));
198
+ });
199
+
200
+ program.parse();
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * HealCode - Postinstall Script
5
+ * This script runs automatically after npm install
6
+ * Prompts for token and configures the library
7
+ */
8
+
9
+ const readline = require('readline');
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const https = require('https');
13
+ const http = require('http');
14
+
15
+ const CONFIG_FILE_NAME = 'healcode.config.json';
16
+
17
+ // Load URLs from config
18
+ let urlsConfig = { backendUrl: 'https://api.healcode.io', agentUrl: 'https://api.healcode.io' };
19
+ try {
20
+ const urlsConfigPath = path.join(__dirname, '..', 'urls.config.json');
21
+ if (fs.existsSync(urlsConfigPath)) {
22
+ urlsConfig = JSON.parse(fs.readFileSync(urlsConfigPath, 'utf-8'));
23
+ }
24
+ } catch (e) {
25
+ // Use defaults
26
+ }
27
+
28
+ const DEFAULT_BACKEND_URL = urlsConfig.backendUrl;
29
+ const DEFAULT_AGENT_URL = urlsConfig.agentUrl;
30
+
31
+ // ANSI Colors
32
+ const colors = {
33
+ green: '\x1b[32m',
34
+ yellow: '\x1b[33m',
35
+ red: '\x1b[31m',
36
+ cyan: '\x1b[36m',
37
+ gray: '\x1b[90m',
38
+ bold: '\x1b[1m',
39
+ reset: '\x1b[0m'
40
+ };
41
+
42
+ function log(color, message) {
43
+ console.log(`${color}${message}${colors.reset}`);
44
+ }
45
+
46
+ function findProjectRoot() {
47
+ // When installed via npm, we need to go up from node_modules/@healcode/client
48
+ let dir = process.cwd();
49
+
50
+ // If we're inside node_modules, go up to project root
51
+ if (dir.includes('node_modules')) {
52
+ const parts = dir.split('node_modules');
53
+ dir = parts[0];
54
+ }
55
+
56
+ return dir;
57
+ }
58
+
59
+ function configExists() {
60
+ const projectRoot = findProjectRoot();
61
+ const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
62
+ return fs.existsSync(configPath);
63
+ }
64
+
65
+ function validateToken(token, endpoint) {
66
+ return new Promise((resolve, reject) => {
67
+ const url = new URL(`${endpoint}/api/Tokens/validate`);
68
+ const protocol = url.protocol === 'https:' ? https : http;
69
+
70
+ const postData = JSON.stringify({ token: token });
71
+
72
+ const options = {
73
+ hostname: url.hostname,
74
+ port: url.port || (url.protocol === 'https:' ? 443 : 80),
75
+ path: url.pathname,
76
+ method: 'POST',
77
+ headers: {
78
+ 'Content-Type': 'application/json',
79
+ 'Content-Length': Buffer.byteLength(postData)
80
+ },
81
+ timeout: 10000
82
+ };
83
+
84
+ const req = protocol.request(options, (res) => {
85
+ let data = '';
86
+ res.on('data', chunk => data += chunk);
87
+ res.on('end', () => {
88
+ try {
89
+ const result = JSON.parse(data);
90
+ resolve(result);
91
+ } catch (e) {
92
+ reject(new Error('Invalid response from server'));
93
+ }
94
+ });
95
+ });
96
+
97
+ req.on('error', reject);
98
+ req.on('timeout', () => {
99
+ req.destroy();
100
+ reject(new Error('Request timed out'));
101
+ });
102
+
103
+ req.write(postData);
104
+ req.end();
105
+ });
106
+ }
107
+
108
+ async function main() {
109
+ // Skip if running in CI or non-interactive mode
110
+ if (process.env.CI || process.env.HEALCODE_SKIP_SETUP || !process.stdin.isTTY) {
111
+ return;
112
+ }
113
+
114
+ // Skip if we're in development mode (not installed as a dependency)
115
+ // When installed as dependency, __dirname will be inside node_modules
116
+ const currentDir = __dirname;
117
+ if (!currentDir.includes('node_modules')) {
118
+ // We're in the library's own development directory, skip setup
119
+ return;
120
+ }
121
+
122
+ // Skip if config already exists
123
+ if (configExists()) {
124
+ log(colors.gray, '\n[HealCode] Configuration already exists. Skipping setup.');
125
+ return;
126
+ }
127
+
128
+ console.log('');
129
+ log(colors.green + colors.bold, '🩺 HealCode Setup');
130
+ console.log('');
131
+
132
+ const rl = readline.createInterface({
133
+ input: process.stdin,
134
+ output: process.stdout
135
+ });
136
+
137
+ const question = (prompt) => new Promise((resolve) => {
138
+ rl.question(prompt, resolve);
139
+ });
140
+
141
+ try {
142
+ // Get token
143
+ const token = await question(`${colors.cyan}Enter your HealCode token: ${colors.reset}`);
144
+
145
+ if (!token || token.trim().length === 0) {
146
+ log(colors.yellow, '\n⚠️ No token provided. Run "npx healcode init" later to configure.');
147
+ rl.close();
148
+ return;
149
+ }
150
+
151
+ // Get endpoint (with default)
152
+ let endpoint = await question(`${colors.cyan}API Endpoint ${colors.gray}(press Enter for default)${colors.cyan}: ${colors.reset}`);
153
+
154
+ if (!endpoint || endpoint.trim().length === 0) {
155
+ // Default endpoint - use configured backend URL
156
+ endpoint = DEFAULT_BACKEND_URL;
157
+ }
158
+
159
+ log(colors.yellow, '\n⏳ Validating token...');
160
+
161
+ try {
162
+ const result = await validateToken(token.trim(), endpoint.trim());
163
+
164
+ if (!result.isValid) {
165
+ log(colors.red, `\n❌ Token validation failed: ${result.errorMessage || 'Invalid token'}`);
166
+ log(colors.gray, 'Get a valid token at your HealCode dashboard\n');
167
+ rl.close();
168
+ return;
169
+ }
170
+
171
+ log(colors.green, '✅ Token validated successfully!');
172
+ if (result.projectId) {
173
+ log(colors.gray, ` Project ID: ${result.projectId}`);
174
+ }
175
+
176
+ // Get agent endpoint for error reporting (from server response or use default)
177
+ let agentEndpoint = result.agentEndpoint || DEFAULT_AGENT_URL;
178
+
179
+ // Create config
180
+ const projectRoot = findProjectRoot();
181
+ const config = {
182
+ token: token.trim(),
183
+ endpoint: agentEndpoint,
184
+ enabled: true,
185
+ options: {
186
+ captureConsoleErrors: true,
187
+ captureUnhandledRejections: true,
188
+ maxBreadcrumbs: 20
189
+ }
190
+ };
191
+
192
+ // Apply remote configuration if available
193
+ if (result.configuration) {
194
+ Object.assign(config.options, result.configuration);
195
+ log(colors.green, '✅ Configuration loaded from Dashboard.');
196
+ }
197
+
198
+ const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
199
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
200
+
201
+ log(colors.green, `\n✅ Config saved to ${CONFIG_FILE_NAME}`);
202
+
203
+ // Add to .gitignore
204
+ const gitignorePath = path.join(projectRoot, '.gitignore');
205
+ if (fs.existsSync(gitignorePath)) {
206
+ let gitignore = fs.readFileSync(gitignorePath, 'utf-8');
207
+ if (!gitignore.includes(CONFIG_FILE_NAME)) {
208
+ fs.appendFileSync(gitignorePath, `\n# HealCode\n${CONFIG_FILE_NAME}\n`);
209
+ log(colors.gray, `Added ${CONFIG_FILE_NAME} to .gitignore`);
210
+ }
211
+ }
212
+
213
+ // Show usage
214
+ console.log('');
215
+ log(colors.cyan, '📖 Usage:');
216
+ console.log('');
217
+ log(colors.gray, ' // In your main entry file (e.g., main.ts, index.js)');
218
+ log(colors.gray, " import { initFromConfig } from '@healcode/client';");
219
+ log(colors.gray, ' initFromConfig();');
220
+ console.log('');
221
+ log(colors.green + colors.bold, '🎉 HealCode is ready! Errors will be automatically tracked.\n');
222
+
223
+ } catch (error) {
224
+ log(colors.yellow, `\n⚠️ Could not validate token: ${error.message}`);
225
+ log(colors.gray, 'You can configure manually later with "npx healcode init"\n');
226
+ }
227
+
228
+ } finally {
229
+ rl.close();
230
+ }
231
+ }
232
+
233
+ main().catch(() => {
234
+ // Silent fail - postinstall should not break npm install
235
+ });
@@ -0,0 +1,61 @@
1
+ interface HealCodeConfig {
2
+ token: string;
3
+ endpoint?: string;
4
+ enabled?: boolean;
5
+ captureConsoleErrors?: boolean;
6
+ captureUnhandledRejections?: boolean;
7
+ maxBreadcrumbs?: number;
8
+ beforeSend?: (payload: ErrorPayload) => ErrorPayload | null;
9
+ }
10
+ interface HealCodeFileConfig {
11
+ token: string;
12
+ endpoint?: string;
13
+ enabled?: boolean;
14
+ options?: {
15
+ captureConsoleErrors?: boolean;
16
+ captureUnhandledRejections?: boolean;
17
+ maxBreadcrumbs?: number;
18
+ };
19
+ }
20
+ interface Breadcrumb {
21
+ type: string;
22
+ message: string;
23
+ timestamp: string;
24
+ data?: Record<string, unknown>;
25
+ }
26
+ interface ErrorPayload {
27
+ token: string;
28
+ message: string;
29
+ stacktrace?: string;
30
+ url: string;
31
+ level: string;
32
+ userAgent?: string;
33
+ networkStatus?: string;
34
+ breadcrumbs: Breadcrumb[];
35
+ timestamp: string;
36
+ }
37
+
38
+ declare class HealCode {
39
+ private config;
40
+ private breadcrumbs;
41
+ private sentHashes;
42
+ private initialized;
43
+ constructor(config: HealCodeConfig);
44
+ private init;
45
+ private setupNetworkListeners;
46
+ private setupInteractionListeners;
47
+ private interceptConsole;
48
+ private interceptWindowErrors;
49
+ private interceptUnhandledRejections;
50
+ addBreadcrumb(type: string, message: string, data?: Record<string, unknown>): void;
51
+ capture(level: string, message: string, stacktrace?: string): void;
52
+ private generateHash;
53
+ private send;
54
+ setEnabled(enabled: boolean): void;
55
+ isEnabled(): boolean;
56
+ }
57
+
58
+ declare function loadConfig(configPath?: string): HealCodeFileConfig | null;
59
+ declare function initFromConfig(configPath?: string): HealCode | null;
60
+
61
+ export { HealCode, type HealCodeConfig, type HealCodeFileConfig, initFromConfig, loadConfig };
@@ -0,0 +1,61 @@
1
+ interface HealCodeConfig {
2
+ token: string;
3
+ endpoint?: string;
4
+ enabled?: boolean;
5
+ captureConsoleErrors?: boolean;
6
+ captureUnhandledRejections?: boolean;
7
+ maxBreadcrumbs?: number;
8
+ beforeSend?: (payload: ErrorPayload) => ErrorPayload | null;
9
+ }
10
+ interface HealCodeFileConfig {
11
+ token: string;
12
+ endpoint?: string;
13
+ enabled?: boolean;
14
+ options?: {
15
+ captureConsoleErrors?: boolean;
16
+ captureUnhandledRejections?: boolean;
17
+ maxBreadcrumbs?: number;
18
+ };
19
+ }
20
+ interface Breadcrumb {
21
+ type: string;
22
+ message: string;
23
+ timestamp: string;
24
+ data?: Record<string, unknown>;
25
+ }
26
+ interface ErrorPayload {
27
+ token: string;
28
+ message: string;
29
+ stacktrace?: string;
30
+ url: string;
31
+ level: string;
32
+ userAgent?: string;
33
+ networkStatus?: string;
34
+ breadcrumbs: Breadcrumb[];
35
+ timestamp: string;
36
+ }
37
+
38
+ declare class HealCode {
39
+ private config;
40
+ private breadcrumbs;
41
+ private sentHashes;
42
+ private initialized;
43
+ constructor(config: HealCodeConfig);
44
+ private init;
45
+ private setupNetworkListeners;
46
+ private setupInteractionListeners;
47
+ private interceptConsole;
48
+ private interceptWindowErrors;
49
+ private interceptUnhandledRejections;
50
+ addBreadcrumb(type: string, message: string, data?: Record<string, unknown>): void;
51
+ capture(level: string, message: string, stacktrace?: string): void;
52
+ private generateHash;
53
+ private send;
54
+ setEnabled(enabled: boolean): void;
55
+ isEnabled(): boolean;
56
+ }
57
+
58
+ declare function loadConfig(configPath?: string): HealCodeFileConfig | null;
59
+ declare function initFromConfig(configPath?: string): HealCode | null;
60
+
61
+ export { HealCode, type HealCodeConfig, type HealCodeFileConfig, initFromConfig, loadConfig };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ 'use strict';const a0_0x5a3a5c=a0_0x3829;(function(_0x2dc44e,_0x4c947a){const _0x17031c=a0_0x3829,_0x4e81f0=_0x2dc44e();while(!![]){try{const _0x542e04=parseInt(_0x17031c(0x14c))/0x1+parseInt(_0x17031c(0x126))/0x2*(parseInt(_0x17031c(0xd9))/0x3)+-parseInt(_0x17031c(0x15d))/0x4*(-parseInt(_0x17031c(0x13f))/0x5)+parseInt(_0x17031c(0x144))/0x6+parseInt(_0x17031c(0x150))/0x7+-parseInt(_0x17031c(0x15a))/0x8+parseInt(_0x17031c(0x112))/0x9*(-parseInt(_0x17031c(0x102))/0xa);if(_0x542e04===_0x4c947a)break;else _0x4e81f0['push'](_0x4e81f0['shift']());}catch(_0x57d922){_0x4e81f0['push'](_0x4e81f0['shift']());}}}(a0_0x3c52,0x640c4));var C=Object[a0_0x5a3a5c(0x13a)],l=Object['defineProperty'],m=Object[a0_0x5a3a5c(0x100)],b=Object[a0_0x5a3a5c(0x131)],w=Object[a0_0x5a3a5c(0xda)],H=Object[a0_0x5a3a5c(0x12c)][a0_0x5a3a5c(0x121)],v=(_0x5bfce9,_0xe03a1e)=>{const _0x516a12=a0_0x5a3a5c,_0x352e23={'ZjBSJ':function(_0xd82f5,_0x48098b,_0x1d3a07,_0x35d285){return _0xd82f5(_0x48098b,_0x1d3a07,_0x35d285);}};for(var _0x3e7fd8 in _0xe03a1e)_0x352e23[_0x516a12(0x105)](l,_0x5bfce9,_0x3e7fd8,{'get':_0xe03a1e[_0x3e7fd8],'enumerable':!0x0});},u=(_0x514493,_0x2f346e,_0x47b9de,_0x5d0e0a)=>{const _0x139804=a0_0x5a3a5c,_0x4543e5={'pKitS':function(_0x2b6216,_0x1834fd){return _0x2b6216==_0x1834fd;},'LlEXo':_0x139804(0x167),'YXTPl':'function','RjppJ':function(_0x1dfe2b,_0x5764ae){return _0x1dfe2b(_0x5764ae);},'Hbues':function(_0x3d4553,_0x283bbe){return _0x3d4553!==_0x283bbe;},'cOPZv':function(_0x42b4dd,_0x5cdd8b,_0x308db8,_0x45b812){return _0x42b4dd(_0x5cdd8b,_0x308db8,_0x45b812);},'eHKuA':function(_0x1746e7,_0x218e00,_0x4fe2d1){return _0x1746e7(_0x218e00,_0x4fe2d1);}};if(_0x2f346e&&_0x4543e5[_0x139804(0x11c)](typeof _0x2f346e,_0x4543e5[_0x139804(0x119)])||_0x4543e5[_0x139804(0x11c)](typeof _0x2f346e,_0x4543e5[_0x139804(0x158)])){for(let _0xa418c8 of _0x4543e5[_0x139804(0xea)](b,_0x2f346e))!H[_0x139804(0xe7)](_0x514493,_0xa418c8)&&_0x4543e5[_0x139804(0x155)](_0xa418c8,_0x47b9de)&&_0x4543e5[_0x139804(0xe9)](l,_0x514493,_0xa418c8,{'get':()=>_0x2f346e[_0xa418c8],'enumerable':!(_0x5d0e0a=_0x4543e5[_0x139804(0x11e)](m,_0x2f346e,_0xa418c8))||_0x5d0e0a[_0x139804(0x146)]});}return _0x514493;},f=(_0x22ad50,_0x239689,_0x33053e)=>(_0x33053e=_0x22ad50!=null?C(w(_0x22ad50)):{},u(_0x239689||!_0x22ad50||!_0x22ad50[a0_0x5a3a5c(0x13b)]?l(_0x33053e,'default',{'value':_0x22ad50,'enumerable':!0x0}):_0x33053e,_0x22ad50)),y=_0x18e047=>u(l({},a0_0x5a3a5c(0x13b),{'value':!0x0}),_0x18e047),N={};function a0_0x3829(_0x5ebf82,_0x1e21d7){_0x5ebf82=_0x5ebf82-0xd7;const _0x3c52cf=a0_0x3c52();let _0x3829a3=_0x3c52cf[_0x5ebf82];if(a0_0x3829['DpnGLE']===undefined){var _0x2a5301=function(_0xa9eef5){const _0x59f0a6='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x380c9a='',_0x2ff39b='';for(let _0x1ba2ee=0x0,_0x54eecb,_0x5ec5ce,_0x2a6759=0x0;_0x5ec5ce=_0xa9eef5['charAt'](_0x2a6759++);~_0x5ec5ce&&(_0x54eecb=_0x1ba2ee%0x4?_0x54eecb*0x40+_0x5ec5ce:_0x5ec5ce,_0x1ba2ee++%0x4)?_0x380c9a+=String['fromCharCode'](0xff&_0x54eecb>>(-0x2*_0x1ba2ee&0x6)):0x0){_0x5ec5ce=_0x59f0a6['indexOf'](_0x5ec5ce);}for(let _0x50a02d=0x0,_0x318128=_0x380c9a['length'];_0x50a02d<_0x318128;_0x50a02d++){_0x2ff39b+='%'+('00'+_0x380c9a['charCodeAt'](_0x50a02d)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2ff39b);};a0_0x3829['lJLHGL']=_0x2a5301,a0_0x3829['KNiQkT']={},a0_0x3829['DpnGLE']=!![];}const _0x576947=_0x3c52cf[0x0],_0x3b0fe2=_0x5ebf82+_0x576947,_0x185caf=a0_0x3829['KNiQkT'][_0x3b0fe2];return!_0x185caf?(_0x3829a3=a0_0x3829['lJLHGL'](_0x3829a3),a0_0x3829['KNiQkT'][_0x3b0fe2]=_0x3829a3):_0x3829a3=_0x185caf,_0x3829a3;}v(N,{'HealCode':()=>s,'initFromConfig':()=>h,'loadConfig':()=>p}),module['exports']=y(N);var g=a0_0x5a3a5c(0x139),E=g+'/api/logs/',x=0x14,s=class{constructor(_0x5879a8){const _0x13fcff=a0_0x5a3a5c,_0x46a00c={'fXBQU':function(_0x84db9a,_0x1842cf){return _0x84db9a!==_0x1842cf;},'vZjPB':function(_0x21e8c3,_0x29a0b5){return _0x21e8c3!==_0x29a0b5;},'aNXyR':function(_0x336b7e,_0x4bef67){return _0x336b7e<_0x4bef67;}};this[_0x13fcff(0xf3)]=[],this[_0x13fcff(0xf7)]=new Set(),this[_0x13fcff(0x16d)]=!0x1,(this['config']={'token':_0x5879a8[_0x13fcff(0x15b)],'endpoint':_0x5879a8['endpoint']||E,'enabled':_0x46a00c[_0x13fcff(0x16c)](_0x5879a8[_0x13fcff(0x113)],!0x1),'captureConsoleErrors':_0x5879a8[_0x13fcff(0x154)]!==!0x1,'captureUnhandledRejections':_0x46a00c[_0x13fcff(0x14e)](_0x5879a8[_0x13fcff(0xeb)],!0x1),'maxBreadcrumbs':_0x5879a8[_0x13fcff(0xf9)]||x,'beforeSend':_0x5879a8[_0x13fcff(0xff)]},this[_0x13fcff(0x110)][_0x13fcff(0x113)]&&_0x46a00c[_0x13fcff(0x13d)](typeof window,'u')&&this['init']());}[a0_0x5a3a5c(0x11f)](){const _0x1125a5=a0_0x5a3a5c,_0x1c0310={'UFEvc':'[HealCode]\x20Initialized\x20successfully'};this[_0x1125a5(0x16d)]||(this[_0x1125a5(0x16d)]=!0x0,this[_0x1125a5(0xee)](),this[_0x1125a5(0x117)](),this[_0x1125a5(0x110)]['captureConsoleErrors']&&this[_0x1125a5(0x101)](),this['interceptWindowErrors'](),this[_0x1125a5(0x110)]['captureUnhandledRejections']&&this['interceptUnhandledRejections'](),console[_0x1125a5(0x120)](_0x1c0310['UFEvc']));}[a0_0x5a3a5c(0xee)](){const _0x30ddcb=a0_0x5a3a5c,_0x31ac45={'tYpKS':_0x30ddcb(0x14b),'PUOcw':_0x30ddcb(0x133)};window['addEventListener'](_0x31ac45['tYpKS'],()=>this[_0x30ddcb(0x106)](_0x30ddcb(0x104),'Connection\x20restored',{'status':_0x30ddcb(0x14b)})),window[_0x30ddcb(0x161)](_0x31ac45['PUOcw'],()=>this['addBreadcrumb'](_0x30ddcb(0x104),_0x30ddcb(0x157),{'status':_0x30ddcb(0x133)}));}[a0_0x5a3a5c(0x117)](){const _0x2e7dc3=a0_0x5a3a5c,_0x380f24={'liVlg':function(_0x154bac,_0x173130){return _0x154bac||_0x173130;},'QOUru':function(_0x5bed50,_0x4ba273){return _0x5bed50<_0x4ba273;},'IipEi':function(_0x3f45dd,_0x43a361){return _0x3f45dd-_0x43a361;},'PjVix':function(_0x4d10f4,_0x4c641a){return _0x4d10f4<<_0x4c641a;},'NariC':function(_0x1fc8ed,_0x13741f){return _0x1fc8ed&_0x13741f;},'ArNiD':function(_0x1d3789,_0x5dd72f){return _0x1d3789!==_0x5dd72f;},'jmtSL':'TUFfw','OmMNG':_0x2e7dc3(0xfd),'SPuEB':'click'};document[_0x2e7dc3(0x161)](_0x380f24[_0x2e7dc3(0x165)],_0x82432d=>{const _0x1c20a3=_0x2e7dc3;if(_0x380f24[_0x1c20a3(0x10a)](_0x380f24[_0x1c20a3(0x130)],_0x1c20a3(0x160))){let _0x56cc6d=_0x82432d[_0x1c20a3(0x15c)];this[_0x1c20a3(0x106)](_0x380f24[_0x1c20a3(0xf1)],_0x1c20a3(0xe3)+_0x56cc6d[_0x1c20a3(0xd7)],{'id':_0x56cc6d['id']||void 0x0,'className':_0x56cc6d['className']||void 0x0,'text':_0x56cc6d[_0x1c20a3(0xd8)]?.[_0x1c20a3(0x142)](0x0,0x32)||void 0x0});}else{let _0x23b565=_0x53b8ef+_0x380f24[_0x1c20a3(0x114)](_0x28d233,''),_0x1045c2=0x0;for(let _0x56c20e=0x0;_0x380f24[_0x1c20a3(0xe0)](_0x56c20e,_0x23b565[_0x1c20a3(0x132)]);_0x56c20e++){let _0x2a1270=_0x23b565[_0x1c20a3(0xe5)](_0x56c20e);_0x1045c2=_0x380f24['IipEi'](_0x380f24[_0x1c20a3(0x11d)](_0x1045c2,0x5),_0x1045c2)+_0x2a1270,_0x1045c2=_0x380f24[_0x1c20a3(0xe2)](_0x1045c2,_0x1045c2);}return _0x1045c2[_0x1c20a3(0xdb)]();}},!0x0);}[a0_0x5a3a5c(0x101)](){const _0x387059=a0_0x5a3a5c,_0x550e19={'xemSj':function(_0x5b54d7,_0x39b97a){return _0x5b54d7==_0x39b97a;},'pClzE':'string','hNhxO':_0x387059(0xef),'tehpQ':_0x387059(0xe8),'FboXt':function(_0x48b9fe,_0x3a74a9){return _0x48b9fe!==_0x3a74a9;},'CfhnF':_0x387059(0x143),'SHhHK':'HfGdH'};let _0x2cfa05=console[_0x387059(0xe8)];console[_0x387059(0xe8)]=(..._0x34a3f4)=>{const _0x4d7e7b=_0x387059,_0x3f45d2={'ShDtI':function(_0x39e8ca,_0x5271c7){const _0x586a6d=a0_0x3829;return _0x550e19[_0x586a6d(0x13c)](_0x39e8ca,_0x5271c7);},'uKwtj':_0x550e19[_0x4d7e7b(0x10e)],'yDPeg':_0x550e19[_0x4d7e7b(0x163)],'tuNEd':_0x550e19[_0x4d7e7b(0xfe)]};if(_0x550e19['FboXt'](_0x550e19[_0x4d7e7b(0x140)],_0x550e19['SHhHK'])){let _0x1cc978=_0x34a3f4[_0x4d7e7b(0x15e)](_0x4a2b0c=>typeof _0x4a2b0c==_0x4d7e7b(0x167)?JSON[_0x4d7e7b(0x10d)](_0x4a2b0c):String(_0x4a2b0c))[_0x4d7e7b(0xdd)]('\x20');this[_0x4d7e7b(0x152)](_0x550e19[_0x4d7e7b(0xfe)],_0x1cc978),_0x2cfa05['apply'](console,_0x34a3f4);}else _0x38093c['onerror']=(_0x4483f6,_0x563732,_0x565547,_0x528eed,_0x4f16b6)=>{const _0x32c5e5=_0x4d7e7b;let _0x2b29f8=_0x3f45d2[_0x32c5e5(0x107)](typeof _0x4483f6,_0x3f45d2[_0x32c5e5(0x128)])?_0x4483f6:_0x3f45d2[_0x32c5e5(0x135)];this['capture'](_0x3f45d2['tuNEd'],_0x2b29f8+'\x20at\x20'+_0x563732+':'+_0x565547+':'+_0x528eed,_0x4f16b6?.[_0x32c5e5(0x156)]);};};}[a0_0x5a3a5c(0x12f)](){const _0x5ee505=a0_0x5a3a5c,_0xd10e73={'kQzSM':function(_0x2c0871,_0x1c2f4a){return _0x2c0871==_0x1c2f4a;},'lRKCv':'string','lRayg':'Unknown\x20error','oqBns':_0x5ee505(0xe8)};window['onerror']=(_0x1760b9,_0x329ca2,_0x47dd2a,_0x5e2b0a,_0x3452f9)=>{const _0x3742e9=_0x5ee505;let _0x401d3a=_0xd10e73['kQzSM'](typeof _0x1760b9,_0xd10e73[_0x3742e9(0x13e)])?_0x1760b9:_0xd10e73[_0x3742e9(0x153)];this[_0x3742e9(0x152)](_0xd10e73[_0x3742e9(0x170)],_0x401d3a+_0x3742e9(0x14d)+_0x329ca2+':'+_0x47dd2a+':'+_0x5e2b0a,_0x3452f9?.[_0x3742e9(0x156)]);};}[a0_0x5a3a5c(0x16e)](){const _0x4fc200=a0_0x5a3a5c,_0x8f1f33={'wkqAS':'error'};window[_0x4fc200(0xe6)]=_0x7b4fb8=>{const _0x568be8=_0x4fc200;this['capture'](_0x8f1f33[_0x568be8(0x11b)],'Unhandled\x20Rejection:\x20'+_0x7b4fb8[_0x568be8(0x12b)]);};}[a0_0x5a3a5c(0x106)](_0x167bf3,_0x3a28a2,_0x97c40a){const _0x5c2ab7=a0_0x5a3a5c;let _0x1a045d={'type':_0x167bf3,'message':_0x3a28a2,'timestamp':new Date()[_0x5c2ab7(0xfb)](),'data':_0x97c40a};this[_0x5c2ab7(0xf3)][_0x5c2ab7(0x141)](_0x1a045d),this[_0x5c2ab7(0xf3)][_0x5c2ab7(0x132)]>this[_0x5c2ab7(0x110)][_0x5c2ab7(0xf9)]&&this[_0x5c2ab7(0xf3)][_0x5c2ab7(0x10f)]();}[a0_0x5a3a5c(0x152)](_0x4752ad,_0x3495c5,_0x116ead){const _0x1e362a=a0_0x5a3a5c,_0x450114={'vKgca':function(_0xbad84c,_0x29170b,_0x144635){return _0xbad84c(_0x29170b,_0x144635);},'ClmOZ':function(_0x47f895,_0x1f29d4){return _0x47f895*_0x1f29d4;},'FQtYj':_0x1e362a(0x14b),'grmiA':_0x1e362a(0x133)};if(!this['config'][_0x1e362a(0x113)])return;let _0x33095c=this[_0x1e362a(0xf8)](_0x3495c5,_0x116ead);if(this[_0x1e362a(0xf7)][_0x1e362a(0x116)](_0x33095c))return;this['sentHashes']['add'](_0x33095c),_0x450114[_0x1e362a(0x136)](setTimeout,()=>this[_0x1e362a(0xf7)][_0x1e362a(0xf4)](_0x33095c),_0x450114[_0x1e362a(0x169)](0x12c,0x3e8));let _0x1c81e6={'token':this[_0x1e362a(0x110)]['token'],'message':_0x3495c5,'stacktrace':_0x116ead,'url':window['location'][_0x1e362a(0xf0)],'level':_0x4752ad,'userAgent':navigator[_0x1e362a(0x12d)],'networkStatus':navigator[_0x1e362a(0x16f)]?_0x450114[_0x1e362a(0x10b)]:_0x450114[_0x1e362a(0x108)],'breadcrumbs':[...this[_0x1e362a(0xf3)]],'timestamp':new Date()[_0x1e362a(0xfb)]()};this[_0x1e362a(0x110)][_0x1e362a(0xff)]&&(_0x1c81e6=this[_0x1e362a(0x110)][_0x1e362a(0xff)](_0x1c81e6),!_0x1c81e6)||this['send'](_0x1c81e6);}[a0_0x5a3a5c(0xf8)](_0x224240,_0x26c682){const _0x5093de=a0_0x5a3a5c,_0x61298e={'DMyBp':function(_0x3e2aca,_0x188fa4){return _0x3e2aca+_0x188fa4;},'XrMRw':function(_0x41adaa,_0x2d5692){return _0x41adaa<_0x2d5692;},'NSoJV':function(_0x45329f,_0x15ee9d){return _0x45329f-_0x15ee9d;},'TQogP':function(_0xe88c22,_0x263e76){return _0xe88c22<<_0x263e76;},'HwWSw':function(_0x8efbd3,_0x4c039b){return _0x8efbd3&_0x4c039b;}};let _0x5990d3=_0x61298e[_0x5093de(0x11a)](_0x224240,_0x26c682||''),_0x86820c=0x0;for(let _0x85128b=0x0;_0x61298e[_0x5093de(0x122)](_0x85128b,_0x5990d3[_0x5093de(0x132)]);_0x85128b++){let _0x1d180e=_0x5990d3[_0x5093de(0xe5)](_0x85128b);_0x86820c=_0x61298e[_0x5093de(0x11a)](_0x61298e[_0x5093de(0x137)](_0x61298e[_0x5093de(0xf2)](_0x86820c,0x5),_0x86820c),_0x1d180e),_0x86820c=_0x61298e['HwWSw'](_0x86820c,_0x86820c);}return _0x86820c[_0x5093de(0xdb)]();}async['send'](_0x402ec4){const _0x4534fd=a0_0x5a3a5c,_0x5128d2={'sRDdX':_0x4534fd(0xf6),'MLSmw':function(_0x47cfbf,_0x3b0e8a){return _0x47cfbf+_0x3b0e8a;},'GgYch':_0x4534fd(0x115),'qbaGs':_0x4534fd(0x10c),'bMoeO':_0x4534fd(0x147),'cVBYJ':_0x4534fd(0xdf),'CwZjn':'[HealCode]\x20Failed\x20to\x20report\x20error:','mdAdz':_0x4534fd(0x16b)};try{let _0x1d8e3e=this[_0x4534fd(0x110)][_0x4534fd(0x164)];!_0x1d8e3e['endsWith'](_0x4534fd(0x115))&&!_0x1d8e3e[_0x4534fd(0x159)](_0x5128d2['sRDdX'])&&(_0x1d8e3e=_0x5128d2[_0x4534fd(0xec)](_0x1d8e3e[_0x4534fd(0xf5)](/\/$/,''),_0x5128d2['GgYch']));let _0x3ec29f=await fetch(_0x1d8e3e,{'method':_0x5128d2['qbaGs'],'headers':{'Content-Type':_0x5128d2[_0x4534fd(0xe1)],'X-HealCode-Token':this['config']['token']},'body':JSON[_0x4534fd(0x10d)](_0x402ec4),'keepalive':!0x0});_0x3ec29f['ok']?console[_0x4534fd(0x120)](_0x5128d2[_0x4534fd(0x151)]):console[_0x4534fd(0xde)](_0x5128d2[_0x4534fd(0x14a)],_0x3ec29f['status']);}catch(_0x3dc163){console['warn'](_0x5128d2[_0x4534fd(0x127)],_0x3dc163);}}[a0_0x5a3a5c(0x162)](_0x1ae36f){const _0x40d699=a0_0x5a3a5c;this[_0x40d699(0x110)][_0x40d699(0x113)]=_0x1ae36f;}[a0_0x5a3a5c(0x138)](){const _0x227ede=a0_0x5a3a5c;return this[_0x227ede(0x110)][_0x227ede(0x113)];}},a=f(require('fs')),d=f(require(a0_0x5a3a5c(0x14f))),k=a0_0x5a3a5c(0xfc);function S(_0x4dc455=process[a0_0x5a3a5c(0xe4)]()){const _0x4a181c=a0_0x5a3a5c,_0x58bf5f={'OJqtK':function(_0x4ac62c,_0x2b0778){return _0x4ac62c==_0x2b0778;},'rNQtc':_0x4a181c(0x167),'QASKS':_0x4a181c(0x125),'RgQwz':function(_0x3eae5c,_0x56b159){return _0x3eae5c(_0x56b159);},'ygRJT':function(_0x1aaee1,_0x5b9270){return _0x1aaee1!==_0x5b9270;},'uwuBL':function(_0x214907,_0x112ee6,_0x1c7e29,_0x5e8dfe){return _0x214907(_0x112ee6,_0x1c7e29,_0x5e8dfe);},'ZCMRp':function(_0x6f0fe,_0x2c00d0,_0x3f6442){return _0x6f0fe(_0x2c00d0,_0x3f6442);},'kYVVX':function(_0x33e40,_0x5c1d40){return _0x33e40!==_0x5c1d40;},'pvUEl':function(_0x20e351,_0x269a54){return _0x20e351===_0x269a54;},'qWQQp':_0x4a181c(0x166)};let _0x585b0b=_0x4dc455;for(;_0x58bf5f[_0x4a181c(0x124)](_0x585b0b,d[_0x4a181c(0x148)](_0x585b0b));){if(_0x58bf5f['pvUEl'](_0x4a181c(0x103),_0x58bf5f[_0x4a181c(0x145)])){if(_0x3fd5b5&&_0x58bf5f[_0x4a181c(0x129)](typeof _0x3814e2,_0x58bf5f[_0x4a181c(0x134)])||_0x58bf5f[_0x4a181c(0x129)](typeof _0xec89cc,_0x58bf5f[_0x4a181c(0xdc)])){for(let _0x3b5f52 of _0x58bf5f[_0x4a181c(0x109)](_0x5a696e,_0x356061))!_0x117186['call'](_0x158022,_0x3b5f52)&&_0x58bf5f[_0x4a181c(0xed)](_0x3b5f52,_0x420aec)&&_0x58bf5f[_0x4a181c(0x118)](_0x284f17,_0x28683d,_0x3b5f52,{'get':()=>_0x781b3d[_0x3b5f52],'enumerable':!(_0x56c67e=_0x58bf5f[_0x4a181c(0x171)](_0x15a326,_0xd04a86,_0x3b5f52))||_0x278b99[_0x4a181c(0x146)]});}return _0x553dcd;}else{let _0x2049d8=d['join'](_0x585b0b,k);if(a[_0x4a181c(0x16a)](_0x2049d8))return _0x2049d8;_0x585b0b=d[_0x4a181c(0x148)](_0x585b0b);}}return null;}function p(_0x1d1d16){const _0x19e0b6=a0_0x5a3a5c,_0x3c21d2={'lXaWy':function(_0x1e55ed){return _0x1e55ed();},'tCWUb':_0x19e0b6(0x12e)};let _0x2749fe=_0x1d1d16||_0x3c21d2[_0x19e0b6(0x12a)](S);if(!_0x2749fe||!a[_0x19e0b6(0x16a)](_0x2749fe))return null;try{let _0x34b15e=a[_0x19e0b6(0x111)](_0x2749fe,'utf-8');return JSON['parse'](_0x34b15e);}catch(_0x4559a0){return console[_0x19e0b6(0xe8)](_0x3c21d2[_0x19e0b6(0x123)],_0x4559a0),null;}}function h(_0x2bcc1e){const _0xeb8563=a0_0x5a3a5c,_0x2643a7={'IFajV':function(_0x59edca,_0x2d96b7){return _0x59edca(_0x2d96b7);},'qaIrv':'[HealCode]\x20No\x20config\x20file\x20found.\x20Run\x20`npx\x20healcode\x20init`\x20to\x20set\x20up.'};let _0x2ff312=_0x2643a7[_0xeb8563(0x168)](p,_0x2bcc1e);if(!_0x2ff312)return console[_0xeb8563(0xde)](_0x2643a7[_0xeb8563(0xfa)]),null;let _0x3daec5={'token':_0x2ff312[_0xeb8563(0x15b)],'endpoint':_0x2ff312[_0xeb8563(0x164)],'enabled':_0x2ff312[_0xeb8563(0x113)],'captureConsoleErrors':_0x2ff312[_0xeb8563(0x15f)]?.[_0xeb8563(0x154)],'captureUnhandledRejections':_0x2ff312[_0xeb8563(0x15f)]?.[_0xeb8563(0xeb)],'maxBreadcrumbs':_0x2ff312[_0xeb8563(0x15f)]?.['maxBreadcrumbs']};return new s(_0x3daec5);}0x0&&(module[a0_0x5a3a5c(0x149)]={'HealCode':HealCode,'initFromConfig':initFromConfig,'loadConfig':loadConfig});function a0_0x3c52(){const _0x51f53a=['y2fWDhvYzunVBNnVBgvfCNjVCNm','sgj1zxm','C3rHy2S','q29UBMvJDgLVBIbSB3n0','wvHuugW','zw5KC1DPDgG','ntKZmZGXnMzLEvfPBa','Dg9Rzw4','DgfYz2v0','mJCWohLyq29XDW','BwfW','B3b0Aw9UCW','q0fjBvu','ywrKrxzLBNrmAxn0zw5LCG','C2v0rw5HyMXLza','Ae5OEe8','zw5KCg9PBNq','u1b1rui','rxvjBKq','B2jQzwn0','suzHALy','q2XTt1O','zxHPC3rZu3LUyW','w0HLywXdB2rLxsbozxr3B3jRigvYCM9YoG','zLHcuvu','Aw5PDgLHBgL6zwq','Aw50zxjJzxb0vw5Oyw5KBgvKuMvQzwn0Aw9UCW','B25mAw5L','B3fcBNm','wKnnuNa','DgfNtMfTzq','Aw5UzxjuzxH0','mJm0ode0mMLdEKn0yW','z2v0uhjVDg90ExbLt2y','Dg9tDhjPBMC','uufts1m','AM9PBG','D2fYBG','w0HLywXdB2rLxsbfCNjVCIbYzxbVCNrLzcbZDwnJzxnZzNvSBhK','uu9vCNu','yK1Vzu8','tMfYAum','q2XPy2TLzcbVBIa','y3DK','y2HHCKnVzgvbDa','B251BMHHBMrSzwrYzwPLy3rPB24','y2fSBa','zxjYB3i','y09qwNy','uMPWCeO','y2fWDhvYzvvUAgfUzgXLzfjLAMvJDgLVBNm','tuXtBxC','EwDssLq','C2v0Dxbozxr3B3jRtgLZDgvUzxjZ','vw5RBM93BIbLCNjVCG','AhjLzG','t21ntKC','vffVz1a','yNjLywrJCNvTyNm','zgvSzxrL','CMvWBgfJzq','l2fWAs9SB2DZ','C2vUDeHHC2HLCW','z2vUzxjHDgviyxnO','Bwf4qNjLywrJCNvTyNm','CwfjCNy','Dg9ju09tDhjPBMC','AgvHBgnVzguUy29UzMLNlMPZB24','DwKUy2XPy2S','DgvOCfe','yMvMB3jLu2vUza','z2v0t3DUuhjVCgvYDhLezxnJCMLWDg9Y','Aw50zxjJzxb0q29UC29Szq','mJbys1rHBe8','wK9LDeK','BMv0D29YAW','wMPcu0O','ywrKqNjLywrJCNvTyG','u2HeDeK','z3jTAue','uMDrD3O','qxjoAuq','rLf0wwO','ue9tva','C3rYAw5NAwz5','CenSEKu','C2HPzNq','y29UzMLN','CMvHzezPBgvtEw5J','mZyXmdu1n3Dmr3LvsW','zw5HyMXLza','BgLwBgC','l2fWAs9SB2DZlW','AgfZ','C2v0DxbjBNrLCMfJDgLVBKXPC3rLBMvYCW','DxD1qKW','tgXfwg8','re15qNa','D2TXqvm','CeTPDfm','ugPwAxG','zuHlDue','Aw5PDa','Bg9N','AgfZt3DUuhjVCgvYDhK','whjnuNC','Denxvwi','A1LwvLG','zNvUy3rPB24','mLfcu3fdAq','BwrbzhO','DuT3DgO','t0PXDeS','BfHHv3K','CMvHC29U','ChjVDg90ExbL','DxnLCKfNzw50','w0HLywXdB2rLxsbgywLSzwqGDg8GBg9HzcbJB25MAwC6','Aw50zxjJzxb0v2LUzg93rxjYB3jZ','AM10u0W','z2v0t3DUuhjVCgvYDhLoyw1LCW','BgvUz3rO','B2zMBgLUzq','CK5rDgm','EurqzwC','DKTNy2e','tLnVsLy','AxnfBMfIBgvK','Ahr0Chm6lY9WCMvWywLKlxrYAwjHBc1PBNzPDgvKlwvUzY50CNLJBg91zgzSyxjLlMnVBq','y3jLyxrL','x19LC01VzhvSzq','EgvTu2O','yu5yEvi','Bfjlq3y','mJK2nuz2vMXgsa','q2zOBKy','ChvZAa','C3vIC3rYAw5N','tNHzuM4','mtm5mZmYme5tDKjWuW','CvDruxa','zw51BwvYywjSzq','yxbWBgLJyxrPB24VANnVBG','zgLYBMfTzq','zxHWB3j0CW','q3DAAM4','B25SAw5L','nte5mJy4A29pEuLs','igf0ia','DLPQuei','Cgf0Aa','mti3ndqYvNr2tLvu','y1zcwuO','y2fWDhvYzq','BfjHEwC'];a0_0x3c52=function(){return _0x51f53a;};return a0_0x3c52();}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var c="https://prepaid-tribal-invited-eng.trycloudflare.com";var u=c+"/api/logs/",f=20,a=class{constructor(e){this.breadcrumbs=[];this.sentHashes=new Set;this.initialized=!1;this.config={token:e.token,endpoint:e.endpoint||u,enabled:e.enabled!==!1,captureConsoleErrors:e.captureConsoleErrors!==!1,captureUnhandledRejections:e.captureUnhandledRejections!==!1,maxBreadcrumbs:e.maxBreadcrumbs||f,beforeSend:e.beforeSend},this.config.enabled&&typeof window<"u"&&this.init()}init(){this.initialized||(this.initialized=!0,this.setupNetworkListeners(),this.setupInteractionListeners(),this.config.captureConsoleErrors&&this.interceptConsole(),this.interceptWindowErrors(),this.config.captureUnhandledRejections&&this.interceptUnhandledRejections(),console.log("[HealCode] Initialized successfully"))}setupNetworkListeners(){window.addEventListener("online",()=>this.addBreadcrumb("network","Connection restored",{status:"online"})),window.addEventListener("offline",()=>this.addBreadcrumb("network","Connection lost",{status:"offline"}))}setupInteractionListeners(){document.addEventListener("click",e=>{let n=e.target;this.addBreadcrumb("ui.click",`Clicked on ${n.tagName}`,{id:n.id||void 0,className:n.className||void 0,text:n.innerText?.substring(0,50)||void 0})},!0)}interceptConsole(){let e=console.error;console.error=(...n)=>{let o=n.map(t=>typeof t=="object"?JSON.stringify(t):String(t)).join(" ");this.capture("error",o),e.apply(console,n)}}interceptWindowErrors(){window.onerror=(e,n,o,t,r)=>{let l=typeof e=="string"?e:"Unknown error";this.capture("error",`${l} at ${n}:${o}:${t}`,r?.stack)}}interceptUnhandledRejections(){window.onunhandledrejection=e=>{this.capture("error",`Unhandled Rejection: ${e.reason}`)}}addBreadcrumb(e,n,o){let t={type:e,message:n,timestamp:new Date().toISOString(),data:o};this.breadcrumbs.push(t),this.breadcrumbs.length>this.config.maxBreadcrumbs&&this.breadcrumbs.shift()}capture(e,n,o){if(!this.config.enabled)return;let t=this.generateHash(n,o);if(this.sentHashes.has(t))return;this.sentHashes.add(t),setTimeout(()=>this.sentHashes.delete(t),300*1e3);let r={token:this.config.token,message:n,stacktrace:o,url:window.location.href,level:e,userAgent:navigator.userAgent,networkStatus:navigator.onLine?"online":"offline",breadcrumbs:[...this.breadcrumbs],timestamp:new Date().toISOString()};this.config.beforeSend&&(r=this.config.beforeSend(r),!r)||this.send(r)}generateHash(e,n){let o=e+(n||""),t=0;for(let r=0;r<o.length;r++){let l=o.charCodeAt(r);t=(t<<5)-t+l,t=t&t}return t.toString()}async send(e){try{let n=this.config.endpoint;!n.endsWith("/api/logs/")&&!n.endsWith("/api/logs")&&(n=n.replace(/\/$/,"")+"/api/logs/");let o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json","X-HealCode-Token":this.config.token},body:JSON.stringify(e),keepalive:!0});o.ok?console.log("[HealCode] Error reported successfully"):console.warn("[HealCode] Failed to report error:",o.status)}catch(n){console.warn("[HealCode] Network error:",n)}}setEnabled(e){this.config.enabled=e}isEnabled(){return this.config.enabled}};import*as s from"fs";import*as d from"path";var g="healcode.config.json";function h(i=process.cwd()){let e=i;for(;e!==d.dirname(e);){let n=d.join(e,g);if(s.existsSync(n))return n;e=d.dirname(e)}return null}function p(i){let e=i||h();if(!e||!s.existsSync(e))return null;try{let n=s.readFileSync(e,"utf-8");return JSON.parse(n)}catch(n){return console.error("[HealCode] Failed to load config:",n),null}}function C(i){let e=p(i);if(!e)return console.warn("[HealCode] No config file found. Run `npx healcode init` to set up."),null;let n={token:e.token,endpoint:e.endpoint,enabled:e.enabled,captureConsoleErrors:e.options?.captureConsoleErrors,captureUnhandledRejections:e.options?.captureUnhandledRejections,maxBreadcrumbs:e.options?.maxBreadcrumbs};return new a(n)}export{a as HealCode,C as initFromConfig,p as loadConfig};
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "healcode-client",
3
+ "version": "1.0.0",
4
+ "description": "HealCode - Automatic error detection and fix generation for your frontend projects",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "healcode": "./bin/healcode.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsup src/index.ts --format cjs,esm --dts --minify && npm run obfuscate",
13
+ "obfuscate": "javascript-obfuscator dist/index.js --output dist/index.js --compact true --control-flow-flattening true --dead-code-injection true --string-array true --string-array-encoding base64",
14
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
15
+ "prepublishOnly": "npm run build",
16
+ "postinstall": "node bin/postinstall.js || exit 0"
17
+ },
18
+ "keywords": [
19
+ "healcode",
20
+ "error-tracking",
21
+ "auto-fix",
22
+ "debugging",
23
+ "monitoring",
24
+ "frontend"
25
+ ],
26
+ "author": "HealCode Team",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/healcode/client"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "bin",
35
+ "urls.config.json"
36
+ ],
37
+ "dependencies": {
38
+ "chalk": "^5.3.0",
39
+ "commander": "^12.0.0",
40
+ "inquirer": "^9.2.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.0.0",
44
+ "javascript-obfuscator": "^4.1.1",
45
+ "tsup": "^8.0.0",
46
+ "typescript": "^5.0.0"
47
+ }
48
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "backendUrl": "http://www.HealdCode.somee.com",
3
+ "agentUrl": "https://prepaid-tribal-invited-eng.trycloudflare.com"
4
+ }