devex: minimal initialization logs

This commit is contained in:
KernelDeimos
2025-10-09 19:39:02 -04:00
committed by Eric Dubé
parent 9b34e67d0d
commit ea9c222c09
14 changed files with 149 additions and 70 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ module.exports = {
HostOSModule,
CoreModule,
WebModule,
TemplateModule,
// TemplateModule,
AppsModule,
CaptchaModule,
EntityStoreModule,
+25
View File
@@ -36,6 +36,20 @@ class Extension extends AdvancedBase {
]
}),
];
randomBrightColor() {
// Bright colors in ANSI (foreground codes 9097)
const brightColors = [
// 91, // Bright Red
92, // Bright Green
// 93, // Bright Yellow
94, // Bright Blue
95, // Bright Magenta
// 96, // Bright Cyan
];
return brightColors[Math.floor(Math.random() * brightColors.length)];
}
constructor (...a) {
super(...a);
@@ -43,6 +57,9 @@ class Extension extends AdvancedBase {
this.log = null;
this.ensure_service_();
// this.terminal_color = this.randomBrightColor();
this.terminal_color = 94;
this.log = (...a) => {
this.log_context.info(a.join(' '));
};
@@ -260,6 +277,14 @@ class Extension extends AdvancedBase {
}
this.only_one_init_fn = callback;
}
get console () {
const extensionConsole = Object.create(console);
extensionConsole.log = (...a) => {
console.log(`\x1B[${this.terminal_color};1m(extension/${this.name})\x1B[0m`, ...a);
};
return extensionConsole;
}
/**
* This method will create the "default service" for an extension.
+4 -3
View File
@@ -218,8 +218,6 @@ class Kernel extends AdvancedBase {
await services.ready;
globalThis.services = services;
const log = services.get('log-service').create('init');
log.info('services ready');
log.system('server ready', {
deployment_type: globalThis.deployment_type,
});
@@ -411,6 +409,7 @@ class Kernel extends AdvancedBase {
`const { use: puter } = globalThis.__puter_extension_globals__.useapi;`,
`const extension = globalThis.__puter_extension_globals__` +
`.extensionObjectRegistry[${JSON.stringify(extension_id)}];`,
`const console = extension.console;`,
`const runtime = extension.runtime;`,
`const config = extension.config;`,
`const registry = extension.registry;`,
@@ -465,6 +464,8 @@ class Kernel extends AdvancedBase {
},
});
mod.extension.name = packageJSON.name;
const maybe_promise = (typ => typ.trim().toLowerCase())(packageJSON.type ?? '') === 'module'
? await import(path_.join(require_dir, packageJSON.main ?? 'index.js'))
: require(require_dir);
@@ -577,7 +578,7 @@ class Kernel extends AdvancedBase {
async run_npm_install (path) {
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
const proc = spawn(npmCmd, ["install"], { cwd: path, shell: true, stdio: "pipe" });
const proc = spawn(npmCmd, ["install"], { cwd: path, stdio: "pipe" });
let buffer = '';
-5
View File
@@ -17,11 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
class BootLogger {
constructor () {
console.log(
`\x1B[36;1mBoot logger started :)\x1B[0m`,
);
}
info (...args) {
console.log(
'\x1B[36;1m[BOOT/INFO]\x1B[0m',
+1 -1
View File
@@ -381,7 +381,7 @@ class RuntimeEnvironment extends AdvancedBase {
if ( ! checks_pass ) continue;
this.logger.info(
`${hl('USING')} ${quot(entry.path)} for ${meta.pathFor}.`
`${hl(meta.pathFor)} ${quot(entry.path)}`
)
return entry;
@@ -102,11 +102,6 @@ class BroadcastService extends BaseService {
});
});
});
this.log.noticeme(
require('node:util').inspect(this.config)
);
}
_register_commands (commands) {
@@ -54,7 +54,7 @@ class ComplainAboutVersionsService extends BaseService {
const cur_date_obj = new Date();
if ( cur_date_obj < eol_date ) {
this.log.info('node.js version looks good');
this.log.debug('node.js version looks good');
return;
}
@@ -75,22 +75,13 @@ class ComplainAboutVersionsService extends BaseService {
return str;
})();
const svc_devConsole = this.services.get('dev-console');
svc_devConsole.add_widget(() => {
const widget_lines = [];
widget_lines.push(
`Node.js version ${major} is past EOL by ${timeago};`,
`Everything should work, but you should still upgrade.`,
);
surrounding_box('31;1', widget_lines);
return widget_lines;
});
this.log.warn(`Node.js version ${major} is past EOL by ${timeago}`);
}
async get_eol_data_ () {
const require = this.require;
const axios = require('axios');
const url = 'https://endoflife.date/api/nodejs.json'
const url = 'https://endoflife.date/api/nodejs.json';
let data;
try {
({ data } = await axios.get(url));
@@ -176,7 +176,14 @@ class DevWatcherService extends BaseService {
const webpacker = webpack(webpackConfig);
let errorAfterLastEnd = false;
let firstEvent = true;
webpacker.watch({}, (err, stats) => {
let hideSuccess = false;
if ( firstEvent ) {
firstEvent = false;
hideSuccess = true;
}
if (err || stats.hasErrors()) {
this.log.error(`error information: ${entry.directory} using Webpack`, {
err,
@@ -187,7 +194,9 @@ class DevWatcherService extends BaseService {
// Normally success messages aren't important, but sometimes it takes
// a little bit for the bundle to update so a developer probably would
// like to have a visual indication in the console when it happens.
this.log.info(`✅ updated ${entry.directory} using Webpack`);
if ( ! hideSuccess ) {
this.log.info(`✅ updated ${entry.directory} using Webpack`);
}
}
});
}
@@ -244,13 +253,21 @@ class DevWatcherService extends BaseService {
const watcher = rollupModule.watch(rollupConfig);
let errorAfterLastEnd = false;
let firstEvent = true;
watcher.on('event', (event) => {
if ( event.code === 'END' ) {
let hideSuccess = false;
if ( firstEvent ) {
firstEvent = false;
hideSuccess = true;
}
if ( errorAfterLastEnd ) {
errorAfterLastEnd = false;
return;
}
this.log.info(`✅ updated ${entry.directory} using Rollup`);
if ( ! hideSuccess ) {
this.log.info(`✅ updated ${entry.directory} using Rollup`);
}
} else if ( event.code === 'ERROR' ) {
this.log.error(`error information: ${entry.directory} using Rollup`, {
event,
@@ -41,8 +41,8 @@ class SelfHostedModule extends AdvancedBase {
const { DBKVServiceWrapper } = require("../../services/repositories/DBKVStore/index.mjs");
services.registerService('puter-kvstore', DBKVServiceWrapper);
const MinLogService = require('./MinLogService');
services.registerService('min-log', MinLogService);
// const MinLogService = require('./MinLogService');
// services.registerService('min-log', MinLogService);
// TODO: sucks
const RELATIVE_PATH = '../../../../../';
+14 -15
View File
@@ -117,7 +117,7 @@ class WebServerService extends BaseService {
const services = this.services;
await services.emit('start.webserver');
await services.emit('ready.webserver');
this.print_puter_logo_();
// this.print_puter_logo_();
}
@@ -223,21 +223,13 @@ class WebServerService extends BaseService {
console.log('Error opening browser', e);
}
}
/**
* Starts the HTTP server.
*
* This method sets up the Express server, initializes middleware, and starts the HTTP server.
* It handles error handling, authentication, and other necessary configurations.
*
* @returns {Promise} A Promise that resolves when the server is listening.
*/
const link = `\x1B[34;1m${strutil.osclink(url)}\x1B[0m`;
const lines = [
`Puter is now live at: ${link}`,
];
this.startup_widget = () => {
const link = `\x1B[34;1m${strutil.osclink(url)}\x1B[0m`;
const lines = [
`Puter is now live at: ${link}`,
`Type web:dismiss to un-stick this message`,
];
const lengths = [
(`Puter is now live at: `).length + url.length,
lines[1].length,
@@ -245,9 +237,16 @@ class WebServerService extends BaseService {
surrounding_box('34;1', lines, lengths);
return lines;
};
{
if ( this.config.old_widget_behavior ) {
const svc_devConsole = this.services.get('dev-console', { optional: true });
if ( svc_devConsole ) svc_devConsole.add_widget(this.startup_widget);
} else {
const svc_devConsole = this.services.get('dev-console', { optional: true });
svc_devConsole.notice({
colors: { bg: '38;2;0;0;0;48;2;0;202;252;1', bginv: '38;2;0;202;252' },
title: 'Puter is live!',
lines,
});
}
server.timeout = 1000 * 60 * 60 * 2; // 2 hours
+3 -1
View File
@@ -50,7 +50,9 @@ class BaseService extends concepts.Service {
Object.defineProperty(this, 'config', {
get: () => configOverride ?? config.services?.[name] ?? {},
set: why => {
console.warn('replacing config like this is probably a bad idea');
// TODO: uncomment and fix these in legacy services
// (not very important; low priority)
// console.warn('replacing config like this is probably a bad idea');
configOverride = why;
},
});
+12 -1
View File
@@ -90,7 +90,18 @@ class DevConsoleService extends BaseService {
this.widgets = this.widgets.filter(w => w !== id_or_outputter);
this.mark_updated();
}
notice ({ colors, title, lines }) {
colors = colors ?? {
bg: '46',
bginv: '36',
};
console.log(`\x1B[${colors.bginv}m▐\x1B[0m\x1B[${colors.bg}m ${title} \x1B[0m`);
for ( const line of lines ) {
console.log(`\x1B[${colors.bginv}m▐▌\x1B[0m${line}\x1B[0m`);
}
}
/**
* Updates the displayed output based on the current state of widgets.
@@ -142,7 +153,7 @@ class DevConsoleService extends BaseService {
for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) {
if ( size_ok() ) break;
const w = this.widgets[i];
if ( w.critical ) continue;
if ( w.critical ) continue;
n_hidden++;
const [start, length] = positions[i];
this.static_lines.splice(start, length);
+33 -21
View File
@@ -17,6 +17,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const putility = require("@heyputer/putility");
const { surrounding_box } = require("../fun/dev-console-ui-utils");
const BaseService = require("./BaseService");
@@ -88,28 +89,39 @@ class DevTODService extends BaseService {
*/
async ['__on_boot.consolidation'] () {
let random_tip = tips[Math.floor(Math.random() * tips.length)];
random_tip = wordwrap(
random_tip,
process.stdout.columns
? process.stdout.columns - 6 : 50
);
this.tod_widget = () => {
const lines = [
...random_tip,
];
if ( ! this.global_config.minimal_console ) {
lines.unshift("\x1B[1mTip of the Day\x1B[0m");
lines.push("Type tod:dismiss to un-stick this message");
}
surrounding_box('33;1', lines);
return lines;
if ( this.config.old_widget_behavior ) {
random_tip = wordwrap(
random_tip,
process.stdout.columns
? process.stdout.columns - 6 : 50,
);
this.tod_widget = () => {
const lines = [
...random_tip,
];
if ( ! this.global_config.minimal_console ) {
lines.unshift("\x1B[1mTip of the Day\x1B[0m");
lines.push("Type tod:dismiss to un-stick this message");
}
surrounding_box('33;1', lines);
return lines;
};
this.tod_widget.unimportant = true;
const svc_devConsole = this.services.get('dev-console', { optional: true });
if ( ! svc_devConsole ) return;
svc_devConsole.add_widget(this.tod_widget);
} else {
const svc_devConsole = this.services.get('dev-console', { optional: true });
if ( ! svc_devConsole ) return;
svc_devConsole.notice({
colors: { bg: '38;2;0;0;0;48;2;255;255;0;1', bginv: '38;2;255;255;0' },
title: 'Tip of the Day',
lines: putility.libs.string.wrap_text(random_tip),
});
}
this.tod_widget.unimportant = true;
const svc_devConsole = this.services.get('dev-console', { optional: true });
if ( ! svc_devConsole ) return;
svc_devConsole.add_widget(this.tod_widget);
}
_register_commands (commands) {
+32 -1
View File
@@ -68,9 +68,40 @@ const format_as_usd = (amount) => {
return '$' + amount.toFixed(2);
}
// wrap.js
const wrap_text = (text, width = 71) => {
const out = [];
const paras = text.split(/\r?\n\s*\r?\n/); // split on blank lines
for (const p of paras) {
const words = p.trim().replace(/\s+/g, ' ').split(' ');
if (words.length === 1 && words[0] === '') { out.push(''); continue; }
let line = '';
for (const w of words) {
if (line.length === 0) {
// start new line; do NOT split long words
line = w;
} else if (line.length + 1 + w.length <= width) {
line += ' ' + w;
} else {
out.push(line);
line = w; // put word on its own new line (even if > width)
}
}
if (line) out.push(line);
out.push(''); // blank line between paragraphs
}
// remove the extra trailing blank line
if (out.length && out[out.length - 1] === '') out.pop();
return out;
};
module.exports = {
quot,
osclink,
format_as_usd,
wrap_text,
};