@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
407 lines (406 loc) • 17.5 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OperationColors = exports.consoleText_bgGray = exports.consoleText_bgWhite = exports.consoleText_bgCyan = exports.consoleText_bgMagenta = exports.consoleText_bgBlue = exports.consoleText_bgYellow = exports.consoleText_bgGreen = exports.consoleText_bgRed = exports.consoleText_bgBlack = exports.consoleText_fgGray = exports.consoleText_fgWhite = exports.consoleText_fgCyan = exports.consoleText_fgMagenta = exports.consoleText_fgBlue = exports.consoleText_fgYellow = exports.consoleText_fgGreen = exports.consoleText_fgRed = exports.consoleText_fgBlack = exports.consoleText_hidden = exports.consoleText_reverse = exports.consoleText_blink = exports.consoleText_underscore = exports.consoleText_dim = exports.consoleText_bright = exports.consoleText_reset = void 0;
const LocalUtilities_1 = __importDefault(require("./LocalUtilities"));
const NodeStorage_1 = __importDefault(require("./NodeStorage"));
const fs = __importStar(require("fs"));
const Utilities_1 = __importDefault(require("../core/Utilities"));
const crypto = __importStar(require("crypto"));
const worker_threads_1 = require("worker_threads");
const Log_1 = __importStar(require("../core/Log"));
exports.consoleText_reset = "\x1b[0m";
exports.consoleText_bright = "\x1b[1m";
exports.consoleText_dim = "\x1b[2m";
exports.consoleText_underscore = "\x1b[4m";
exports.consoleText_blink = "\x1b[5m";
exports.consoleText_reverse = "\x1b[7m";
exports.consoleText_hidden = "\x1b[8m";
exports.consoleText_fgBlack = "\x1b[30m";
exports.consoleText_fgRed = "\x1b[31m";
exports.consoleText_fgGreen = "\x1b[32m";
exports.consoleText_fgYellow = "\x1b[33m";
exports.consoleText_fgBlue = "\x1b[34m";
exports.consoleText_fgMagenta = "\x1b[35m";
exports.consoleText_fgCyan = "\x1b[36m";
exports.consoleText_fgWhite = "\x1b[37m";
exports.consoleText_fgGray = "\x1b[90m";
exports.consoleText_bgBlack = "\x1b[40m";
exports.consoleText_bgRed = "\x1b[41m";
exports.consoleText_bgGreen = "\x1b[42m";
exports.consoleText_bgYellow = "\x1b[43m";
exports.consoleText_bgBlue = "\x1b[44m";
exports.consoleText_bgMagenta = "\x1b[45m";
exports.consoleText_bgCyan = "\x1b[46m";
exports.consoleText_bgWhite = "\x1b[47m";
exports.consoleText_bgGray = "\x1b[100m";
exports.OperationColors = [exports.consoleText_fgGreen, exports.consoleText_fgCyan, exports.consoleText_fgBlue, exports.consoleText_fgMagenta];
class LocalEnvironment {
#data;
utilities;
#isLoaded = false;
#prefsStorage;
#rootPrefFolder;
#configFile;
#worldContainerStorage;
logToStdError = false;
#displayInfo = false;
#displayVerbose = false;
_inmemTokenEncryptionPassword;
_inmemDisplayReadOnlyPasscode;
_inmemDisplayReadOnlySessionId;
_inmemFullReadOnlyPasscode;
_inmemFullReadOnlySessionId;
_inmemUpdateStatePasscode;
_inmemUpdateStateSessionId;
_inmemAdminPasscode;
_inmemAdminSessionId;
// Experimental SSL config - intentionally not persisted to disk
_sslConfig;
get sslConfig() {
return this._sslConfig;
}
set sslConfig(config) {
this._sslConfig = config;
}
get pathMappings() {
if (this.#data.pathMappings === undefined) {
return {};
}
return this.#data.pathMappings;
}
set pathMappings(newVal) {
this.#data.pathMappings = newVal;
}
get displayInfo() {
return this.#displayInfo;
}
set displayInfo(newInfoValue) {
this.#displayInfo = newInfoValue;
}
get displayVerbose() {
return this.#displayVerbose;
}
set displayVerbose(newVerboseValue) {
this.#displayVerbose = newVerboseValue;
}
get worldContainerStorage() {
return this.#worldContainerStorage;
}
get worldContainerPath() {
return this.#data.worldContainerPath;
}
get serverHostPort() {
return this.#data.serverHostPort;
}
set serverHostPort(newPort) {
if (newPort !== this.#data.serverHostPort) {
this.#data.serverHostPort = newPort;
}
}
get serverDomainName() {
return this.#data.serverDomainName;
}
set serverDomainName(newDomainName) {
if (newDomainName !== this.#data.serverDomainName) {
this.#data.serverDomainName = newDomainName;
}
}
get serverTitle() {
return this.#data.serverTitle;
}
set serverTitle(newTitle) {
if (newTitle !== this.#data.serverTitle) {
this.#data.serverTitle = newTitle;
}
}
get serverMessageOfTheDay() {
return this.#data.serverMessageOfTheDay;
}
set serverMessageOfTheDay(messageOfTheDay) {
if (messageOfTheDay !== this.#data.serverMessageOfTheDay) {
this.#data.serverMessageOfTheDay = messageOfTheDay;
}
}
get allowedCorsOrigins() {
return this.#data.allowedCorsOrigins;
}
set allowedCorsOrigins(newOrigins) {
if (newOrigins !== this.#data.allowedCorsOrigins) {
this.#data.allowedCorsOrigins = newOrigins;
}
}
get tokenEncryptionKey() {
if (this._inmemTokenEncryptionPassword === undefined) {
this._inmemTokenEncryptionPassword = this.generateRandomTokenPassword();
}
return this._inmemTokenEncryptionPassword;
}
get displayReadOnlyPasscode() {
return this._inmemDisplayReadOnlyPasscode; //this.#data.displayReadOnlyPasscode;
}
get displayReadOnlySessionId() {
return this._inmemDisplayReadOnlySessionId; //this.#data.displayReadOnlySessionId;
}
setDisplayReadOnlyPasscodeAndRandomizeComplement(newPasscode) {
if (newPasscode === undefined) {
throw new Error();
}
newPasscode = newPasscode.toLowerCase();
newPasscode = newPasscode.replace("-", "");
if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) {
throw new Error("Improperly formatted display read-only passcode. Passcodes should be 8 alphanumeric characters.");
}
this._inmemDisplayReadOnlyPasscode = newPasscode;
this._inmemDisplayReadOnlySessionId = this.generateRandomPasscode();
}
get fullReadOnlyPasscode() {
return this._inmemFullReadOnlyPasscode;
}
get fullReadOnlySessionId() {
return this._inmemFullReadOnlySessionId;
}
setFullReadOnlyPasscodeAndRandomizeComplement(newPasscode) {
if (newPasscode === undefined) {
throw new Error();
}
newPasscode = newPasscode.toLowerCase();
newPasscode = newPasscode.replace("-", "");
if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) {
throw new Error("Improperly formatted full read-only passcode. Passcodes should be 8 alphanumeric characters.");
}
this._inmemFullReadOnlyPasscode = newPasscode;
this._inmemFullReadOnlySessionId = this.generateRandomPasscode();
}
get updateStatePasscode() {
return this._inmemUpdateStatePasscode;
}
get updateStateSessionId() {
return this._inmemUpdateStateSessionId;
}
setUpdateStatePasscodeAndRandomizeComplement(newPasscode) {
if (newPasscode === undefined) {
throw new Error();
}
newPasscode = newPasscode.toLowerCase();
newPasscode = newPasscode.replace("-", "");
if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) {
throw new Error("Improperly formatted update passcode. Passcodes should be 8 alphanumeric characters.");
}
this._inmemUpdateStatePasscode = newPasscode;
this._inmemUpdateStateSessionId = this.generateRandomPasscode();
}
get adminPasscode() {
return this._inmemAdminPasscode;
}
get adminSessionId() {
return this._inmemAdminSessionId;
}
setAdminPasscodeAndRandomizeComplement(newPasscode) {
if (newPasscode === undefined) {
throw new Error();
}
newPasscode = newPasscode.toLowerCase();
newPasscode = newPasscode.replace("-", "");
if (newPasscode.length !== 8 || !Utilities_1.default.isAlphaNumeric(newPasscode)) {
throw new Error("Improperly formatted admin passcode. Passcodes should be 8 alphanumeric characters.");
}
this._inmemAdminPasscode = newPasscode;
this._inmemAdminSessionId = this.generateRandomPasscode();
}
get iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula() {
return this.#data.iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula;
}
set iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula(iAgreeValue) {
this.#data.iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula = iAgreeValue;
}
constructor(subscribeToLog) {
this.#data = {};
this.load = this.load.bind(this);
this.save = this.save.bind(this);
this.utilities = new LocalUtilities_1.default();
this.handleNewLogMessage = this.handleNewLogMessage.bind(this);
if (subscribeToLog) {
Log_1.default.onItemAdded.subscribe(this.handleNewLogMessage);
}
if (!fs.existsSync(this.utilities.serverWorkingPath)) {
fs.mkdirSync(this.utilities.serverWorkingPath, { recursive: true });
}
this.#data.worldContainerPath = this.utilities.worldsWorkingPath;
if (this.utilities.worldsWorkingPath && !fs.existsSync(this.utilities.worldsWorkingPath)) {
fs.mkdirSync(this.utilities.worldsWorkingPath, { recursive: true });
}
this.#worldContainerStorage = new NodeStorage_1.default(this.utilities.worldsWorkingPath, "");
if (!fs.existsSync(this.utilities.cliWorkingPath)) {
fs.mkdirSync(this.utilities.cliWorkingPath, { recursive: true });
}
if (!fs.existsSync(this.utilities.envPrefsPath)) {
fs.mkdirSync(this.utilities.envPrefsPath, { recursive: true });
}
if (!fs.existsSync(this.utilities.packCachePath)) {
fs.mkdirSync(this.utilities.packCachePath, { recursive: true });
}
this.#prefsStorage = new NodeStorage_1.default(this.utilities.envPrefsPath, "");
this.#rootPrefFolder = this.#prefsStorage.rootFolder;
this.#configFile = this.#rootPrefFolder.ensureFile("envprefs.json");
}
setWorldContainerPath(newPath) {
if (newPath !== this.#data.worldContainerPath) {
this.#data.worldContainerPath = newPath;
if (newPath) {
if (!fs.existsSync(newPath)) {
fs.mkdirSync(newPath, { recursive: true });
}
this.#worldContainerStorage = new NodeStorage_1.default(newPath, "");
}
}
}
handleNewLogMessage(log, item) {
if (item.level === Log_1.LogItemLevel.verbose && !this.displayVerbose) {
return;
}
// In MCP/stdio mode, only send errors and important messages to stderr.
// Regular messages and debug output would show as [warning] in VS Code's
// MCP output panel, which is confusing for users.
if (this.logToStdError) {
let context = "";
if (item.context && item.context.length > 0) {
context = item.context + " ";
}
if (item.level === Log_1.LogItemLevel.error) {
console.error(exports.consoleText_fgRed + context + "Error: " + item.message + exports.consoleText_reset);
}
else if (item.level === Log_1.LogItemLevel.important) {
console.error(exports.consoleText_fgYellow + context + item.message + exports.consoleText_reset);
}
// Suppress message/verbose/debug in MCP mode — they're not actionable
return;
}
let context = "";
if (this.displayVerbose) {
context = worker_threads_1.threadId + ": ";
}
if (item.context && item.context.length > 0) {
context = item.context + " ";
}
if (item.level === Log_1.LogItemLevel.verbose) {
console.log(exports.consoleText_fgGray + context + item.message + exports.consoleText_reset);
}
else if (item.level === Log_1.LogItemLevel.error) {
console.error(exports.consoleText_fgRed + context + "Error: " + item.message + exports.consoleText_reset);
}
else if (item.level === Log_1.LogItemLevel.important) {
// NOTE: This is the Log framework's own output handler — using Log.important()
// here would cause infinite recursion. console.log with yellow coloring is intentional.
console.log(exports.consoleText_fgYellow + context + "Important: " + item.message + exports.consoleText_reset);
}
else {
console.log(context + item.message);
}
}
async load() {
if (this.#isLoaded) {
return;
}
if (!this.#configFile.isContentLoaded) {
await this.#configFile.loadContent(false);
}
if (this.#configFile.content !== null &&
this.#configFile.content !== undefined &&
typeof this.#configFile.content === "string") {
this.#data = JSON.parse(this.#configFile.content);
}
this.#isLoaded = true;
}
async setDefaults() {
await this.load();
if (this.#data.serverDomainName === undefined) {
this.#data.serverDomainName = "localhost";
}
if (this.#data.serverHostPort === undefined) {
this.#data.serverHostPort = 6126;
}
if (this._inmemDisplayReadOnlyPasscode === undefined || this._inmemDisplayReadOnlySessionId === undefined) {
this.setDisplayReadOnlyPasscodeAndRandomizeComplement(this.generateRandomPasscode());
}
if (this._inmemAdminPasscode === undefined || this._inmemAdminSessionId === undefined) {
this.setAdminPasscodeAndRandomizeComplement(this.generateRandomPasscode());
}
if (this._inmemFullReadOnlyPasscode === undefined || this._inmemFullReadOnlySessionId === undefined) {
this.setFullReadOnlyPasscodeAndRandomizeComplement(this.generateRandomPasscode());
}
if (this._inmemUpdateStatePasscode === undefined || this._inmemUpdateStateSessionId === undefined) {
this.setUpdateStatePasscodeAndRandomizeComplement(this.generateRandomPasscode());
}
await this.save();
}
generateRandomPasscode() {
let newPasscode = "";
for (let i = 0; i < 8; i++) {
const rand = crypto.randomInt(34); // don't include 0 and 1 to preclude O/I confusion
if (rand <= 7) {
newPasscode += String.fromCharCode(rand + 50);
}
else {
newPasscode += String.fromCharCode(rand + 89); // 89 + 8 = starts at A range.
}
}
return newPasscode;
}
generateRandomTokenPassword() {
let newPasscode = "";
for (let i = 0; i < 12; i++) {
const rand = crypto.randomInt(36);
if (rand <= 9) {
newPasscode += String.fromCharCode(rand + 48);
}
else {
newPasscode += String.fromCharCode(rand + 87); // 87 + 10 = starts at A range.
}
}
return newPasscode;
}
async save() {
const content = JSON.stringify(this.#data, null, 2);
this.#configFile.setContent(content);
this.#configFile.saveContent();
}
}
exports.default = LocalEnvironment;