@agility/cli
Version:
Agility CLI for working with your content. (Public Beta)
934 lines โข 64 kB
JavaScript
"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 /*