Initial commit: Complete Shopify Price Updater implementation
- Full Node.js application with Shopify GraphQL API integration - Compare At price support for promotional pricing - Comprehensive error handling and retry logic - Progress tracking with markdown logging - Complete test suite with unit and integration tests - Production-ready with proper exit codes and signal handling
This commit is contained in:
119
src/config/environment.js
Normal file
119
src/config/environment.js
Normal file
@@ -0,0 +1,119 @@
|
||||
const dotenv = require("dotenv");
|
||||
|
||||
// Load environment variables from .env file
|
||||
dotenv.config();
|
||||
|
||||
/**
|
||||
* Validates and loads environment configuration
|
||||
* @returns {Object} Configuration object with validated environment variables
|
||||
* @throws {Error} If required environment variables are missing or invalid
|
||||
*/
|
||||
function loadEnvironmentConfig() {
|
||||
const config = {
|
||||
shopDomain: process.env.SHOPIFY_SHOP_DOMAIN,
|
||||
accessToken: process.env.SHOPIFY_ACCESS_TOKEN,
|
||||
targetTag: process.env.TARGET_TAG,
|
||||
priceAdjustmentPercentage: process.env.PRICE_ADJUSTMENT_PERCENTAGE,
|
||||
};
|
||||
|
||||
// Validate required environment variables
|
||||
const requiredVars = [
|
||||
{
|
||||
key: "SHOPIFY_SHOP_DOMAIN",
|
||||
value: config.shopDomain,
|
||||
name: "Shopify shop domain",
|
||||
},
|
||||
{
|
||||
key: "SHOPIFY_ACCESS_TOKEN",
|
||||
value: config.accessToken,
|
||||
name: "Shopify access token",
|
||||
},
|
||||
{ key: "TARGET_TAG", value: config.targetTag, name: "Target product tag" },
|
||||
{
|
||||
key: "PRICE_ADJUSTMENT_PERCENTAGE",
|
||||
value: config.priceAdjustmentPercentage,
|
||||
name: "Price adjustment percentage",
|
||||
},
|
||||
];
|
||||
|
||||
const missingVars = [];
|
||||
|
||||
for (const variable of requiredVars) {
|
||||
if (!variable.value || variable.value.trim() === "") {
|
||||
missingVars.push(variable.key);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingVars.length > 0) {
|
||||
const errorMessage =
|
||||
`Missing required environment variables: ${missingVars.join(", ")}\n` +
|
||||
"Please check your .env file and ensure all required variables are set.\n" +
|
||||
"See .env.example for reference.";
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// Validate and convert price adjustment percentage
|
||||
const percentage = parseFloat(config.priceAdjustmentPercentage);
|
||||
if (isNaN(percentage)) {
|
||||
throw new Error(
|
||||
`Invalid PRICE_ADJUSTMENT_PERCENTAGE: "${config.priceAdjustmentPercentage}". Must be a valid number.`
|
||||
);
|
||||
}
|
||||
|
||||
// Validate shop domain format
|
||||
if (
|
||||
!config.shopDomain.includes(".myshopify.com") &&
|
||||
!config.shopDomain.includes(".")
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid SHOPIFY_SHOP_DOMAIN: "${config.shopDomain}". Must be a valid Shopify domain (e.g., your-shop.myshopify.com)`
|
||||
);
|
||||
}
|
||||
|
||||
// Validate access token format (basic check)
|
||||
if (config.accessToken.length < 10) {
|
||||
throw new Error(
|
||||
"Invalid SHOPIFY_ACCESS_TOKEN: Token appears to be too short. Please verify your access token."
|
||||
);
|
||||
}
|
||||
|
||||
// Validate target tag is not empty after trimming
|
||||
const trimmedTag = config.targetTag.trim();
|
||||
if (trimmedTag === "") {
|
||||
throw new Error(
|
||||
"Invalid TARGET_TAG: Tag cannot be empty or contain only whitespace."
|
||||
);
|
||||
}
|
||||
|
||||
// Return validated configuration
|
||||
return {
|
||||
shopDomain: config.shopDomain.trim(),
|
||||
accessToken: config.accessToken.trim(),
|
||||
targetTag: trimmedTag,
|
||||
priceAdjustmentPercentage: percentage,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get validated environment configuration
|
||||
* Caches the configuration after first load
|
||||
*/
|
||||
let cachedConfig = null;
|
||||
|
||||
function getConfig() {
|
||||
if (!cachedConfig) {
|
||||
try {
|
||||
cachedConfig = loadEnvironmentConfig();
|
||||
} catch (error) {
|
||||
console.error("Environment Configuration Error:");
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
return cachedConfig;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getConfig,
|
||||
loadEnvironmentConfig, // Export for testing purposes
|
||||
};
|
||||
Reference in New Issue
Block a user