Simulating native touch events

I am having a system which recives data samples of sensors in WebSocket and translates it into touch events.
The data is irelevant to the question, Eventually I have a x,y samples I need to simulate a touch event from.
I wrote a simple code to simulate the gestures using dispatchEvent

I wrote a code which simply stores the point detected in an object, and if it’s close to an existing point (within radius, TOW_POINT_DISTANCE_THRESHOLD) it declares it as an initial point for the later click recognition (distance of start and end points is smaller than a constant).
end point is determined if there are no other points for duration of MOUSE_INACTIVITY_THRESHOLD (80ms)

let isFirst = true;
const startPointKey = Object.keys(activeTouchPoints.current).find((key) => {
    if (Math.hypot(activeTouchPoints.current[key].x - point.x, activeTouchPoints.current[key].y - point.y) <= TOW_POINT_DISTANCE_THRESHOLD) {
        isFirst = false;
        return true;
    }
}) || `${point.x},${point.y}`;

const theElement = (anyParent.ownerDocument || anyParent).elementFromPoint(point.x, point.y) as HTMLElement;
if (!theElement || !anyParent.contains(theElement)) return;

if (isFirst) {
    theElement.focus();
    activeTouchPoints.current[startPointKey] = {
        x: point.x,
        y: point.y,
        downX: point.x,
        downY: point.y,
    };


    const touch = new Touch({
        identifier: Date.now(),
        target: theElement,
        clientX: point.x,
        clientY: point.y,

    });
    const pointerOverEvent = new PointerEvent('pointerover', {
        bubbles: true,
        pointerId: touch.identifier,
        pointerType: 'touch',

        clientX: point.x,
        clientY: point.y,
    });

    theElement.dispatchEvent(pointerOverEvent);

    const pointerEnterEvent = new PointerEvent('pointerenter', {
        bubbles: true,
        pointerId: touch.identifier,
        pointerType: 'touch',
        clientX: point.x,
        clientY: point.y,
    });

    theElement.dispatchEvent(pointerEnterEvent);


    const pointerEvent = new PointerEvent('pointerdown', {
        bubbles: true,

        pointerId: touch.identifier,
        pointerType: 'touch',
        clientX: point.x,
        clientY: point.y,
    });

    theElement.dispatchEvent(pointerEvent);

    const touchEvent = new TouchEvent('touchstart', {
        bubbles: true,

        touches: [touch],
        targetTouches: [touch],
        changedTouches: [touch],
    });

    theElement.dispatchEvent(touchEvent);

    const gotPointerCaptureEvent = new PointerEvent('gotpointercapture', {
        bubbles: true,

        pointerId: touch.identifier,
        pointerType: 'touch',
        clientX: point.x,
        clientY: point.y,
    });

    theElement.dispatchEvent(gotPointerCaptureEvent);

    const mouseDownEvent = new MouseEvent('mousedown', {
        bubbles: true,


        clientX: point.x,
        clientY: point.y,
    });


    theElement.dispatchEvent(mouseDownEvent);




} else {
    // Touch move

    activeTouchPoints.current[startPointKey].x = point.x;
    activeTouchPoints.current[startPointKey].y = point.y;

    // Dispatch touchmove and mousemove events
    const touch = new Touch({
        identifier: Date.now(),
        target: theElement,
        clientX: point.x,
        clientY: point.y,

    });

    const pointerEvent = new PointerEvent('pointermove', {
        bubbles: true,


        pointerId: touch.identifier,
        pointerType: 'touch',
        clientX: point.x,
        clientY: point.y,
    });


    theElement.dispatchEvent(pointerEvent);



    const touchEvent = new TouchEvent('touchmove', {
        bubbles: true,

        touches: [touch],
        targetTouches: [touch],
        changedTouches: [touch],
    });



    theElement.dispatchEvent(touchEvent);


    // Reset inactivity timer
    if (activeTouchPoints.current[startPointKey].timerId) {
        clearTimeout(activeTouchPoints.current[startPointKey].timerId);
    }
}

