@bugspotter/sdk 1.0.0 → 1.1.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.
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConsoleCapture = exports.SDK_LOG_PREFIX = void 0;
4
4
  const base_capture_1 = require("./base-capture");
5
- const circular_buffer_1 = require("../core/circular-buffer");
5
+ const common_1 = require("@bugspotter/common");
6
6
  const CONSOLE_METHODS = [
7
7
  'log',
8
8
  'warn',
@@ -21,7 +21,7 @@ class ConsoleCapture extends base_capture_1.BaseCapture {
21
21
  super(options);
22
22
  this.originalMethods = new Map();
23
23
  const maxLogs = (_a = options.maxLogs) !== null && _a !== void 0 ? _a : 100;
24
- this.buffer = new circular_buffer_1.CircularBuffer(maxLogs);
24
+ this.buffer = new common_1.CircularBuffer(maxLogs);
25
25
  this.captureStackTrace = (_b = options.captureStackTrace) !== null && _b !== void 0 ? _b : true;
26
26
  this.interceptConsole((_c = options.levels) !== null && _c !== void 0 ? _c : CONSOLE_METHODS);
27
27
  }
@@ -2,14 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NetworkCapture = void 0;
4
4
  const base_capture_1 = require("./base-capture");
5
- const circular_buffer_1 = require("../core/circular-buffer");
5
+ const common_1 = require("@bugspotter/common");
6
6
  class NetworkCapture extends base_capture_1.BaseCapture {
7
7
  constructor(options = {}) {
8
8
  var _a;
9
9
  super(options);
10
10
  this.isIntercepting = false;
11
11
  const maxRequests = (_a = options.maxRequests) !== null && _a !== void 0 ? _a : 50;
12
- this.buffer = new circular_buffer_1.CircularBuffer(maxRequests);
12
+ this.buffer = new common_1.CircularBuffer(maxRequests);
13
13
  this.filterUrls = options.filterUrls;
14
14
  this.originalFetch = window.fetch;
15
15
  this.originalXHR = {
package/dist/index.esm.js CHANGED
@@ -1940,106 +1940,124 @@ class ScreenshotProcessor {
1940
1940
  }
1941
1941
 
1942
1942
  /**
1943
- * PII Pattern Definitions
1944
- * Configurable regex patterns for detecting sensitive data (PII + credentials)
1943
+ * Generic circular buffer — fixed-size FIFO that overwrites oldest items.
1944
+ *
1945
+ * @template T The type of items stored in the buffer
1945
1946
  */
1947
+ let CircularBuffer$1 = class CircularBuffer {
1948
+ constructor(maxSize) {
1949
+ this.maxSize = maxSize;
1950
+ this.items = [];
1951
+ this.index = 0;
1952
+ this.count = 0;
1953
+ if (maxSize <= 0) {
1954
+ throw new Error('CircularBuffer maxSize must be greater than 0');
1955
+ }
1956
+ }
1957
+ /**
1958
+ * Add an item to the buffer. If full, the oldest item is overwritten.
1959
+ */
1960
+ add(item) {
1961
+ if (this.count < this.maxSize) {
1962
+ this.items.push(item);
1963
+ this.count++;
1964
+ }
1965
+ else {
1966
+ this.items[this.index] = item;
1967
+ }
1968
+ this.index = (this.index + 1) % this.maxSize;
1969
+ }
1970
+ /**
1971
+ * Get all items in chronological order (oldest to newest).
1972
+ * Returns a copy of the internal array.
1973
+ */
1974
+ getAll() {
1975
+ if (this.count < this.maxSize) {
1976
+ return [...this.items];
1977
+ }
1978
+ return [
1979
+ ...this.items.slice(this.index),
1980
+ ...this.items.slice(0, this.index),
1981
+ ];
1982
+ }
1983
+ /**
1984
+ * Clear all items from the buffer.
1985
+ */
1986
+ clear() {
1987
+ this.items = [];
1988
+ this.index = 0;
1989
+ this.count = 0;
1990
+ }
1991
+ get size() {
1992
+ return this.count;
1993
+ }
1994
+ get capacity() {
1995
+ return this.maxSize;
1996
+ }
1997
+ get isEmpty() {
1998
+ return this.count === 0;
1999
+ }
2000
+ get isFull() {
2001
+ return this.count >= this.maxSize;
2002
+ }
2003
+ };
2004
+
1946
2005
  /**
1947
- * Default built-in patterns
2006
+ * PII pattern definitions for data sanitization.
1948
2007
  */
1949
2008
  const DEFAULT_PATTERNS = {
1950
2009
  email: {
1951
2010
  name: 'email',
1952
2011
  regex: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
1953
2012
  description: 'Email addresses',
1954
- examples: [
1955
- 'user@example.com',
1956
- 'john.doe+tag@company.co.uk',
1957
- 'test_user@sub.domain.com',
1958
- ],
1959
- priority: 1, // Highest priority - most specific
2013
+ priority: 1,
1960
2014
  },
1961
2015
  creditcard: {
1962
2016
  name: 'creditcard',
1963
2017
  regex: /\b(?:\d{4}[-\s]){3}\d{4}\b|\b\d{4}[-\s]\d{6}[-\s]\d{5}\b|\b\d{13,19}\b/g,
1964
- description: 'Credit card numbers (Visa, MC, Amex, Discover, etc.)',
1965
- examples: [
1966
- '4532-1488-0343-6467',
1967
- '4532148803436467',
1968
- '5425 2334 3010 9903',
1969
- '3782 822463 10005',
1970
- ],
2018
+ description: 'Credit card numbers',
1971
2019
  priority: 2,
1972
2020
  },
1973
2021
  ssn: {
1974
2022
  name: 'ssn',
1975
2023
  regex: /\b\d{3}-\d{2}-\d{4}\b|\b(?<!\d)\d{9}(?!\d)\b/g,
1976
2024
  description: 'US Social Security Numbers',
1977
- examples: ['123-45-6789', '987654321'],
1978
2025
  priority: 3,
1979
2026
  },
1980
2027
  iin: {
1981
2028
  name: 'iin',
1982
2029
  regex: /\b[0-9]{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12][0-9]|3[01])\d{6}\b/g,
1983
- description: 'Kazakhstan IIN/BIN (12 digits with date validation)',
1984
- examples: ['950315300123', '880612500456', '021225123456'],
2030
+ description: 'Kazakhstan IIN/BIN',
1985
2031
  priority: 4,
1986
2032
  },
1987
2033
  ip: {
1988
2034
  name: 'ip',
1989
2035
  regex: /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b|(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g,
1990
2036
  description: 'IPv4 and IPv6 addresses',
1991
- examples: [
1992
- '192.168.1.100',
1993
- '127.0.0.1',
1994
- '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
1995
- ],
1996
2037
  priority: 5,
1997
2038
  },
1998
2039
  phone: {
1999
2040
  name: 'phone',
2000
2041
  regex: /\+\d{1,3}[-.\s]\d{3}[-.\s]\d{4}\b|\+\d{1,3}[-.\s]\d{3}[-.\s]\d{3}[-.\s]\d{4}\b|\(\d{3}\)\s*\d{3}[-.\s]\d{4}\b|\b\d{3}[-.\s]\d{3}[-.\s]\d{4}\b/g,
2001
- description: 'International phone numbers',
2002
- examples: [
2003
- '+1-555-1234',
2004
- '+1-555-123-4567',
2005
- '(555) 123-4567',
2006
- '555-123-4567',
2007
- '+7 777 123 4567',
2008
- ],
2042
+ description: 'Phone numbers',
2009
2043
  priority: 6,
2010
2044
  },
2011
2045
  apikey: {
2012
2046
  name: 'apikey',
2013
2047
  regex: /\b(?:sk|pk)_(?:live|test)_[a-zA-Z0-9]{24,}\b|AIza[a-zA-Z0-9_-]{35}|ya29\.[a-zA-Z0-9_-]+|AKIA[a-zA-Z0-9]{16}\b/g,
2014
- description: 'API keys (Stripe, Google, AWS, etc.)',
2015
- examples: [
2016
- 'sk_live_abc123def456ghi789jkl',
2017
- 'pk_test_xyz789abc123def456',
2018
- 'AIzaSyD1234567890abcdefghijklmnopqrst',
2019
- 'AKIAIOSFODNN7EXAMPLE',
2020
- ],
2048
+ description: 'API keys (Stripe, Google, AWS)',
2021
2049
  priority: 7,
2022
2050
  },
2023
2051
  token: {
2024
2052
  name: 'token',
2025
2053
  regex: /\b(?:Bearer\s+)?[a-zA-Z0-9_-]{32,}\b|ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36}|github_pat_[a-zA-Z0-9_]{82}/g,
2026
- description: 'Authentication tokens (Bearer, GitHub, JWT-like)',
2027
- examples: [
2028
- 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
2029
- 'ghp_abc123def456ghi789jkl012mno345pqr',
2030
- 'gho_xyz789abc123def456ghi789jkl012mno',
2031
- ],
2054
+ description: 'Auth tokens (Bearer, GitHub, JWT-like)',
2032
2055
  priority: 8,
2033
2056
  },
2034
2057
  password: {
2035
2058
  name: 'password',
2036
2059
  regex: /(?:password|passwd|pwd)[\s:=]+[^\s]{6,}|(?:password|passwd|pwd)["']?\s*[:=]\s*["']?[^\s"']{6,}/gi,
2037
- description: 'Password fields in text (password=..., pwd:...)',
2038
- examples: [
2039
- 'password: MySecret123!',
2040
- 'passwd=SecurePass456',
2041
- 'pwd: "MyP@ssw0rd"',
2042
- ],
2060
+ description: 'Password fields in text',
2043
2061
  priority: 9,
2044
2062
  },
2045
2063
  };
@@ -2055,13 +2073,147 @@ const PATTERN_CATEGORIES = {
2055
2073
  kazakhstan: ['iin'],
2056
2074
  };
2057
2075
  /**
2058
- * Get patterns sorted by priority
2076
+ * Pre-configured pattern sets for common compliance/use cases
2059
2077
  */
2078
+ const PATTERN_PRESETS = {
2079
+ all: Object.keys(DEFAULT_PATTERNS),
2080
+ minimal: ['email', 'creditcard', 'ssn'],
2081
+ financial: ['creditcard', 'ssn'],
2082
+ contact: ['email', 'phone'],
2083
+ identification: ['ssn', 'iin'],
2084
+ credentials: ['apikey', 'token', 'password'],
2085
+ kazakhstan: ['email', 'phone', 'iin'],
2086
+ gdpr: ['email', 'phone', 'ip'],
2087
+ pci: ['creditcard'],
2088
+ security: [
2089
+ 'email',
2090
+ 'phone',
2091
+ 'creditcard',
2092
+ 'ssn',
2093
+ 'apikey',
2094
+ 'token',
2095
+ 'password',
2096
+ ],
2097
+ };
2060
2098
  function getPatternsByPriority(patterns) {
2061
- return [...patterns].sort((a, b) => {
2062
- return a.priority - b.priority;
2063
- });
2099
+ return [...patterns].sort((a, b) => a.priority - b.priority);
2100
+ }
2101
+ function createPatternConfig(preset) {
2102
+ const names = typeof preset === 'string' ? PATTERN_PRESETS[preset] : preset;
2103
+ return names.map((name) => DEFAULT_PATTERNS[name]);
2064
2104
  }
2105
+ /**
2106
+ * Validate a custom pattern regex for performance issues
2107
+ */
2108
+ function validatePattern(pattern) {
2109
+ const errors = [];
2110
+ if (!pattern.name)
2111
+ errors.push('Pattern must have a name');
2112
+ if (!pattern.regex) {
2113
+ errors.push('Pattern must have a regex');
2114
+ }
2115
+ else {
2116
+ if (!pattern.regex.global)
2117
+ errors.push('Pattern regex must have global flag');
2118
+ try {
2119
+ const testString = 'a'.repeat(1000);
2120
+ const start = Date.now();
2121
+ testString.match(pattern.regex);
2122
+ if (Date.now() - start > 100) {
2123
+ errors.push('Pattern regex may cause performance issues');
2124
+ }
2125
+ }
2126
+ catch (e) {
2127
+ errors.push(`Pattern regex error: ${e.message}`);
2128
+ }
2129
+ }
2130
+ return { valid: errors.length === 0, errors };
2131
+ }
2132
+
2133
+ /**
2134
+ * URL helper utilities for endpoint validation and parsing.
2135
+ */
2136
+ /**
2137
+ * Custom error for invalid endpoint URLs
2138
+ */
2139
+ class InvalidEndpointError extends Error {
2140
+ constructor(endpoint, reason) {
2141
+ super(`Invalid endpoint URL: ${endpoint}. ${reason}`);
2142
+ this.endpoint = endpoint;
2143
+ this.reason = reason;
2144
+ this.name = 'InvalidEndpointError';
2145
+ }
2146
+ }
2147
+ /**
2148
+ * Custom error for insecure endpoints
2149
+ */
2150
+ class InsecureEndpointError extends Error {
2151
+ constructor(endpoint) {
2152
+ super(`Secure HTTPS connection required. Attempted to connect to insecure endpoint: "${endpoint}"`);
2153
+ this.endpoint = endpoint;
2154
+ this.name = 'InsecureEndpointError';
2155
+ }
2156
+ }
2157
+ /**
2158
+ * Strip known endpoint suffixes from path.
2159
+ * Removes /api/v1/reports path.
2160
+ */
2161
+ function stripEndpointSuffix(path) {
2162
+ const reportsIndex = path.lastIndexOf('/api/v1/reports');
2163
+ if (reportsIndex !== -1) {
2164
+ return path.substring(0, reportsIndex);
2165
+ }
2166
+ return path.replace(/\/$/, '') || '';
2167
+ }
2168
+ /**
2169
+ * Extract base API URL from endpoint.
2170
+ * Returns scheme + host + base path (without /api/v1/reports suffix).
2171
+ *
2172
+ * @example
2173
+ * getApiBaseUrl('https://api.example.com/api/v1/reports')
2174
+ * // Returns: 'https://api.example.com'
2175
+ *
2176
+ * @throws InvalidEndpointError if endpoint is not a valid absolute URL
2177
+ */
2178
+ function getApiBaseUrl(endpoint) {
2179
+ if (!endpoint) {
2180
+ throw new InvalidEndpointError('', 'No endpoint configured');
2181
+ }
2182
+ try {
2183
+ const url = new URL(endpoint);
2184
+ const basePath = stripEndpointSuffix(url.pathname);
2185
+ return url.origin + basePath;
2186
+ }
2187
+ catch {
2188
+ throw new InvalidEndpointError(endpoint, 'Must be a valid absolute URL (e.g., https://api.example.com/api/v1/reports)');
2189
+ }
2190
+ }
2191
+ /**
2192
+ * Checks if the endpoint uses a secure protocol.
2193
+ * Uses the URL API for robust parsing.
2194
+ *
2195
+ * Allows HTTPS in production, HTTP only on localhost/127.0.0.1 for development.
2196
+ */
2197
+ function isSecureEndpoint(endpoint) {
2198
+ if (!endpoint)
2199
+ return false;
2200
+ try {
2201
+ const url = new URL(endpoint.trim());
2202
+ return (url.protocol === 'https:' ||
2203
+ (url.protocol === 'http:' &&
2204
+ (url.hostname === 'localhost' || url.hostname === '127.0.0.1')));
2205
+ }
2206
+ catch {
2207
+ return false;
2208
+ }
2209
+ }
2210
+
2211
+ /**
2212
+ * PII Pattern Definitions
2213
+ * Re-exports from @bugspotter/common + SDK-specific extensions
2214
+ */
2215
+ // Re-export everything from @bugspotter/common
2216
+ // SDK-specific extensions
2065
2217
  /**
2066
2218
  * Get pattern by name
2067
2219
  */
@@ -2076,12 +2228,6 @@ function getPatternsByCategory(category) {
2076
2228
  return DEFAULT_PATTERNS[name];
2077
2229
  });
2078
2230
  }
2079
- /**
2080
- * Get all pattern names
2081
- */
2082
- function getAllPatternNames() {
2083
- return Object.keys(DEFAULT_PATTERNS);
2084
- }
2085
2231
  /**
2086
2232
  * Custom pattern builder for advanced use cases
2087
2233
  */
@@ -2094,7 +2240,6 @@ class PatternBuilder {
2094
2240
  return this;
2095
2241
  }
2096
2242
  regex(regex) {
2097
- // Ensure global flag
2098
2243
  if (!regex.global) {
2099
2244
  const flags = regex.flags.includes('g') ? regex.flags : regex.flags + 'g';
2100
2245
  this.pattern.regex = new RegExp(regex.source, flags);
@@ -2130,85 +2275,6 @@ class PatternBuilder {
2130
2275
  };
2131
2276
  }
2132
2277
  }
2133
- /**
2134
- * Pre-configured pattern sets for common use cases
2135
- */
2136
- const PATTERN_PRESETS = {
2137
- /** All patterns enabled (PII + credentials) - default */
2138
- all: getAllPatternNames(),
2139
- /** Minimal - only most critical PII */
2140
- minimal: ['email', 'creditcard', 'ssn'],
2141
- /** Financial data only */
2142
- financial: PATTERN_CATEGORIES.financial,
2143
- /** Contact information only */
2144
- contact: PATTERN_CATEGORIES.contact,
2145
- /** Identification numbers only */
2146
- identification: PATTERN_CATEGORIES.identification,
2147
- /** Credentials and secrets only */
2148
- credentials: PATTERN_CATEGORIES.credentials,
2149
- /** Kazakhstan-specific patterns */
2150
- kazakhstan: ['email', 'phone', 'iin'],
2151
- /** GDPR compliance recommended set */
2152
- gdpr: ['email', 'phone', 'ip'],
2153
- /** PCI DSS compliance required */
2154
- pci: ['creditcard'],
2155
- /** Security-focused: PII + credentials */
2156
- security: [
2157
- 'email',
2158
- 'phone',
2159
- 'creditcard',
2160
- 'ssn',
2161
- 'apikey',
2162
- 'token',
2163
- 'password',
2164
- ],
2165
- };
2166
- /**
2167
- * Create custom pattern configuration
2168
- */
2169
- function createPatternConfig(preset) {
2170
- const names = typeof preset === 'string' ? PATTERN_PRESETS[preset] : preset;
2171
- return names.map((name) => {
2172
- return DEFAULT_PATTERNS[name];
2173
- });
2174
- }
2175
- /**
2176
- * Validate pattern regex
2177
- */
2178
- function validatePattern(pattern) {
2179
- const errors = [];
2180
- if (!pattern.name) {
2181
- errors.push('Pattern must have a name');
2182
- }
2183
- if (!pattern.regex) {
2184
- errors.push('Pattern must have a regex');
2185
- }
2186
- else {
2187
- if (!pattern.regex.global) {
2188
- errors.push('Pattern regex must have global flag');
2189
- }
2190
- // Test regex doesn't cause catastrophic backtracking
2191
- try {
2192
- const testString = 'a'.repeat(1000);
2193
- const start = Date.now();
2194
- testString.match(pattern.regex);
2195
- const duration = Date.now() - start;
2196
- if (duration > 100) {
2197
- errors.push(`Pattern regex may cause performance issues (took ${duration}ms on test)`);
2198
- }
2199
- }
2200
- catch (error) {
2201
- errors.push(`Pattern regex error: ${error.message}`);
2202
- }
2203
- }
2204
- if (pattern.priority < 0) {
2205
- errors.push('Pattern priority must be non-negative');
2206
- }
2207
- return {
2208
- valid: errors.length === 0,
2209
- errors,
2210
- };
2211
- }
2212
2278
 
2213
2279
  /**
2214
2280
  * PII Detection and Sanitization Utility - REFACTORED
@@ -2530,7 +2596,7 @@ function createLogger(config) {
2530
2596
  return new BugSpotterLogger(config);
2531
2597
  }
2532
2598
 
2533
- const logger$8 = getLogger();
2599
+ const logger$7 = getLogger();
2534
2600
  /**
2535
2601
  * BugReportModal
2536
2602
  *
@@ -2810,7 +2876,7 @@ class BugReportModal {
2810
2876
  finalScreenshot = yield this.screenshotProcessor.mergeRedactions(this.originalScreenshot, this.redactionCanvas.getCanvas());
2811
2877
  }
2812
2878
  catch (mergeError) {
2813
- logger$8.error('Failed to merge redactions:', mergeError);
2879
+ logger$7.error('Failed to merge redactions:', mergeError);
2814
2880
  finalScreenshot = this.originalScreenshot;
2815
2881
  }
2816
2882
  }
@@ -2871,98 +2937,6 @@ const DEFAULT_REPLAY_DURATION_SECONDS = 15;
2871
2937
  */
2872
2938
  const MAX_RECOMMENDED_REPLAY_DURATION_SECONDS = 30;
2873
2939
 
2874
- /**
2875
- * URL Helper Utilities
2876
- * Extract base API URL from endpoint configuration
2877
- */
2878
- const logger$7 = getLogger();
2879
- /**
2880
- * Custom error for invalid endpoint URLs
2881
- */
2882
- class InvalidEndpointError extends Error {
2883
- constructor(endpoint, reason) {
2884
- super(`Invalid endpoint URL: ${endpoint}. ${reason}`);
2885
- this.endpoint = endpoint;
2886
- this.reason = reason;
2887
- this.name = 'InvalidEndpointError';
2888
- }
2889
- }
2890
- /**
2891
- * Strip known endpoint suffixes from path
2892
- * Removes /api/v1/reports path
2893
- */
2894
- function stripEndpointSuffix(path) {
2895
- // Use lastIndexOf to handle paths like '/prefix/api/v1/reports'
2896
- const reportsIndex = path.lastIndexOf('/api/v1/reports');
2897
- if (reportsIndex !== -1) {
2898
- return path.substring(0, reportsIndex);
2899
- }
2900
- // Remove trailing slash
2901
- return path.replace(/\/$/, '') || '';
2902
- }
2903
- /**
2904
- * Extract base API URL from endpoint
2905
- * Returns scheme + host + base path (without /api/v1/reports suffix)
2906
- *
2907
- * @example
2908
- * getApiBaseUrl('https://api.example.com/api/v1/reports')
2909
- * // Returns: 'https://api.example.com'
2910
- *
2911
- * @throws InvalidEndpointError if endpoint is not a valid absolute URL
2912
- */
2913
- function getApiBaseUrl(endpoint) {
2914
- if (!endpoint) {
2915
- throw new InvalidEndpointError('', 'No endpoint configured');
2916
- }
2917
- try {
2918
- const url = new URL(endpoint);
2919
- const basePath = stripEndpointSuffix(url.pathname);
2920
- return url.origin + basePath;
2921
- }
2922
- catch (error) {
2923
- const errorMessage = error instanceof Error ? error.message : String(error);
2924
- logger$7.error('Invalid endpoint URL - must be a valid absolute URL', {
2925
- endpoint,
2926
- error: errorMessage,
2927
- });
2928
- throw new InvalidEndpointError(endpoint, 'Must be a valid absolute URL (e.g., https://api.example.com/api/v1/reports)');
2929
- }
2930
- }
2931
- /**
2932
- * specific error for insecure endpoints
2933
- */
2934
- class InsecureEndpointError extends Error {
2935
- constructor(endpoint) {
2936
- super(`Secure HTTPS connection required. Attempted to connect to insecure endpoint: "${endpoint}"`);
2937
- this.endpoint = endpoint;
2938
- this.name = 'InsecureEndpointError';
2939
- }
2940
- }
2941
- /**
2942
- * Checks if the endpoint uses the secure HTTPS protocol.
2943
- * Uses the URL API for robust parsing.
2944
- *
2945
- * @param endpoint The endpoint URL to check
2946
- * @returns True if the endpoint uses HTTPS
2947
- */
2948
- function isSecureEndpoint(endpoint) {
2949
- if (!endpoint)
2950
- return false;
2951
- try {
2952
- const url = new URL(endpoint.trim());
2953
- // STRICT SECURITY:
2954
- // 1. Production must use HTTPS
2955
- // 2. Development allowed on localhost/127.0.0.1 via HTTP
2956
- return (url.protocol === 'https:' ||
2957
- (url.protocol === 'http:' &&
2958
- (url.hostname === 'localhost' || url.hostname === '127.0.0.1')));
2959
- }
2960
- catch (_a) {
2961
- // If it's not a valid URL, it's definitely not a secure endpoint
2962
- return false;
2963
- }
2964
- }
2965
-
2966
2940
  /**
2967
2941
  * SDK version - auto-generated from package.json
2968
2942
  * DO NOT EDIT THIS FILE MANUALLY
@@ -2970,7 +2944,7 @@ function isSecureEndpoint(endpoint) {
2970
2944
  * This file is automatically generated during the build process.
2971
2945
  * To update the version, modify package.json
2972
2946
  */
2973
- const VERSION = '1.0.0';
2947
+ const VERSION = '1.1.0';
2974
2948
 
2975
2949
  /**
2976
2950
  * Configuration Validation Utilities
@@ -11089,83 +11063,6 @@ class ScreenshotCapture extends BaseCapture {
11089
11063
  }
11090
11064
  }
11091
11065
 
11092
- /**
11093
- * A generic circular buffer implementation for storing a fixed number of items.
11094
- * When the buffer is full, new items overwrite the oldest items.
11095
- *
11096
- * @template T The type of items stored in the buffer
11097
- */
11098
- let CircularBuffer$1 = class CircularBuffer {
11099
- constructor(maxSize) {
11100
- this.maxSize = maxSize;
11101
- this.items = [];
11102
- this.index = 0;
11103
- this.count = 0;
11104
- if (maxSize <= 0) {
11105
- throw new Error('CircularBuffer maxSize must be greater than 0');
11106
- }
11107
- }
11108
- /**
11109
- * Add an item to the buffer. If the buffer is full, the oldest item is overwritten.
11110
- */
11111
- add(item) {
11112
- if (this.count < this.maxSize) {
11113
- this.items.push(item);
11114
- this.count++;
11115
- }
11116
- else {
11117
- this.items[this.index] = item;
11118
- }
11119
- this.index = (this.index + 1) % this.maxSize;
11120
- }
11121
- /**
11122
- * Get all items in chronological order (oldest to newest).
11123
- * Returns a copy of the internal array.
11124
- */
11125
- getAll() {
11126
- if (this.count < this.maxSize) {
11127
- return [...this.items];
11128
- }
11129
- // Return items in chronological order when buffer is full
11130
- return [
11131
- ...this.items.slice(this.index),
11132
- ...this.items.slice(0, this.index),
11133
- ];
11134
- }
11135
- /**
11136
- * Clear all items from the buffer.
11137
- */
11138
- clear() {
11139
- this.items = [];
11140
- this.index = 0;
11141
- this.count = 0;
11142
- }
11143
- /**
11144
- * Get the current number of items in the buffer.
11145
- */
11146
- get size() {
11147
- return this.count;
11148
- }
11149
- /**
11150
- * Get the maximum capacity of the buffer.
11151
- */
11152
- get capacity() {
11153
- return this.maxSize;
11154
- }
11155
- /**
11156
- * Check if the buffer is empty.
11157
- */
11158
- get isEmpty() {
11159
- return this.count === 0;
11160
- }
11161
- /**
11162
- * Check if the buffer is full.
11163
- */
11164
- get isFull() {
11165
- return this.count >= this.maxSize;
11166
- }
11167
- };
11168
-
11169
11066
  const CONSOLE_METHODS = [
11170
11067
  'log',
11171
11068
  'warn',