Solution for [email protected] LocalAuth App Crashing When User Logs Out Manually on Phone

Issue:
If you’re using [email protected] with LocalAuth and encounter an issue where the app crashes when a user logs out manually from their phone, this is due to an error in the logout method of the LocalAuth.js file.

The error occurs because the fs.promises.rm() method does not handle retries properly, causing the app to crash if the session directory removal fails.

Solution:
Update the LocalAuth.js file to include a retry mechanism for removing the session directory. Here’s the fix:

Old Code (in LocalAuth.js):

'use strict';

const path = require('path');
const fs = require('fs');
const BaseAuthStrategy = require('./BaseAuthStrategy');

class LocalAuth extends BaseAuthStrategy {
    constructor({ clientId, dataPath }={}) {
        super();

        const idRegex = /^[-_w]+$/i;
        if(clientId && !idRegex.test(clientId)) {
            throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
        }

        this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
        this.clientId = clientId;
    }

    async logout() {
        if (this.userDataDir) {
            await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
                .catch((e) => {
                    throw new Error(e);
                });
        }
    }
}

module.exports = LocalAuth;

New Code (in LocalAuth.js):

'use strict';

const path = require('path');
const fs = require('fs-extra');
const BaseAuthStrategy = require('./BaseAuthStrategy');


// Helper function

async function deleteDirectoryWithRetries(path, retries = 5, delayMs = 500) {
    for (let attempt = 1; attempt <= retries; attempt++) {
        try {
            await fs.rm(path, { recursive: true, force: true });
            console.log(`Successfully deleted directory: ${path}`);
            return;
        } catch (error) {
            if (error.code === 'EBUSY' && attempt < retries) {
                console.warn(`Attempt ${attempt} to delete directory failed due to EBUSY. Retrying in ${delayMs}ms...`);
                await new Promise(res => setTimeout(res, delayMs));
            } else {
                throw error;
            }
        }
    }
}

////



/**
 * Local directory-based authentication
 * @param {object} options - options
 * @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
 * @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/" 
*/
class LocalAuth extends BaseAuthStrategy {
    constructor({ clientId, dataPath } = {}) {
        super();

        const idRegex = /^[-_w]+$/i;
        if (clientId && !idRegex.test(clientId)) {
            throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
        }

        this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
        this.clientId = clientId;
    }

    async beforeBrowserInitialized() {
        const puppeteerOpts = this.client.options.puppeteer;
        const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
        const dirPath = path.join(this.dataPath, sessionDirName);

        if (puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
            throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
        }

        fs.mkdirSync(dirPath, { recursive: true });

        this.client.options.puppeteer = {
            ...puppeteerOpts,
            userDataDir: dirPath
        };

        this.userDataDir = dirPath;
    }

    async logout() {
        if (this.userDataDir) {
            try {
                // 1) First, gracefully shut down the client/browser
                if (this.client) {
                    await this.client.destroy();
                }

                // 2) Then, remove the session files from disk
                await deleteDirectoryWithRetries(this.userDataDir);

                console.log('Logout completed successfully. Session directory removed.');

            } catch (e) {
                console.error(`Logout failed: ${e.message}`);
                // throw new Error(`Logout failed: ${e.message}`); // or handle it as needed
            }
        }
    }

}

module.exports = LocalAuth;

How to Use:
To apply this fix, use the patched library from GitHub by installing it directly:

npm install github:Max77788/whatsapp-web.js#fix/localauth-logout

This will pull the updated LocalAuth.js file with the retry mechanism added to the logout method.

Why This Works:
The new implementation includes a maxRetries option for fs.promises.rm() to ensure that session directory removal is retried in case of transient file system issues. This prevents the app from crashing during a manual logout.

If you still face issues, feel free to comment below!

How do I get onmouseenter and onmouseleave to report with respect to an image rather than to its containing div?

Consider an img contained in a div. (See example below.) I’d like onmouseenter and onmouseleave to trigger when the pointer enters and leaves an image, but instead they trigger when the pointer enters and leaves… the image’s container?!? How do I fix this?

Things that work but are unsuitable for my purposes:

  • removing width: 100%; from the container’s styling
  • changing object-fit: contain; in the image’s styling
function mouse_entered() {
  console.log("mouse entered!")
}

function mouse_left() {
  console.log("mouse left!")
}
.image-container {
  width: 100%;
  height: 100vh;
}

