diff --git a/adminforth/auth.ts b/adminforth/auth.ts
index 6faff95e0..6c8416f80 100644
--- a/adminforth/auth.ts
+++ b/adminforth/auth.ts
@@ -3,6 +3,7 @@ import jwt from 'jsonwebtoken';
import crypto from 'crypto';
import AdminForth from './index.js';
import { IAdminForthAuth } from './types/Back.js';
+import { afLogger } from './modules/logger.js';
// Function to generate a password hash using PBKDF2
function calcPasswordHash(password, salt, iterations = 100000, keyLength = 64, digest = 'sha512') {
@@ -105,7 +106,7 @@ class AdminForthAuth implements IAdminForthAuth {
if (expirySeconds !== undefined) {
expiryMs = expirySeconds * 1000;
} else if (expiry !== undefined) {
- console.warn('setCustomCookie: expiry(in ms) is deprecated, use expirySeconds instead (seconds), traceback:', new Error().stack);
+ afLogger.warn(`setCustomCookie: expiry(in ms) is deprecated, use expirySeconds instead (seconds), traceback: ${new Error().stack}`);
expiryMs = expiry;
}
@@ -145,23 +146,23 @@ class AdminForthAuth implements IAdminForthAuth {
decoded = jwt.verify(jwtToken, secret);
} catch (err) {
if (err.name === 'TokenExpiredError') {
- console.error('Token expired:', err.message);
+ afLogger.error(`Token expired: ${err.message}`);
} else if (err.name === 'JsonWebTokenError') {
- console.error('Token error:', err.message);
+ afLogger.error(`Token error: ${err.message}`);
} else {
- console.error('Failed to verify JWT token', err);
+ afLogger.error(`Failed to verify JWT token: ${err}`);
}
return null;
}
const { pk, t } = decoded;
if (t !== mustHaveType) {
- console.error(`Invalid token type during verification: ${t}, must be ${mustHaveType}`);
+ afLogger.error(`Invalid token type during verification: ${t}, must be ${mustHaveType}`);
return null;
}
if (decodeUser !== false) {
const dbUser = await this.adminforth.getUserByPk(pk);
if (!dbUser) {
- console.error(`User with pk ${pk} not found in database`);
+ afLogger.error(`User with pk ${pk} not found in database`);
// will logout user which was deleted
return null;
}
diff --git a/adminforth/basePlugin.ts b/adminforth/basePlugin.ts
index cbb3b37fa..82229b325 100644
--- a/adminforth/basePlugin.ts
+++ b/adminforth/basePlugin.ts
@@ -6,6 +6,8 @@ import fs from 'fs';
import crypto from 'crypto';
+import { afLogger } from './modules/logger.js';
+
export default class AdminForthPlugin implements IAdminForthPlugin {
@@ -24,7 +26,7 @@ export default class AdminForthPlugin implements IAdminForthPlugin {
this.pluginDir = currentFileDir(metaUrl);
this.customFolderPath = path.join(this.pluginDir, this.customFolderName);
this.pluginOptions = pluginOptions;
- process.env.HEAVY_DEBUG && console.log(`๐ชฒ ๐ชฒ AdminForthPlugin.constructor`, this.constructor.name);
+ afLogger.trace(`๐ชฒ ๐ชฒ AdminForthPlugin.constructor ${this.constructor.name}`);
this.className = this.constructor.name;
}
@@ -42,7 +44,7 @@ export default class AdminForthPlugin implements IAdminForthPlugin {
const seed = `af_pl_${this.constructor.name}_${resourceConfig.resourceId}_${uniqueness}`;
this.pluginInstanceId = md5hash(seed);
- process.env.HEAVY_DEBUG && console.log(`๐ชฒ AdminForthPlugin.modifyResourceConfig`, seed, 'id', this.pluginInstanceId);
+ afLogger.trace(`๐ชฒ AdminForthPlugin.modifyResourceConfig, ${seed}, 'id', ${this.pluginInstanceId}`);
this.adminforth = adminforth;
}
diff --git a/adminforth/commands/createCustomComponent/main.js b/adminforth/commands/createCustomComponent/main.js
index 2b62eb65c..243a8c666 100644
--- a/adminforth/commands/createCustomComponent/main.js
+++ b/adminforth/commands/createCustomComponent/main.js
@@ -188,9 +188,6 @@ async function handleCrudPageInjectionCreation(config, resources) {
const injectionPosition = await select({
message: 'Where exactly do you want to inject the component?',
choices: [
- ...(crudType === 'create' || crudType === 'edit'
- ? [{ name: '๐พ Save button on create/edit page', value: 'saveButton' }, new Separator()]
- : []),
{ name: 'โฌ๏ธ Before Breadcrumbs', value: 'beforeBreadcrumbs' },
{ name: 'โก๏ธ Before Action Buttons', value: 'beforeActionButtons' },
{ name: 'โฌ๏ธ After Breadcrumbs', value: 'afterBreadcrumbs' },
diff --git a/adminforth/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs b/adminforth/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs
deleted file mode 100644
index 06ed5e2ac..000000000
--- a/adminforth/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
diff --git a/adminforth/dataConnectors/baseConnector.ts b/adminforth/dataConnectors/baseConnector.ts
index eed448b8e..d53233753 100644
--- a/adminforth/dataConnectors/baseConnector.ts
+++ b/adminforth/dataConnectors/baseConnector.ts
@@ -10,6 +10,7 @@ import { suggestIfTypo } from "../modules/utils.js";
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections } from "../types/Common.js";
import { randomUUID } from "crypto";
import dayjs from "dayjs";
+import { afLogger } from '../modules/logger.js';
export default class AdminForthBaseConnector implements IAdminForthDataSourceConnectorBase {
@@ -17,7 +18,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
client: any;
get db() {
- console.warn('.db is deprecated, use .client instead');
+ afLogger.warn('.db is deprecated, use .client instead');
return this.client;
}
@@ -80,7 +81,6 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
// in case column isArray and enumerator/foreign resource - IN filter must be transformed into OR filter
if (filterValidation.ok && f.operator == AdminForthFilterOperators.IN) {
const column = resource.dataSourceColumns.find((col) => col.name == (f as IAdminForthSingleFilter).field);
- // console.log(`\n~~~ column: ${JSON.stringify(column, null, 2)}\n~~~ resource.columns: ${JSON.stringify(resource.dataSourceColumns, null, 2)}\n~~~ filter: ${JSON.stringify(f, null, 2)}\n`);
if (column.isArray?.enabled && (column.enum || column.foreignResource)) {
filters[fIndex] = {
operator: AdminForthFilterOperators.OR,
@@ -138,7 +138,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
);
}
if (isPolymorphicTarget) {
- process.env.HEAVY_DEBUG && console.log(`โ ๏ธ Field '${filtersAsSingle.field}' not found in polymorphic target resource '${resource.resourceId}', allowing query to proceed.`);
+ afLogger.trace(`โ ๏ธ Field '${filtersAsSingle.field}' not found in polymorphic target resource '${resource.resourceId}', allowing query to proceed.`);
return { ok: true, error: '' };
} else {
throw new Error(`Field '${filtersAsSingle.field}' not found in resource '${resource.resourceId}'. ${similar ? `Did you mean '${similar}'?` : ''}`);
@@ -329,7 +329,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
}
async checkUnique(resource: AdminForthResource, column: AdminForthResourceColumn, value: any, record?: any): Promise {
- process.env.HEAVY_DEBUG && console.log('โ๏ธ๐ชฒ๐ชฒ๐ชฒ๐ชฒ checkUnique|||', column, value);
+ afLogger.trace(`โ๏ธ๐ชฒ๐ชฒ๐ชฒ๐ชฒ checkUnique||| ${column.name}, ${value}`);
const primaryKeyField = this.getPrimaryKey(resource);
const existingRecord = await this.getData({
@@ -385,11 +385,11 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
})
);
if (error) {
- process.env.HEAVY_DEBUG && console.log('๐ชฒ๐ check unique error', error);
+ afLogger.trace(`๐ชฒ๐ check unique error, ${error}`);
return { error, ok: false };
}
- process.env.HEAVY_DEBUG && console.log('๐ชฒ๐ creating record',JSON.stringify(recordWithOriginalValues));
+ afLogger.trace(`๐ชฒ๐ creating record, ${JSON.stringify(recordWithOriginalValues)}`);
let pkValue = await this.createRecordOriginalValues({ resource, record: recordWithOriginalValues });
if (recordWithOriginalValues[this.getPrimaryKey(resource)] !== undefined) {
// some data sources always return some value for pk, even if it is was not auto generated
@@ -441,12 +441,12 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
})
);
if (error) {
- process.env.HEAVY_DEBUG && console.log('๐ชฒ๐ check unique error', error);
+ afLogger.trace(`๐ชฒ๐ check unique error, ${error}`);
return { error, ok: false };
}
- process.env.HEAVY_DEBUG && console.log(`๐ชฒโ๏ธ updating record id:${recordId}, values: ${JSON.stringify(recordWithOriginalValues)}`);
+ afLogger.trace(`๐ชฒโ๏ธ updating record id:${recordId}, values: ${JSON.stringify(recordWithOriginalValues)}`);
await this.updateRecordOriginalValues({ resource, recordId, newValues: recordWithOriginalValues });
diff --git a/adminforth/dataConnectors/clickhouse.ts b/adminforth/dataConnectors/clickhouse.ts
index 0e848c378..798682647 100644
--- a/adminforth/dataConnectors/clickhouse.ts
+++ b/adminforth/dataConnectors/clickhouse.ts
@@ -4,6 +4,7 @@ import dayjs from 'dayjs';
import { createClient } from '@clickhouse/client'
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections } from '../types/Common.js';
+import { afLogger } from '../modules/logger.js';
class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForthDataSourceConnector {
@@ -95,7 +96,7 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
});
rows = await q.json();
} catch (e) {
- console.error(` ๐Error connecting to datasource URL ${this.url}:`, e);
+ afLogger.error(` ๐Error connecting to datasource URL ${this.url}: ${e}`);
return null;
}
@@ -169,7 +170,7 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
return {'error': `Failed to parse JSON: ${e.message}`}
}
} else {
- console.error(`AdminForth: JSON field is not a string but ${field._underlineType}, this is not supported yet`);
+ afLogger.error(`AdminForth: JSON field is not a string but ${field._underlineType}, this is not supported yet`);
}
}
return value;
@@ -197,7 +198,7 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
if (field._underlineType.startsWith('String') || field._underlineType.startsWith('FixedString')) {
return JSON.stringify(value);
} else {
- console.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
+ afLogger.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
}
}
diff --git a/adminforth/dataConnectors/mongo.ts b/adminforth/dataConnectors/mongo.ts
index d6b58f786..94487e26a 100644
--- a/adminforth/dataConnectors/mongo.ts
+++ b/adminforth/dataConnectors/mongo.ts
@@ -3,7 +3,7 @@ import { MongoClient } from 'mongodb';
import { Decimal128, Double } from 'bson';
import { IAdminForthDataSourceConnector, IAdminForthSingleFilter, IAdminForthAndOrFilter, AdminForthResource } from '../types/Back.js';
import AdminForthBaseConnector from './baseConnector.js';
-
+import { afLogger } from '../modules/logger.js';
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections, } from '../types/Common.js';
const escapeRegex = (value) => {
@@ -36,11 +36,11 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
try {
await this.client.connect();
this.client.on('error', (err) => {
- console.log('Mongo error: ', err.message)
+ afLogger.error(`Mongo error: ${err.message}`);
});
- console.log('Connected to Mongo');
+ afLogger.info('Connected to Mongo');
} catch (e) {
- console.error(`Failed to connect to Mongo: ${e}`);
+ afLogger.error(`Failed to connect to Mongo: ${e}`);
}
})();
}
@@ -262,7 +262,7 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
// explicitly ignore raw SQL filters for MongoDB
if ((filter as IAdminForthSingleFilter).insecureRawSQL !== undefined) {
- console.warn('โ ๏ธ Ignoring insecureRawSQL filter for MongoDB:', (filter as IAdminForthSingleFilter).insecureRawSQL);
+ afLogger.warn(`โ ๏ธ Ignoring insecureRawSQL filter for MongoDB:, ${(filter as IAdminForthSingleFilter).insecureRawSQL}`);
return {};
}
diff --git a/adminforth/dataConnectors/mysql.ts b/adminforth/dataConnectors/mysql.ts
index 2d2179c10..ed97a8563 100644
--- a/adminforth/dataConnectors/mysql.ts
+++ b/adminforth/dataConnectors/mysql.ts
@@ -3,6 +3,7 @@ import { AdminForthResource, IAdminForthSingleFilter, IAdminForthAndOrFilter, IA
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections, } from '../types/Common.js';
import AdminForthBaseConnector from './baseConnector.js';
import mysql from 'mysql2/promise';
+import { dbLogger, afLogger } from '../modules/logger.js';
class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataSourceConnector {
@@ -15,7 +16,7 @@ class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataS
queueLimit: 0
});
} catch (e) {
- console.error(`Failed to connect to MySQL: ${e}`);
+ afLogger.error(`Failed to connect to MySQL: ${e}`);
}
}
@@ -175,8 +176,8 @@ class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataS
} else if (typeof value === 'object') {
return value;
} else {
- console.error('JSON field value is not string or object, but has type:', typeof value);
- console.error('Field:', field);
+ afLogger.error(`JSON field value is not string or object, but has type: ${typeof value}`);
+ afLogger.error(`Field:, ${field}`);
return {}
}
}
@@ -317,9 +318,9 @@ class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataS
if (orderBy) selectQuery += ` ${orderBy}`;
if (limit) selectQuery += ` LIMIT ${limit}`;
if (offset) selectQuery += ` OFFSET ${offset}`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ MySQL Q:', selectQuery, 'values:', filterValues);
- }
+
+ dbLogger.trace(`๐ชฒ๐ MySQL Q: ${selectQuery} values: ${JSON.stringify(filterValues)}`);
+
const [results] = await this.client.execute(selectQuery, filterValues);
return results.map((row) => {
const newRow = {};
@@ -341,9 +342,7 @@ class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataS
}
const { sql: where, values: filterValues } = this.whereClauseAndValues(filters);
const q = `SELECT COUNT(*) FROM ${tableName} ${where}`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ MySQL Q:', q, 'values:', filterValues);
- }
+ dbLogger.trace(`๐ชฒ๐ MySQL Q: ${q} values: ${JSON.stringify(filterValues)}`);
const [results] = await this.client.execute(q, filterValues);
return +results[0]["COUNT(*)"];
}
@@ -353,9 +352,7 @@ class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataS
const result = {};
await Promise.all(columns.map(async (col) => {
const q = `SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ MySQL Q:', q);
- }
+ dbLogger.trace(`๐ชฒ๐ MySQL Q: ${q}`);
const [results] = await this.client.execute(q);
const { min, max } = results[0];
result[col.name] = {
@@ -371,9 +368,7 @@ class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataS
const placeholders = columns.map(() => '?').join(', ');
const values = columns.map((colName) => typeof record[colName] === 'undefined' ? null : record[colName]);
const q = `INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ MySQL Q:', q, 'values:', values);
- }
+ dbLogger.trace(`๐ชฒ๐ MySQL Q: ${q} values: ${JSON.stringify(values)}`);
const ret = await this.client.execute(q, values);
return ret.insertId;
}
@@ -382,17 +377,13 @@ class MysqlConnector extends AdminForthBaseConnector implements IAdminForthDataS
const values = [...Object.values(newValues), recordId];
const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `${col} = ?`).join(', ');
const q = `UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = ?`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ MySQL Q:', q, 'values:', values);
- }
+ dbLogger.trace(`๐ชฒ๐ MySQL Q: ${q} values: ${JSON.stringify(values)}`);
await this.client.execute(q, values);
}
async deleteRecord({ resource, recordId }): Promise {
const q = `DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = ?`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ MySQL Q:', q, 'values:', [recordId]);
- }
+ dbLogger.trace(`๐ชฒ๐ MySQL Q: ${q} values: ${JSON.stringify([recordId])}`);
const res = await this.client.execute(q, [recordId]);
return res.rowCount > 0;
}
diff --git a/adminforth/dataConnectors/postgres.ts b/adminforth/dataConnectors/postgres.ts
index bae17dea8..639a29bc3 100644
--- a/adminforth/dataConnectors/postgres.ts
+++ b/adminforth/dataConnectors/postgres.ts
@@ -3,6 +3,8 @@ import { AdminForthResource, IAdminForthSingleFilter, IAdminForthAndOrFilter, IA
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections, } from '../types/Common.js';
import AdminForthBaseConnector from './baseConnector.js';
import pkg from 'pg';
+import { afLogger, dbLogger } from '../modules/logger.js';
+
const { Client } = pkg;
@@ -15,13 +17,13 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
try {
await this.client.connect();
this.client.on('error', async (err) => {
- console.log('Postgres error: ', err.message, err.stack)
+ afLogger.error(`Postgres error: ${err.message} ${err.stack}`);
this.client.end();
await new Promise((resolve) => { setTimeout(resolve, 1000) });
this.setupClient(url);
});
} catch (e) {
- console.error(`Failed to connect to Postgres ${e}`);
+ afLogger.error(`Failed to connect to Postgres ${e}`);
}
}
@@ -198,8 +200,8 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
} else if (typeof value == 'object') {
return value;
} else {
- console.error('JSON field value is not string or object, but has type:', typeof value);
- console.error('Field:', field);
+ afLogger.error(`JSON field value is not string or object, but has type: ${typeof value}`);
+ afLogger.error(`Field:, ${field}`);
return {}
}
}
@@ -351,9 +353,7 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
const d = [...filterValues, limit, offset];
const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `"${s.field}" ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
const selectQuery = `SELECT ${columns} FROM "${tableName}" ${where} ${orderBy} ${limitOffset}`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ PG Q:', selectQuery, 'params:', d);
- }
+ dbLogger.trace(`๐ชฒ๐ PG Q: ${selectQuery}, params: ${JSON.stringify(d)}`);
const stmt = await this.client.query(selectQuery, d);
const rows = stmt.rows;
return rows.map((row) => {
@@ -376,9 +376,7 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
}
const { sql: where, values: filterValues } = this.whereClauseAndValues(resource, filters);
const q = `SELECT COUNT(*) FROM "${tableName}" ${where}`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ PG Q:', q, 'values:', filterValues);
- }
+ dbLogger.trace(`๐ชฒ๐ PG Q: ${q}, values: ${JSON.stringify(filterValues)}`);
const stmt = await this.client.query(q, filterValues);
return +stmt.rows[0].count;
}
@@ -388,9 +386,7 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
const result = {};
await Promise.all(columns.map(async (col) => {
const q = `SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM "${tableName}"`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ PG Q:', q);
- }
+ dbLogger.trace(`๐ชฒ๐ PG Q: ${q}`);
const stmt = await this.client.query(q);
const { min, max } = stmt.rows[0];
result[col.name] = {
@@ -410,11 +406,7 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
}
const primaryKey = this.getPrimaryKey(resource);
const q = `INSERT INTO "${tableName}" (${columns.join(', ')}) VALUES (${placeholders}) RETURNING "${primaryKey}"`;
- // console.log('\n๐ต [PG INSERT]:', q);
- // console.log('๐ฆ [VALUES]:', JSON.stringify(values, null, 2));
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ PG Q:', q, 'values:', values);
- }
+ dbLogger.trace(`๐ชฒ๐ PG Q: ${q}, values: ${JSON.stringify(values)}`);
const ret = await this.client.query(q, values);
return ret.rows[0][primaryKey];
}
@@ -423,17 +415,13 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
const values = [...Object.values(newValues), recordId];
const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `"${col}" = $${i + 1}`).join(', ');
const q = `UPDATE "${resource.table}" SET ${columnsWithPlaceholders} WHERE "${this.getPrimaryKey(resource)}" = $${values.length}`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ PG Q:', q, 'values:', values);
- }
+ dbLogger.trace(`๐ชฒ๐ PG Q: ${q}, values: ${JSON.stringify(values)}`);
await this.client.query(q, values);
}
async deleteRecord({ resource, recordId }): Promise {
const q = `DELETE FROM "${resource.table}" WHERE "${this.getPrimaryKey(resource)}" = $1`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ PG Q:', q, 'values:', [recordId]);
- }
+ dbLogger.trace(`๐ชฒ๐ PG Q: ${q}, values: ${JSON.stringify([recordId])}`);
const res = await this.client.query(q, [recordId]);
return res.rowCount > 0;
}
diff --git a/adminforth/dataConnectors/sqlite.ts b/adminforth/dataConnectors/sqlite.ts
index 1b8b8f30e..5538e23fc 100644
--- a/adminforth/dataConnectors/sqlite.ts
+++ b/adminforth/dataConnectors/sqlite.ts
@@ -3,6 +3,7 @@ import { IAdminForthDataSourceConnector, IAdminForthSingleFilter, IAdminForthAnd
import AdminForthBaseConnector from './baseConnector.js';
import dayjs from 'dayjs';
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections } from '../types/Common.js';
+import { dbLogger, afLogger } from '../modules/logger.js';
class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthDataSourceConnector {
@@ -122,7 +123,7 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
return {'error': `Failed to parse JSON: ${e.message}`}
}
} else {
- console.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
+ afLogger.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
}
}
@@ -156,7 +157,7 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
if (field._underlineType == 'text' || field._underlineType == 'varchar') {
return JSON.stringify(value);
} else {
- console.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
+ afLogger.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
}
}
@@ -287,9 +288,7 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
const stmt = this.client.prepare(q);
const d = [...filterValues, limit, offset];
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ SQLITE Q', q, 'params:', d);
- }
+ dbLogger.trace(`๐ชฒ๐ SQLITE Q: ${q}, params: ${JSON.stringify(d)}`);
const rows = await stmt.all(d);
return rows.map((row) => {
@@ -313,9 +312,7 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
const where = this.whereClause(filters);
const filterValues = this.getFilterParams(filters);
const q = `SELECT COUNT(*) FROM ${tableName} ${where}`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ SQLITE Q', q, 'params:', filterValues);
- }
+ dbLogger.trace(`๐ชฒ๐ SQLITE Q: ${q}, params: ${JSON.stringify(filterValues)}`);
const totalStmt = this.client.prepare(q);
return +totalStmt.get([...filterValues])['COUNT(*)'];
}
@@ -338,14 +335,9 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
const columns = Object.keys(record);
const placeholders = columns.map(() => '?').join(', ');
const values = columns.map((colName) => record[colName]);
- // const q = this.client.prepare(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`);
const sql = `INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`;
- //console.log('\n๐ข [SQLITE INSERT]:', sql);
- //console.log('๐ฆ [VALUES]:', JSON.stringify(values, null, 2));
const q = this.client.prepare(sql);
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ SQL Q:', q, 'values:', values);
- }
+ dbLogger.trace(`๐ชฒ๐ SQLITE Q: ${sql}, values: ${JSON.stringify(values)}`);
const ret = await q.run(values);
return ret.lastInsertRowid;
}
@@ -354,9 +346,7 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
const columnsWithPlaceholders = Object.keys(newValues).map((col) => `${col} = ?`);
const values = [...Object.values(newValues), recordId];
const q = `UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = ?`;
- if (process.env.HEAVY_DEBUG_QUERY) {
- console.log('๐ชฒ๐ SQLITE Q', q, 'params:', values);
- }
+ dbLogger.trace(`๐ชฒ๐ SQLITE Q: ${q}, params: ${JSON.stringify(values)}`);
const query = this.client.prepare(q);
await query.run(values);
}
diff --git a/adminforth/documentation/blog/2024-10-01-ai-blog/index.md b/adminforth/documentation/blog/2024-10-01-ai-blog/index.md
index 8a294008b..291b4fcb7 100644
--- a/adminforth/documentation/blog/2024-10-01-ai-blog/index.md
+++ b/adminforth/documentation/blog/2024-10-01-ai-blog/index.md
@@ -212,7 +212,7 @@ Open `index.ts` file in root directory and update it with the following content:
```ts title="./index.ts"
import express from 'express';
-import AdminForth, { Filters, Sorts } from 'adminforth';
+import AdminForth, { Filters, Sorts, logger } from 'adminforth';
import userResource from './resources/adminuser.js';
import postResource from './resources/posts.js';
import contentImageResource from './resources/content-image.js';
@@ -287,7 +287,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
const port = 3500;
admin.bundleNow({ hotReload: process.env.NODE_ENV === 'development' }).then(() => {
- console.log('Bundling AdminForth SPA done.');
+ logger.info('Bundling AdminForth SPA done.');
});
// api to server recent posts
@@ -343,7 +343,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
});
admin.express.listen(port, () => {
- console.log(`\nโก AdminForth is available at http://localhost:${port}/admin\n`)
+ logger.info(`\nโก AdminForth is available at http://localhost:${port}/admin\n`)
});
}
```
diff --git a/adminforth/documentation/docs/tutorial/01-helloWorld.md b/adminforth/documentation/docs/tutorial/01-helloWorld.md
index 24db51226..f5a79f3d5 100644
--- a/adminforth/documentation/docs/tutorial/01-helloWorld.md
+++ b/adminforth/documentation/docs/tutorial/01-helloWorld.md
@@ -131,7 +131,7 @@ Create `index.ts` file in root directory with following content:
```ts title="./index.ts"
import express from 'express';
-import AdminForth, { AdminForthDataTypes, Filters } from 'adminforth';
+import AdminForth, { AdminForthDataTypes, Filters, logger } from 'adminforth';
import type { AdminForthResourceInput, AdminForthResource, AdminUser } from 'adminforth';
export const admin = new AdminForth({
@@ -218,7 +218,7 @@ export const admin = new AdminForth({
},
edit: {
beforeSave: async ({ oldRecord, updates, adminUser, resource }: { oldRecord: any, updates: any, adminUser: AdminUser, resource: AdminForthResource }) => {
- console.log('Updating user', updates);
+ logger.info('Updating user', updates);
if (oldRecord.id === adminUser.dbUser.id && updates.role) {
return { ok: false, error: 'You cannot change your own role' };
}
@@ -321,7 +321,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
// needed to compile SPA. Call it here or from a build script e.g. in Docker build time to reduce downtime
admin.bundleNow({ hotReload: process.env.NODE_ENV === 'development' }).then(() => {
- console.log('Bundling AdminForth SPA done.');
+ logger.info('Bundling AdminForth SPA done.');
});
// serve after you added all api
@@ -338,7 +338,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
});
admin.express.listen(port, () => {
- console.log(`\nโก AdminForth is available at http://localhost:${port}\n`)
+ logger.info(`\nโก AdminForth is available at http://localhost:${port}\n`)
});
}
```
diff --git a/adminforth/documentation/docs/tutorial/03-Customization/09-Actions.md b/adminforth/documentation/docs/tutorial/03-Customization/09-Actions.md
index 1d0a595cd..8e50b4897 100644
--- a/adminforth/documentation/docs/tutorial/03-Customization/09-Actions.md
+++ b/adminforth/documentation/docs/tutorial/03-Customization/09-Actions.md
@@ -22,7 +22,7 @@ Here's how to add a custom action:
// Handler function when action is triggered
action: async ({ recordId, adminUser }) => {
- console.log("auto submit", recordId, adminUser);
+ logger.info("auto submit", recordId, adminUser);
return {
ok: true,
successMessage: "Auto submitted"
diff --git a/adminforth/documentation/docs/tutorial/03-Customization/16-websocket.md b/adminforth/documentation/docs/tutorial/03-Customization/16-websocket.md
index 497fb4c42..38b18d7ed 100644
--- a/adminforth/documentation/docs/tutorial/03-Customization/16-websocket.md
+++ b/adminforth/documentation/docs/tutorial/03-Customization/16-websocket.md
@@ -7,10 +7,11 @@ In two words, to subscribe to a topic from any frontend component you need to do
```javascript
import websocket from '@/websocket';
+import { logger } from 'adminforth'
websocket.subscribe('/topic-name', (data) => {
// this callback called when we receive publish in topic from the websocket
- console.log(data);
+ logger.info(data);
});
```
@@ -192,7 +193,7 @@ const admin = new AdminForth({
//diff-add
const [subject, param] = /^\/(.+?)\/(.+)/.exec(topic)!.slice(1);
//diff-add
- console.log(`Websocket user ${adminUser.username} tries to subscribe to topic ${subject} with param ${param}`);
+ logger.info(`Websocket user ${adminUser.username} tries to subscribe to topic ${subject} with param ${param}`);
//diff-add
if (subject === 'property-cost') {
//diff-add
diff --git a/adminforth/documentation/docs/tutorial/05-Plugins/15-email-invite.md b/adminforth/documentation/docs/tutorial/05-Plugins/15-email-invite.md
index 261d1fce3..3fde70097 100644
--- a/adminforth/documentation/docs/tutorial/05-Plugins/15-email-invite.md
+++ b/adminforth/documentation/docs/tutorial/05-Plugins/15-email-invite.md
@@ -31,6 +31,7 @@ To Setup SES, you need to have an AWS account and SES service enabled. You can f
```typescript title="./resources/adminuser.ts"
import EmailInvitePlugin from '@adminforth/email-invite';
import EmailAdapterAwsSes from '@adminforth/email-adapter-aws-ses';
+import { logger } from 'adminforth'
export default {
dataSource: 'maindb',
@@ -77,7 +78,7 @@ export default {
},
edit: {
beforeSave: async ({ oldRecord, updates, adminUser, resource }: { oldRecord: any, updates: any, adminUser: AdminUser, resource: AdminForthResource }) => {
- console.log('Updating user', updates);
+ logger.info('Updating user', updates);
if (oldRecord.id === adminUser.dbUser.id && updates.role) {
return { ok: false, error: 'You cannot change your own role' };
}
diff --git a/adminforth/documentation/docs/tutorial/07-Plugins/16-email-invite.md b/adminforth/documentation/docs/tutorial/07-Plugins/16-email-invite.md
index 6f2ea4b62..7ab89bf15 100644
--- a/adminforth/documentation/docs/tutorial/07-Plugins/16-email-invite.md
+++ b/adminforth/documentation/docs/tutorial/07-Plugins/16-email-invite.md
@@ -31,6 +31,7 @@ To Setup SES, you need to have an AWS account and SES service enabled. You can f
```typescript title="./resources/adminuser.ts"
import EmailInvitePlugin from '@adminforth/email-invite';
import EmailAdapterAwsSes from '@adminforth/email-adapter-aws-ses';
+import { logger } from 'adminforth'
export default {
dataSource: 'maindb',
@@ -77,7 +78,7 @@ export default {
},
edit: {
beforeSave: async ({ oldRecord, updates, adminUser, resource }: { oldRecord: any, updates: any, adminUser: AdminUser, resource: AdminForthResource }) => {
- console.log('Updating user', updates);
+ logger.info('Updating user', updates);
if (oldRecord.id === adminUser.dbUser.id && updates.role) {
return { ok: false, error: 'You cannot change your own role' };
}
diff --git a/adminforth/index.ts b/adminforth/index.ts
index 25b48752c..225e04c18 100644
--- a/adminforth/index.ts
+++ b/adminforth/index.ts
@@ -34,6 +34,8 @@ import AdminForthRestAPI, { interpretResource } from './modules/restApi.js';
import ClickhouseConnector from './dataConnectors/clickhouse.js';
import OperationalResource from './modules/operationalResource.js';
import SocketBroker from './modules/socketBroker.js';
+import { afLogger } from './modules/logger.js';
+export { logger } from './modules/logger.js';
// exports
export * from './types/Back.js';
@@ -124,62 +126,62 @@ class AdminForth implements IAdminForth {
}
constructor(config: AdminForthInputConfig) {
- process.env.HEAVY_DEBUG && console.log('๐ง AdminForth constructor started');
+ afLogger.trace('๐ง AdminForth constructor started');
if (global.adminforth) {
throw new Error('AdminForth instance already created in this process. '+
'If you want to use multiple instances, consider using different process for each instance');
}
- process.env.HEAVY_DEBUG && console.log('๐ง Creating CodeInjector...');
+ afLogger.trace('๐ง Creating CodeInjector...');
this.codeInjector = new CodeInjector(this);
- process.env.HEAVY_DEBUG && console.log('๐ง CodeInjector created');
+ afLogger.trace('๐ง CodeInjector created');
- process.env.HEAVY_DEBUG && console.log('๐ง Creating ConfigValidator...');
+ afLogger.trace('๐ง Creating ConfigValidator...');
this.configValidator = new ConfigValidator(this, config);
- process.env.HEAVY_DEBUG && console.log('๐ง ConfigValidator created');
+ afLogger.trace('๐ง ConfigValidator created');
- process.env.HEAVY_DEBUG && console.log('๐ง Creating AdminForthRestAPI...');
+ afLogger.trace('๐ง Creating AdminForthRestAPI...');
this.restApi = new AdminForthRestAPI(this);
- process.env.HEAVY_DEBUG && console.log('๐ง AdminForthRestAPI created');
+ afLogger.trace('๐ง AdminForthRestAPI created');
- process.env.HEAVY_DEBUG && console.log('๐ง Creating SocketBroker...');
+ afLogger.trace('๐ง Creating SocketBroker...');
this.websocket = new SocketBroker(this);
- process.env.HEAVY_DEBUG && console.log('๐ง SocketBroker created');
+ afLogger.trace('๐ง SocketBroker created');
this.activatedPlugins = [];
- process.env.HEAVY_DEBUG && console.log('๐ง Validating config...');
+ afLogger.trace('๐ง Validating config...');
this.configValidator.validateConfig();
- process.env.HEAVY_DEBUG && console.log('๐ง Config validated');
+ afLogger.trace('๐ง Config validated');
- process.env.HEAVY_DEBUG && console.log('๐ง Activating plugins...');
+ afLogger.trace('๐ง Activating plugins...');
this.activatePlugins();
- process.env.HEAVY_DEBUG && console.log('๐ง Plugins activated');
+ afLogger.trace('๐ง Plugins activated');
- process.env.HEAVY_DEBUG && console.log('๐ง Validating after plugin activation...');
+ afLogger.trace('๐ง Validating after plugin activation...');
this.configValidator.validateAfterPluginsActivation();
- process.env.HEAVY_DEBUG && console.log('๐ง Config validated');
+ afLogger.trace('๐ง Config validated');
- process.env.HEAVY_DEBUG && console.log('๐ง Creating ExpressServer...');
+ afLogger.trace('๐ง Creating ExpressServer...');
this.express = new ExpressServer(this);
- process.env.HEAVY_DEBUG && console.log('๐ง ExpressServer created');
+ afLogger.trace('๐ง ExpressServer created');
// this.fastify = new FastifyServer(this);
- process.env.HEAVY_DEBUG && console.log('๐ง Creating AdminForthAuth...');
+ afLogger.trace('๐ง Creating AdminForthAuth...');
this.auth = new AdminForthAuth(this);
- process.env.HEAVY_DEBUG && console.log('๐ง AdminForthAuth created');
+ afLogger.trace('๐ง AdminForthAuth created');
this.connectors = {};
this.statuses = {
dbDiscover: 'running',
};
- console.log(`${this.formatAdminForth()} v${ADMINFORTH_VERSION} initializing...`);
- process.env.HEAVY_DEBUG && console.log('๐ง About to set global.adminforth...');
+ afLogger.info(`${this.formatAdminForth()} v${ADMINFORTH_VERSION} initializing...`);
+ afLogger.trace('๐ง About to set global.adminforth...');
global.adminforth = this;
- process.env.HEAVY_DEBUG && console.log('๐ง global.adminforth set successfully');
- process.env.HEAVY_DEBUG && console.log('๐ง AdminForth constructor completed');
+ afLogger.trace('๐ง global.adminforth set successfully');
+ afLogger.trace('๐ง AdminForth constructor completed');
}
formatAdminForth() {
@@ -202,16 +204,16 @@ class AdminForth implements IAdminForth {
}
activatePlugins() {
- process.env.HEAVY_DEBUG && console.log('๐๐๐ Activating plugins');
+ afLogger.trace('๐๐๐ Activating plugins');
const allPluginInstances = [];
for (let resource of this.config.resources) {
- process.env.HEAVY_DEBUG && console.log(`๐ Checking plugins for resource: ${resource.resourceId}`);
+ afLogger.trace(`๐ Checking plugins for resource: ${resource.resourceId}`);
for (let pluginInstance of resource.plugins || []) {
- process.env.HEAVY_DEBUG && console.log(`๐ Found plugin: ${pluginInstance.constructor.name} for resource ${resource.resourceId}`);
+ afLogger.trace(`๐ Found plugin: ${pluginInstance.constructor.name} for resource ${resource.resourceId}`);
allPluginInstances.push({pi: pluginInstance, resource});
}
}
- process.env.HEAVY_DEBUG && console.log(`๐ Total plugins to activate: ${allPluginInstances.length}`);
+ afLogger.trace(`๐ Total plugins to activate: ${allPluginInstances.length}`);
let activationLoopCounter = 0;
while (true) {
@@ -219,8 +221,8 @@ class AdminForth implements IAdminForth {
if (activationLoopCounter > 10) {
throw new Error('Plugin activation loop exceeded 10 iterations, possible infinite loop (some plugin tries to activate himself in a loop)');
}
- process.env.HEAVY_DEBUG && console.log(`๐ Plugin activation loop iteration: ${activationLoopCounter}`);
- process.env.HEAVY_DEBUG && console.log(`๐ Activated plugins count: ${this.activatedPlugins.length}/${allPluginInstances.length}`);
+ afLogger.trace(`๐ Plugin activation loop iteration: ${activationLoopCounter}`);
+ afLogger.trace(`๐ Activated plugins count: ${this.activatedPlugins.length}/${allPluginInstances.length}`);
const allPluginsAreActivated = allPluginInstances.length === this.activatedPlugins.length;
if (allPluginsAreActivated) {
break;
@@ -230,33 +232,33 @@ class AdminForth implements IAdminForth {
!this.activatedPlugins.find((p) => p.pluginInstanceId === pluginInstance.pluginInstanceId)
);
- process.env.HEAVY_DEBUG && console.log(`๐ Unactivated plugins remaining: ${unactivatedPlugins.length}`);
+ afLogger.trace(`๐ Unactivated plugins remaining: ${unactivatedPlugins.length}`);
- process.env.HEAVY_DEBUG && console.log(`๐ Unactivated plugins count: ${unactivatedPlugins.length}`);
+ afLogger.trace(`๐ Unactivated plugins count: ${unactivatedPlugins.length}`);
unactivatedPlugins.sort(({pi: a}, {pi: b}) => a.activationOrder - b.activationOrder);
- process.env.HEAVY_DEBUG && console.log(`๐ Activating plugins in order:`, unactivatedPlugins.map(({pi}) => pi.constructor.name));
+ afLogger.trace(`๐ Activating plugins in order: ${unactivatedPlugins.map(({pi}) => pi.constructor.name)}`);
unactivatedPlugins.forEach(
({pi: pluginInstance, resource}, index) => {
- process.env.HEAVY_DEBUG && console.log("Activating plugin:",pluginInstance.constructor.name)
- process.env.HEAVY_DEBUG && console.log(`๐ Activating plugin ${index + 1}/${allPluginInstances.length}: ${pluginInstance.constructor.name} for resource ${resource.resourceId}`);
+ afLogger.trace(`Activating plugin: ${pluginInstance.constructor.name}`);
+ afLogger.trace(`๐ Activating plugin ${index + 1}/${allPluginInstances.length}: ${pluginInstance.constructor.name} for resource ${resource.resourceId}`);
pluginInstance.modifyResourceConfig(this, resource, allPluginInstances);
- process.env.HEAVY_DEBUG && console.log(`๐ Plugin ${pluginInstance.constructor.name} modifyResourceConfig completed`);
+ afLogger.trace(`๐ Plugin ${pluginInstance.constructor.name} modifyResourceConfig completed`);
const plugin = this.activatedPlugins.find((p) => p.pluginInstanceId === pluginInstance.pluginInstanceId);
if (plugin) {
- process.env.HEAVY_DEBUG && console.log(`Current plugin pluginInstance.pluginInstanceId ${pluginInstance.pluginInstanceId}`);
+ afLogger.trace(`Current plugin pluginInstance.pluginInstanceId ${pluginInstance.pluginInstanceId}`);
throw new Error(`Attempt to activate Plugin ${pluginInstance.constructor.name} second time for same resource, but plugin does not support it.
To support multiple plugin instance pre one resource, plugin should return unique string values for each installation from instanceUniqueRepresentation`);
}
this.activatedPlugins.push(pluginInstance);
- process.env.HEAVY_DEBUG && console.log(`๐ Plugin ${pluginInstance.constructor.name} activated successfully`);
+ afLogger.trace(`๐ Plugin ${pluginInstance.constructor.name} activated successfully`);
}
);
- process.env.HEAVY_DEBUG && console.log(`๐activated plugins:`, this.activatedPlugins.map((pi) => pi.constructor.name));
+ afLogger.trace(`๐activated plugins: ${this.activatedPlugins.map((pi) => pi.constructor.name)}`);
}
- process.env.HEAVY_DEBUG && console.log('๐ All plugins activation completed');
+ afLogger.trace('๐ All plugins activation completed');
}
getPluginsByClassName(className: string): T[] {
@@ -382,7 +384,7 @@ class AdminForth implements IAdminForth {
try {
await this.connectors[dataSourceId].setupClient(this.config.dataSources.find((ds) => ds.id === dataSourceId).url);
} catch (e) {
- console.error(`Error while connecting to datasource '${dataSourceId}':`, e);
+ afLogger.error(`Error while connecting to datasource '${dataSourceId}': ${e}`);
}
}));
@@ -397,13 +399,13 @@ class AdminForth implements IAdminForth {
try {
fieldTypes = await this.connectors[res.dataSource].discoverFields(res);
} catch (e) {
- console.error(`Error discovering fields for resource '${res.table}' (In resource '${res.resourceId}')`, e);
+ afLogger.error(`Error discovering fields for resource '${res.table}' (In resource '${res.resourceId}') ${e}`);
}
if (fieldTypes !== null && !Object.keys(fieldTypes).length) {
throw new Error(`Table '${res.table}' (In resource '${res.resourceId}') has no fields or does not exist`);
}
if (fieldTypes === null) {
- console.error(`โ DataSource ${res.dataSource} was not able to perform field discovery. It will not work properly`);
+ afLogger.error(`โ DataSource ${res.dataSource} was not able to perform field discovery. It will not work properly`);
if (process.env.NODE_ENV === 'production') {
process.exit(1);
}
@@ -440,13 +442,11 @@ class AdminForth implements IAdminForth {
this.operationalResources[resource.resourceId] = new OperationalResource(this.connectors[resource.dataSource], resource);
});
- // console.log('โ๏ธโ๏ธโ๏ธ Database discovery done', JSON.stringify(this.config.resources, null, 2));
}
async getAllTables(): Promise<{ [dataSourceId: string]: string[] }> {
const results: { [dataSourceId: string]: string[] } = {};
- // console.log('Connectors to process:', Object.keys(this.connectors));
if (!this.config.databaseConnectors) {
this.config.databaseConnectors = {...this.connectorClasses};
}
@@ -458,11 +458,10 @@ class AdminForth implements IAdminForth {
const tables = await connector.getAllTables();
results[dataSourceId] = tables;
} catch (err) {
- console.error(`Error getting tables for dataSource ${dataSourceId}:`, err);
+ afLogger.error(`Error getting tables for dataSource ${dataSourceId}: ${err}`);
results[dataSourceId] = [];
}
} else {
- // console.log(`Connector ${dataSourceId} does not have getAllTables method`);
results[dataSourceId] = [];
}
})
@@ -490,7 +489,7 @@ class AdminForth implements IAdminForth {
isUUID: isProbablyUUIDColumn(column),
}));
} catch (err) {
- console.error(`Error getting columns for table ${tableName} in dataSource ${dataSourceId}:`, err);
+ afLogger.error(`Error getting columns for table ${tableName} in dataSource ${dataSourceId}: ${err}`);
results[dataSourceId] = [];
}
} else {
@@ -551,7 +550,7 @@ class AdminForth implements IAdminForth {
// execute hook if needed
for (const hook of listify(resource.hooks?.create?.beforeSave)) {
- console.log('๐ชฒ Hook beforeSave', hook);
+ afLogger.debug(`๐ชฒ Hook beforeSave ${hook}`);
const resp = await hook({
resource,
record,
@@ -584,7 +583,7 @@ class AdminForth implements IAdminForth {
}
}
const connector = this.connectors[resource.dataSource];
- process.env.HEAVY_DEBUG && console.log('๐ชฒ๐ creating record createResourceRecord', record);
+ afLogger.trace(`๐ชฒ๐ creating record createResourceRecord, record: ${JSON.stringify(record)}`);
const { error, createdRecord } = await connector.createRecord({ resource, record, adminUser });
if ( error ) {
return { error };
@@ -594,7 +593,7 @@ class AdminForth implements IAdminForth {
// execute hook if needed
for (const hook of listify(resource.hooks?.create?.afterSave)) {
- process.env.HEAVY_DEBUG && console.log('๐ชฒ Hook afterSave', hook);
+ afLogger.trace(`๐ชฒ Hook afterSave ${hook}`);
const resp = await hook({
recordId: primaryKey,
resource,
@@ -632,7 +631,7 @@ class AdminForth implements IAdminForth {
}
if (record) {
- console.warn(`updateResourceRecord function received 'record' param which is deprecated and will be removed in future version, please use 'updates' instead.`);
+ afLogger.warn(`updateResourceRecord function received 'record' param which is deprecated and will be removed in future version, please use 'updates' instead.`);
}
// remove editReadonly columns from record
diff --git a/adminforth/modules/codeInjector.ts b/adminforth/modules/codeInjector.ts
index 987c12ab8..b40d10322 100644
--- a/adminforth/modules/codeInjector.ts
+++ b/adminforth/modules/codeInjector.ts
@@ -9,6 +9,7 @@ import AdminForth, { AdminForthConfigMenuItem } from '../index.js';
import { ADMIN_FORTH_ABSOLUTE_PATH, getComponentNameFromPath, transformObject, deepMerge, md5hash, slugifyString } from './utils.js';
import { ICodeInjector } from '../types/Back.js';
import { StylesGenerator } from './styleGenerator.js';
+import { afLogger } from '../modules/logger.js';
let TMP_DIR;
@@ -64,9 +65,9 @@ function hashify(obj) {
}
function notifyWatcherIssue(limit) {
- console.log('Ran out of file handles after watching %s files.', limit);
- console.log('Falling back to polling which uses more CPU.');
- console.log('Run ulimit -n 10000 to increase the limit for open files.');
+ afLogger.info('Ran out of file handles after watching %s files.', limit);
+ afLogger.info('Falling back to polling which uses more CPU.');
+ afLogger.info('Run ulimit -n 10000 to increase the limit for open files.');
}
class CodeInjector implements ICodeInjector {
@@ -91,7 +92,7 @@ class CodeInjector implements ICodeInjector {
}
cleanup() {
- console.log('Cleaning up...');
+ afLogger.info('Cleaning up...');
this.allWatchers.forEach((watcher) => {
watcher.removeAll();
});
@@ -107,14 +108,6 @@ class CodeInjector implements ICodeInjector {
}
- // async runShell({ command }) {
- // console.log(`โ๏ธ Running shell ${command}...`);
- // console.time(`${command} done in`);
- // const { stdout: out, stderr: err } = await execAsync(command);
- // console.timeEnd(`${command} done in`);
- // console.log(`Command ${command} output:`, out, err);
- // }
-
async runNpmShell({command, cwd, envOverrides = {}}: {
command: string,
cwd: string,
@@ -131,9 +124,9 @@ class CodeInjector implements ICodeInjector {
...envOverrides,
};
- console.log(`โ๏ธ exec: npm ${command}`);
- process.env.HEAVY_DEBUG && console.log(`๐ชฒ npm ${command} cwd:`, cwd);
- process.env.HEAVY_DEBUG && console.time(`npm ${command} done in`);
+ afLogger.trace(`โ๏ธ exec: npm ${command}`);
+ afLogger.trace(`๐ชฒ npm ${command} cwd: ${cwd}`);
+ afLogger.trace(`npm ${command} done in`);
// On Windows, execute npm.cmd directly; on Unix, use node + npm
let execCommand: string;
@@ -159,11 +152,10 @@ class CodeInjector implements ICodeInjector {
}
const { stdout: out, stderr: err } = await execAsync(execCommand, execOptions);
- process.env.HEAVY_DEBUG && console.timeEnd(`npm ${command} done in`);
+ afLogger.trace(`npm ${command} done in`);
- // process.env.HEAVY_DEBUG && console.log(`๐ชฒ npm ${command} output:`, out);
if (err) {
- process.env.HEAVY_DEBUG && console.error(`๐ชฒnpm ${command} errors/warnings:`, err);
+ afLogger.trace(`๐ชฒnpm ${command} errors/warnings: ${err}`);
}
}
@@ -243,9 +235,7 @@ class CodeInjector implements ICodeInjector {
dereference: true, // needed to dereference types
// preserveTimestamps: true, // needed to not invalidate any caches
});
- if (process.env.HEAVY_DEBUG) {
- console.log('๐ชฒโ๏ธ fsExtra.copy copy single file', src, dest);
- }
+ afLogger.trace(`๐ชฒโ๏ธ fsExtra.copy copy single file, ${src}, ${dest}`);
}));
}
async migrateLegacyCustomLayout(oldMeta) {
@@ -350,9 +340,7 @@ class CodeInjector implements ICodeInjector {
registerSettingPages(this.adminforth.config.auth.userMenuSettingsPages);
const spaDir = this.getSpaDir();
- if (process.env.HEAVY_DEBUG) {
- console.log(`๐ชฒโ๏ธ fsExtra.copy from ${spaDir} -> ${this.spaTmpPath()}`);
- }
+ afLogger.trace(`๐ชฒโ๏ธ fsExtra.copy from ${spaDir} -> ${this.spaTmpPath()}`);
// try to rm /src/types directory
try {
@@ -368,8 +356,8 @@ class CodeInjector implements ICodeInjector {
// /adminforth/* used for local development and /dist/* used for production
const filterPasses = !src.includes(`${path.sep}adminforth${path.sep}spa${path.sep}node_modules`) && !src.includes(`${path.sep}adminforth${path.sep}spa${path.sep}dist`)
&& !src.includes(`${path.sep}dist${path.sep}spa${path.sep}node_modules`) && !src.includes(`${path.sep}dist${path.sep}spa${path.sep}dist`);
- if (process.env.HEAVY_DEBUG && !filterPasses) {
- console.log('๐ชฒโ๏ธ fsExtra.copy filtered out', src);
+ if (!filterPasses) {
+ afLogger.trace(`๐ชฒโ๏ธ fsExtra.copy filtered out, ${src}`);
}
return filterPasses
@@ -398,9 +386,7 @@ class CodeInjector implements ICodeInjector {
for (const [src, dest] of Object.entries(this.srcFoldersToSync)) {
const to = path.join(this.spaTmpPath(), 'src', 'custom', dest);
- if (process.env.HEAVY_DEBUG) {
- console.log(`๐ชฒโ๏ธ srcFoldersToSync: fsExtra.copy from ${src}, ${to}`);
- }
+ afLogger.trace(`๐ชฒโ๏ธ srcFoldersToSync: fsExtra.copy from ${src}, ${to}`);
await fsExtra.copy(src, to, {
recursive: true,
@@ -517,7 +503,6 @@ class CodeInjector implements ICodeInjector {
this.allComponentNames[filePath] = componentName;
});
- // console.log('๐ง Injecting code into Vue sources...', this.allComponentNames);
let customComponentsImports = '';
for (const [targetPath, component] of Object.entries(this.allComponentNames)) {
@@ -649,7 +634,7 @@ class CodeInjector implements ICodeInjector {
// for every installed plugin generate packages
for (const plugin of this.adminforth.activatedPlugins) {
- process.env.HEAVY_DEBUG && console.log('๐ง Checking packages for plugin', plugin.constructor.name, plugin.customFolderPath);
+ afLogger.trace(`๐ง Checking packages for plugin, ${plugin.constructor.name}, ${plugin.customFolderPath}`);
const [lockHash, packages] = await this.packagesFromNpm(plugin.customFolderPath);
if (packages.length) {
pluginPackages.push({
@@ -670,14 +655,14 @@ class CodeInjector implements ICodeInjector {
try {
const existingHash = await fs.promises.readFile(hashPath, 'utf-8');
if (existingHash === fullHash) {
- process.env.HEAVY_DEBUG && console.log(`๐ชฒHashes match, skipping npm ci/install, from file: ${existingHash}, actual: ${fullHash}`);
+ afLogger.trace(`๐ชฒHashes match, skipping npm ci/install, from file: ${existingHash}, actual: ${fullHash}`);
return;
} else {
- process.env.HEAVY_DEBUG && console.log(`๐ชฒ Hashes do not match: from file: ${existingHash} actual: ${fullHash}, proceeding with npm ci/install`);
+ afLogger.trace(`๐ชฒ Hashes do not match: from file: ${existingHash} actual: ${fullHash}, proceeding with npm ci/install`);
}
} catch (e) {
// ignore
- process.env.HEAVY_DEBUG && console.log('๐ชฒHash file does not exist, proceeding with npm ci/install', e);
+ afLogger.trace(`๐ชฒHash file does not exist, proceeding with npm ci/install, ${e}`);
}
await this.runNpmShell({command: 'ci', cwd: this.spaTmpPath(), envOverrides: {
@@ -730,7 +715,7 @@ class CodeInjector implements ICodeInjector {
};
await collectDirectories(spaPath);
- process.env.HEAVY_DEBUG && console.log('๐ชฒ๐ Watch for:', directories.join(','));
+ afLogger.trace(`๐ชฒ๐ Watch for: ${directories.join(',')}`);
const watcher = filewatcher({ debounce: 30 });
directories.forEach((dir) => {
@@ -739,7 +724,7 @@ class CodeInjector implements ICodeInjector {
files.forEach((file) => {
const fullPath = path.join(dir, file);
if (fs.lstatSync(fullPath).isFile()) {
- process.env.HEAVY_DEBUG && console.log(`๐ชฒ๐ Watch for file ${fullPath}`);
+ afLogger.trace(`๐ชฒ๐ Watch for file ${fullPath}`);
watcher.add(fullPath);
}
})
@@ -748,7 +733,7 @@ class CodeInjector implements ICodeInjector {
watcher.on(
'change',
async (file) => {
- process.env.HEAVY_DEBUG && console.log(`๐ File ${file} changed (SPA), preparing sources...`);
+ afLogger.trace(`๐ File ${file} changed (SPA), preparing sources...`);
await this.updatePartials({ filesUpdated: [file.replace(spaPath + path.sep, '')] });
}
)
@@ -764,7 +749,7 @@ class CodeInjector implements ICodeInjector {
try {
await fs.promises.access(customComponentsDir, fs.constants.F_OK);
} catch (e) {
- process.env.HEAVY_DEBUG && console.log(`๐ชฒCustom components dir ${customComponentsDir} does not exist, skipping watching`);
+ afLogger.trace(`๐ชฒCustom components dir ${customComponentsDir} does not exist, skipping watching`);
return;
}
@@ -796,27 +781,25 @@ class CodeInjector implements ICodeInjector {
const watcher = filewatcher({ debounce: 30 });
files.forEach((file) => {
- process.env.HEAVY_DEBUG && console.log(`๐ชฒ๐ Watch for file ${file}`);
+ afLogger.trace(`๐ชฒ๐ Watch for file ${file}`);
watcher.add(file);
});
- process.env.HEAVY_DEBUG && console.log('๐ชฒ๐ Watch for:', directories.join(','));
+ afLogger.trace(`๐ชฒ๐ Watch for: ${directories.join(',')}`);
watcher.on(
'change',
async (fileOrDir) => {
// copy one file
const relativeFilename = fileOrDir.replace(customComponentsDir + path.sep, '');
- if (process.env.HEAVY_DEBUG) {
- console.log(`๐ fileOrDir ${fileOrDir} changed`);
- console.log(`๐ relativeFilename ${relativeFilename}`);
- console.log(`๐ customComponentsDir ${customComponentsDir}`);
- console.log(`๐ destination ${destination}`);
- }
+ afLogger.trace(`๐ fileOrDir ${fileOrDir} changed`);
+ afLogger.trace(`๐ relativeFilename ${relativeFilename}`);
+ afLogger.trace(`๐ customComponentsDir ${customComponentsDir}`);
+ afLogger.trace(`๐ destination ${destination}`);
const isFile = fs.lstatSync(fileOrDir).isFile();
if (isFile) {
const destPath = path.join(this.spaTmpPath(), 'src', 'custom', destination, relativeFilename);
- process.env.HEAVY_DEBUG && console.log(`๐ Copying file ${fileOrDir} to ${destPath}`);
+ afLogger.trace(`๐ Copying file ${fileOrDir} to ${destPath}`);
await fsExtra.copy(fileOrDir, destPath);
return;
} else {
@@ -836,7 +819,7 @@ class CodeInjector implements ICodeInjector {
return content;
} catch (e) {
// file does not exist
- process.env.HEAVY_DEBUG && console.log(`๐ชฒFile ${filePath} does not exist, returning null`);
+ afLogger.trace(`๐ชฒFile ${filePath} does not exist, returning null`);
return null;
}
}
@@ -867,7 +850,7 @@ class CodeInjector implements ICodeInjector {
}
async bundleNow({ hotReload = false }: { hotReload: boolean }) {
- console.log(`${this.adminforth.formatAdminForth()} Bundling ${hotReload ? 'and listening for changes (๐ฅ Hotreload)' : ' (no hot reload)'}`);
+ afLogger.info(`${this.adminforth.formatAdminForth()} Bundling ${hotReload ? 'and listening for changes (๐ฅ Hotreload)' : ' (no hot reload)'}`);
this.adminforth.runningHotReload = hotReload;
await this.prepareSources();
@@ -890,8 +873,8 @@ class CodeInjector implements ICodeInjector {
const allFiles = [];
const sourcesHash = await this.computeSourcesHash(this.spaTmpPath(), allFiles);
- process.env.VERY_HEAVY_DEBUG && console.log('๐ชฒ๐ชฒ allFiles:', JSON.stringify(
- allFiles.sort((a,b) => a.localeCompare(b)), null, 1))
+ afLogger.trace(`๐ชฒ๐ชฒ allFiles:, ${JSON.stringify(
+ allFiles.sort((a,b) => a.localeCompare(b)), null, 1)}`);
const buildHash = await this.tryReadFile(path.join(serveDir, '.adminforth_build_hash'));
const messagesHash = await this.tryReadFile(path.join(serveDir, '.adminforth_messages_hash'));
@@ -899,11 +882,9 @@ class CodeInjector implements ICodeInjector {
const skipBuild = buildHash === sourcesHash;
const skipExtract = messagesHash === sourcesHash;
- if (process.env.HEAVY_DEBUG) {
- console.log(`๐ชฒ SPA build hash: ${buildHash}`);
- console.log(`๐ชฒ SPA messages hash: ${messagesHash}`);
- console.log(`๐ชฒ SPA sources hash: ${sourcesHash}`);
- }
+ afLogger.trace(`๐ชฒ SPA build hash: ${buildHash}`);
+ afLogger.trace(`๐ชฒ SPA messages hash: ${messagesHash}`);
+ afLogger.trace(`๐ชฒ SPA sources hash: ${sourcesHash}`);
if (!skipBuild) {
// remove serveDir if exists
@@ -927,7 +908,7 @@ class CodeInjector implements ICodeInjector {
// save hash
await fs.promises.writeFile(path.join(serveDir, '.adminforth_messages_hash'), sourcesHash);
} else {
- console.log(`AdminForth i18n message extraction skipped โ build already performed for the current sources.`);
+ afLogger.info(`AdminForth i18n message extraction skipped โ build already performed for the current sources.`);
}
if (!hotReload) {
@@ -942,14 +923,14 @@ class CodeInjector implements ICodeInjector {
// save hash
await fs.promises.writeFile(path.join(serveDir, '.adminforth_build_hash'), sourcesHash);
} else {
- console.log(`Skipping AdminForth SPA bundling - already completed for the current sources.`);
+ afLogger.info(`Skipping AdminForth SPA bundling - already completed for the current sources.`);
}
} else {
const command = 'run dev';
- console.log(`โ๏ธ spawn: npm ${command}...`);
+ afLogger.info(`โ๏ธ spawn: npm ${command}...`);
if (process.env.VITE_ADMINFORTH_PUBLIC_PATH) {
- console.log('โ ๏ธ Your VITE_ADMINFORTH_PUBLIC_PATH:', process.env.VITE_ADMINFORTH_PUBLIC_PATH, 'has no effect');
+ afLogger.info(`โ ๏ธ Your VITE_ADMINFORTH_PUBLIC_PATH: ${process.env.VITE_ADMINFORTH_PUBLIC_PATH} has no effect`);
}
const env = {
VITE_ADMINFORTH_PUBLIC_PATH: this.adminforth.config.baseUrl,
@@ -973,19 +954,19 @@ class CodeInjector implements ICodeInjector {
// parse port from message " โ Local: http://localhost:xyz/"
const s = stripAnsiCodes(data.toString());
- process.env.HEAVY_DEBUG && console.log('๐ชฒ devServer stdout โ (port detect):', s);
+ afLogger.trace(`๐ชฒ devServer stdout โ (port detect): ${s}`);
const portMatch = s.match(/.+?http:\/\/.+?:(\d+).+?/m);
if (portMatch) {
this.devServerPort = parseInt(portMatch[1]);
}
} else {
- process.env.HEAVY_DEBUG && console.log(`[AdminForth SPA]:`);
- process.env.HEAVY_DEBUG && process.stdout.write(data);
+ afLogger.trace(`[AdminForth SPA]:`);
+ afLogger.trace(data.toString());
}
});
devServer.stderr.on('data', (data) => {
- console.error(`[AdminForth SPA ERROR]:`);
- process.stdout.write(data);
+ afLogger.error(`[AdminForth SPA ERROR]:`);
+ afLogger.error(data.toString());
});
}
diff --git a/adminforth/modules/configValidator.ts b/adminforth/modules/configValidator.ts
index 8aa830ebc..1d60c3ee8 100644
--- a/adminforth/modules/configValidator.ts
+++ b/adminforth/modules/configValidator.ts
@@ -29,6 +29,7 @@ import {
} from "../types/Common.js";
import AdminForth from "adminforth";
import { AdminForthConfigMenuItem } from "adminforth";
+import { afLogger } from "./logger.js";
export default class ConfigValidator implements IConfigValidator {
@@ -1211,7 +1212,7 @@ export default class ConfigValidator implements IConfigValidator {
}
if (warnings.length > 0) {
- console.warn(`AdminForth config warnings: ${warnings.join(', ')}`);
+ afLogger.warn(`AdminForth config warnings: ${warnings.join(', ')}`);
}
//add ids for onSelectedAllActions for each resource
diff --git a/adminforth/modules/logger.ts b/adminforth/modules/logger.ts
new file mode 100644
index 000000000..cf6a8d405
--- /dev/null
+++ b/adminforth/modules/logger.ts
@@ -0,0 +1,28 @@
+import pino from 'pino';
+
+const baseLogger = pino({
+ transport: {
+ target: 'pino-pretty',
+ options: {
+ colorize: true,
+ ignore: 'pid,hostname',
+ hideObject: true,
+ messageFormat: '{layer}: {msg}',
+ }
+ },
+});
+
+export const logger = baseLogger.child(
+ { layer: 'user_logs' },
+ { level: process.env.HEAVY_DEBUG ? 'trace' : ( process.env.DEBUG_LEVEL || 'info' ) }
+);
+
+export const afLogger = baseLogger.child(
+ { layer: 'af' },
+ { level: process.env.HEAVY_DEBUG ? 'trace' : ( process.env.AF_DEBUG_LEVEL || 'info' ) }
+);
+
+export const dbLogger = baseLogger.child(
+ { layer: 'db' },
+ { level: process.env.HEAVY_DEBUG_QUERY ? 'trace' : (process.env.DB_DEBUG_LEVEL|| 'info') }
+);
\ No newline at end of file
diff --git a/adminforth/modules/restApi.ts b/adminforth/modules/restApi.ts
index 1f784d3fe..1765711fd 100644
--- a/adminforth/modules/restApi.ts
+++ b/adminforth/modules/restApi.ts
@@ -15,6 +15,8 @@ import {
Filters,
} from "../types/Back.js";
+import { afLogger } from "./logger.js";
+
import { ADMINFORTH_VERSION, listify, md5hash, getLoginPromptHTML } from './utils.js';
import AdminForthAuth from "../auth.js";
@@ -77,9 +79,7 @@ export async function interpretResource(
source: ActionCheckSource,
adminforth: IAdminForth
): Promise<{allowedActions: AllowedActionsResolved}> {
- if (process.env.HEAVY_DEBUG) {
- console.log('๐ชฒInterpreting resource', resource.resourceId, source, 'adminUser', adminUser);
- }
+ afLogger.trace(`๐ชฒInterpreting resource, ${resource.resourceId}, ${source}, 'adminUser', ${adminUser}`);
const allowedActions = {} as AllowedActionsResolved;
// we need to compute only allowed actions for this source:
@@ -176,7 +176,7 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
showIn: Object.values(AdminForthResourcePages).reduce((acc, page) => { return { ...acc, [page]: false } }, {} as ShowInResolved),
type: AdminForthDataTypes.STRING,
});
- console.log('Adding passwordHashField to userResource', userResource)
+ afLogger.info(`Adding passwordHashField to userResource, ${userResource}`);
}
const userRecord = (
@@ -208,7 +208,6 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
const expireInDuration = rememberMe
? (this.adminforth.config.auth.rememberMeDuration || '30d')
: '1d';
- console.log('expireInDuration', expireInDuration);
await this.processLoginCallbacks(adminUser, toReturn, response, {
body, headers, query, cookies, requestUrl,
@@ -1046,13 +1045,13 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
const availableSearchFields = searchableFields.filter((fieldName) => {
const fieldExists = targetResource.columns.some(col => col.name === fieldName);
if (!fieldExists) {
- process.env.HEAVY_DEBUG && console.log(`โ ๏ธ Field '${fieldName}' not found in polymorphic target resource '${targetResource.resourceId}', skipping in search filter.`);
+ afLogger.trace(`โ ๏ธ Field '${fieldName}' not found in polymorphic target resource '${targetResource.resourceId}', skipping in search filter.`);
}
return fieldExists;
});
if (availableSearchFields.length === 0) {
- process.env.HEAVY_DEBUG && console.log(`โ ๏ธ No searchable fields available in polymorphic target resource '${targetResource.resourceId}', skipping resource.`);
+ afLogger.trace(`โ ๏ธ No searchable fields available in polymorphic target resource '${targetResource.resourceId}', skipping resource.`);
resolve({ items: [] });
return;
}
diff --git a/adminforth/modules/socketBroker.ts b/adminforth/modules/socketBroker.ts
index 6fe9e9880..8e68f97b4 100644
--- a/adminforth/modules/socketBroker.ts
+++ b/adminforth/modules/socketBroker.ts
@@ -1,5 +1,6 @@
import { IAdminForth, IWebSocketBroker, IWebSocketClient } from "../types/Back.js";
import { AdminUser } from "../types/Common.js";
+import { afLogger } from '../modules/logger.js';
export default class SocketBroker implements IWebSocketBroker {
clients: IWebSocketClient[] = [];
@@ -72,7 +73,7 @@ export default class SocketBroker implements IWebSocketBroker {
try {
authResult = await this.adminforth.config.auth.websocketTopicAuth(data.topic, client.adminUser);
} catch (e) {
- console.error('Error in websocketTopicAuth, assuming connection not allowed', e);
+ afLogger.error(`Error in websocketTopicAuth, assuming connection not allowed ${e}`);
}
if (!authResult) {
client.send(JSON.stringify({ type: 'error', message: 'Unauthorized' }));
@@ -93,7 +94,7 @@ export default class SocketBroker implements IWebSocketBroker {
try {
await this.adminforth.config.auth.websocketSubscribed(data.topic, client.adminUser);
} catch (e) {
- console.error(`Error in websocketSubscribed for topic ${data.topic}`, e);
+ afLogger.error(`Error in websocketSubscribed for topic ${data.topic}, ${e}`);
}
})(); // run in background
}
@@ -125,18 +126,17 @@ export default class SocketBroker implements IWebSocketBroker {
async publish(topic: string, data: any, filterUsers?: (adminUser: AdminUser) => Promise): Promise {
if (!this.topics[topic]) {
- process.env.HEAVY_DEBUG && console.log('No clients subscribed to topic', topic);
+ afLogger.trace(`No clients subscribed to topic ${topic}`);
return;
}
for (const client of this.topics[topic]) {
if (filterUsers) {
if (! (await filterUsers(client.adminUser)) ) {
- process.env.HEAVY_DEBUG && console.log('Client not authorized to receive message', topic, client.adminUser);
+ afLogger.trace(`Client not authorized to receive message ${topic} ${client.adminUser}`);
continue;
}
}
- process.env.HEAVY_DEBUG && console.log('Sending data to soket', topic, data);
-
+ afLogger.trace(`Sending data to socket ${topic} ${JSON.stringify(data)}`);
client.send(JSON.stringify({ type: 'message', topic, data }));
}
}
diff --git a/adminforth/package-lock.json b/adminforth/package-lock.json
index f8e1fc6e8..8ae3340a3 100644
--- a/adminforth/package-lock.json
+++ b/adminforth/package-lock.json
@@ -36,6 +36,8 @@
"mysql2": "^3.14.2",
"node-fetch": "^3.3.2",
"pg": "^8.11.5",
+ "pino": "^10.1.0",
+ "pino-pretty": "^13.1.3",
"rate-limiter-flexible": "^8.1.0",
"recast": "^0.23.11",
"ws": "^8.18.0"
@@ -623,6 +625,12 @@
"@octokit/openapi-types": "^27.0.0"
}
},
+ "node_modules/@pinojs/redact": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz",
+ "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==",
+ "license": "MIT"
+ },
"node_modules/@pnpm/config.env-replace": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
@@ -1211,6 +1219,15 @@
"node": ">=4"
}
},
+ "node_modules/atomic-sleep": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
@@ -1996,6 +2013,15 @@
"node": ">= 12"
}
},
+ "node_modules/dateformat": {
+ "version": "4.6.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz",
+ "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/dayjs": {
"version": "1.11.11",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
@@ -2609,6 +2635,18 @@
],
"license": "MIT"
},
+ "node_modules/fast-copy": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz",
+ "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==",
+ "license": "MIT"
+ },
+ "node_modules/fast-safe-stringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+ "license": "MIT"
+ },
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
@@ -3052,6 +3090,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/help-me": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
+ "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
+ "license": "MIT"
+ },
"node_modules/highlight.js": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
@@ -3501,6 +3545,15 @@
"jiti": "lib/jiti-cli.mjs"
}
},
+ "node_modules/joycon": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
+ "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -4905,6 +4958,7 @@
},
"node_modules/npm/node_modules/@isaacs/cliui": {
"version": "8.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -4921,6 +4975,7 @@
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": {
"version": "6.1.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -4932,11 +4987,13 @@
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": {
"version": "9.2.2",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -4953,6 +5010,7 @@
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": {
"version": "7.1.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -4967,6 +5025,7 @@
},
"node_modules/npm/node_modules/@isaacs/fs-minipass": {
"version": "4.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -4978,11 +5037,13 @@
},
"node_modules/npm/node_modules/@isaacs/string-locale-compare": {
"version": "1.1.0",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/@npmcli/agent": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -4998,6 +5059,7 @@
},
"node_modules/npm/node_modules/@npmcli/arborist": {
"version": "8.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5046,6 +5108,7 @@
},
"node_modules/npm/node_modules/@npmcli/config": {
"version": "9.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5064,6 +5127,7 @@
},
"node_modules/npm/node_modules/@npmcli/fs": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5075,6 +5139,7 @@
},
"node_modules/npm/node_modules/@npmcli/git": {
"version": "6.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5094,6 +5159,7 @@
},
"node_modules/npm/node_modules/@npmcli/installed-package-contents": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5109,6 +5175,7 @@
},
"node_modules/npm/node_modules/@npmcli/map-workspaces": {
"version": "4.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5123,6 +5190,7 @@
},
"node_modules/npm/node_modules/@npmcli/metavuln-calculator": {
"version": "8.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5138,6 +5206,7 @@
},
"node_modules/npm/node_modules/@npmcli/metavuln-calculator/node_modules/pacote": {
"version": "20.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5168,6 +5237,7 @@
},
"node_modules/npm/node_modules/@npmcli/name-from-folder": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -5176,6 +5246,7 @@
},
"node_modules/npm/node_modules/@npmcli/node-gyp": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -5184,6 +5255,7 @@
},
"node_modules/npm/node_modules/@npmcli/package-json": {
"version": "6.1.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5201,6 +5273,7 @@
},
"node_modules/npm/node_modules/@npmcli/promise-spawn": {
"version": "8.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5212,6 +5285,7 @@
},
"node_modules/npm/node_modules/@npmcli/query": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5223,6 +5297,7 @@
},
"node_modules/npm/node_modules/@npmcli/redact": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -5231,6 +5306,7 @@
},
"node_modules/npm/node_modules/@npmcli/run-script": {
"version": "9.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5247,6 +5323,7 @@
},
"node_modules/npm/node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -5256,6 +5333,7 @@
},
"node_modules/npm/node_modules/@sigstore/protobuf-specs": {
"version": "0.3.2",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"engines": {
@@ -5264,6 +5342,7 @@
},
"node_modules/npm/node_modules/@sigstore/tuf": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
@@ -5276,6 +5355,7 @@
},
"node_modules/npm/node_modules/@tufjs/canonical-json": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5284,6 +5364,7 @@
},
"node_modules/npm/node_modules/abbrev": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -5292,6 +5373,7 @@
},
"node_modules/npm/node_modules/agent-base": {
"version": "7.1.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5303,6 +5385,7 @@
},
"node_modules/npm/node_modules/aggregate-error": {
"version": "3.1.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5315,6 +5398,7 @@
},
"node_modules/npm/node_modules/ansi-regex": {
"version": "5.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5323,6 +5407,7 @@
},
"node_modules/npm/node_modules/ansi-styles": {
"version": "6.2.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5334,21 +5419,25 @@
},
"node_modules/npm/node_modules/aproba": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/archy": {
"version": "1.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/balanced-match": {
"version": "1.0.2",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/bin-links": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5364,6 +5453,7 @@
},
"node_modules/npm/node_modules/binary-extensions": {
"version": "2.3.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5375,6 +5465,7 @@
},
"node_modules/npm/node_modules/brace-expansion": {
"version": "2.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5383,6 +5474,7 @@
},
"node_modules/npm/node_modules/cacache": {
"version": "19.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5405,6 +5497,7 @@
},
"node_modules/npm/node_modules/cacache/node_modules/chownr": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "BlueOak-1.0.0",
"engines": {
@@ -5413,6 +5506,7 @@
},
"node_modules/npm/node_modules/cacache/node_modules/minizlib": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5425,6 +5519,7 @@
},
"node_modules/npm/node_modules/cacache/node_modules/mkdirp": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"bin": {
@@ -5439,6 +5534,7 @@
},
"node_modules/npm/node_modules/cacache/node_modules/p-map": {
"version": "7.0.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5450,6 +5546,7 @@
},
"node_modules/npm/node_modules/cacache/node_modules/tar": {
"version": "7.4.3",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5466,6 +5563,7 @@
},
"node_modules/npm/node_modules/cacache/node_modules/yallist": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "BlueOak-1.0.0",
"engines": {
@@ -5474,6 +5572,7 @@
},
"node_modules/npm/node_modules/chalk": {
"version": "5.3.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5485,6 +5584,7 @@
},
"node_modules/npm/node_modules/chownr": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -5493,6 +5593,7 @@
},
"node_modules/npm/node_modules/ci-info": {
"version": "4.1.0",
+ "dev": true,
"funding": [
{
"type": "github",
@@ -5507,6 +5608,7 @@
},
"node_modules/npm/node_modules/cidr-regex": {
"version": "4.1.1",
+ "dev": true,
"inBundle": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -5518,6 +5620,7 @@
},
"node_modules/npm/node_modules/clean-stack": {
"version": "2.2.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5526,6 +5629,7 @@
},
"node_modules/npm/node_modules/cli-columns": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5538,6 +5642,7 @@
},
"node_modules/npm/node_modules/cmd-shim": {
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -5546,6 +5651,7 @@
},
"node_modules/npm/node_modules/color-convert": {
"version": "2.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5557,16 +5663,19 @@
},
"node_modules/npm/node_modules/color-name": {
"version": "1.1.4",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/common-ancestor-path": {
"version": "1.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/cross-spawn": {
"version": "7.0.6",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5580,6 +5689,7 @@
},
"node_modules/npm/node_modules/cross-spawn/node_modules/which": {
"version": "2.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5594,6 +5704,7 @@
},
"node_modules/npm/node_modules/cssesc": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"bin": {
@@ -5605,6 +5716,7 @@
},
"node_modules/npm/node_modules/debug": {
"version": "4.3.7",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5621,6 +5733,7 @@
},
"node_modules/npm/node_modules/diff": {
"version": "5.2.0",
+ "dev": true,
"inBundle": true,
"license": "BSD-3-Clause",
"engines": {
@@ -5629,16 +5742,19 @@
},
"node_modules/npm/node_modules/eastasianwidth": {
"version": "0.2.0",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/emoji-regex": {
"version": "8.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/encoding": {
"version": "0.1.13",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -5648,6 +5764,7 @@
},
"node_modules/npm/node_modules/env-paths": {
"version": "2.2.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5656,16 +5773,19 @@
},
"node_modules/npm/node_modules/err-code": {
"version": "2.0.3",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/exponential-backoff": {
"version": "3.1.1",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0"
},
"node_modules/npm/node_modules/fastest-levenshtein": {
"version": "1.0.16",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5674,6 +5794,7 @@
},
"node_modules/npm/node_modules/foreground-child": {
"version": "3.3.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5689,6 +5810,7 @@
},
"node_modules/npm/node_modules/fs-minipass": {
"version": "3.0.3",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5700,6 +5822,7 @@
},
"node_modules/npm/node_modules/glob": {
"version": "10.4.5",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5719,11 +5842,13 @@
},
"node_modules/npm/node_modules/graceful-fs": {
"version": "4.2.11",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/hosted-git-info": {
"version": "8.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5735,11 +5860,13 @@
},
"node_modules/npm/node_modules/http-cache-semantics": {
"version": "4.1.1",
+ "dev": true,
"inBundle": true,
"license": "BSD-2-Clause"
},
"node_modules/npm/node_modules/http-proxy-agent": {
"version": "7.0.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5752,6 +5879,7 @@
},
"node_modules/npm/node_modules/https-proxy-agent": {
"version": "7.0.5",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5764,6 +5892,7 @@
},
"node_modules/npm/node_modules/iconv-lite": {
"version": "0.6.3",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
@@ -5776,6 +5905,7 @@
},
"node_modules/npm/node_modules/ignore-walk": {
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5787,6 +5917,7 @@
},
"node_modules/npm/node_modules/imurmurhash": {
"version": "0.1.4",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5795,6 +5926,7 @@
},
"node_modules/npm/node_modules/indent-string": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5803,6 +5935,7 @@
},
"node_modules/npm/node_modules/ini": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -5811,6 +5944,7 @@
},
"node_modules/npm/node_modules/init-package-json": {
"version": "7.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5828,6 +5962,7 @@
},
"node_modules/npm/node_modules/ip-address": {
"version": "9.0.5",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -5840,6 +5975,7 @@
},
"node_modules/npm/node_modules/ip-regex": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5851,6 +5987,7 @@
},
"node_modules/npm/node_modules/is-cidr": {
"version": "5.1.0",
+ "dev": true,
"inBundle": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -5862,6 +5999,7 @@
},
"node_modules/npm/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5870,11 +6008,13 @@
},
"node_modules/npm/node_modules/isexe": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/jackspeak": {
"version": "3.4.3",
+ "dev": true,
"inBundle": true,
"license": "BlueOak-1.0.0",
"dependencies": {
@@ -5889,11 +6029,13 @@
},
"node_modules/npm/node_modules/jsbn": {
"version": "1.1.0",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/json-parse-even-better-errors": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -5902,6 +6044,7 @@
},
"node_modules/npm/node_modules/json-stringify-nice": {
"version": "1.1.4",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"funding": {
@@ -5910,6 +6053,7 @@
},
"node_modules/npm/node_modules/jsonparse": {
"version": "1.3.1",
+ "dev": true,
"engines": [
"node >= 0.2.0"
],
@@ -5918,16 +6062,19 @@
},
"node_modules/npm/node_modules/just-diff": {
"version": "6.0.2",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/just-diff-apply": {
"version": "5.5.0",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/libnpmaccess": {
"version": "9.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5940,6 +6087,7 @@
},
"node_modules/npm/node_modules/libnpmdiff": {
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5958,6 +6106,7 @@
},
"node_modules/npm/node_modules/libnpmexec": {
"version": "9.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5978,6 +6127,7 @@
},
"node_modules/npm/node_modules/libnpmfund": {
"version": "6.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -5989,6 +6139,7 @@
},
"node_modules/npm/node_modules/libnpmhook": {
"version": "11.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6001,6 +6152,7 @@
},
"node_modules/npm/node_modules/libnpmorg": {
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6013,6 +6165,7 @@
},
"node_modules/npm/node_modules/libnpmpack": {
"version": "8.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6027,6 +6180,7 @@
},
"node_modules/npm/node_modules/libnpmpublish": {
"version": "10.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6045,6 +6199,7 @@
},
"node_modules/npm/node_modules/libnpmsearch": {
"version": "8.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6056,6 +6211,7 @@
},
"node_modules/npm/node_modules/libnpmteam": {
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6068,6 +6224,7 @@
},
"node_modules/npm/node_modules/libnpmversion": {
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6083,11 +6240,13 @@
},
"node_modules/npm/node_modules/lru-cache": {
"version": "10.4.3",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/make-fetch-happen": {
"version": "14.0.3",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6109,6 +6268,7 @@
},
"node_modules/npm/node_modules/make-fetch-happen/node_modules/negotiator": {
"version": "1.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -6117,6 +6277,7 @@
},
"node_modules/npm/node_modules/minimatch": {
"version": "9.0.5",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6131,6 +6292,7 @@
},
"node_modules/npm/node_modules/minipass": {
"version": "7.1.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6139,6 +6301,7 @@
},
"node_modules/npm/node_modules/minipass-collect": {
"version": "2.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6150,6 +6313,7 @@
},
"node_modules/npm/node_modules/minipass-fetch": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6166,6 +6330,7 @@
},
"node_modules/npm/node_modules/minipass-fetch/node_modules/minizlib": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6178,6 +6343,7 @@
},
"node_modules/npm/node_modules/minipass-flush": {
"version": "1.0.5",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6189,6 +6355,7 @@
},
"node_modules/npm/node_modules/minipass-flush/node_modules/minipass": {
"version": "3.3.6",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6200,6 +6367,7 @@
},
"node_modules/npm/node_modules/minipass-pipeline": {
"version": "1.2.4",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6211,6 +6379,7 @@
},
"node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": {
"version": "3.3.6",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6222,6 +6391,7 @@
},
"node_modules/npm/node_modules/minipass-sized": {
"version": "1.0.3",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6233,6 +6403,7 @@
},
"node_modules/npm/node_modules/minipass-sized/node_modules/minipass": {
"version": "3.3.6",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6244,6 +6415,7 @@
},
"node_modules/npm/node_modules/minizlib": {
"version": "2.1.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6256,6 +6428,7 @@
},
"node_modules/npm/node_modules/minizlib/node_modules/minipass": {
"version": "3.3.6",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6267,6 +6440,7 @@
},
"node_modules/npm/node_modules/mkdirp": {
"version": "1.0.4",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"bin": {
@@ -6278,11 +6452,13 @@
},
"node_modules/npm/node_modules/ms": {
"version": "2.1.3",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/mute-stream": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6291,6 +6467,7 @@
},
"node_modules/npm/node_modules/node-gyp": {
"version": "11.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6314,6 +6491,7 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/chownr": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "BlueOak-1.0.0",
"engines": {
@@ -6322,6 +6500,7 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/minizlib": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6334,6 +6513,7 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/mkdirp": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"bin": {
@@ -6348,6 +6528,7 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/tar": {
"version": "7.4.3",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6364,6 +6545,7 @@
},
"node_modules/npm/node_modules/node-gyp/node_modules/yallist": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "BlueOak-1.0.0",
"engines": {
@@ -6372,6 +6554,7 @@
},
"node_modules/npm/node_modules/nopt": {
"version": "8.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6386,6 +6569,7 @@
},
"node_modules/npm/node_modules/nopt/node_modules/abbrev": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6394,6 +6578,7 @@
},
"node_modules/npm/node_modules/normalize-package-data": {
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -6407,6 +6592,7 @@
},
"node_modules/npm/node_modules/npm-audit-report": {
"version": "6.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6415,6 +6601,7 @@
},
"node_modules/npm/node_modules/npm-bundled": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6426,6 +6613,7 @@
},
"node_modules/npm/node_modules/npm-install-checks": {
"version": "7.1.1",
+ "dev": true,
"inBundle": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -6437,6 +6625,7 @@
},
"node_modules/npm/node_modules/npm-normalize-package-bin": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6445,6 +6634,7 @@
},
"node_modules/npm/node_modules/npm-package-arg": {
"version": "12.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6459,6 +6649,7 @@
},
"node_modules/npm/node_modules/npm-packlist": {
"version": "9.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6470,6 +6661,7 @@
},
"node_modules/npm/node_modules/npm-pick-manifest": {
"version": "10.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6484,6 +6676,7 @@
},
"node_modules/npm/node_modules/npm-profile": {
"version": "11.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6496,6 +6689,7 @@
},
"node_modules/npm/node_modules/npm-registry-fetch": {
"version": "18.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6514,6 +6708,7 @@
},
"node_modules/npm/node_modules/npm-registry-fetch/node_modules/minizlib": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6526,6 +6721,7 @@
},
"node_modules/npm/node_modules/npm-user-validate": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "BSD-2-Clause",
"engines": {
@@ -6534,6 +6730,7 @@
},
"node_modules/npm/node_modules/p-map": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6548,11 +6745,13 @@
},
"node_modules/npm/node_modules/package-json-from-dist": {
"version": "1.0.1",
+ "dev": true,
"inBundle": true,
"license": "BlueOak-1.0.0"
},
"node_modules/npm/node_modules/pacote": {
"version": "19.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6583,6 +6782,7 @@
},
"node_modules/npm/node_modules/parse-conflict-json": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6596,6 +6796,7 @@
},
"node_modules/npm/node_modules/path-key": {
"version": "3.1.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -6604,6 +6805,7 @@
},
"node_modules/npm/node_modules/path-scurry": {
"version": "1.11.1",
+ "dev": true,
"inBundle": true,
"license": "BlueOak-1.0.0",
"dependencies": {
@@ -6619,6 +6821,7 @@
},
"node_modules/npm/node_modules/postcss-selector-parser": {
"version": "6.1.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6631,6 +6834,7 @@
},
"node_modules/npm/node_modules/proc-log": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6639,6 +6843,7 @@
},
"node_modules/npm/node_modules/proggy": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6647,6 +6852,7 @@
},
"node_modules/npm/node_modules/promise-all-reject-late": {
"version": "1.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"funding": {
@@ -6655,6 +6861,7 @@
},
"node_modules/npm/node_modules/promise-call-limit": {
"version": "3.0.2",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"funding": {
@@ -6663,11 +6870,13 @@
},
"node_modules/npm/node_modules/promise-inflight": {
"version": "1.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/promise-retry": {
"version": "2.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6680,6 +6889,7 @@
},
"node_modules/npm/node_modules/promzard": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6691,6 +6901,7 @@
},
"node_modules/npm/node_modules/qrcode-terminal": {
"version": "0.12.0",
+ "dev": true,
"inBundle": true,
"bin": {
"qrcode-terminal": "bin/qrcode-terminal.js"
@@ -6698,6 +6909,7 @@
},
"node_modules/npm/node_modules/read": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6709,6 +6921,7 @@
},
"node_modules/npm/node_modules/read-cmd-shim": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6717,6 +6930,7 @@
},
"node_modules/npm/node_modules/read-package-json-fast": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6729,6 +6943,7 @@
},
"node_modules/npm/node_modules/retry": {
"version": "0.12.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -6737,6 +6952,7 @@
},
"node_modules/npm/node_modules/rimraf": {
"version": "5.0.10",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6751,12 +6967,14 @@
},
"node_modules/npm/node_modules/safer-buffer": {
"version": "2.1.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"optional": true
},
"node_modules/npm/node_modules/semver": {
"version": "7.6.3",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"bin": {
@@ -6768,6 +6986,7 @@
},
"node_modules/npm/node_modules/shebang-command": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6779,6 +6998,7 @@
},
"node_modules/npm/node_modules/shebang-regex": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -6787,6 +7007,7 @@
},
"node_modules/npm/node_modules/signal-exit": {
"version": "4.1.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -6798,6 +7019,7 @@
},
"node_modules/npm/node_modules/sigstore": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
@@ -6814,6 +7036,7 @@
},
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/bundle": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
@@ -6825,6 +7048,7 @@
},
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/core": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"engines": {
@@ -6833,6 +7057,7 @@
},
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/sign": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
@@ -6849,6 +7074,7 @@
},
"node_modules/npm/node_modules/sigstore/node_modules/@sigstore/verify": {
"version": "2.0.0",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
@@ -6862,6 +7088,7 @@
},
"node_modules/npm/node_modules/smart-buffer": {
"version": "4.2.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -6871,6 +7098,7 @@
},
"node_modules/npm/node_modules/socks": {
"version": "2.8.3",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6884,6 +7112,7 @@
},
"node_modules/npm/node_modules/socks-proxy-agent": {
"version": "8.0.4",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6897,6 +7126,7 @@
},
"node_modules/npm/node_modules/spdx-correct": {
"version": "3.2.0",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
@@ -6906,6 +7136,7 @@
},
"node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6915,11 +7146,13 @@
},
"node_modules/npm/node_modules/spdx-exceptions": {
"version": "2.5.0",
+ "dev": true,
"inBundle": true,
"license": "CC-BY-3.0"
},
"node_modules/npm/node_modules/spdx-expression-parse": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6929,16 +7162,19 @@
},
"node_modules/npm/node_modules/spdx-license-ids": {
"version": "3.0.20",
+ "dev": true,
"inBundle": true,
"license": "CC0-1.0"
},
"node_modules/npm/node_modules/sprintf-js": {
"version": "1.1.3",
+ "dev": true,
"inBundle": true,
"license": "BSD-3-Clause"
},
"node_modules/npm/node_modules/ssri": {
"version": "12.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -6950,6 +7186,7 @@
},
"node_modules/npm/node_modules/string-width": {
"version": "4.2.3",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6964,6 +7201,7 @@
"node_modules/npm/node_modules/string-width-cjs": {
"name": "string-width",
"version": "4.2.3",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6977,6 +7215,7 @@
},
"node_modules/npm/node_modules/strip-ansi": {
"version": "6.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -6989,6 +7228,7 @@
"node_modules/npm/node_modules/strip-ansi-cjs": {
"name": "strip-ansi",
"version": "6.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7000,6 +7240,7 @@
},
"node_modules/npm/node_modules/supports-color": {
"version": "9.4.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -7011,6 +7252,7 @@
},
"node_modules/npm/node_modules/tar": {
"version": "6.2.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -7027,6 +7269,7 @@
},
"node_modules/npm/node_modules/tar/node_modules/fs-minipass": {
"version": "2.1.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -7038,6 +7281,7 @@
},
"node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": {
"version": "3.3.6",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -7049,6 +7293,7 @@
},
"node_modules/npm/node_modules/tar/node_modules/minipass": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -7057,16 +7302,19 @@
},
"node_modules/npm/node_modules/text-table": {
"version": "0.2.0",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/tiny-relative-date": {
"version": "1.3.0",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/treeverse": {
"version": "3.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -7075,6 +7323,7 @@
},
"node_modules/npm/node_modules/tuf-js": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7088,6 +7337,7 @@
},
"node_modules/npm/node_modules/tuf-js/node_modules/@tufjs/models": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7100,6 +7350,7 @@
},
"node_modules/npm/node_modules/unique-filename": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -7111,6 +7362,7 @@
},
"node_modules/npm/node_modules/unique-slug": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -7122,11 +7374,13 @@
},
"node_modules/npm/node_modules/util-deprecate": {
"version": "1.0.2",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/validate-npm-package-license": {
"version": "3.0.4",
+ "dev": true,
"inBundle": true,
"license": "Apache-2.0",
"dependencies": {
@@ -7136,6 +7390,7 @@
},
"node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7145,6 +7400,7 @@
},
"node_modules/npm/node_modules/validate-npm-package-name": {
"version": "6.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -7153,11 +7409,13 @@
},
"node_modules/npm/node_modules/walk-up-path": {
"version": "3.0.1",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
"node_modules/npm/node_modules/which": {
"version": "5.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -7172,6 +7430,7 @@
},
"node_modules/npm/node_modules/which/node_modules/isexe": {
"version": "3.1.1",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"engines": {
@@ -7180,6 +7439,7 @@
},
"node_modules/npm/node_modules/wrap-ansi": {
"version": "8.1.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7197,6 +7457,7 @@
"node_modules/npm/node_modules/wrap-ansi-cjs": {
"name": "wrap-ansi",
"version": "7.0.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7213,6 +7474,7 @@
},
"node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
"version": "4.3.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7227,6 +7489,7 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": {
"version": "6.1.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"engines": {
@@ -7238,11 +7501,13 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": {
"version": "9.2.2",
+ "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": {
"version": "5.1.2",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7259,6 +7524,7 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": {
"version": "7.1.0",
+ "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -7273,6 +7539,7 @@
},
"node_modules/npm/node_modules/write-file-atomic": {
"version": "6.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -7285,6 +7552,7 @@
},
"node_modules/npm/node_modules/yallist": {
"version": "4.0.0",
+ "dev": true,
"inBundle": true,
"license": "ISC"
},
@@ -7310,6 +7578,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/on-exit-leak-free": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
+ "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -7696,6 +7973,88 @@
"node": ">=4"
}
},
+ "node_modules/pino": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz",
+ "integrity": "sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==",
+ "license": "MIT",
+ "dependencies": {
+ "@pinojs/redact": "^0.4.0",
+ "atomic-sleep": "^1.0.0",
+ "on-exit-leak-free": "^2.1.0",
+ "pino-abstract-transport": "^2.0.0",
+ "pino-std-serializers": "^7.0.0",
+ "process-warning": "^5.0.0",
+ "quick-format-unescaped": "^4.0.3",
+ "real-require": "^0.2.0",
+ "safe-stable-stringify": "^2.3.1",
+ "sonic-boom": "^4.0.1",
+ "thread-stream": "^3.0.0"
+ },
+ "bin": {
+ "pino": "bin.js"
+ }
+ },
+ "node_modules/pino-abstract-transport": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz",
+ "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==",
+ "license": "MIT",
+ "dependencies": {
+ "split2": "^4.0.0"
+ }
+ },
+ "node_modules/pino-pretty": {
+ "version": "13.1.3",
+ "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz",
+ "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==",
+ "license": "MIT",
+ "dependencies": {
+ "colorette": "^2.0.7",
+ "dateformat": "^4.6.3",
+ "fast-copy": "^4.0.0",
+ "fast-safe-stringify": "^2.1.1",
+ "help-me": "^5.0.0",
+ "joycon": "^3.1.1",
+ "minimist": "^1.2.6",
+ "on-exit-leak-free": "^2.1.0",
+ "pino-abstract-transport": "^3.0.0",
+ "pump": "^3.0.0",
+ "secure-json-parse": "^4.0.0",
+ "sonic-boom": "^4.0.1",
+ "strip-json-comments": "^5.0.2"
+ },
+ "bin": {
+ "pino-pretty": "bin.js"
+ }
+ },
+ "node_modules/pino-pretty/node_modules/pino-abstract-transport": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz",
+ "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==",
+ "license": "MIT",
+ "dependencies": {
+ "split2": "^4.0.0"
+ }
+ },
+ "node_modules/pino-pretty/node_modules/strip-json-comments": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz",
+ "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pino-std-serializers": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz",
+ "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==",
+ "license": "MIT"
+ },
"node_modules/pkg-conf": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz",
@@ -7792,6 +8151,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/process-warning": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz",
+ "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -7843,6 +8218,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/quick-format-unescaped": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
+ "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
+ "license": "MIT"
+ },
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -7995,6 +8376,15 @@
"node": ">= 6"
}
},
+ "node_modules/real-require": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
+ "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12.13.0"
+ }
+ },
"node_modules/recast": {
"version": "0.23.11",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz",
@@ -8152,11 +8542,36 @@
}
]
},
+ "node_modules/safe-stable-stringify": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
+ "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
+ "node_modules/secure-json-parse": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz",
+ "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
"node_modules/semantic-release": {
"version": "24.2.1",
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.1.tgz",
@@ -8813,6 +9228,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/sonic-boom": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz",
+ "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==",
+ "license": "MIT",
+ "dependencies": {
+ "atomic-sleep": "^1.0.0"
+ }
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -9155,6 +9579,15 @@
"node": ">=0.8"
}
},
+ "node_modules/thread-stream": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz",
+ "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==",
+ "license": "MIT",
+ "dependencies": {
+ "real-require": "^0.2.0"
+ }
+ },
"node_modules/through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
diff --git a/adminforth/package.json b/adminforth/package.json
index 47749f829..2fbbf9ebe 100644
--- a/adminforth/package.json
+++ b/adminforth/package.json
@@ -82,6 +82,8 @@
"mysql2": "^3.14.2",
"node-fetch": "^3.3.2",
"pg": "^8.11.5",
+ "pino": "^10.1.0",
+ "pino-pretty": "^13.1.3",
"rate-limiter-flexible": "^8.1.0",
"recast": "^0.23.11",
"ws": "^8.18.0"
diff --git a/adminforth/servers/express.ts b/adminforth/servers/express.ts
index b732ceb67..7c321084e 100644
--- a/adminforth/servers/express.ts
+++ b/adminforth/servers/express.ts
@@ -10,6 +10,7 @@ import { AdminUser } from '../types/Common.js';
import http from 'http';
import { randomUUID } from 'crypto';
import { listify } from '../modules/utils.js';
+import { afLogger } from '../modules/logger.js';
function replaceAtStart(string, substring) {
if (string.startsWith(substring)) {
@@ -113,13 +114,12 @@ class ExpressServer implements IExpressHttpServer {
}
await proxyTo(`http://localhost:${this.adminforth.codeInjector.devServerPort}${req.url}`, res);
} catch (e) {
- // console.log('Failed to proxy', e);
res.status(500).send(respondNoServer('AdminForth SPA is not ready yet', 'Vite is still starting up. Please wait a moment...'));
return;
}
}
this.expressApp.get(`${slashedPrefix}assets/*`, handler);
- process.env.HEAVY_DEBUG && console.log('ยฎ๏ธ Registering SPA serve handler', `${slashedPrefix}assets/*`);
+ afLogger.trace(`ยฎ๏ธ Registering SPA serve handler', ${slashedPrefix}assets/*`);
this.expressApp.get(`${prefix}*`, handler);
@@ -172,7 +172,7 @@ class ExpressServer implements IExpressHttpServer {
this.server = http.createServer(this.expressApp);
const wss = new WebSocketServer({ server: this.server, path: `${base}/afws` });
- console.log(`${this.adminforth.formatAdminForth()} ๐ WebSocket server started`);
+ afLogger.info(`${this.adminforth.formatAdminForth()} ๐ WebSocket server started`);
// Handle WebSocket connections
wss.on('connection', async (ws, req) => {
try {
@@ -200,7 +200,7 @@ class ExpressServer implements IExpressHttpServer {
})
);
} catch (e) {
- console.error('Failed to handle WS connection', e);
+ afLogger.error(`Failed to handle WS connection ${e}`);
}
});
@@ -244,7 +244,7 @@ class ExpressServer implements IExpressHttpServer {
// check if multiple adminforth_jwt providerd and show warning
const jwts = cookies.filter(({key}) => key === `adminforth_${brandSlug}_jwt`);
if (jwts.length > 1) {
- console.error('Multiple adminforth_jwt cookies provided');
+ afLogger.error('Multiple adminforth_jwt cookies provided');
}
const jwt = jwts[0]?.value;
@@ -260,7 +260,7 @@ class ExpressServer implements IExpressHttpServer {
// this might happen if e.g. database intialization in progress.
// so we can't answer with 401 (would logout user)
// reproduced during usage of listRowsAutoRefreshSeconds
- console.error(e.stack);
+ afLogger.error(e.stack);
res.status(500).send('Failed to verify JWT token - something went wrong');
return;
}
@@ -313,7 +313,7 @@ class ExpressServer implements IExpressHttpServer {
try {
body = JSON.parse(body);
} catch (e) {
- console.error('Failed to parse body', e);
+ afLogger.error(`Failed to parse body, ${e}`);
res.status(400).send('Invalid JSON body');
}
}
@@ -330,7 +330,7 @@ class ExpressServer implements IExpressHttpServer {
message: undefined,
setHeader(name, value) {
- process.env.HEAVY_DEBUG && console.log(' ๐ชฒSetting header', name, value);
+ afLogger.trace(`๐ชฒSetting header, ${name}, ${value}`);
this.headers.push([name, value]);
},
@@ -355,9 +355,9 @@ class ExpressServer implements IExpressHttpServer {
try {
output = await handler(input);
} catch (e) {
- console.error('Error in handler', e);
+ afLogger.error(`Error in handler ${e}`);
// print full stack trace
- console.error(e.stack);
+ afLogger.error(e.stack);
res.status(500).send('Internal server error');
return;
}
@@ -376,7 +376,7 @@ class ExpressServer implements IExpressHttpServer {
res.json(output);
}
- process.env.HEAVY_DEBUG && console.log(`๐ Adding endpoint ${method} ${fullPath}`);
+ afLogger.trace(`๐ Adding endpoint ${method} ${fullPath}`);
this.expressApp[method.toLowerCase()](fullPath, noAuth ? expressHandler : this.authorize(expressHandler));
}
diff --git a/adminforth/spa/src/afcl/DatePicker.vue b/adminforth/spa/src/afcl/DatePicker.vue
index b9ac32fa9..a6dd2390f 100644
--- a/adminforth/spa/src/afcl/DatePicker.vue
+++ b/adminforth/spa/src/afcl/DatePicker.vue
@@ -134,7 +134,6 @@ onMounted(() => {
})
watch(start, () => {
- //console.log('โก emit', start.value)
emit('update:valueStart', start.value)
})
diff --git a/adminforth/spa/src/components/CustomDateRangePicker.vue b/adminforth/spa/src/components/CustomDateRangePicker.vue
index bb929a922..5b3e40d16 100644
--- a/adminforth/spa/src/components/CustomDateRangePicker.vue
+++ b/adminforth/spa/src/components/CustomDateRangePicker.vue
@@ -197,12 +197,10 @@ onMounted(() => {
})
watch(start, () => {
- //console.log('โก emit', start.value)
emit('update:valueStart', start.value)
})
watch(end, () => {
- //console.log('โก emit', end.value)
emit('update:valueEnd', end.value)
})
diff --git a/adminforth/spa/src/components/CustomRangePicker.vue b/adminforth/spa/src/components/CustomRangePicker.vue
index 6bde0aaa7..ac75b9bde 100644
--- a/adminforth/spa/src/components/CustomRangePicker.vue
+++ b/adminforth/spa/src/components/CustomRangePicker.vue
@@ -89,12 +89,10 @@ function updateEndFromProps() {
}
watch(start, () => {
- console.log('โก emit', start.value)
emit('update:valueStart', start.value)
})
watch(end, () => {
- console.log('โก emit', end.value)
emit('update:valueEnd', end.value);
})
diff --git a/dev-demo/index.ts b/dev-demo/index.ts
index 9eea00f11..717470a87 100644
--- a/dev-demo/index.ts
+++ b/dev-demo/index.ts
@@ -16,6 +16,7 @@ import { FICTIONAL_CAR_BRANDS, FICTIONAL_CAR_MODELS_BY_BRAND, ENGINE_TYPES, BODY
import passkeysResource from './resources/passkeys.js';
import carsDescriptionImage from './resources/cars_description_image.js';
import translations from "./resources/translations.js";
+import { logger } from 'adminforth';
const ADMIN_BASE_URL = '';
@@ -183,7 +184,7 @@ if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
const port = 3000;
admin.bundleNow({ hotReload: process.env.NODE_ENV === 'development' }).then(() => {
- console.log('Bundling AdminForth SPA done.');
+ logger.info('Bundling AdminForth SPA done.');
});
admin.express.serve(app);
@@ -282,6 +283,6 @@ if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
});
admin.express.listen(port, () => {
- console.log(`\nโก AdminForth is available at http://localhost:${port}${ADMIN_BASE_URL}\n`);
+ logger.info(`โก AdminForth is available at http://localhost:${port}${ADMIN_BASE_URL}\n`);
});
}
diff --git a/dev-demo/resources/adminuser.ts b/dev-demo/resources/adminuser.ts
index 89f7d5165..6cc60d787 100644
--- a/dev-demo/resources/adminuser.ts
+++ b/dev-demo/resources/adminuser.ts
@@ -1,4 +1,4 @@
-import AdminForth, { AdminForthDataTypes } from '../../adminforth/index.js';
+import AdminForth, { AdminForthDataTypes, logger } from '../../adminforth/index.js';
import type { AdminForthResourceInput, AdminForthResource, AdminUser, AdminForthResourceColumn } from '../../adminforth/index.js';
import { randomUUID } from 'crypto';
import TwoFactorsAuthPlugin from '../../plugins/adminforth-two-factors-auth/index.js'
@@ -205,7 +205,7 @@ export default {
},
edit: {
beforeSave: async ({ oldRecord, updates, adminUser, resource }: { oldRecord: any, updates: any, adminUser: AdminUser, resource: AdminForthResource }) => {
- console.log('Updating user', updates);
+ logger.info('Updating user', updates);
if (oldRecord.id === adminUser.dbUser.id && updates.role) {
return { ok: false, error: 'You cannot change your own role' };
}
diff --git a/dev-demo/resources/carsResourseTemplate.ts b/dev-demo/resources/carsResourseTemplate.ts
index b96ba61d9..0cad95a67 100644
--- a/dev-demo/resources/carsResourseTemplate.ts
+++ b/dev-demo/resources/carsResourseTemplate.ts
@@ -17,6 +17,8 @@ import ImageGenerationAdapterOpenAI from '../../adapters/adminforth-image-genera
import AdminForthStorageAdapterLocalFilesystem from "../../adapters/adminforth-storage-adapter-local/index.js";
import AdminForthAdapterS3Storage from '../../adapters/adminforth-storage-adapter-amazon-s3/index.js';
import AdminForthImageVisionAdapterOpenAi from '../../adapters/adminforth-image-vision-adapter-openai/index.js';
+import { logger } from 'adminforth'
+import { afLogger } from '../../adminforth/modules/logger.js';
export default function carsResourseTemplate(resourceId: string, dataSource: string, pkFileldName: string) {
return {
@@ -285,7 +287,7 @@ export default function carsResourseTemplate(resourceId: string, dataSource: str
if (!record.promo_picture) {
return [];
}
- console.log('Attaching file for analysis:', `http://localhost:3000/static/source/cars_promo_images/${record.promo_picture}`);
+ afLogger.info(`Attaching file for analysis: http://localhost:3000/static/source/cars_promo_images/${record.promo_picture}`);
return [`http://localhost:3000/static/source/${record.promo_picture}`];
},
visionAdapter: new AdminForthImageVisionAdapterOpenAi(
@@ -341,6 +343,7 @@ export default function carsResourseTemplate(resourceId: string, dataSource: str
name: 'Approve Listing',
icon: 'flowbite:check-outline',
action: async ({ recordId, adminUser, adminforth, extra, response }) => {
+ logger.info(`Admin User is approving listing for record ${recordId} in resource ${resourceId}`);
//@ts-ignore
const verificationResult = extra?.verificationResult
if (!verificationResult) {