@bugspotter/sdk 0.3.1 → 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.
package/dist/index.js CHANGED
@@ -313,3 +313,5 @@ function sanitize(text) {
313
313
  });
314
314
  return sanitizer.sanitize(text);
315
315
  }
316
+ // Default export for convenience
317
+ exports.default = BugSpotter;
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.validateAuthConfig = validateAuthConfig;
8
8
  exports.validateDeduplicationConfig = validateDeduplicationConfig;
9
+ const url_helpers_1 = require("./url-helpers");
9
10
  /**
10
11
  * Validate authentication configuration
11
12
  * @throws Error if configuration is invalid
@@ -14,6 +15,11 @@ function validateAuthConfig(context) {
14
15
  if (!context.endpoint) {
15
16
  throw new Error('No endpoint configured for bug report submission');
16
17
  }
18
+ // SECURITY: Ensure endpoint uses HTTPS
19
+ // This prevents credentials and sensitive data from being sent over plain HTTP
20
+ if (!(0, url_helpers_1.isSecureEndpoint)(context.endpoint)) {
21
+ throw new url_helpers_1.InsecureEndpointError(context.endpoint);
22
+ }
17
23
  if (!context.auth) {
18
24
  throw new Error('API key authentication is required');
19
25
  }
@@ -1,42 +1,9 @@
1
1
  /**
2
2
  * PII Pattern Definitions
3
- * Configurable regex patterns for detecting sensitive data (PII + credentials)
3
+ * Re-exports from @bugspotter/common + SDK-specific extensions
4
4
  */
5
- export type PIIPatternName = 'email' | 'phone' | 'creditcard' | 'ssn' | 'iin' | 'ip' | 'apikey' | 'token' | 'password';
6
- /**
7
- * Pattern definition with metadata
8
- */
9
- export interface PatternDefinition {
10
- /** Pattern name/identifier */
11
- name: PIIPatternName;
12
- /** Regular expression for detection */
13
- regex: RegExp;
14
- /** Human-readable description */
15
- description: string;
16
- /** Examples of data this pattern matches */
17
- examples: string[];
18
- /** Priority order (lower = higher priority, checked first) */
19
- priority: number;
20
- }
21
- /**
22
- * Default built-in patterns
23
- */
24
- export declare const DEFAULT_PATTERNS: Record<PIIPatternName, PatternDefinition>;
25
- /**
26
- * Pattern categories for grouping
27
- */
28
- export declare const PATTERN_CATEGORIES: {
29
- readonly financial: PIIPatternName[];
30
- readonly contact: PIIPatternName[];
31
- readonly identification: PIIPatternName[];
32
- readonly network: PIIPatternName[];
33
- readonly credentials: PIIPatternName[];
34
- readonly kazakhstan: PIIPatternName[];
35
- };
36
- /**
37
- * Get patterns sorted by priority
38
- */
39
- export declare function getPatternsByPriority(patterns: PatternDefinition[]): PatternDefinition[];
5
+ export { type PIIPatternName, type PatternDefinition, type PatternPresetName, DEFAULT_PATTERNS, PATTERN_CATEGORIES, PATTERN_PRESETS, getAllPatternNames, getPatternsByPriority, getPatternsByPreset, createPatternConfig, validatePattern, } from '@bugspotter/common';
6
+ import { type PIIPatternName, type PatternDefinition, PATTERN_CATEGORIES } from '@bugspotter/common';
40
7
  /**
41
8
  * Get pattern by name
42
9
  */
@@ -45,10 +12,6 @@ export declare function getPattern(name: PIIPatternName): PatternDefinition;
45
12
  * Get patterns by category
46
13
  */
47
14
  export declare function getPatternsByCategory(category: keyof typeof PATTERN_CATEGORIES): PatternDefinition[];
48
- /**
49
- * Get all pattern names
50
- */
51
- export declare function getAllPatternNames(): PIIPatternName[];
52
15
  /**
53
16
  * Custom pattern builder for advanced use cases
54
17
  */