.image {
  width: inherit;
  height: inherit;
  object-fit: contain;
}
<div class="image-container">
  <img src="https://lh3.googleusercontent.com/-s05ILbxi6YA/AAAAAAAAAAI/AAAAAAAAACc/yAd6W8jNSBI/photo.jpg?sz=256"
     class="image"
     onmouseenter="mouse_entered()"
     onmouseleave="mouse_left()"
>
</div>

Slow rendering of image from cache

I try to dynamically prefetch the next image on mouse enter or after 400ms. The network tab shows that it works correctly. But even though the network tab says that it is cached and not making a request the first render of any image is slower than the next ones. Any ideas why?


function RouteComponent() {
    const images = {
        1: "https://images.unsplash.com/photo-1721332149274-586f2604884d?q=80&w=1936&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
        2: "https://plus.unsplash.com/premium_photo-1736798695947-2c7661f72bc8?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
        3: "https://images.unsplash.com/photo-1735732519861-3b67d0aee297?q=80&w=1935&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
        4: "https://images.unsplash.com/photo-1735767976699-6096acda642d?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
        5: "https://plus.unsplash.com/premium_photo-1732721750556-f5aef2460dfd?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
    }

    const [page, setPage] = useState(1)
    const loadedImagesRef = useRef(new Set<number>([1]))

    const handleChange = (_event: React.ChangeEvent<unknown>, value: number) => {
        setPage(value) // Update the state with the new page
        console.log("Current page:", value) // Log the current page
        setTimeout(() => {
            fetchNewImage(value)
            console.log("fired")
        }, 400)
    }

    const fetchNewImage = (value: number) => {
        if (!images[(value + 1) as keyof typeof images]) {
            return
        }
        if (loadedImagesRef.current.has(value + 1)) {
            return
        }
        const img = new Image()
        img.src = images[(value + 1) as keyof typeof images]
    }

    const handleHover = () => {
        fetchNewImage(page)
    }

    return (
        <Box
            sx={{
                border: "1px solid red",
                height: "100vh",
                display: "flex",
                flexDirection: "column",
                justifyContent: "end",
                alignItems: "center",
                paddingBottom: "50px",
            }}
        >
            <Box
                sx={{
                    border: "1px solid red",
                }}
            >
                <img src={images[page as keyof typeof images]} alt="d" width="500px" />
            </Box>
            <Pagination count={5} page={page} onChange={handleChange} onMouseEnter={handleHover} />
        </Box>
    )
}

Where should I start software, except for cliché answers? [closed]

I am a 2nd year software engineer student and I have no knowledge about software.I don’t know where and how to start this journey.When I start doing research, I always get the same cliché answers and frankly I can’t start this process.Where and how should I start this journey? How can I decide which field to turn to? First of all, what do I need to know about software before learning coding language? Can you share your experiences with me?

I tried to learn html, css, java, c ++, but I could not learn anything because I did not know the basics of software and I could not determine how to work from Turkish sources or channels because my English level is a2 level.

I want to use URLs in Vue.js to navigate between pages

I am developing an application using Spring Boot for the backend and Vue.js for the frontend.

I want to navigate to a specific page using the following URL:
localhost:8080/event_detail/:role/:objectId/:eventId.

Navigation works correctly when using a button, but when I type the URL directly into the browser, the backend processes the request, and the intended page is not displayed.

What I want to achieve is for the application to behave the same way when the URL is entered directly as it does when navigating via a button.

Here is my router.js configuration:

router.js { path: '/event_detail/:role/:objectId/:eventId', name: 'EventDetail', component: event_detail, props: true, }

Here is the backend controller:

@RestController @RequestMapping("/event_detail") public class EventDetailController {
@Autowired
private EventDetailService eventService;

@GetMapping("/{role}/{objectId}/{eventId}")
public ResponseEntity<Map<String, Object>> getEventDetail(
        @PathVariable String role,
        @PathVariable ObjectId objectId,
        @PathVariable String eventId) {
}
}

Here is the code for navigating via a button:

redirectToEventPage() {this.$router.push({ path: this.Url });} else {alert("B");},

This question was generated using automatic translation.

Fitty Library text overflow issue after removal when resizing beyond initial width in React

I’m currently working on a React project where I’m using Fitty to dynamically resize text to fit its container. The library works well for shorter text like “AAAAAAA” or “AAA AAA A AAA,” but I’ve encountered an issue with very long words.

When the window width exceeds the initial size at which Fitty was applied, the code removes Fitty, assuming it’s no longer needed. However, this causes issues with very long words that fail to wrap correctly:

