(dsn: string, config?: ConnectorConfig)
| 28 | */ |
| 29 | class MySQLDSNParser implements DSNParser { |
| 30 | async parse(dsn: string, config?: ConnectorConfig): Promise<mysql.ConnectionOptions> { |
| 31 | const connectionTimeoutSeconds = config?.connectionTimeoutSeconds; |
| 32 | // Capture this before the local `config` (mysql.ConnectionOptions) shadows the param below |
| 33 | const timezone = config?.timezone; |
| 34 | // Basic validation |
| 35 | if (!this.isValidDSN(dsn)) { |
| 36 | const obfuscatedDSN = obfuscateDSNPassword(dsn); |
| 37 | const expectedFormat = this.getSampleDSN(); |
| 38 | throw new Error( |
| 39 | `Invalid MySQL DSN format.\nProvided: ${obfuscatedDSN}\nExpected: ${expectedFormat}` |
| 40 | ); |
| 41 | } |
| 42 | |
| 43 | try { |
| 44 | // Use the SafeURL helper instead of the built-in URL |
| 45 | // This will handle special characters in passwords, etc. |
| 46 | const url = new SafeURL(dsn); |
| 47 | |
| 48 | const config: mysql.ConnectionOptions = { |
| 49 | host: url.hostname, |
| 50 | port: url.port ? parseInt(url.port) : 3306, |
| 51 | database: url.pathname ? url.pathname.substring(1) : '', // Remove leading '/' if exists |
| 52 | user: url.username, |
| 53 | password: url.password, |
| 54 | multipleStatements: true, // Enable native multi-statement support |
| 55 | supportBigNumbers: true, // Return BIGINT as string when value exceeds Number.MAX_SAFE_INTEGER |
| 56 | }; |
| 57 | |
| 58 | // Handle query parameters |
| 59 | url.forEachSearchParam((value, key) => { |
| 60 | if (key === "sslmode") { |
| 61 | if (value === "disable") { |
| 62 | config.ssl = undefined; |
| 63 | } else if (value === "require") { |
| 64 | config.ssl = { rejectUnauthorized: false }; |
| 65 | } else { |
| 66 | config.ssl = {}; |
| 67 | } |
| 68 | } |
| 69 | // Add other parameters as needed |
| 70 | }); |
| 71 | |
| 72 | // Apply connection timeout if specified |
| 73 | if (connectionTimeoutSeconds !== undefined) { |
| 74 | // mysql2 library expects connectTimeout in milliseconds |
| 75 | config.connectTimeout = connectionTimeoutSeconds * 1000; |
| 76 | } |
| 77 | |
| 78 | // Apply timezone if specified: controls how mysql2 interprets DATETIME values |
| 79 | // ("Z", "local", or "±HH:MM"). Without it, mysql2 assumes "local", which can |
| 80 | // produce an incorrect instant when the server timezone differs from the data's. |
| 81 | if (timezone !== undefined) { |
| 82 | config.timezone = timezone; |
| 83 | } |
| 84 | |
| 85 | // Auto-detect AWS IAM authentication tokens and configure cleartext plugin |
| 86 | // AWS RDS IAM tokens are ~800+ character strings containing "X-Amz-Credential" |
| 87 | if (url.password && url.password.includes("X-Amz-Credential")) { |
nothing calls this directly
no test coverage detected