// Set up inactivity timer for mouseup
activeTouchPoints.current[startPointKey].timerId = setTimeout(() => {

    const touch = new Touch({
        identifier: Date.now(),
        target: theElement,
        clientX: activeTouchPoints.current[startPointKey].x,
        clientY: activeTouchPoints.current[startPointKey].y,
    });


    const pointerEvent = new PointerEvent('pointerup', {
        bubbles: true,

        pointerId: touch.identifier,
        pointerType: 'touch',
        clientX: point.x,
        clientY: point.y,
        isPrimary: activeTouchPoints.current[startPointKey].isPrimary,
    });


    theElement.dispatchEvent(pointerEvent);




    const touchEvent = new TouchEvent('touchend', {
        bubbles: true,

        touches: [touch], //?
        targetTouches: [touch], //?
        changedTouches: [touch],
    });

    theElement.dispatchEvent(touchEvent);


    const mouseUpEvent = new MouseEvent('mouseup', {
        bubbles: true,
        clientX: point.x,
        clientY: point.y,
    });

    theElement.dispatchEvent(mouseUpEvent);
    // Check for click based on distance


    const distance = Math.hypot(
        activeTouchPoints.current[startPointKey].x - activeTouchPoints.current[startPointKey].downX,
        activeTouchPoints.current[startPointKey].y - activeTouchPoints.current[startPointKey].downY
    );

    if (distance <= CLICK_DISTANCE_THRESHOLD) {

        const clickEvent = new MouseEvent('click', {
            bubbles: true,

            clientX: activeTouchPoints.current[startPointKey].x,
            clientY: activeTouchPoints.current[startPointKey].y,
        });
        theElement.dispatchEvent(clickEvent);

    }

    // Clean up
    delete activeTouchPoints.current[startPointKey];

}, MOUSE_INACTIVITY_THRESHOLD);
}

I thought using it ay the app level (aka using dispatchEvent) and not in the browser/system level, and that’s where the problem start.

The problem is that it doesn’t work for simple native components like Sliders which requires change event and don’t response to mouse/touch events, or advanced external components like SwipperJS for example which doesn’t response to those events also (even to clicks), and I am not even talking about scrolling a text on swipe if it’s long like in real device.

TL;DR: the problem is the simulating level, simulating directly at web level is problematic and not native (unless you have a clever general solution that will work everywhere).

I guess I have to simulate at the browser level (I originally didn’t mean to, because I wanted it to support also an external browser), luckily I can choose the main browser and I can use electron (which I currently use) or any other framework for running it.

I am looking for soluton to do this part the best way, is there any library (testing one maybe) that simulates those events at the user level? Or any general way to do it in electron (contolling the touch like it’s System’s)? / faking events at the system level for only this app?

My electron code eventally is very simple, it jsut open’s the app in a BrowserWindow with some args, I don’t insists in using electorn, if there is a better and easier way of doing it in other platform like CefSharp or anything else I would be glad to hear.

Any hint and help is appricated.

Why doesn’t this input lose focus?

My background is WPF/Winforms and I am just starting to learn React. From my understanding, on every keypress, the following code will re-render, and so will re-generate the elements including the text box. So the old textbox is thrown away and a new one created (losing focus).

So if the old textbox has focus, and a new textbox is then created after I press a key, how is it that the new text box still has the focus?

Interestingly, when I google this, people seem to experience what I expected, in that you would have to refocus the textbox after each key press. Yet for me, it seems to magically work.

I am guessing that React is being a little smarter here and recycling the elements? or is it still re-creating a new textbox, but restoring focus behind the scenes?

function App() {
  const [userText, setUserText] = useState("empty")

  return (
    <>
      <p>{userText}</p>

      <input type='text' value={userText} onChange={e => setUserText(e.target.value)}/>
    </>
  )
}

export default App

Using custom processor.js file to generate custom JWT header per user when load testing websockets