Fitty adjusts the text size based on the starting window width (e.g., 1200px) and stores it as initialWidth (a local variable).
When the window width exceeds initialWidth (e.g., resized to 1400px), Fitty is removed, and the text reverts to its original size, causing overflow and breaking the layout.
This is particularly problematic for long words like “AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA”, which fail to wrap correctly.

I’ve attempted removing Fitty when the window width increases beyond initialWidth. However, removing Fitty causes text overflow for longer words.
I experimented with checking initialWidth to reapply Fitty, but the solution doesn’t address cases where text still overflows after Fitty is removed.

How to access variable from module in the global scope with JS

I have this code in my index.html:

<script type='module'>

import { Synthetizer } from "xxx.js";

window.test = () => {

    const synth = new Synthetizer(context.destination,soundFontBuffer);

};

window.customfunction = () => {

    //Here I need to use the variable `synth` created when `window.test` was executed. 
    synth.setProperty();

};

</script>
    

I have a div element on my page and the onclick event of that element triggers the function customfunction(); however I cant find a way to access the variable synth. I tried setting the synth variable as global with var however for some reason the library stops working, it only allows me to use const when using that variable synth.

Any idea how I can solve this?

Suppress warnings in bun js for HTMLParseError using non-html markup

I am using bun (and a library called bun-plugin-html) to inject css and javascript and build a source html file to a target file.

The html is actually a Tumblr template so it uses handlebars/moustache-like syntax for variables.

Currently bun is clever enough that it complains about the markup not being valid.

It does seem to work and parse the file, but I would like to suppress these warnings in the console. I am assuming this is possible.

Although the file uses curly braces style syntax, it is not the same as an .hbs file (that seems to use the rewriter in a different way). Any pointers? Can’t seem to find much information online about this, but maybe it’s not a bun issue (hence the jsdom tag).

Here is an example

   <li class="post photo">
      {LinkOpenTag}
         <img src="{PhotoURL-500}" {block:HighRes}style="display:none"{/block:HighRes} />
             {block:HighRes}
                           ^
HTMLParseError: Specified <img> src '{PhotoURL-500}' does not exist!

Screenshot with a bit more context.

enter image description here

How do I set the values of several variables in a simple algebraic method relating to each other in Javascript?

I am trying to make a program to procedurally generate a circular language. I already crafted the letters and am going to hardcode them after I set up the foundations. I have an issue where I cannot manage to get three variables to change based on a simple algebraic equation. I want the long length to be thrice the length of the small, and the medium twice the length of the small.

The way I wanted to do it was a long the lines of this(yes 270 is the full rotation, the code is a little wacky, don’t judge);

270=(3*longLength*longCount)+(2*mediumLength*mediumCount)+(shortLength*shortCount);

which doesn’t work for various reasons, but the point is that I need the length vars to be defined such that they are 1:2:3 ratio, and when you add the lengths of every character it reaches 270. right now I am using a variant of that code,

//def vars
var shortLength;
var mediumLength;
var longLength;
var shortCount=0;
var mediumCount=0;
var longCount=0;
//I have a counting and input function that works, that's all that needs to be said there, assume that the Values of the counts are neither identically valued, nor at 0
if (totalCount>1){
    shortLength=((-3*longLength*longCount)+(-2*mediumLength*mediumCount)+270)/shortCount;
} else {
    shortLength=270;
    mediumLength=270;
    longLength=270;
}

which is scuffed and does not work at all as expected.

Is there a way to link it? L.Routing.control spliceWaypoints - marker option & bindPopup

■ spliceWaypointsに option & bindPopupを 関連付けたい
    ( want to associate [1] and [2])

 ★個別追加(Individual Addition) 
// https://www.npmjs.com/package/leaflet-routing-machine/v/2.2.4
//start:0,Move:1 /Add:0 /latlng
routeControl.spliceWaypoints(0, 0, [38.2601, 140.8824]); ---------[1]

//↓↓ 同じマーカーを追加しても、二重に重なって希望の結果が得られない
    (Adding the same marker results in duplicates and the desired results are not achieved)
L.marker([38.2601, 140.8824], {     --------------------------------[2]
        icon: startIcon,
        draggable: true
        }).bindPopup('popupText')

I want to export geojson with popup comments and then import it, and I want to include the popup comments. I’ve tried various things but I haven’t gotten the results I want.

PS
Because the questions are from Japanese people, some of the questions are difficult to understand.

Problem with Flask subprocess using Electron-builder

I’m testing with electron, it’s the first time I’ve used it to package a desktop application. My application is composed of a frontend made in React and the backend in flask.

