/** * Product identity — reads from a product.json file or falls back to env vars. * Eliminates the need for hardcoded product-config.ts files in every service. */ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; export interface ProductIdentity { productId: string; displayName: string; licensePrefix: string; configDirName: string; envVarPrefix: string; bundleIdSuffix: string; packageName: string; } let _cached: ProductIdentity | null = null; /** * Load product identity from a JSON file or environment variables. * * @param jsonPath - Path to product.json (optional, tries common locations) * @returns Product identity object */ export function loadProductIdentity(jsonPath?: string): ProductIdentity { if (_cached) return _cached; // Try loading from file const paths = jsonPath ? [jsonPath] : [ resolve("shared/product.json"), resolve("../shared/product.json"), resolve("../../shared/product.json"), ]; for (const p of paths) { try { const raw = readFileSync(p, "utf-8"); _cached = JSON.parse(raw) as ProductIdentity; return _cached; } catch { // Try next path } } // Fallback to env vars / defaults _cached = { productId: process.env.PRODUCT_ID || "lysnrai", displayName: process.env.DISPLAY_NAME || "LysnrAI", licensePrefix: process.env.LICENSE_PREFIX || "LYSNR", configDirName: process.env.CONFIG_DIR_NAME || ".LysnrAI", envVarPrefix: process.env.ENV_VAR_PREFIX || "LYSNR", bundleIdSuffix: process.env.BUNDLE_ID_SUFFIX || "LysnrAI", packageName: process.env.PACKAGE_NAME || "lysnrai", }; return _cached; } /** * Convenience: get just the product ID string. */ export function getProductId(): string { return loadProductIdentity().productId; } /** * Reset the cache (useful for testing). * @internal */ export function _resetProductIdentity(): void { _cached = null; }