@salesforce/pwa-kit-mcp
Version:
MCP server that helps you build Salesforce Commerce Cloud PWA Kit Composable Storefront
179 lines (175 loc) • 7.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Telemetry = void 0;
var _crypto = require("crypto");
var _telemetry = require("@salesforce/telemetry");
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _os = _interopRequireDefault(require("os"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
* Copyright (c) 2025, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
// NOTE: This is a workaround to import JSON files as ES modules.
// eslint-disable-next-line @typescript-eslint/no-var-requires
const packageJson = require('../package.json');
const PROJECT = 'pwa-kit-mcp';
const loadConfigValue = key => {
try {
const cfgPath = _path.default.resolve(__dirname, './config.json');
if (!_fs.default.existsSync(cfgPath)) return null;
const raw = _fs.default.readFileSync(cfgPath, 'utf8');
const cfg = JSON.parse(raw);
const v = cfg === null || cfg === void 0 ? void 0 : cfg[key];
return typeof v === 'string' && v.trim() ? v.trim() : null;
} catch {
return null;
}
};
const customAppInsightsKey = loadConfigValue('applicationInsightsConnectionString');
const generateRandomId = () => (0, _crypto.randomBytes)(20).toString('hex');
// Our own persistent CLI ID location: ~/.pwa-kit-mcp/cliid
const getOwnCliIdPath = () => {
const home = _os.default.homedir();
if (!home) return null;
const dir = _path.default.join(home, '.pwa-kit-mcp');
const file = _path.default.join(dir, 'cliid');
return {
dir,
file
};
};
const readOrCreateOwnCliId = () => {
const loc = getOwnCliIdPath();
if (!loc) return null;
if (_fs.default.existsSync(loc.file)) {
const value = _fs.default.readFileSync(loc.file, 'utf8');
const trimmed = value === null || value === void 0 ? void 0 : value.trim();
if (trimmed) return trimmed;
}
// Create new
const newId = generateRandomId();
try {
if (!_fs.default.existsSync(loc.dir)) {
_fs.default.mkdirSync(loc.dir, {
recursive: true,
mode: 0o700
});
}
_fs.default.writeFileSync(loc.file, newId, {
encoding: 'utf8',
mode: 0o600
});
} catch {
// If we can't persist, still return the generated id
}
return newId;
};
const readCliIdIfPresent = () => {
// Use our own persisted cliid under the user's home; if not present, generate one
const ownId = readOrCreateOwnCliId();
if (ownId) return ownId;
// Fallback: generate a random id for this session
return generateRandomId();
};
class McpTelemetryReporter extends _telemetry.TelemetryReporter {
// Always allow telemetry for this reporter; gating is handled by instantiation site.
isSfdxTelemetryEnabled() {
return true;
}
}
class Telemetry {
constructor(initialAttributes = {}) {
this.sessionId = generateRandomId();
this.cliId = readCliIdIfPresent();
this.started = false;
this.reporter = undefined;
this.attributes = _objectSpread({}, initialAttributes);
}
addAttributes(attributes) {
this.attributes = _objectSpread(_objectSpread({}, this.attributes), attributes);
}
sendEvent(eventName, attributes) {
try {
var _this$reporter;
(_this$reporter = this.reporter) === null || _this$reporter === void 0 ? void 0 : _this$reporter.sendTelemetryEvent(eventName, _objectSpread(_objectSpread(_objectSpread({}, this.attributes), attributes), {}, {
// Identifiers
sessionId: this.sessionId,
cliId: this.cliId,
// System information
version: packageJson === null || packageJson === void 0 ? void 0 : packageJson.version,
platform: process.platform,
arch: process.arch,
nodeVersion: process.version,
nodeEnv: process.env.NODE_ENV,
origin: PROJECT,
// Timestamps
date: new Date().toUTCString(),
timestamp: String(Date.now()),
processUptime: process.uptime() * 1000
}));
} catch {
// ignore send errors
}
}
// Convenience helper for external callers to send custom events
sendCustomEvent(eventName, properties = {}) {
this.sendEvent(eventName, properties);
}
start() {
var _this = this;
return _asyncToGenerator(function* () {
if (_this.started) return;
_this.started = true;
try {
yield _this.createMcpTelemetryReporter();
} catch (error) {
// Best-effort retry after ~1s: first runs can hit transient failures
// establishing the Application Insights connection (DNS/proxy/VPN warm-up,
// brief network blips, or backend cold start). One short delay usually fixes it.
// If the retry still fails, ignore it to avoid impacting the server.
try {
yield new Promise(r => setTimeout(r, 1000));
yield _this.createMcpTelemetryReporter();
} catch (retryError) {
// ignore
}
}
})();
}
stop() {
var _this$reporter2;
if (!this.started) return;
this.started = false;
(_this$reporter2 = this.reporter) === null || _this$reporter2 === void 0 ? void 0 : _this$reporter2.stop();
}
/**
* Creates and initializes the MCP telemetry reporter with App Insights.
* @returns {Promise<void>}
*/
createMcpTelemetryReporter() {
var _this2 = this;
return _asyncToGenerator(function* () {
// TODO: update configs based on approved telemetry approach
_this2.reporter = yield McpTelemetryReporter.create({
project: PROJECT,
key: customAppInsightsKey,
userId: _this2.cliId,
waitForConnection: true
});
_this2.reporter.start();
})();
}
}
exports.Telemetry = Telemetry;