My flask application was packaged with pyinstaller, this app runs a local server on the PC where the electron application is opened

My problem is that when I run the application everything runs perfectly, but when I close it the local flask server remains running in the background, and I want the process to end when closing the app so as not to generate performance problems.

thread i’m talking about

I tried many things but I can’t get the application to finish the process when closing the application. If anyone had a similar problem and can help me, I would be very grateful. Thanks.

This is the main.js electron config:

const { app, BrowserWindow } = require('electron');
const { execFile, exec } = require('child_process');
const path = require('path');
const kill = require('tree-kill');

let mainWindow;
let flaskProcess;

app.on('ready', () => {

    // Iniciar Flask

    flaskProcess = execFile(
      path.join(__dirname, 'back', 'dist', 'main.exe'),
      (error, stdout, stderr) => {
          if (error) {
              console.error(`Error al ejecutar el backend Flask: ${error.message}`);
          }
          if (stderr) {
              console.error(`Errores del backend Flask: ${stderr}`);
          }
      }
  );


    // Crear la ventana principal
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            nodeIntegration: true,
        },
    });

    // Cargar la aplicación React
    mainWindow.loadFile(path.join(__dirname, 'build', 'dist', 'index.html'));

    mainWindow.on('closed', () => {
        if (flaskProcess) {
            console.log('Cerrando el servidor Flask...');
            flaskProcess.kill('SIGKILL');
        }
        mainWindow = null;
    });
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
      app.quit();
    }
  });

// Detener Flask al salir
app.on('quit', () => {
    if (flaskProcess && !flaskProcess.killed) {
        console.log('Cerrando el servidor Flask...');
        kill(flaskProcess.pid, 'SIGKILL', (err) => {
            if (err) {
                console.error(`Error al cerrar el proceso: ${err.message}`);
            } else {
                console.log('Servidor Flask cerrado correctamente.');
            }
        }); // Fuerza la terminación del proceso
    }
});

As you can see I’m forcing the closure with SIGKILL, I also tried with SIGTERM, but neither of them works for me.
I saw somewhere that you have to capture these signals from my flask backend in the following way

Flask code

import signal
import sys

def handle_exit(signal, frame):
    print('Cerrando Flask...')
    sys.exit(0)

signal.signal(signal.SIGINT, handle_exit)
signal.signal(signal.SIGTERM, handle_exit)

This is mi package.json electorn config

{
  "devDependencies": {
    "electron": "^34.0.0",
    "electron-builder": "^25.1.8"
  },
  "name": "appprueba",
  "version": "0.1.0",
  "description": "Aplicacion de prueba",
  "author": {
    "name": "Benja",
    "email": "[email protected]"
  },
  "main": "main.js",
  "scripts": {
    "build": "react-scripts build",
    "electron": "electron .",
    "dist": "electron-builder"
  },
  "build": {
    "appId": "com.appprueba.id",
    "productName": "Aplicacion Prueba",
    "directories": {
      "output": "dist"
    },
    "files": [
      "build/**/*",
      "back/**/*",
      "main.js",
      "preload.js"
    ],
    "extraFiles": [
      {
        "from": "back/dist/",
        "to": "back/dist/",
        "filter": [
          "**/*"
        ]
      }
    ],
    "mac": {
      "category": "public.app-category.utilities"
    },
    "win": {
      "target": "nsis",
      "requestedExecutionLevel": "requireAdministrator"
    },
    "linux": {
      "target": "AppImage"
    }
  },
  "asar": true,
  "dependencies": {
    "tree-kill": "^1.2.2"
  }
}

Fix the position of an infobox relative to a sigma.js node

I was experimenting with sigma.js with the help of AI,and I had a need to click a node and make it show me a info box of information. I added the info box and two nodes so I could test, but I can’t seem to make the info box stay put right below the node, it appears on the top left corner when I click, and nothing I did changed that. Here is the code:

import Graph from "graphology";
import Sigma from "sigma";

// Create a new graph instance
const graph = new Graph();

// Add nodes and an edge to the graph
graph.addNode("1", { label: "Node 1", x: 0, y: 0, size: 10, color: "blue" });
graph.addNode("2", { label: "Node 2", x: 1, y: 1, size: 20, color: "red" });
graph.addEdge("1", "2", { size: 5, color: "purple" });