@@ -61,42 +24,6 @@ export declare class PatternBuilder {
61
24
  priority(priority: number): this;
62
25
  build(): PatternDefinition;
63
26
  }
64
- /**
65
- * Pre-configured pattern sets for common use cases
66
- */
67
- export declare const PATTERN_PRESETS: {
68
- /** All patterns enabled (PII + credentials) - default */
69
- readonly all: PIIPatternName[];
70
- /** Minimal - only most critical PII */
71
- readonly minimal: PIIPatternName[];
72
- /** Financial data only */
73
- readonly financial: PIIPatternName[];
74
- /** Contact information only */
75
- readonly contact: PIIPatternName[];
76
- /** Identification numbers only */
77
- readonly identification: PIIPatternName[];
78
- /** Credentials and secrets only */
79
- readonly credentials: PIIPatternName[];
80
- /** Kazakhstan-specific patterns */
81
- readonly kazakhstan: PIIPatternName[];
82
- /** GDPR compliance recommended set */
83
- readonly gdpr: PIIPatternName[];
84
- /** PCI DSS compliance required */
85
- readonly pci: PIIPatternName[];
86
- /** Security-focused: PII + credentials */
87
- readonly security: PIIPatternName[];
88
- };
89
- /**
90
- * Create custom pattern configuration
91
- */
92
- export declare function createPatternConfig(preset: keyof typeof PATTERN_PRESETS | PIIPatternName[]): PatternDefinition[];
93
- /**
94
- * Validate pattern regex
95
- */
96
- export declare function validatePattern(pattern: PatternDefinition): {
97
- valid: boolean;
98
- errors: string[];
99
- };
100
27
  /**
101
28
  * Merge pattern configurations
102
29
  */
@@ -1,156 +1,39 @@
1
1
  "use strict";
