UNPKG

@agility/cli

Version:

Agility CLI for working with your content. (Public Beta)

934 lines โ€ข 64 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Auth = void 0; var state_1 = require("./state"); var mgmtApi = __importStar(require("@agility/management-sdk")); var open = require("open"); var FormData = require("form-data"); var fs_1 = __importDefault(require("fs")); var path_1 = __importDefault(require("path")); var https_1 = __importDefault(require("https")); var keytar_1 = __importDefault(require("keytar")); var process_1 = require("process"); var ansi_colors_1 = __importDefault(require("ansi-colors")); var SERVICE_NAME = "agility-cli"; var lastLength = 0; function logReplace(text) { var clear = " ".repeat(lastLength); process.stdout.write("\r" + clear + "\r" + text); lastLength = text.length; } var Auth = /** @class */ (function () { function Auth(insecureMode) { if (insecureMode === void 0) { insecureMode = false; } this.insecureMode = false; this.insecureMode = insecureMode; } Auth.prototype.setInsecureMode = function (insecure) { this.insecureMode = insecure; }; Auth.prototype.createHttpsAgent = function () { if (this.insecureMode) { return new https_1.default.Agent({ rejectUnauthorized: false, }); } return undefined; }; Auth.prototype.getFetchConfig = function () { var config = { headers: { "Cache-Control": "no-cache", "User-Agent": "agility-cli-fetch/1.0", }, }; if (this.insecureMode) { // For fetch with Node.js, we need to handle SSL differently // This is a simplified approach - in production, you might need more sophisticated SSL handling process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; } return config; }; Auth.prototype.handleSSLError = function (error) { var _a; if (error.code === "UNABLE_TO_GET_ISSUER_CERT_LOCALLY" || error.code === "SELF_SIGNED_CERT_IN_CHAIN" || ((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("certificate"))) { console.error("โŒ SSL Certificate Error detected."); console.error("This often happens in corporate environments with proxy servers."); console.error("Try running with the --insecure flag to bypass SSL verification:"); console.error(" npx agility login --insecure"); console.error(" npx agility pull --insecure --sourceGuid <your-guid>"); console.error(" npx agility sync --insecure --sourceGuid <guid1> --targetGuid <guid2>"); } throw error; }; Auth.prototype.getEnv = function () { return state_1.state.local ? "local" : state_1.state.dev ? "dev" : state_1.state.preprod ? "preprod" : "prod"; }; Auth.prototype.checkForEnvFile = function () { var envFiles = [".env", ".env.local", ".env.development", ".env.production"]; var result = { hasEnvFile: false }; for (var _i = 0, envFiles_1 = envFiles; _i < envFiles_1.length; _i++) { var envFile = envFiles_1[_i]; var envPath = path_1.default.join(process.cwd(), envFile); if (fs_1.default.existsSync(envPath)) { var envContent = fs_1.default.readFileSync(envPath, "utf8"); var guidMatch = envContent.match(/AGILITY_GUID=([^\n]+)/); var channelMatch = envContent.match(/AGILITY_WEBSITE=([^\n]+)/); var localeMatch = envContent.match(/AGILITY_LOCALES=([^\n]+)/); if (guidMatch && guidMatch[1]) { result.hasEnvFile = true; result.guid = guidMatch[1].trim(); } if (channelMatch && channelMatch[1]) { result.hasEnvFile = true; result.channel = channelMatch[1].trim(); } if (localeMatch && localeMatch[1]) { result.hasEnvFile = true; result.locales = localeMatch[1].trim().split(","); } if (result.hasEnvFile) { return result; } } } return result; }; Auth.prototype.getEnvKey = function (env) { return "cli-auth-token:".concat(env); }; Auth.prototype.logout = function () { return __awaiter(this, void 0, void 0, function () { var env, key, removed, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: env = this.getEnv(); key = this.getEnvKey(env); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, keytar_1.default.deletePassword(SERVICE_NAME, key)]; case 2: removed = _a.sent(); if (removed) { console.log("Logged out from ".concat(env, " environment.")); } else { console.log("No token found in ".concat(env, " environment.")); } return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); console.error("\u274C Failed to delete token:", err_1); return [3 /*break*/, 4]; case 4: (0, process_1.exit)(); return [2 /*return*/]; } }); }); }; Auth.prototype.generateCode = function () { return __awaiter(this, void 0, void 0, function () { var firstPart, secondPart, firstString, secondString; return __generator(this, function (_a) { firstPart = (Math.random() * 46656) | 0; secondPart = (Math.random() * 46656) | 0; firstString = ("000" + firstPart.toString(36)).slice(-3); secondString = ("000" + secondPart.toString(36)).slice(-3); return [2 /*return*/, firstString + secondString]; }); }); }; Auth.prototype.determineBaseUrl = function (guid, userBaseUrl) { if (userBaseUrl === void 0) { userBaseUrl = null; } if (userBaseUrl) { return userBaseUrl; } if (state_1.state.local) { return "https://localhost:5050"; } if (state_1.state.dev) { return "https://mgmt-dev.aglty.io"; } if (state_1.state.preprod) { return "https://management-api-us-pre-prod.azurewebsites.net"; } if (guid === null || guid === void 0 ? void 0 : guid.endsWith("d")) { return "https://mgmt-dev.aglty.io"; } else if (guid === null || guid === void 0 ? void 0 : guid.endsWith("u")) { return "https://mgmt.aglty.io"; } else if (guid === null || guid === void 0 ? void 0 : guid.endsWith("c")) { return "https://mgmt-ca.aglty.io"; } else if (guid === null || guid === void 0 ? void 0 : guid.endsWith("e")) { return "https://mgmt-eu.aglty.io"; } else if (guid === null || guid === void 0 ? void 0 : guid.endsWith("a")) { return "https://mgmt-aus.aglty.io"; } return "https://mgmt.aglty.io"; }; Auth.prototype.getBaseUrl = function (guid, userBaseUrl) { if (userBaseUrl === void 0) { userBaseUrl = null; } var baseUrl = this.determineBaseUrl(guid, userBaseUrl); return "".concat(baseUrl, "/oauth"); }; Auth.prototype.getBaseUrlPoll = function () { var baseURL = "https://mgmt.aglty.io"; if (state_1.state.dev) { baseURL = "https://mgmt-dev.aglty.io"; } if (state_1.state.preprod) { baseURL = "https://management-api-us-pre-prod.azurewebsites.net"; } if (state_1.state.local) { baseURL = "https://localhost:5050"; } return "".concat(baseURL, "/oauth"); }; Auth.prototype.executeGet = function (apiPath_1, guid_1) { return __awaiter(this, arguments, void 0, function (apiPath, guid, userBaseUrl) { var baseUrl, url, token, response, contentType, textResponse, err_2; if (userBaseUrl === void 0) { userBaseUrl = null; } return __generator(this, function (_a) { switch (_a.label) { case 0: baseUrl = this.getBaseUrl(guid, userBaseUrl); url = "".concat(baseUrl).concat(apiPath); _a.label = 1; case 1: _a.trys.push([1, 8, , 9]); return [4 /*yield*/, this.getToken()]; case 2: token = _a.sent(); return [4 /*yield*/, fetch(url, { method: "GET", headers: { Authorization: "Bearer ".concat(token), "Cache-Control": "no-cache", "User-Agent": "agility-cli-fetch/1.0", }, })]; case 3: response = _a.sent(); if (!response.ok) { throw new Error("HTTP ".concat(response.status, ": ").concat(response.statusText, " for ").concat(url)); } contentType = response.headers.get("content-type"); if (!(contentType && contentType.includes("application/json"))) return [3 /*break*/, 5]; return [4 /*yield*/, response.json()]; case 4: return [2 /*return*/, _a.sent()]; case 5: return [4 /*yield*/, response.text()]; case 6: textResponse = _a.sent(); // Handle both quoted and unquoted string responses return [2 /*return*/, textResponse.startsWith('"') && textResponse.endsWith('"') ? textResponse.slice(1, -1) : textResponse]; case 7: return [3 /*break*/, 9]; case 8: err_2 = _a.sent(); this.handleSSLError(err_2); return [3 /*break*/, 9]; case 9: return [2 /*return*/]; } }); }); }; Auth.prototype.executePost = function (apiPath, guid, data) { return __awaiter(this, void 0, void 0, function () { var baseUrl, url, body, headers, response, err_3; return __generator(this, function (_a) { switch (_a.label) { case 0: baseUrl = this.getBaseUrlPoll(); url = "".concat(baseUrl).concat(apiPath); _a.label = 1; case 1: _a.trys.push([1, 4, , 5]); body = void 0; headers = { "Cache-Control": "no-cache", "User-Agent": "agility-cli-fetch/1.0", }; if (data instanceof FormData) { body = data; // Don't set Content-Type for FormData, let fetch set it with boundary } else if (data instanceof URLSearchParams) { body = data; headers["Content-Type"] = "application/x-www-form-urlencoded"; } else { body = JSON.stringify(data); headers["Content-Type"] = "application/json"; } return [4 /*yield*/, fetch(url, { method: "POST", body: body, headers: headers, })]; case 2: response = _a.sent(); if (!response.ok) { throw new Error("HTTP ".concat(response.status, ": ").concat(response.statusText, " for ").concat(url)); } return [4 /*yield*/, response.json()]; case 3: return [2 /*return*/, _a.sent()]; case 4: err_3 = _a.sent(); this.handleSSLError(err_3); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }; Auth.prototype.authorize = function () { return __awaiter(this, void 0, void 0, function () { var code, baseUrl, redirectUri, authUrl; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.generateCode()]; case 1: code = _a.sent(); baseUrl = this.determineBaseUrl(); redirectUri = "".concat(baseUrl, "/oauth/CliAuth"); authUrl = "".concat(baseUrl, "/oauth/Authorize?response_type=code&redirect_uri=").concat(encodeURIComponent(redirectUri), "&state=cli-code%2e").concat(code); return [4 /*yield*/, open(authUrl)]; case 2: _a.sent(); return [2 /*return*/, code]; } }); }); }; /** * Complete initialization: .env priming + validation + authentication + setup * Handles everything needed to get the CLI ready for operation */ Auth.prototype.init = function () { return __awaiter(this, void 0, void 0, function () { var configureSSL, isAuthenticated, allGuids, _i, allGuids_1, guid, previewKey, fetchKey, error_1, shouldSkip, mgmtApiOptions, _a, primaryGuid_1, user, error_2, sourceLocales_1, targetLocales_1, missingLocales, localesToUse, validLocales, guidLocaleMap, error_3, fallbackLocales, _b, allGuids_2, guid; return __generator(this, function (_c) { switch (_c.label) { case 0: return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./state")); })]; case 1: configureSSL = (_c.sent()).configureSSL; configureSSL(); return [4 /*yield*/, this.checkAuthorization()]; case 2: isAuthenticated = _c.sent(); if (!isAuthenticated) { return [2 /*return*/, false]; } allGuids = __spreadArray(__spreadArray([], state_1.state.sourceGuid, true), state_1.state.targetGuid, true); state_1.state.apiKeys = []; _i = 0, allGuids_1 = allGuids; _c.label = 3; case 3: if (!(_i < allGuids_1.length)) return [3 /*break*/, 9]; guid = allGuids_1[_i]; if (!guid) return [3 /*break*/, 8]; _c.label = 4; case 4: _c.trys.push([4, 7, , 8]); return [4 /*yield*/, this.getPreviewKey(guid)]; case 5: previewKey = _c.sent(); return [4 /*yield*/, this.getFetchKey(guid)]; case 6: fetchKey = _c.sent(); state_1.state.apiKeys.push({ guid: guid, previewKey: previewKey, fetchKey: fetchKey }); return [3 /*break*/, 8]; case 7: error_1 = _c.sent(); console.log(ansi_colors_1.default.yellow("Warning: Could not get keys for GUID ".concat(guid, ": ").concat(error_1.message))); return [3 /*break*/, 8]; case 8: _i++; return [3 /*break*/, 3]; case 9: // Step 4: Set up UI mode in state state_1.state.useHeadless = state_1.state.headless; // headless takes precedence state_1.state.useVerbose = !state_1.state.useHeadless && state_1.state.verbose; shouldSkip = this.shouldSkipPermissionCheck(); if (shouldSkip) { if (state_1.state.test) { console.log(ansi_colors_1.default.yellow("๐Ÿงช TEST MODE: Bypassing permission checks for analysis...")); } else if (state_1.state.test) { console.log(ansi_colors_1.default.yellow("๐Ÿงช TEST MODE: Bypassing permission checks...")); } } return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("@agility/management-sdk")); })]; case 10: mgmtApiOptions = new (_c.sent()).Options(); _a = mgmtApiOptions; return [4 /*yield*/, this.getToken()]; case 11: _a.token = _c.sent(); // // Store basic mgmt API options in state state_1.state.mgmtApiOptions = mgmtApiOptions; // Clear cached API client to ensure fresh connection with new auth state // const { clearApiClient } = await import('./state'); // clearApiClient(); state_1.state.cachedApiClient = new mgmtApi.ApiClient(state_1.state.mgmtApiOptions); if (!(state_1.state.sourceGuid.length > 0)) return [3 /*break*/, 15]; _c.label = 12; case 12: _c.trys.push([12, 14, , 15]); primaryGuid_1 = state_1.state.sourceGuid[0]; return [4 /*yield*/, this.getUser(primaryGuid_1)]; case 13: user = _c.sent(); if (user) { state_1.state.user = user; state_1.state.currentWebsite = user.websiteAccess.find(function (website) { return website.guid === primaryGuid_1; }); } return [3 /*break*/, 15]; case 14: error_2 = _c.sent(); // Non-fatal for interactive mode - user data will be loaded when needed console.log(ansi_colors_1.default.yellow("Note: Could not load user data: ".concat(error_2.message))); return [3 /*break*/, 15]; case 15: if (!(allGuids.length > 0)) return [3 /*break*/, 22]; _c.label = 16; case 16: _c.trys.push([16, 21, , 22]); sourceLocales_1 = []; if (!(state_1.state.sourceGuid.length > 0)) return [3 /*break*/, 18]; return [4 /*yield*/, state_1.state.cachedApiClient.instanceMethods.getLocales(state_1.state.sourceGuid[0])]; case 17: sourceLocales_1 = (_c.sent()).map(function (locale) { return locale.localeCode; }); state_1.state.availableLocales = sourceLocales_1; _c.label = 18; case 18: targetLocales_1 = []; if (!(state_1.state.targetGuid.length > 0)) return [3 /*break*/, 20]; return [4 /*yield*/, state_1.state.cachedApiClient.instanceMethods.getLocales(state_1.state.targetGuid[0])]; case 19: targetLocales_1 = (_c.sent()).map(function (locale) { return locale.localeCode; }); missingLocales = sourceLocales_1.filter(function (locale) { return !targetLocales_1.includes(locale); }); if (missingLocales.length > 0) { console.log(ansi_colors_1.default.yellow("\u26A0\uFE0F Target instance ".concat(state_1.state.targetGuid[0], ": Missing locales ").concat(missingLocales.join(', '), " (available: ").concat(targetLocales_1.join(', '), ")"))); return [2 /*return*/, false]; // Cannot proceed with missing locales } _c.label = 20; case 20: localesToUse = sourceLocales_1; if (state_1.state.locale.length > 0) { validLocales = state_1.state.locale.filter(function (l) { return sourceLocales_1.includes(l); }); if (validLocales.length === 0) { console.log(ansi_colors_1.default.yellow("\u26A0\uFE0F None of the specified locales exist in the source instance ".concat(state_1.state.sourceGuid[0], ". Using all available locales."))); } else { localesToUse = validLocales; // Use only valid locales that exist in the source } } guidLocaleMap = new Map(); guidLocaleMap.set(state_1.state.sourceGuid[0], localesToUse); if (state_1.state.targetGuid.length > 0) { //if we have a target... guidLocaleMap.set(state_1.state.targetGuid[0], localesToUse); } state_1.state.locale = localesToUse; // Set the state locale list to the determined locales state_1.state.guidLocaleMap = guidLocaleMap; return [3 /*break*/, 22]; case 21: error_3 = _c.sent(); console.log(ansi_colors_1.default.yellow("Note: Could not auto-detect locales: ".concat(error_3.message))); state_1.state.availableLocales = ["en-us"]; // Fallback to default fallbackLocales = state_1.state.locale.length > 0 ? [state_1.state.locale[0]] : ["en-us"]; for (_b = 0, allGuids_2 = allGuids; _b < allGuids_2.length; _b++) { guid = allGuids_2[_b]; if (guid) { state_1.state.guidLocaleMap.set(guid, fallbackLocales); } } console.log("\uD83D\uDCDD Using fallback mapping: all GUIDs \u2192 ".concat(fallbackLocales.join(", "))); return [3 /*break*/, 22]; case 22: return [2 /*return*/, true]; } }); }); }; /** * Validate user access to an instance */ Auth.prototype.validateInstanceAccess = function (guid, instanceType) { return __awaiter(this, void 0, void 0, function () { var user, permission, error_4; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 3, , 4]); return [4 /*yield*/, this.getUser(guid)]; case 1: user = _a.sent(); if (!user) { throw new Error("Could not retrieve user details for ".concat(instanceType, " instance ").concat(guid, ". Please ensure it's a valid GUID and you have access.")); } return [4 /*yield*/, this.checkUserRole(guid)]; case 2: permission = _a.sent(); if (!permission.hasPermission) { throw new Error("You do not have the required permissions on the ".concat(instanceType, " instance ").concat(guid, ".")); } // Store user info for the primary instance if (instanceType === "instance" || instanceType === "source") { state_1.state.user = user; // Store current website details if (state_1.state.sourceGuid) { state_1.state.currentWebsite = user.websiteAccess.find(function (website) { return website.guid === state_1.state.sourceGuid; }); } } return [3 /*break*/, 4]; case 3: error_4 = _a.sent(); throw new Error("".concat(instanceType.charAt(0).toUpperCase() + instanceType.slice(1), " instance authentication failed: ").concat(error_4.message)); case 4: return [2 /*return*/]; } }); }); }; Auth.prototype.checkAuthorization = function () { return __awaiter(this, void 0, void 0, function () { var env, key, tokenRaw, token, issuedAt, expiresAt, cliCode; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: env = this.getEnv(); key = this.getEnvKey(env); return [4 /*yield*/, keytar_1.default.getPassword(SERVICE_NAME, key)]; case 1: tokenRaw = _a.sent(); if (tokenRaw) { try { token = JSON.parse(tokenRaw); if (token.access_token && token.expires_in && token.timestamp) { issuedAt = new Date(token.timestamp).getTime(); expiresAt = issuedAt + token.expires_in * 1000; if (Date.now() < expiresAt) { console.log(ansi_colors_1.default.green("\r\u25CF Authenticated to ".concat(env === "prod" ? "Agility" : env, " servers.\n"))); return [2 /*return*/, true]; } else { console.log("Existing token has expired. Starting re-authentication..."); } } else { console.warn("Token is missing expiration metadata. Re-authentication required."); } } catch (err) { console.warn("Failed to parse token. Re-authentication required."); } } else { console.log(ansi_colors_1.default.yellow("No token found in keychain. Starting auth flow...")); } return [4 /*yield*/, this.authorize()]; case 2: cliCode = _a.sent(); logReplace("\rWaiting for authentication in your browser..."); return [2 /*return*/, new Promise(function (resolve, reject) { var interval = setInterval(function () { return __awaiter(_this, void 0, void 0, function () { var params, token, err_4; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 4, , 5]); params = new URLSearchParams(); params.append("cliCode", cliCode); return [4 /*yield*/, this.cliPoll(params)]; case 1: token = _a.sent(); if (!(token && token.access_token && token.expires_in && token.timestamp)) return [3 /*break*/, 3]; // Store token in keytar console.log(ansi_colors_1.default.green("\r\uD83D\uDD11 Authenticated to ".concat(env, " servers.\n"))); console.log("----------------------------------\n"); return [4 /*yield*/, keytar_1.default.setPassword(SERVICE_NAME, key, JSON.stringify(token))]; case 2: _a.sent(); clearInterval(interval); resolve(true); _a.label = 3; case 3: return [3 /*break*/, 5]; case 4: err_4 = _a.sent(); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }, 2000); setTimeout(function () { clearInterval(interval); reject(new Error("Authorization timed out after 60 seconds.")); }, 60000); })]; } }); }); }; Auth.prototype.login = function () { return __awaiter(this, void 0, void 0, function () { var env, key, cliCode; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: console.log("๐Ÿ”‘ Authenticating to Agility CMS..."); env = this.getEnv(); key = this.getEnvKey(env); return [4 /*yield*/, this.authorize()]; case 1: cliCode = _a.sent(); logReplace("\rWaiting for authentication in your browser..."); return [2 /*return*/, new Promise(function (resolve, reject) { var interval = setInterval(function () { return __awaiter(_this, void 0, void 0, function () { var params, token, err_5; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 4, , 5]); params = new URLSearchParams(); params.append("cliCode", cliCode); return [4 /*yield*/, this.cliPoll(params, "blank-d")]; case 1: token = _a.sent(); if (!(token && token.access_token && token.expires_in && token.timestamp)) return [3 /*break*/, 3]; // Store token in keytar console.log(ansi_colors_1.default.green("\r\uD83D\uDD11 Authenticated to ".concat(env, " servers.\n"))); console.log("----------------------------------\n"); return [4 /*yield*/, keytar_1.default.setPassword(SERVICE_NAME, key, JSON.stringify(token))]; case 2: _a.sent(); clearInterval(interval); resolve(true); _a.label = 3; case 3: return [3 /*break*/, 5]; case 4: err_5 = _a.sent(); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }, 2000); setTimeout(function () { clearInterval(interval); reject(new Error("Authentication timed out after 60 seconds.")); }, 60000); })]; } }); }); }; Auth.prototype.getToken = function () { return __awaiter(this, void 0, void 0, function () { var env, key, tokenRaw, token, issuedAt, expiresAt; return __generator(this, function (_a) { switch (_a.label) { case 0: env = this.getEnv(); key = this.getEnvKey(env); return [4 /*yield*/, keytar_1.default.getPassword(SERVICE_NAME, key)]; case 1: tokenRaw = _a.sent(); if (!tokenRaw) { throw new Error("\u274C No token found in keychain for environment: ".concat(env, ". Run 'agility login' to authenticate.")); } try { token = JSON.parse(tokenRaw); if (token.access_token && token.expires_in && token.timestamp) { issuedAt = new Date(token.timestamp).getTime(); expiresAt = issuedAt + token.expires_in * 1000; if (Date.now() < expiresAt) { return [2 /*return*/, token.access_token]; } else { throw new Error("โŒ Token has expired. Please run `agility login` again."); } } else { throw new Error("โŒ Token is missing required fields (access_token, expires_in, timestamp)."); } } catch (err) { throw new Error("โŒ Failed to parse stored token. Please log in again."); } return [2 /*return*/]; } }); }); }; Auth.prototype.cliPoll = function (data_1) { return __awaiter(this, arguments, void 0, function (data, guid) { var result, err_6; if (guid === void 0) { guid = "blank-d"; } return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.executePost("/CliPoll", guid, data)]; case 1: result = _a.sent(); // Add timestamp if it's missing if (result.access_token && !result.timestamp) { result.timestamp = new Date().toISOString(); } return [2 /*return*/, result]; case 2: err_6 = _a.sent(); throw new Error("during CLI poll: ".concat(err_6.message)); case 3: return [2 /*return*/]; } }); }); }; Auth.prototype.getPreviewKey = function (guid_1) { return __awaiter(this, arguments, void 0, function (guid, userBaseUrl) { var result, err_7; if (userBaseUrl === void 0) { userBaseUrl = null; } return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.executeGet("/GetPreviewKey?guid=" + guid, guid, userBaseUrl)]; case 1: result = _a.sent(); // The API returns a raw string, not a JSON object with a previewKey property return [2 /*return*/, result]; case 2: err_7 = _a.sent(); throw err_7; case 3: return [2 /*return*/]; } }); }); }; Auth.prototype.getFetchKey = function (guid_1) { return __awaiter(this, arguments, void 0, function (guid, userBaseUrl) { var result, err_8; if (userBaseUrl === void 0) { userBaseUrl = null; } return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.executeGet("/GetFetchKey?guid=" + guid, guid, userBaseUrl)]; case 1: result = _a.sent(); // The API returns a raw string, not a JSON object with a fetchKey property return [2 /*return*/, result]; case 2: err_8 = _a.sent(); throw err_8; case 3: return [2 /*return*/]; } }); }); }; Auth.prototype.checkUserRole = function (guid) { return __awaiter(this, void 0, void 0, function () { var userData, instanceAccess, err_9; var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: _b.trys.push([0, 2, , 3]); return [4 /*yield*/, this.getUser(guid)]; case 1: userData = _b.sent(); instanceAccess = (_a = userData.websiteAccess) === null || _a === void 0 ? void 0 : _a.find(function (access) { return access.guid === guid; }); if (!instanceAccess) { console.log(ansi_colors_1.default.red("\u274C You do not have access to instance: ".concat(guid))); console.log(ansi_colors_1.default.yellow("Contact your instance administrator to get access.")); return [2 /*return*/, { hasPermission: false, role: null }]; } // Check if user is owner of this instance if (instanceAccess.isOwner) { return [2 /*return*/, { hasPermission: true, role: "Owner" }]; } else { // Non-owners still have manager-level access in Agility CMS // For sync operations, we'll allow any user with access return [2 /*return*/, { hasPermission: true, role: "Manager" }]; } return [3 /*break*/, 3]; case 2: err_9 = _b.sent(); console.log(ansi_colors_1.default.red("Error checking user role: ".concat(err_9))); console.log(ansi_colors_1.default.yellow("You do not have the required permissions on the target instance ".concat(guid, "."))); return [2 /*return*/, { hasPermission: false, role: null }]; case 3: return [2 /*return*/]; } }); }); }; Auth.prototype.getUser = function (guid) { return __awaiter(this, void 0, void 0, function () { var baseUrl, apiPath, endpoint, token, response, data, error_5; return __generator(this, function (_a) { switch (_a.label) { case 0: baseUrl = this.determineBaseUrl(guid); apiPath = "/users/me"; endpoint = "".concat(baseUrl, "/api/v1").concat(apiPath); return [4 /*yield*/, this.getToken()]; case 1: token = _a.sent(); _a.label = 2; case 2: _a.trys.push([2, 5, , 6]); return [4 /*yield*/, fetch(endpoint, { method: "GET", headers: { Authorization: "Bearer ".concat(token), "Cache-Control": "no-cache", }, })]; case 3: response = _a.sent(); if (!response.ok) { throw new Error("HTTP error! status: ".concat(response.status)); } return [4 /*yield*/, response.json()]; case 4: data = _a.sent(); if (!data || !data.websiteAccess) { throw new Error("Invalid user data received"); } if (!data.websiteAccess || data.websiteAccess.length === 0) { throw new Error("User does not have access to any instances."); } return [2 /*return*/, data]; case 5: error_5 = _a.sent(); console.error("Error fetching user:", error_5); throw new Error("Failed to get user data. Please try logging in again."); case 6: return [2 /*return*/]; } }); }); }; Auth.prototype.getUsers = function (guid_1) { return __awaiter(this, arguments, void 0, function (guid, userBaseUrl) { var baseUrl, token, response, err_10; if (userBaseUrl === void 0) { userBaseUrl = null; } return __generator(this, function (_a) { switch (_a.label) { case 0: baseUrl = this.determineBaseUrl(guid, userBaseUrl); return [4 /*yield*/, this.getToken()]; case 1: token = _a.sent(); _a.label = 2; case 2: _a.trys.push([2, 5, , 6]); return [4 /*yield*/, fetch("".concat(baseUrl, "/api/v1/instance/").concat(guid, "/users"), { method: "GET", headers: { Authorization: "Bearer ".concat(token), "Cache-Control": "no-cache", "User-Agent": "agility-cli-fetch/1.0", }, })]; case 3: response = _a.sent(); if (!response.ok) { throw new Error("HTTP ".concat(response.status, ": ").concat(response.statusText)); } return [4 /*yield*/, response.json()]; case 4: return [2 /*return*/, _a.sent()]; case 5: err_10 = _a.sent(); this.handleSSLError(err_10); return [3 /*break*/, 6]; case 6: return [2 /*