Reapply "Logs Update" (#1730)

This reverts commit 8f7a68ace6.
This commit is contained in:
KernelDeimos
2025-10-10 13:39:52 -04:00
committed by Eric Dubé
parent 9607706d11
commit 70c7aa41ac
42 changed files with 4959 additions and 1158 deletions

View File

@@ -25,6 +25,6 @@ extension.on('init', async () => {
// and just a little bit longer
// await sleep(100);
console.log('kv key should no longer have the value', kv.get('example-kv-key'));
console.log('kv key should no longer have the value', await kv.get('example-kv-key'));
})();
});

5543
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -57,6 +57,7 @@
},
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.879.0",
"@aws-sdk/client-sns": "^3.907.0",
"@google/genai": "^1.19.0",
"@heyputer/putility": "^1.0.2",
"@paralleldrive/cuid2": "^2.2.2",
@@ -74,11 +75,11 @@
"uuid": "^9.0.1"
},
"optionalDependencies": {
"sharp": "^0.34.3",
"sharp": "^0.34.4",
"sharp-bmp": "^0.1.5",
"sharp-ico": "^0.1.5"
},
"engines": {
"node": ">=20.19.5"
}
}
}

View File

@@ -63,7 +63,7 @@ module.exports = {
HostOSModule,
CoreModule,
WebModule,
TemplateModule,
// TemplateModule,
AppsModule,
CaptchaModule,
EntityStoreModule,

View File

@@ -24,7 +24,6 @@
"@pagerduty/pdjs": "^2.2.4",
"@smithy/node-http-handler": "^2.2.2",
"args": "^5.0.3",
"aws-sdk": "^2.1383.0",
"axios": "^1.8.2",
"bcrypt": "^5.1.0",
"better-sqlite3": "^11.9.0",

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.

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,18 +578,34 @@ 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: "inherit" });
const proc = spawn(npmCmd, ["install"], { cwd: path, stdio: "pipe" });
let buffer = '';
proc.stdout.on('data', (data) => {
buffer += data.toString();
});
proc.stderr.on('data', (data) => {
buffer += data.toString();
});
return new Promise((rslv, rjct) => {
proc.on('close', code => {
if ( code !== 0 ) {
throw new Error(`exit code: ${code}`);
// Print buffered output on error
if ( buffer ) process.stdout.write(buffer);
rjct(new Error(`exit code: ${code}`));
return;
}
rslv();
});
proc.on('error', err => {
// Print buffered output on error
if ( buffer ) process.stdout.write(buffer);
rjct(err);
})
})
});
});
}
}

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',

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;

View File