2
2
  /**
3
3
  * PII Pattern Definitions
4
- * Configurable regex patterns for detecting sensitive data (PII + credentials)
4
+ * Re-exports from @bugspotter/common + SDK-specific extensions
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.PATTERN_PRESETS = exports.PatternBuilder = exports.PATTERN_CATEGORIES = exports.DEFAULT_PATTERNS = void 0;
8
- exports.getPatternsByPriority = getPatternsByPriority;
7
+ exports.PatternBuilder = exports.validatePattern = exports.createPatternConfig = exports.getPatternsByPreset = exports.getPatternsByPriority = exports.getAllPatternNames = exports.PATTERN_PRESETS = exports.PATTERN_CATEGORIES = exports.DEFAULT_PATTERNS = void 0;
9
8
  exports.getPattern = getPattern;
10
9
  exports.getPatternsByCategory = getPatternsByCategory;
11
- exports.getAllPatternNames = getAllPatternNames;
12
- exports.createPatternConfig = createPatternConfig;
13
- exports.validatePattern = validatePattern;
14
10
  exports.mergePatternConfigs = mergePatternConfigs;
15
- /**
16
- * Default built-in patterns
17
- */
18
- exports.DEFAULT_PATTERNS = {
19
- email: {
20
- name: 'email',
21
- regex: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
22
- description: 'Email addresses',
23
- examples: [
24
- 'user@example.com',
25
- 'john.doe+tag@company.co.uk',
26
- 'test_user@sub.domain.com',
27
- ],
28
- priority: 1, // Highest priority - most specific
29
- },
30
- creditcard: {
31
- name: 'creditcard',
32
- 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,
33
- description: 'Credit card numbers (Visa, MC, Amex, Discover, etc.)',
34
- examples: [
35
- '4532-1488-0343-6467',
36
- '4532148803436467',
37
- '5425 2334 3010 9903',
38
- '3782 822463 10005',
39
- ],
40
- priority: 2,
41
- },
42
- ssn: {
43
- name: 'ssn',
44
- regex: /\b\d{3}-\d{2}-\d{4}\b|\b(?<!\d)\d{9}(?!\d)\b/g,
45
- description: 'US Social Security Numbers',
46
- examples: ['123-45-6789', '987654321'],
47
- priority: 3,
48
- },
49
- iin: {
50
- name: 'iin',
51
- regex: /\b[0-9]{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12][0-9]|3[01])\d{6}\b/g,
52
- description: 'Kazakhstan IIN/BIN (12 digits with date validation)',
53
- examples: ['950315300123', '880612500456', '021225123456'],
54
- priority: 4,
55
- },
56
- ip: {
57
- name: 'ip',
58
- 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,
59
- description: 'IPv4 and IPv6 addresses',
60
- examples: [
61
- '192.168.1.100',
62
- '127.0.0.1',
63
- '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
64
- ],
65
- priority: 5,
66
- },
67
- phone: {
68
- name: 'phone',
69
- 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,
70
- description: 'International phone numbers',
71
- examples: [
72
- '+1-555-1234',
73
- '+1-555-123-4567',
74
- '(555) 123-4567',
75
- '555-123-4567',
76
- '+7 777 123 4567',
77
- ],
78
- priority: 6,
79
- },
80
- apikey: {
81
- name: 'apikey',
82
- 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,
83
- description: 'API keys (Stripe, Google, AWS, etc.)',
84
- examples: [
85
- 'sk_live_abc123def456ghi789jkl',
86
- 'pk_test_xyz789abc123def456',
87
- 'AIzaSyD1234567890abcdefghijklmnopqrst',
88
- 'AKIAIOSFODNN7EXAMPLE',
89
- ],
90
- priority: 7,
91
- },
92
- token: {
93
- name: 'token',
94
- 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,
95
- description: 'Authentication tokens (Bearer, GitHub, JWT-like)',
96
- examples: [
97
- 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
98
- 'ghp_abc123def456ghi789jkl012mno345pqr',
99
- 'gho_xyz789abc123def456ghi789jkl012mno',
100
- ],
101
- priority: 8,
102
- },
103
- password: {
104
- name: 'password',
105
- regex: /(?:password|passwd|pwd)[\s:=]+[^\s]{6,}|(?:password|passwd|pwd)["']?\s*[:=]\s*["']?[^\s"']{6,}/gi,
106
- description: 'Password fields in text (password=..., pwd:...)',
107
- examples: [
108
- 'password: MySecret123!',
109
- 'passwd=SecurePass456',
110
- 'pwd: "MyP@ssw0rd"',
111
- ],
112
- priority: 9,
113
- },
114
- };
115
- /**
116
- * Pattern categories for grouping
117
- */
118
- exports.PATTERN_CATEGORIES = {
119
- financial: ['creditcard', 'ssn'],
120
- contact: ['email', 'phone'],
121
- identification: ['ssn', 'iin'],
122
- network: ['ip', 'email'],
123
- credentials: ['apikey', 'token', 'password'],
124
- kazakhstan: ['iin'],
125
- };
126
- /**
127
- * Get patterns sorted by priority
128
- */
129
- function getPatternsByPriority(patterns) {
130
- return [...patterns].sort((a, b) => {
131
- return a.priority - b.priority;
132
- });
133
- }
11
+ // Re-export everything from @bugspotter/common
12
+ var common_1 = require("@bugspotter/common");
13
+ Object.defineProperty(exports, "DEFAULT_PATTERNS", { enumerable: true, get: function () { return common_1.DEFAULT_PATTERNS; } });
14
+ Object.defineProperty(exports, "PATTERN_CATEGORIES", { enumerable: true, get: function () { return common_1.PATTERN_CATEGORIES; } });
15
+ Object.defineProperty(exports, "PATTERN_PRESETS", { enumerable: true, get: function () { return common_1.PATTERN_PRESETS; } });
16
+ Object.defineProperty(exports, "getAllPatternNames", { enumerable: true, get: function () { return common_1.getAllPatternNames; } });
17
+ Object.defineProperty(exports, "getPatternsByPriority", { enumerable: true, get: function () { return common_1.getPatternsByPriority; } });
18
+ Object.defineProperty(exports, "getPatternsByPreset", { enumerable: true, get: function () { return common_1.getPatternsByPreset; } });
19
+ Object.defineProperty(exports, "createPatternConfig", { enumerable: true, get: function () { return common_1.createPatternConfig; } });
20
+ Object.defineProperty(exports, "validatePattern", { enumerable: true, get: function () { return common_1.validatePattern; } });
21
+ const common_2 = require("@bugspotter/common");
22
+ // SDK-specific extensions
134
23
  /**
135
24
  * Get pattern by name
136
25
  */