I am trying to load test a websocket server where I want to add a JSON Web Token (JWT) as a header which is different per user – and that gets passed when establishing the connection.
Here are the files
processor.js

let tokens = [
  "token1",
  "token2,
  "token3"
]
function generateRandomToken (userContext, events, done) {
  userContext.vars.token = tokens[Math.floor(Math.random() * tokens.length)];
  return done()
}

module.exports = {
    generateRandomToken
};

Here is the main yaml file where the load test script is executed

config:
  target: "ws://localhost:8080/userMessages"
  phases:
    - duration: 1
      arrivalRate: 1
  processor: "./processor.js"
  function: "generateRandomToken"
  ws:
    headers:
      x-jwt-token: "{{ token }}"

scenarios:
  - engine: "ws"
    flow:
      - send: "Test message"
      - think: 30

The error that I am getting when executing this is worker error, id: 1 TypeError [ERR_HTTP_INVALID_HEADER_VALUE]: Invalid value "undefined" for header "x-jwt-token"

I see there is a similar issue open here for socketio – it is closed but without any answer – https://github.com/artilleryio/artillery/issues/2003

I am expecting a proper token to be generated on each request.

Change some text after compose.beginReply function in Thunderbird Add-On

I have Thunderbird addon that compose reply to message.

I need to change some text in the replied message.

The code below:

const fullMessage = await browser.messages.getFull(messageId);

        // Extracting the body of the message
         const body = getBodyFromParts(fullMessage.parts);
         if (!body) {
           console.warn("Message body not found:", fullMessage);
           continue;
         }

        // If text in HTML, will transform it
        if (/<[a-z][sS]*>/i.test(body)) {
          body = body
            .replace(/</p>/gi, "n")      // Paragraph wrapping
            .replace(/<brs*/?>/gi, "n") // Line Wrapping
            .replace(/<[^>]+>/g, "");      // Уtake the remaining HTML tags
        }

        // If the text is still stuck together, add line breaks
        if (!body.includes("n")) {
          body = body.replace(/([.!?])s+/g, "$1n"); // Hyphenation after a period, exclamation or question
        }
              
        // Check for the presence of "[AGREE]"
        if (body.includes("[AGREE]")) {
          const newBody = body.replace("[AGREE]", "[AGREE]+");
          console.log("Text newBody after:", newBody);
        
          // Converting line breaks for HTML
          const htmlBody = newBody.replace(/n/g, "<br>");
          console.log("HTML version of newBody:", htmlBody);
               

          //Create a response message
          const composeDetails = await browser.compose.beginReply(message.id, 'replyToSender');
          
          // Set a new body for the response
          await browser.compose.setComposeDetails(composeDetails.id, { body: htmlBody, isPlainText: false });

I have reply message as below:

enter image description here

If use code without this line:

// Set a new body for the response
          await browser.compose.setComposeDetails(composeDetails.id, { body: htmlBody, isPlainText: false });

reply message looking as that:

enter image description here

But I need reply message see as on picture below:

enter image description here

I try to place code:

//Create a response message
const composeDetails = await browser.compose.beginReply(message.id, ‘replyToSender’);
console.log(“Создано сообщение для ответа:”, composeDetails.id);

    // Receive Full message
    const fullMessage = composeDetails;
    

    console.log("Full message:", fullMessage);

     // Extracting the body of the message
     const body = getBodyFromParts(fullMessage.parts);
     if (!body) {
       console.warn("Message body not found:", fullMessage);
       continue;
     }

before Extracting the body of the message.

And I have the error “Parts of message not found”.

How can i make a rating with JavaScript? [closed]

I am trying to create a rating for a feedback website, but i am stuck because after clicking on the number from 1 to 5, i will need to submit which will take me to another page saying you have selected ___ out of 5. That is where i am stuck, Can anyone assist me in that?

const selectedNumber = document.getElementsByClassName("star");
const contentNumber = document.getElementById("content");

var number = divs
var feedBackNumber = [1, 2, 3, 4, 5];

divs.addEventListener("click", function(){

    if (feedBackNumber.includes(divs)){

        contentNumber.innerHTML = "You selected" + feedBackNumber + "out of 5";
    }
})

How to generate a dynamic list with all the tags of blogger?

I created a blog on Google Blogger and I wanted to create a page where I can index all the tags I use, so users can see a list with all the authors.

The thing is I don’t really know how I can retrieve the “internal” information that my blog has, once I can get that info I can filter the specific tags I want or even post titles, etc.

I supose I have to use javascript for that, or maybe blogger api, but as I said, I have no idea what I have to use, or where to start to retrieve the information that my blog has: tags, post title, etc.

What I have now, which is not dynamic at all, is I created a Page on my blog and I added code on a script tag where I write the tags I use and then dynamicaly create an html list with their specific url.

<script>
// Script para generar una lista de autores organizados por letra del abecedario
document.addEventListener("DOMContentLoaded", function() {
    // Lista de autores con el prefijo "autor-nombre-del-autor"
    const etiquetasAutores = [
        "autor:florencia-arriola",
        "autor:mar-gallego",
        "autor:v.e-schwab",
        "autor:leigh-bardugo",
        "autor:madeline-miller",
        // Añadir más autores aquí manualmente
    ];
    
    // Ordenar la lista de autores alfabéticamente
    etiquetasAutores.sort(function(a, b) {
        return a.localeCompare(b);
    });

    // Elemento donde vamos a añadir la lista de autores
    const contenedorAutores = document.getElementById("lista-autores");
    
    // Función para capitalizar cada palabra
    function capitalizarCadaPalabra(texto) {
        return texto.split(" ").map(palabra => 
            palabra.charAt(0).toUpperCase() + palabra.slice(1).toLowerCase()
        ).join(" ");
    }

    // Crear un objeto para organizar autores por letra
    const autoresPorLetra = {};

    // Organizar los autores por la primera letra de su nombre
    etiquetasAutores.forEach(function(etiqueta) {
        const autorNombre = etiqueta.replace("autor:", "").replace(/-/g, " ");
        const nombreCapitalizado = capitalizarCadaPalabra(autorNombre);
        const letraInicial = nombreCapitalizado.charAt(0).toUpperCase();

        // Si la letra no existe en el objeto, crear un array para esa letra
        if (!autoresPorLetra[letraInicial]) {
            autoresPorLetra[letraInicial] = [];
        }
        // Agregar el autor al array correspondiente
        autoresPorLetra[letraInicial].push({ nombre: nombreCapitalizado, url: `https://bitacoramorada.blogspot.com/search/label/${encodeURIComponent(etiqueta)}` });
    });

    // Generar la lista jerárquica
    for (const letra in autoresPorLetra) {
        // Crear un elemento <li> para la letra
        const liLetra = document.createElement("li");
        liLetra.textContent = letra; // Letra del abecedario
        const ulAutores = document.createElement("ul"); // Crear una lista anidada para los autores

        // Agregar autores a la lista
        autoresPorLetra[letra].forEach(function(autor) {
            const liAutor = document.createElement("li");
            const a = document.createElement("a");
            a.href = autor.url;
            a.textContent = autor.nombre;
            liAutor.appendChild(a);
            ulAutores.appendChild(liAutor);
        });

        // Agregar la lista de autores anidada a la letra
        liLetra.appendChild(ulAutores);
        contenedorAutores.appendChild(liLetra);
    }
});
</script>

What I wanted to do, if possible, is to avoid writing myself the tags and getting that info dynamically somehow.

Thanks in advance!

list with item be a link to another page

Iam working on a car maintenance app . I have a page for the spare parts,page for purchasing order
the purchasing order page contain form region to insert master data and an interactive grid region to insert the detail of purchsing order.
the IG contain order_id,spare_parts_category,part_code,qty,unit_price_total_price.
I want the part_code to be a select list or LOV based on the spare_parts_category column and contain an item named NEW_PART when I clicked on it redirect me to another page to insert new spare part in spare parts table.
I have tried to do that as a LOV based on category table union all new_part as display value and -1 as return value
also create a javascript dynamic action to open the new page but nothing happened.
this is the LOV code

SELECT PART_NAME AS DISPLAY_VALUE, PART_ID AS RETURN_VALUE
FROM SPARE_PARTS
UNION ALL
SELECT 'New Part' AS DISPLAY_VALUE, -1 AS RETURN_VALUE
FROM DUAL
ORDER BY DISPLAY_VALUE; 
and this is the JS code
if (this.triggeringElement.value == '-1') {
    apex.navigation.dialog({
        url: 'f?p=&APP_ID.:<13>:&SESSION.::NO:::'
    });
}```
Can anyone help me to do that?

how to pre compile AJV standalone validation code when you have custom keywords?

I am trying to generate pre compile standalone code like so:

https://ajv.js.org/standalone.html

I have an AJV instance created like so:

  const ajv = require("ajv");
  const add_formats = require("ajv-formats");
  const add_errors = require("ajv-errors");
  const ajv_inst = new ajv({
    code: { source: true }, // needed for standalone pre compiled scripts
    allErrors: true,
    $data: true,
  });
  add_errors(add_formats(ajv_inst));

However, I have custom keywords defined like so:

  ajv_inst.addKeyword({
    keyword: "custom_array",
    validate: (schema, data) => {
      try {
        const unique_name = data.map((tar) => {
          return tar.name.toLowerCase().replaceAll(/s+/g, "");
        });
        const unique_id = data.map((tar) => {
          return tar._id;
        });
        return (
          new Set(unique_name).size === data.length &&
          new Set(unique_id).size === data.length
        );
      } catch (err) {
        return false;
      }
    },
    metaSchema: {
      enum: [true],
    },
  });

In order to generate the standalone code with custom keywords, I think the keyword needs to be defined with a code generator function instead of the validate like so:

  code(cxt: KeywordCxt) {
    const {data, schema} = cxt
    const op = schema ? _`!==` : _`===`
    cxt.fail(_`${data} %2 ${op} 0`) // ... the only code change needed is to use `cxt.fail$data` here
  },

https://ajv.js.org/keywords.html#define-keyword-with-validate-function

questions:

  1. Given that I already have the validate property defined, is there a way to generate the pre compiled standalone code with the function defined as is in the validate property?
  2. If not, is there an easy or automated way to convert my validate function into the required code-gen code?

Javascript – How to obtain the *actual* URL of an image?

Consider the following html page:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
    <h1 id="image-title">Loading...</h1>
    <a href="https://loremflickr.com/g/320/240/paris">
        <img id="image" src="https://loremflickr.com/g/320/240/paris" onLoad="correctTitle()")>
    </a>
    <script>
        function correctTitle() {
            const imageElement = document.getElementById('image');
            const titleElement = document.getElementById('image-title');
            titleElement.textContent = 'Image URL: '+imageElement.getAttribute("src");
        }
    </script>
</body>
</html>

This loads an image from the web and displays it, then updates its title to show its URL.
The image is referenced by its URL:
https://loremflickr.com/g/320/240/paris

However, when opening the image directly in the browser (by clicking on it), the address bar of the browser shows its actual URL:
https://loremflickr.com/cache/resized/defaultImage.small_320_240_g.jpg

How should I modify the code to display the actual URL, and not the URL used as reference?

How can I fix this bug in my todo(localstorage) project?

the following code is my html file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="icons/font/bootstrap-icons.min.css">
    <link rel="stylesheet" href="css/theme-light.css" id="theme-link">
    <link rel="stylesheet" href="css/style.css">
    <title>Todos Mananger | ❤️</title>
</head>
<body>
    <div id="main">
        <h2>Things <span style="color: royalblue;">you</span> want to do...</h2>
        <div class="todos-container">
        </div>
        <div id="info-input">
            <input type="text" placeholder="Add New Task" maxlength="20" minlength="1">
            <button class="adder-button"><i class="bi bi-plus"></i></button>
        </div>
    </div>
    <script src="js/app.js"></script>
</body>
</html>

and the js file is here:

    const $ = document;
    function _id(idName) {
        return $.getElementById(idName);
    }
    function _query(queryName) {
        return $.querySelector(queryName);
    }
    function _class(className) {
        return $.getElementsByClassName(className);
    }

    const todosList = _query(".todos-container");
    const info = _query("input");
    const adder = _query(".adder-button");
    const icon = `<i class="bi bi-trash"></i>`;
    let trashIcons;
    let todos;
    let todoToHandle = -1;
    let todoBoxes;
    let newTodo;

    function trashIconHandler() {
        trashIcons = $.querySelectorAll(".bi-trash");
        trashIcons.forEach(function (trashIcon) {
            trashIcon.addEventListener("click", function (event) {
                event.target.parentElement.remove();
                todos = JSON.parse(localStorage.getItem("todos"));
                todos.splice(
                todos.findIndex((todo) => {
                    return todo.name == event.target.parentElement.textContent;
                }),
                1
            );
            localStorage.setItem("todos", JSON.stringify(todos));
            });
        });
    }

    function todoBoxesSelector() {
        todoBoxes = $.querySelectorAll(".todo");
        // changing the status to "completed or vice versa"
        todoBoxes.forEach((todoBox) => {
            todoBox.addEventListener("click", (e) => {
                if (e.target.style.background != "#057719") {
                    e.target.style.background = "#057719";
                    todos = JSON.parse(localStorage.getItem("todos"));
                    todoToHandle = todos.findIndex((todo) => {
                        return todo.name == e.target.textContent;
                    });
                    todos[todoToHandle].completed = true;
                    localStorage.setItem("todos", JSON.stringify(todos));
                } else if (e.target.style.background == "#057719") {
                    e.target.style.background = "#041a48";
                    todos = JSON.parse(localStorage.getItem("todos"));
                    todoToHandle = todos.findIndex((todo) => {
                        return todo.name == e.target.textContent;
                    });
                    todos[todoToHandle].completed = true;
                    localStorage.setItem("todos", todos);
                }
            });
        });
    }
    todoBoxesSelector();
    trashIconHandler();

window.addEventListener("load", () => {
    info.value = "";
    if (localStorage.getItem("todos") !== null) {
        todos = JSON.parse(localStorage.getItem("todos"));
        // adding existing todos to the todo container

        todos.forEach(function (todo) {
            newTodo = $.createElement("div");
            newTodo.className = "todo";
            newTodo.style.background = "#041a48";
            if (todo.completed == true) {
                newTodo.style.background = "#057719";
            }
            newTodo.innerHTML = todo.name + icon;
            todosList.append(newTodo);
        });
    } else {
        localStorage.setItem("todos", JSON.stringify([]));
    }
    trashIconHandler();
    todoBoxesSelector();
});

// todo adder
adder.addEventListener("click", () => {
    if (info.value.trim() != "" && info.value.trim().length <= 20) {
        newTodo = $.createElement("div");
        newTodo.className = "todo";
        newTodo.style.background = "#041a48";
        newTodo.innerHTML = info.value.trim() + icon;
        todos = JSON.parse(localStorage.getItem("todos"));
        todos.push({ name: info.value.trim(), completed: false });
        localStorage.setItem("todos", JSON.stringify(todos));
        todosList.append(newTodo);
    }
    trashIconHandler();
    todoBoxesSelector();
});

the problem is that todos[todoHandler] is basically undefined and that the completed property could not be recognized. So it could not be changed during the assignment process.

Does anyone have a solution for it?
i’d be grateful

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Voluptate sunt odio rem! Consequatur aliquam saepe voluptatum quam aspernatur error! Facilis, vero modi quis nulla accusamus officia nemo eius quasi nesciunt, minus assumenda saepe temporibus nam iste delectus dolor, ipsum tempora nisi illo expedita id architecto vitae consequuntur hic. Modi, facere.

Why is Auth0’s getAccessTokenSilently not retrieving access token from local cache?

I’ve built a react app that uses Auth0 (free plan tier for now) for authentication/authorisation.

I have an Axios interceptor in my react app that calls Auth0’s getAccessTokenSilently and appends the result of that as a bearer token to allow access to an api.

enter image description here

When I click a page says “Users” on my UI, it works but the moment i refresh that page, the above interceptor logic is triggered and getAccessTokenSilently is having to go back to auth0 to retrieve a new access token which causes a few seconds of delay.

Meaning the users page is not populated until after a few seconds when the getAccessTokenSilently returns the access token.

I am aware of the issue causing this as documented here:

https://community.auth0.com/t/why-is-authentication-lost-after-refreshing-my-single-page-application/56276

enter image description here

And there’s also a guide on what needs to be done to fix it:

enter image description here

Which I’ve done but getAccessTokenSilently is still going back to auth0 to retrieve a new access token even though I can clearly see in localStorage that the auth data is there and the token is valid.

Therefore getAccessTokenSilently should retrieve that access token instead of going to Auth0 as it is documented that it will retrieve the existing access token if it is valid otherwise it will ping auth0 to rerieve a new token.

I have also seen this answer on SO Auth0 does not persist login on page refresh for email/password but again doesnt really solve my issue.

My problem is even after having done the above suggested solutions getAccessTokenSilently is still going to auth0 to rerieve a new access token rather than getting it from local storage?

Accessing nestjs-pino logger within util file functions without passing the logger as an argument?

I have a nestjs-pino logger set up within my NestJS API as prescribed by the official docs.

@Module({
  imports: [
    LoggerModule.forRoot({
      pinoHttp: {
        customProps: (req) => ({
          reqId: req.headers['my-tracking-header'] ?? uuidv4() // uuid lib
        })
      }
    }),
    MyModule
  ],
  controllers: [AppController],
})

I am using the logger within my Service files via dependency injection as expected, where I am calling util functions held within separate non class-based util files in which I am wanting to log out from.

MyModule.module.ts

@Module({
  controllers: [MyController],
  providers: [MyService],
})
export class MyModule {}

MyService.module.ts

@Injectable()
export class ContextService {
  constructor(private readonly logger: Logger) {}

  serviceFunction(): any {
    this.logger.log('logging from the service');

    myUtil(this.logger, 'foo'); // Passing the logger as a argument
  }
}

The only quick and dirty solution I’ve had is to actually pass the logger as an argument to my util functions, but this definitely doesn’t feel like the optimal solution.

MyUtils.util.ts

// Taking the logger as an arg
export const myUtil(logger: Logger, content: string): any {
  logger.log({content}, "Logging from the util");
}

Is there a correct approach to take in order to access my logger in my utils?

MongoDb Dynamic Query Build using Javascript

Does someone know how to dynamically adjust a query to MongoDB api ?

For exemple, if I have a data that is defined with 3 fields :

Car {Driver, ProductionYear, Brand}

Still for example, I would like to make a function that takes 2 couple of parameters (2 of the 3 fields of my data Car associated with the value wanted) and return a dynamic query that allows to search by these parameters.

function getQuery(field, value, current_query) {

  // I don't know here how to make the custom request excepting using a if forest which I do not think is a proper way to do this. I would like the function to add another element to the query and then return the query updated
  return (query);
}

//then I could use :
current_query = getQuery("Brand", "Ford", current_query) {
current_query = getQuery("ProductionYear", "2000", current_query) {

//current_query should be equal to { Brand: { $eq: "Ford" }, ProductionYear: { $eq: "2000" } }

db.collection("Cars").find(query).toArray()

Does anyone have an idea ?

Thanks