@@ -246,7 +246,8 @@ const config_pointer = {};
config_to_export = new Proxy(config_to_export, {
set: (target, prop, value, receiver) => {
const logger = Context.get('logger', { allow_fallback: true });
logger?.debug(
// If no logger, just give up
if ( logger ) logger.debug(
'\x1B[36;1mCONFIGURATION MUTATED AT RUNTIME\x1B[0m',
{ prop, value },
);

View File

@@ -323,7 +323,7 @@ module.exports = class FSNodeContext {
},
};
this.log.info('fetching entry: ' + this.selector.describe());
this.log.debug('fetching entry: ' + this.selector.describe());
const entry = await this.provider.stat({
selector: this.selector,

View File

@@ -64,7 +64,7 @@ class HLReadDir extends HLFilesystemOperation {
let children;
this.log.noticeme('READDIR',
this.log.debug('READDIR',
{
userdir: await subject.isUserDirectory(),
namediff: await subject.get('name') !== user.username

View File

@@ -102,11 +102,6 @@ class BroadcastService extends BaseService {
});
});
});
this.log.noticeme(
require('node:util').inspect(this.config)
);
}
_register_commands (commands) {

View File

@@ -71,7 +71,7 @@ class CaptchaService extends BaseService {
*/
async _init() {
if (!this.enabled) {
this.log.info('Captcha service is disabled');
this.log.debug('Captcha service is disabled');
return;
}
@@ -328,7 +328,7 @@ class CaptchaService extends BaseService {
});
this.endpointsRegistered = true;
this.log.info('Captcha service endpoints registered successfully');
this.log.debug('Captcha service endpoints registered successfully');
// Emit an event that captcha service is ready
try {

View File

@@ -524,7 +524,8 @@ class LogService extends BaseService {
}
this.log = this.create('log-service');
this.log.system('log service started', {
this.log.system('log service started');
this.log.debug('log service configuration', {
output_lvl: this.output_lvl,
log_directory: this.log_directory,
});

View File

@@ -106,7 +106,7 @@ class ServerHealthService extends BaseService {
mem_total: meminfo.MemTotal,
};
this.log.info('memory', log_fields);
this.log.debug('memory', log_fields);
Object.assign(this.stats_, log_fields);

View File

@@ -72,7 +72,7 @@ class DNSService extends BaseService {
});
server.on('listening', () => {
this.log.info('Fake DNS server listening', server.addresses());
this.log.debug('Fake DNS server listening', server.addresses());
if ( this.config.test_server_selftest ) (async () => {
await sleep(5000);

View File

@@ -192,7 +192,7 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
if ( result[0] ) return result[0];
this.log.info(`findByPath (not cached): ${path}`)
this.log.debug(`findByPath (not cached): ${path}`)
const loop = async () => {
for ( let i=0 ; i < parts.length ; i++ ) {

View File

@@ -457,7 +457,7 @@ class DatabaseFSEntryService extends BaseService {
const queue = this.currentState.queue;
this.log.info(
this.log.debug(
`Executing ${queue.length} operations...`
);

View File

@@ -62,7 +62,7 @@ class ResourceService extends BaseService {
};
});
entry.onFree = entry.freePromise.then.bind(entry.freePromise);
this.log.info(`registering resource`, { uid: entry.uid });
this.log.debug(`registering resource`, { uid: entry.uid });
this.uidToEntry[entry.uid] = entry;
if ( entry.path ) {
this.uidToPath[entry.uid] = entry.path;
@@ -72,7 +72,7 @@ class ResourceService extends BaseService {
}
free (uid) {
this.log.info(`freeing`, { uid });
this.log.debug(`freeing`, { uid });
const entry = this.uidToEntry[uid];
if ( ! entry ) return;
delete this.uidToEntry[uid];

View File

@@ -185,7 +185,7 @@ class PuterFSProvider extends putility.AdvancedBase {
}
if ( ! entry ) {
controls.log.info(`entry not found: ${selector.describe(true)}`);
controls.log.warn(`entry not found: ${selector.describe(true)}`);
}
if ( entry === null || typeof entry !== 'object' ) {

View File

@@ -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));

View File

@@ -16,8 +16,13 @@
* 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 { webpack, web } = require("webpack");
const BaseService = require("../../services/BaseService");
const path_ = require('node:path');
const fs = require('node:fs');
const rollupModule = require("rollup");
class ProxyLogger {
constructor (log) {
this.log = log;
@@ -65,7 +70,10 @@ class DevWatcherService extends BaseService {
async ['__on_ready.webserver'] () {
const svc_process = this.services.get('process');
const { root, commands } = this.args;
let { root, commands, webpack, rollup } = this.args;
if ( ! webpack ) webpack = [];
if ( ! rollup ) rollup = [];
let promises = [];
for ( const entry of commands ) {
const { directory } = entry;
@@ -74,12 +82,201 @@ class DevWatcherService extends BaseService {
// promises.push(this.start_({ ...entry, fullpath }));
promises.push(svc_process.start({ ...entry, fullpath }));
}
for ( const entry of webpack ) {
const p = this.start_a_webpack_watcher_(entry);
promises.push(p);
}
for ( const entry of rollup ) {
const p = this.start_a_rollup_watcher_(entry);
promises.push(p);
}
await Promise.all(promises);
// It's difficult to tell when webpack is "done" its first
// run so we just wait a bit before we say we're ready.
await new Promise((resolve) => setTimeout(resolve, 5000));
}
async get_configjs ({ directory, configIsFor, possibleConfigNames }) {
let configjsPath, moduleType;
for ( const [configName, supposedModuleType] of possibleConfigNames ) {
// There isn't really an async fs.exists() funciton. I assume this
// is because 'exists' is already a very fast operation.
const supposedPath = path_.join(this.args.root, directory, configName);
if ( fs.existsSync(supposedPath) ) {
configjsPath = supposedPath;
moduleType = supposedModuleType;
break;
}
}
if ( ! configjsPath ) {
throw new Error(`could not find ${configIsFor} config for: ${directory}`);
}
// If the webpack config ends with .js it could be an ES6 module or a
// CJS module, so the absolute safest thing to do so as not to completely
// break in specific patch version of supported versions of node.js is
// to read the package.json and see what it says is the import mechanism.
if ( moduleType === 'package.json' ) {
const packageJSONPath = path_.join(this.args.root, directory, 'package.json');
const packageJSONObject = JSON.parse(fs.readFileSync(packageJSONPath));
moduleType = packageJSONObject?.type ?? 'module';
}
return {
configjsPath,
moduleType,
};
}
async start_a_webpack_watcher_ (entry) {
const possibleConfigNames = [
['webpack.config.js', 'package.json'],
['webpack.config.cjs', 'commonjs'],
['webpack.config.mjs', 'module'],
];
const {
configjsPath: webpackConfigPath,
moduleType,
} = await this.get_configjs({
directory: entry.directory,
configIsFor: 'webpack', // for error message
possibleConfigNames,
});
let oldEnv;
if ( entry.env ) {
oldEnv = process.env;
const newEnv = Object.create(process.env);
for ( const k in entry.env ) {
newEnv[k] = entry.env[k];
}
process.env = newEnv; // Yep, it totally lets us do this
}
let webpackConfig = moduleType === 'module'
? (await import(webpackConfigPath)).default
: require(webpackConfigPath);
// The webpack config can sometimes be a function
if ( typeof webpackConfig === 'function' ) {
webpackConfig = await webpackConfig();
}
if ( oldEnv ) process.env = oldEnv;
webpackConfig.context = webpackConfig.context
? path_.resolve(path_.join(this.args.root, entry.directory), webpackConfig.context)
: path_.join(this.args.root, entry.directory);
if ( entry.onConfig ) entry.onConfig(webpackConfig);
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,
stats,
});
this.log.error(`❌ failed to update ${entry.directory} using Webpack`);
} else {
// 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.
if ( ! hideSuccess ) {
this.log.info(`✅ updated ${entry.directory} using Webpack`);
}
}
});
}
async start_a_rollup_watcher_ (entry) {
const possibleConfigNames = [
['rollup.config.js', 'package.json'],
['rollup.config.cjs', 'commonjs'],
['rollup.config.mjs', 'module'],
];
const {
configjsPath: rollupConfigPath,
moduleType,
} = await this.get_configjs({
directory: entry.directory,
configIsFor: 'rollup', // for error message
possibleConfigNames,
});
const updateRollupPaths = (config, newBase) => {
const onoutput = o => ({ ...o, file: o.file ? path_.join(newBase, o.file) : o.file });
return {
...config,
input: path_.join(newBase, config.input),
output: Array.isArray(config.output)
? config.output.map(onoutput)
: onoutput(config.output),
};
};
let oldEnv;
if ( entry.env ) {
oldEnv = process.env;
const newEnv = Object.create(process.env);
for ( const k in entry.env ) {
newEnv[k] = entry.env[k];
}
process.env = newEnv; // Yep, it totally lets us do this
}
let rollupConfig = moduleType === 'module'
? (await import(rollupConfigPath)).default
: require(rollupConfigPath);
if ( oldEnv ) process.env = oldEnv;
rollupConfig = updateRollupPaths(
rollupConfig,
path_.join(this.args.root, entry.directory),
);
// rollupConfig.watch = true; // I mean why can't it just...
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;
}
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,
});
this.log.error(`❌ failed to update ${entry.directory} using Rollup`);
errorAfterLastEnd = true;
}
});
}
};
module.exports = DevWatcherService;

View File

@@ -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 = '../../../../../';
@@ -51,48 +51,46 @@ class SelfHostedModule extends AdvancedBase {
{
services.registerService('__dev-watcher', DevWatcherService, {
root: path_.resolve(__dirname, RELATIVE_PATH),
commands: [
rollup: [
{
name: 'puter.js:webpack-watch',
name: 'phoenix',
directory: 'src/phoenix',
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
{
name: 'terminal',
directory: 'src/terminal',
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
],
webpack: [
{
name: 'puter.js',
directory: 'src/puter-js',
command: 'npm',
args: ['run', 'start-webpack'],
onConfig: config => {
config.output.filename = 'puter.dev.js';
config.devtool = 'source-map';
},
env: {
PUTER_ORIGIN: ({ global_config: config }) => config.origin,
PUTER_API_ORIGIN: ({ global_config: config }) => config.api_base_url,
},
},
{
name: 'gui:webpack-watch',
name: 'gui',
directory: 'src/gui',
command: 'npm',
args: ['run', 'start-webpack'],
},
{
name: 'terminal:rollup-watch',
directory: 'src/terminal',
command: 'npx',
args: ['rollup', '-c', 'rollup.config.js', '--watch'],
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
{
name: 'phoenix:rollup-watch',
directory: 'src/phoenix',
command: 'npx',
args: ['rollup', '-c', 'rollup.config.js', '--watch'],
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
{
name: 'emulator:webpack-watch',
name: 'emulator',
directory: 'src/emulator',
command: 'npm',
args: ['run', 'start-webpack'],
},
],
commands: [
],
});
}

View File

@@ -2,7 +2,7 @@ const BaseService = require("../../services/BaseService");
class TestConfigReadService extends BaseService {
async _init () {
this.log.noticeme('test config value (should be abcdefg) is: ' +
this.log.debug('test config value (should be abcdefg) is: ' +
this.global_config.testConfigValue,
);
}

View File

@@ -86,7 +86,7 @@ class WebServerService extends BaseService {
return res.sendStatus(200);
});
this.log.noticeme('web server setup done');
this.log.debug('web server setup done');
}
install_post_middlewares_ ({ app }) {
@@ -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_();
}
@@ -168,7 +168,7 @@ class WebServerService extends BaseService {
for ( let i = 0 ; i < ports_to_try.length ; i++ ) {
const port = ports_to_try[i];
const is_last_port = i === ports_to_try.length - 1;
if ( auto_port ) this.log.info('trying port: ' + port);
if ( auto_port ) this.log.debug('trying port: ' + port);
try {
server = http.createServer(this.app).listen(port);
server.timeout = 1000 * 60 * 60 * 2; // 2 hours
@@ -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
@@ -391,12 +390,11 @@ class WebServerService extends BaseService {
fields.status, fields.responseTime,
].join(' ');
const log = this.services.get('log-service').create('morgan', {
concern: 'web'
});
const log = this.services.get('log-service').create('morgan');
try {
this.context.arun(() => {
log.info(message, fields);
log.info(message);
log.debug(message, fields);
});
} catch (e) {
console.log('failed to log this message properly:', message, fields);

View File

@@ -187,7 +187,7 @@ module.exports = function eggspress (route, settings, handler) {
return next();
}
}
if ( config.env === 'dev' ) {
if ( config.env === 'dev' && process.env.DEBUG ) {
console.log(`request url: ${req.url}, body: ${JSON.stringify(req.body)}`);
}
try {

View File

@@ -113,7 +113,9 @@ class PropType extends AdvancedBase {
this.chains.factory && [...this.chains.factory].reverse()
) || [];
console.log('FACTORIES', factories)
if ( process.env.DEBUG ) {
console.log('FACTORIES', factories);
}
for ( const factory of factories ) {
const result = await factory(extra);

View File

@@ -49,7 +49,7 @@ module.exports = eggspress('/readdir', {
log = x.get('services').get('log-service').create('readdir', {
concern: 'filesystem',
});
log.info(`readdir: ${req.body.subject || req.body.path || req.body.uid}`);
log.debug(`readdir: ${req.body.subject || req.body.path || req.body.uid}`);
}
const subject = req.values.subject;

View File

@@ -59,13 +59,15 @@ const complete_ = async ({ req, res, user }) => {
router.post('/login', express.json(), body_parser_error_handler,
// Add diagnostic middleware to log captcha data
(req, res, next) => {
console.log('====== LOGIN CAPTCHA DIAGNOSTIC ======');
console.log('LOGIN REQUEST RECEIVED with captcha data:', {
hasCaptchaToken: !!req.body.captchaToken,
hasCaptchaAnswer: !!req.body.captchaAnswer,
captchaToken: req.body.captchaToken ? req.body.captchaToken.substring(0, 8) + '...' : undefined,
captchaAnswer: req.body.captchaAnswer
});
if ( process.env.DEBUG ) {
console.log('====== LOGIN CAPTCHA DIAGNOSTIC ======');
console.log('LOGIN REQUEST RECEIVED with captcha data:', {
hasCaptchaToken: !!req.body.captchaToken,
hasCaptchaAnswer: !!req.body.captchaAnswer,
captchaToken: req.body.captchaToken ? req.body.captchaToken.substring(0, 8) + '...' : undefined,
captchaAnswer: req.body.captchaAnswer
});
}
next();
},
requireCaptcha({ strictMode: true, eventType: 'login' }),

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;
},
});

View File

@@ -216,7 +216,7 @@ class Container {
*/
async emit (id, ...args) {
if ( this.logger ) {
this.logger.info(`services:event ${id}`, { args });
this.logger.debug(`services:event ${id}`, { args });
}
const promises = [];

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);

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) {

View File

@@ -62,7 +62,7 @@ class OperationFrame {
this.status_ = status;
this._calc_effective_status();
this.log.info(
this.log.debug(
`FRAME STATUS ${status.label} ` +
(status !== this.effective_status_
? `(effective: ${this.effective_status_.label}) `
@@ -275,7 +275,7 @@ class OperationTraceService {
x
});
parent && parent.push_child(frame);
this.log.info(`FRAME START ` + frame.describe());
this.log.debug(`FRAME START ` + frame.describe());
if ( ! parent ) {
// NOTE: only uncomment in local testing for now;
// this will cause a memory leak until frame

View File

@@ -20,8 +20,6 @@
const { Endpoint } = require("../util/expressutil");
const BaseService = require("./BaseService");
const aws = require('aws-sdk');
const sns = new aws.SNS();
const { LRUCache: LRU } = require('lru-cache');
const crypto = require('crypto');
const axios = require('axios');
@@ -52,10 +50,6 @@ const TEST_CERT = ``;
const TEST_MESSAGE = {};
class SNSService extends BaseService {
static MODULES = {
AWS: require('aws-sdk'),
};
_construct () {
this.cert_cache = new LRU({
// Guide uses 5000 here but that seems excessive
@@ -149,10 +143,6 @@ class SNSService extends BaseService {
}).attach(app);
}
_init () {
this.sns = new this.modules.AWS.SNS();
}
async verify_message_ (message, options = {}) {
let cert;
if ( options.test_mode ) {

View File

@@ -438,7 +438,7 @@ class ACLService extends BaseService {
await appdata_node.is_above(fsNode)
)
) {
console.log('TRUE BECAUSE APPDATA');
this.log.debug('TRUE BECAUSE APPDATA');
return true;
}
}

View File

@@ -209,7 +209,7 @@ class AuthService extends BaseService {
throw APIError.create('forbidden');
}
this.log.info(`generating user-app token for app ${app_uid} and user ${actor_type.user.uuid}`, {
this.log.debug(`generating user-app token for app ${app_uid} and user ${actor_type.user.uuid}`, {
app_uid,
user_uid: actor_type.user.uuid,
})
@@ -251,7 +251,7 @@ class AuthService extends BaseService {
* session's metadata.
*/
async create_session_ (user, meta = {}) {
this.log.info(`CREATING SESSION`);
this.log.debug(`CREATING SESSION`);
if ( meta.req ) {
const req = meta.req;

View File

@@ -179,7 +179,7 @@ class PermissionService extends BaseService {
}
async #scan(actor, permission_options, _reserved, state) {
if ( ! state ) {
this.log.info('scan', {
this.log.debug('scan', {
actor: actor.uid,
permission_options,
});

View File

@@ -467,7 +467,7 @@ class DriverService extends BaseService {
effective_policy = effective_policy.policy;
this.log.info('Invoking Driver Call', {
this.log.debug('Invoking Driver Call', {
service_name,
iface,
method,

View File

@@ -34,7 +34,7 @@ module.exports = async (options = {}) => {
const entries = [];
for ( const extensionsDir of extension_directories ) {
console.log(`Reading extensions from ${extensionsDir}`);
// console.log(`Reading extensions from ${extensionsDir}`);
// Read and process extension entries from the extensions directory
const readdir_entries = fs.readdirSync(extensionsDir, { withFileTypes: true })
for ( const entry of readdir_entries ) {

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,
};