137
26
  function getPattern(name) {
138
- return exports.DEFAULT_PATTERNS[name];
27
+ return common_2.DEFAULT_PATTERNS[name];
139
28
  }
140
29
  /**
141
30
  * Get patterns by category
142
31
  */
143
32
  function getPatternsByCategory(category) {
144
- return exports.PATTERN_CATEGORIES[category].map((name) => {
145
- return exports.DEFAULT_PATTERNS[name];
33
+ return common_2.PATTERN_CATEGORIES[category].map((name) => {
34
+ return common_2.DEFAULT_PATTERNS[name];
146
35
  });
147
36
  }
148
- /**
149
- * Get all pattern names
150
- */
151
- function getAllPatternNames() {
152
- return Object.keys(exports.DEFAULT_PATTERNS);
153
- }
154
37
  /**
155
38
  * Custom pattern builder for advanced use cases
156
39
  */
@@ -163,7 +46,6 @@ class PatternBuilder {
163
46
  return this;
164
47
  }
165
48
  regex(regex) {
166
- // Ensure global flag
167
49
  if (!regex.global) {
168
50
  const flags = regex.flags.includes('g') ? regex.flags : regex.flags + 'g';
169
51
  this.pattern.regex = new RegExp(regex.source, flags);
@@ -200,85 +82,6 @@ class PatternBuilder {
200
82
  }
201
83
  }
202
84
  exports.PatternBuilder = PatternBuilder;
203
- /**
204
- * Pre-configured pattern sets for common use cases
205
- */
206
- exports.PATTERN_PRESETS = {
207
- /** All patterns enabled (PII + credentials) - default */
208
- all: getAllPatternNames(),
209
- /** Minimal - only most critical PII */
210
- minimal: ['email', 'creditcard', 'ssn'],
211
- /** Financial data only */
212
- financial: exports.PATTERN_CATEGORIES.financial,
213
- /** Contact information only */
214
- contact: exports.PATTERN_CATEGORIES.contact,
215
- /** Identification numbers only */
216
- identification: exports.PATTERN_CATEGORIES.identification,
217
- /** Credentials and secrets only */
218
- credentials: exports.PATTERN_CATEGORIES.credentials,
219
- /** Kazakhstan-specific patterns */
220
- kazakhstan: ['email', 'phone', 'iin'],
221
- /** GDPR compliance recommended set */
222
- gdpr: ['email', 'phone', 'ip'],
223
- /** PCI DSS compliance required */
224
- pci: ['creditcard'],
225
- /** Security-focused: PII + credentials */
226
- security: [
227
- 'email',
228
- 'phone',
229
- 'creditcard',
230
- 'ssn',
231
- 'apikey',
232
- 'token',
233
- 'password',
234
- ],
235
- };
236
- /**
237
- * Create custom pattern configuration
238
- */
239
- function createPatternConfig(preset) {
240
- const names = typeof preset === 'string' ? exports.PATTERN_PRESETS[preset] : preset;
241
- return names.map((name) => {
242
- return exports.DEFAULT_PATTERNS[name];
243
- });
244
- }
245
- /**
246
- * Validate pattern regex
247
- */
248
- function validatePattern(pattern) {
249
- const errors = [];
250
- if (!pattern.name) {
251
- errors.push('Pattern must have a name');
252
- }
253
- if (!pattern.regex) {
254
- errors.push('Pattern must have a regex');
255
- }
256
- else {
257
- if (!pattern.regex.global) {
258
- errors.push('Pattern regex must have global flag');
259
- }
260
- // Test regex doesn't cause catastrophic backtracking
261
- try {
262
- const testString = 'a'.repeat(1000);
263
- const start = Date.now();
264
- testString.match(pattern.regex);
265
- const duration = Date.now() - start;
266
- if (duration > 100) {
267
- errors.push(`Pattern regex may cause performance issues (took ${duration}ms on test)`);
268
- }
269
- }
270
- catch (error) {
271
- errors.push(`Pattern regex error: ${error.message}`);
272
- }
273
- }
274
- if (pattern.priority < 0) {
275
- errors.push('Pattern priority must be non-negative');
276
- }
277
- return {
278
- valid: errors.length === 0,
279
- errors,
280
- };
281
- }
282
85
  /**
283
86
  * Merge pattern configurations
284
87
  */
@@ -286,9 +89,8 @@ function mergePatternConfigs(...configs) {
286
89
  const merged = new Map();
287
90
  configs.forEach((config) => {
288
91
  config.forEach((pattern) => {
289
- // Later configs override earlier ones
290
92
  merged.set(pattern.name, pattern);
291
93
  });
292
94
  });
293
- return getPatternsByPriority([...merged.values()]);
95
+ return (0, common_2.getPatternsByPriority)([...merged.values()]);
294
96
  }
@@ -1,28 +1,5 @@
1
1
  /**
2
2
  * URL Helper Utilities
3
- * Extract base API URL from endpoint configuration
3
+ * Re-exports from @bugspotter/common
4
4
  */
5
- /**
6
- * Custom error for invalid endpoint URLs
7
- */
8
- export declare class InvalidEndpointError extends Error {
9
- readonly endpoint: string;
10
- readonly reason: string;
11
- constructor(endpoint: string, reason: string);
12
- }
13
- /**
14
- * Strip known endpoint suffixes from path
15
- * Removes /api/v1/reports path
16
- */
17
- export declare function stripEndpointSuffix(path: string): string;
18
- /**
19
- * Extract base API URL from endpoint
20
- * Returns scheme + host + base path (without /api/v1/reports suffix)
21
- *
22
- * @example
23
- * getApiBaseUrl('https://api.example.com/api/v1/reports')
24
- * // Returns: 'https://api.example.com'
25
- *
26
- * @throws InvalidEndpointError if endpoint is not a valid absolute URL
27
- */
28
- export declare function getApiBaseUrl(endpoint: string): string;
5
+ export { InvalidEndpointError, InsecureEndpointError, stripEndpointSuffix, getApiBaseUrl, isSecureEndpoint, } from '@bugspotter/common';
@@ -1,64 +1,13 @@
1
1
  "use strict";
2
- /**
3
- * URL Helper Utilities
4
- * Extract base API URL from endpoint configuration
5
- */
6
2
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.InvalidEndpointError = void 0;
8
- exports.stripEndpointSuffix = stripEndpointSuffix;
9
- exports.getApiBaseUrl = getApiBaseUrl;
10
- const logger_1 = require("./logger");
11
- const logger = (0, logger_1.getLogger)();
12
- /**
13
- * Custom error for invalid endpoint URLs
14
- */
15
- class InvalidEndpointError extends Error {
16
- constructor(endpoint, reason) {
17
- super(`Invalid endpoint URL: ${endpoint}. ${reason}`);
18
- this.endpoint = endpoint;
19
- this.reason = reason;
20
- this.name = 'InvalidEndpointError';
21
- }
22
- }
23
- exports.InvalidEndpointError = InvalidEndpointError;
3
+ exports.isSecureEndpoint = exports.getApiBaseUrl = exports.stripEndpointSuffix = exports.InsecureEndpointError = exports.InvalidEndpointError = void 0;
24
4
  /**
25
- * Strip known endpoint suffixes from path
26
- * Removes /api/v1/reports path
27
- */
28
- function stripEndpointSuffix(path) {
29
- // Use lastIndexOf to handle paths like '/prefix/api/v1/reports'
30
- const reportsIndex = path.lastIndexOf('/api/v1/reports');
31
- if (reportsIndex !== -1) {
32
- return path.substring(0, reportsIndex);
33
- }
34
- // Remove trailing slash
35
- return path.replace(/\/$/, '') || '';
36
- }
37
- /**
38
- * Extract base API URL from endpoint
39
- * Returns scheme + host + base path (without /api/v1/reports suffix)
40
- *
41
- * @example
42
- * getApiBaseUrl('https://api.example.com/api/v1/reports')
43
- * // Returns: 'https://api.example.com'
44
- *
45
- * @throws InvalidEndpointError if endpoint is not a valid absolute URL
46
- */
47
- function getApiBaseUrl(endpoint) {
48
- if (!endpoint) {
49
- throw new InvalidEndpointError('', 'No endpoint configured');
50
- }
51
- try {
52
- const url = new URL(endpoint);
53
- const basePath = stripEndpointSuffix(url.pathname);
54
- return url.origin + basePath;
55
- }
56
- catch (error) {
57
- const errorMessage = error instanceof Error ? error.message : String(error);
58
- logger.error('Invalid endpoint URL - must be a valid absolute URL', {
59
- endpoint,
60
- error: errorMessage,
61
- });
62
- throw new InvalidEndpointError(endpoint, 'Must be a valid absolute URL (e.g., https://api.example.com/api/v1/reports)');
63
- }
64
- }
5
+ * URL Helper Utilities
6
+ * Re-exports from @bugspotter/common
7
+ */
8
+ var common_1 = require("@bugspotter/common");
9
+ Object.defineProperty(exports, "InvalidEndpointError", { enumerable: true, get: function () { return common_1.InvalidEndpointError; } });
10
+ Object.defineProperty(exports, "InsecureEndpointError", { enumerable: true, get: function () { return common_1.InsecureEndpointError; } });
11
+ Object.defineProperty(exports, "stripEndpointSuffix", { enumerable: true, get: function () { return common_1.stripEndpointSuffix; } });
12
+ Object.defineProperty(exports, "getApiBaseUrl", { enumerable: true, get: function () { return common_1.getApiBaseUrl; } });
13
+ Object.defineProperty(exports, "isSecureEndpoint", { enumerable: true, get: function () { return common_1.isSecureEndpoint; } });
package/dist/version.d.ts CHANGED
@@ -5,4 +5,4 @@
5
5
  * This file is automatically generated during the build process.
6
6
  * To update the version, modify package.json
7
7
  */
8
- export declare const VERSION = "0.3.1";
8
+ export declare const VERSION = "1.1.0";
package/dist/version.js CHANGED
@@ -8,4 +8,4 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.VERSION = void 0;
11
- exports.VERSION = '0.3.1';
11
+ exports.VERSION = '1.1.0';
@@ -21,6 +21,16 @@ export declare class FloatingButton {
21
21
  private eventHandlers;
22
22
  constructor(options?: FloatingButtonOptions);
23
23
  private createButton;
24
+ /**
25
+ * Safely inject HTML content by parsing and validating SVG elements
26
+ * Prevents XSS attacks by only allowing safe SVG elements and attributes
27
+ */
28
+ private setSafeHTMLContent;
29
+ /**
30
+ * Recursively sanitize SVG elements by removing dangerous tags and attributes
31
+ * Uses whitelists to ensure only safe SVG content is preserved
32
+ */
33
+ private sanitizeSVGElement;
24
34
  private getButtonStyles;
25
35
  private getPositionStyles;
26
36
  private handleMouseEnter;