version mise à jour par claude , à tester
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Profile Manager
|
||||
* Handles multiple WMS profiles (AD, LIMAGRAIN, ...) defined in .env.
|
||||
*
|
||||
* Shared settings (same for all profiles):
|
||||
* - WMS_API_AUTH OAuth client Basic auth header
|
||||
* - WMS_APPLICATION Application name (e.g. "EasyWMS")
|
||||
* - WMS_API_PATH URL path to the ApplicationService API
|
||||
* - WMS_TOKEN_PATH URL path to the OAuth token endpoint
|
||||
* - WORKFLOW_API_PATH URL path to the AD API
|
||||
*
|
||||
* Per-profile settings (prefixed by profile name):
|
||||
* - <PROFILE>_HOST Hostname or IP (e.g. "10.255.255.2", "p4swms.mss.mecalux.com")
|
||||
* - <PROFILE>_USERNAME
|
||||
* - <PROFILE>_PASSWORD
|
||||
* - <PROFILE>_TENANT
|
||||
* - <PROFILE>_SAAS "true" | "false" (default false). When true the WMS is
|
||||
* cloud-hosted — local filesystem logs are not reachable,
|
||||
* so log tools return an error instead of probing paths.
|
||||
*
|
||||
* Profile registry:
|
||||
* - WMS_PROFILES Comma-separated list of profile names (e.g. "AD,LIMAGRAIN")
|
||||
* - DEFAULT_WMS_PROFILE Profile activated at startup (optional)
|
||||
*/
|
||||
|
||||
const DEFAULTS = {
|
||||
apiPath: '/ApplicationService/api',
|
||||
tokenPath: '/EasySTS/OAuth/Token',
|
||||
workflowApiPath: '/AD/api',
|
||||
application: 'EasyWMS',
|
||||
protocol: 'https',
|
||||
};
|
||||
|
||||
const listeners = [];
|
||||
let profiles = {};
|
||||
let currentProfileName = null;
|
||||
|
||||
/**
|
||||
* Parse .env into an in-memory profile registry.
|
||||
* Called once at startup; safe to call again after env changes (tests).
|
||||
*/
|
||||
function loadProfiles() {
|
||||
profiles = {};
|
||||
currentProfileName = null;
|
||||
|
||||
const names = (process.env.WMS_PROFILES || '')
|
||||
.split(',')
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
if (names.length === 0) {
|
||||
console.error('[Profile] WARNING: WMS_PROFILES is empty — no profiles loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
const shared = {
|
||||
auth: process.env.WMS_API_AUTH,
|
||||
application: process.env.WMS_APPLICATION || DEFAULTS.application,
|
||||
apiPath: process.env.WMS_API_PATH || DEFAULTS.apiPath,
|
||||
tokenPath: process.env.WMS_TOKEN_PATH || DEFAULTS.tokenPath,
|
||||
workflowApiPath: process.env.WORKFLOW_API_PATH || DEFAULTS.workflowApiPath,
|
||||
};
|
||||
|
||||
for (const name of names) {
|
||||
const host = process.env[`${name}_HOST`];
|
||||
const username = process.env[`${name}_USERNAME`];
|
||||
const password = process.env[`${name}_PASSWORD`];
|
||||
const tenant = process.env[`${name}_TENANT`];
|
||||
const saasRaw = process.env[`${name}_SAAS`];
|
||||
const saas = saasRaw != null && /^(true|1|yes)$/i.test(saasRaw.trim());
|
||||
|
||||
if (!host || !username || !password || !tenant) {
|
||||
console.error(`[Profile] WARNING: profile "${name}" is incomplete (missing HOST/USERNAME/PASSWORD/TENANT) — skipped`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const base = `${DEFAULTS.protocol}://${host}`;
|
||||
profiles[name] = {
|
||||
name,
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
tenant,
|
||||
saas,
|
||||
auth: shared.auth,
|
||||
application: shared.application,
|
||||
apiBaseUrl: `${base}${shared.apiPath}`,
|
||||
tokenUrl: `${base}${shared.tokenPath}`,
|
||||
workflowApiBase: `${base}${shared.workflowApiPath}`,
|
||||
};
|
||||
}
|
||||
|
||||
const defaultName = process.env.DEFAULT_WMS_PROFILE;
|
||||
if (defaultName && profiles[defaultName]) {
|
||||
currentProfileName = defaultName;
|
||||
console.error(`[Profile] Loaded ${Object.keys(profiles).length} profile(s). Active: ${currentProfileName}`);
|
||||
} else if (defaultName) {
|
||||
console.error(`[Profile] DEFAULT_WMS_PROFILE="${defaultName}" is not a valid profile — no profile active`);
|
||||
} else {
|
||||
console.error(`[Profile] Loaded ${Object.keys(profiles).length} profile(s). No default selected — Claude must call switch_wms_profile before any API call`);
|
||||
}
|
||||
}
|
||||
|
||||
function listProfiles() {
|
||||
return Object.keys(profiles).sort();
|
||||
}
|
||||
|
||||
function getCurrentName() {
|
||||
return currentProfileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the active profile config. Throws a helpful error if none is selected,
|
||||
* so tool responses tell Claude exactly what to do next.
|
||||
*/
|
||||
function getCurrent() {
|
||||
if (!currentProfileName) {
|
||||
const available = listProfiles();
|
||||
const hint = available.length > 0
|
||||
? `Available profiles: ${available.join(', ')}. Call switch_wms_profile with one of them.`
|
||||
: 'No profiles configured in .env (WMS_PROFILES is empty).';
|
||||
throw new Error(`No WMS profile selected. ${hint}`);
|
||||
}
|
||||
return profiles[currentProfileName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to a different profile. Notifies listeners (services) so they can
|
||||
* reset token + invalidate caches tied to the previous profile.
|
||||
*/
|
||||
function switchTo(name) {
|
||||
if (!profiles[name]) {
|
||||
const available = listProfiles();
|
||||
throw new Error(`Unknown profile "${name}". Available: ${available.join(', ') || '(none)'}`);
|
||||
}
|
||||
if (name === currentProfileName) {
|
||||
return profiles[name];
|
||||
}
|
||||
const previous = currentProfileName;
|
||||
currentProfileName = name;
|
||||
console.error(`[Profile] Switched: ${previous || '(none)'} → ${name}`);
|
||||
for (const listener of listeners) {
|
||||
try {
|
||||
listener({ previous, current: name });
|
||||
} catch (err) {
|
||||
console.error(`[Profile] Listener error: ${err.message}`);
|
||||
}
|
||||
}
|
||||
return profiles[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback fired whenever the active profile changes.
|
||||
* Used by services to invalidate caches / reset tokens.
|
||||
*/
|
||||
function onSwitch(listener) {
|
||||
listeners.push(listener);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
loadProfiles,
|
||||
listProfiles,
|
||||
getCurrent,
|
||||
getCurrentName,
|
||||
switchTo,
|
||||
onSwitch,
|
||||
};
|
||||
Reference in New Issue
Block a user