UNPKG

@dscodotco/theme-cli

Version:

A CLI tool for developing Shopify themes

158 lines (157 loc) 6.63 kB
/** * Utility to test the Shopify API connection */ import axios from "axios"; import { createLogger } from "../logger.js"; const logger = createLogger("connection-test"); /** * Tests the connection to the Shopify Admin API * @param credentials Shopify API credentials * @returns Object containing test result and message */ export async function testShopifyConnection(credentials) { try { // Test all possible authentication methods logger.info(`Testing connection to ${credentials.storeName}.myshopify.com`); const apiUrl = `https://${credentials.storeName}.myshopify.com/admin/api/2023-04/themes.json`; // Method 1: Access token in header (if it looks like one) const isAccessToken = credentials.password.startsWith("shpat_"); let result; if (isAccessToken) { logger.info("Method 1: Trying with access token in header"); try { const response = await axios.get(apiUrl, { headers: { "X-Shopify-Access-Token": credentials.password, "Content-Type": "application/json", }, }); if (response.status === 200 && response.data && response.data.themes) { const themes = response.data.themes; return { success: true, message: `Successfully connected using access token in header. Found ${themes.length} themes.`, statusCode: 200, themes, }; } } catch (err) { logger.error(`Access token auth failed: ${err.message}`); } } // Method 2: API key + password basic auth logger.info("Method 2: Trying with API key + secret (basic auth)"); try { const response = await axios.get(apiUrl, { auth: { username: credentials.apiKey, password: credentials.password, }, }); if (response.status === 200 && response.data && response.data.themes) { const themes = response.data.themes; return { success: true, message: `Successfully connected using API key + secret (basic auth). Found ${themes.length} themes.`, statusCode: 200, themes, }; } } catch (err) { logger.error(`Basic auth failed: ${err.message}`); } // Method 3: Try using both API key and password together as the password logger.info("Method 3: Trying with API key:password as token"); try { const combinedToken = `${credentials.apiKey}:${credentials.password}`; const response = await axios.get(apiUrl, { headers: { "X-Shopify-Access-Token": combinedToken, "Content-Type": "application/json", }, }); if (response.status === 200 && response.data && response.data.themes) { const themes = response.data.themes; return { success: true, message: `Successfully connected using combined token method. Found ${themes.length} themes.`, statusCode: 200, themes, }; } } catch (err) { logger.error(`Combined token auth failed: ${err.message}`); } // Method 4: Try using just the API key as the access token (some legacy apps) logger.info("Method 4: Trying with just API key as token"); try { const response = await axios.get(apiUrl, { headers: { "X-Shopify-Access-Token": credentials.apiKey, "Content-Type": "application/json", }, }); if (response.status === 200 && response.data && response.data.themes) { const themes = response.data.themes; return { success: true, message: `Successfully connected using API key as token. Found ${themes.length} themes.`, statusCode: 200, themes, }; } } catch (err) { logger.error(`API key as token failed: ${err.message}`); } // Method 5: Try using private app password (legacy) logger.info("Method 5: Trying legacy private app auth"); try { const response = await axios.get(apiUrl, { headers: { Authorization: `Basic ${Buffer.from(`${credentials.apiKey}:${credentials.password}`).toString("base64")}`, "Content-Type": "application/json", }, }); if (response.status === 200 && response.data && response.data.themes) { const themes = response.data.themes; return { success: true, message: `Successfully connected using legacy private app auth. Found ${themes.length} themes.`, statusCode: 200, themes, }; } } catch (err) { logger.error(`Legacy private app auth failed: ${err.message}`); } // If we got here, we tried all methods and none worked // Provide a detailed error message let message = "Failed to authenticate with Shopify using any authentication method. Please verify your credentials."; message += "\n\nFor API key + secret authentication, ensure:"; message += "\n- Your API key is correct"; message += "\n- Your shared secret/password is correct"; message += "\n- Your app has sufficient permissions (themes read/write)"; message += "\n\nFor access token authentication, ensure:"; message += "\n- Your access token starts with 'shpat_'"; message += "\n- The token is not expired"; message += "\n- The token has sufficient permissions"; return { success: false, message, statusCode: 401, }; } catch (error) { // Handle any unexpected errors return { success: false, message: `Unexpected error: ${error.message}`, statusCode: 500, }; } }