@dscodotco/theme-cli
Version:
A CLI tool for developing Shopify themes
158 lines (157 loc) • 6.63 kB
JavaScript
/**
* 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,
};
}
}