// Get the container element from the HTML
const container = document.getElementById("container");
if (!container) {
  console.error("Container element not found. Make sure #container exists in the HTML.");
} else {
  // Initialize Sigma renderer
  const renderer = new Sigma(graph, container);

  // Create a div to act as the info box
  const infoBox = document.createElement("div");
  infoBox.style.position = "absolute";
  infoBox.style.border = "1px solid #ccc";
  infoBox.style.backgroundColor = "#fff";
  infoBox.style.padding = "10px";
  infoBox.style.zIndex = "1000";
  infoBox.style.display = "none"; // Initially hidden
  document.body.appendChild(infoBox);

  // Add event listener for node clicks
  renderer.on("clickNode", (event) => {
    const nodeId = event.node;
    const nodeAttributes = graph.getNodeAttributes(nodeId);

    // Populate the info box with node details
    infoBox.innerHTML = `
      <h3>Node Details</h3>
      <strong>${nodeAttributes.label}</strong>
      <p>This node has a size of ${nodeAttributes.size} and is colored ${nodeAttributes.color}.</p>
      <p>Feel free to explore the graph!</p>
    `;

    // Get the screen coordinates of the node
    const nodeDisplayData = renderer.getNodeDisplayData(nodeId);
    if (nodeDisplayData) {
      // Offset the coordinates to position the info box correctly in the viewport
      const containerRect = container.getBoundingClientRect();
      const adjustedX = containerRect.left + nodeDisplayData.x - infoBox.offsetWidth / 2;
      const adjustedY = containerRect.top + nodeDisplayData.y - infoBox.offsetHeight - 10; // Position above the node

      // Set the info box position
      infoBox.style.left = `${adjustedX}px`;
      infoBox.style.top = `${adjustedY}px`;
      infoBox.style.display = "block";

      // Log the final coordinates of the text box to the console
      console.log(`InfoBox Coordinates: X = ${adjustedX}, Y = ${adjustedY}`);
    }
  });

  // Add event listener to hide the info box when clicking on the stage
  renderer.on("clickStage", () => {
    infoBox.style.display = "none";
  });
}

I tried to change the way it calculated the screen coordinates, but no matter what I changed, the info box continues to appear on the top left corner of my screen.

Kendo Splitter not working well with angular on collapsing dynamic panels

I’m using kendo-ui with angular for four horizontal panels.

when the last panel is toggled it opens and after resizing it if I close it by toggle, the space previously occupied by the last panel stays unoccupied by the adjacent panel

Upon closing the last panel, I want the adjacent panel to take up it’s space

kendo version v17.2.0

Here’s the stackblitz of the repo

https://stackblitz.com/edit/angular-m7fxze-lohztkxe?file=src%2Fapp%2Fapp.component.ts

steps to reproduce:

  1. Click on Toogle 4th Panel button. This opens 4th panel on the right side.
  2. Resize the last panel by using cursor.
  3. Click on Toggle 4th panel, You observe the space previously occupied by 4th panel is empty.

Expectation:
Upon toggling 4th panel the space previously occupied by 4th panel should now be occupied by 3rd panel.

Thanks in advance

Javascript calling the same function separately on different classes

I need to call the same function separately on separate HTML elements. Specifically, that of this repo (now archived, or I would ask there). It gathers all of the elements of a class/figure to put them into a single PhotoSwipe gallery, which I need it to do, but I also need to have several separate galleries on the same page, but this library gathers all of the images and puts them all into every gallery. For that same reason I can’t, say, separate the images of each gallery by class and pass all of them in an array, since they all end up together.

The solution I’ve come upon, which does work, is to call the function repeatedly for each gallery’s class, ie:

initPhotoSwipeFromDOM('.images-container01nnb figure');
initPhotoSwipeFromDOM('.images-container02nnc figure');
initPhotoSwipeFromDOM('.images-container03rv figure');

But, n00b though I am, I still see that as ugly, inelegant, repetitive code. As well, I’m unsure from a performance perspective if that is particularly inefficient or shouldn’t be done in that way? Either way, there surely must be a better, cleaner, more elegant way to call that same function separately on distinct HTML classes?

How to print to stdout or console.log in wdio repl

I am using appium and webdriverio for some mobile app testing. I am debugging some code in the wdio REPL, which I run with npx wdio repl {wdio.conf.js} -h {host} -p {port}. The REPL seems to be working for my needs, however, console.log('foo'); returns undefined and so does process.stdout.write('foo');. However, if I just run node for a plain node repl, I can use either of those commands to print to the console. In the wdio repl, I can do let foo = 'bar'; then call foo which will print 'bar' but this doesn’t work when I attempt to print within a function by calling foo. How can I print to the console in the wdio repl, either by console.log(), process.stdout.write(), or other means?