How do I use php to add custom properties to docx

I am trying to prepare a docx template file with pre-inserted custom properties (Quick Part -> Fields) from a database. The file starts as an empty docx file created in MS Word.

I reviewed this question

But it does not answer my question.

My code is as follows:

$blank_DOCX_template = DATAPATH."formletter_blank_templates/blank.docx";
        
$zip = new ZipArchive;

if ($zip->open($blank_DOCX_template) == true) {
    $updatedXmlContent = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">';
    $id_num = 2;
    foreach($properties as $prop_name=>$prop_val){
         $updatedXmlContent .= '<property fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}" pid="'.$id_num.'" name="'.$prop_name.'"><vt:lpwstr>'.$prop_val.'</vt:lpwstr></property>';
         $id_num++;
    }
    $updatedXmlContent .= '</Properties>';

    $zip->addFromString('docProps/custom.xml', $updatedXmlContent);
    $zip->close();

}else{
    echo "could not open file";
}

Once the code has run (it produces no errors), I can look into the zip file ‘docProps/custom.xml’ and every thing looks right. The xml file exists and has the same content as a file with the same properties manually inserted through the MS Word interface, but when I open the file in MS Word the custom properties inserted from my php code do not appear.

What am I missing?

how to store docx files to cloudinary with multer

i am trying to upload docx file to cloudinary with multer-storage-cloudinary.

here is the code i use

const storage = new CloudinaryStorage({
    cloudinary,
    params: async (req, file) => ({
        folder: 'client-documents',
        resource_type: 'raw',
        allowed_formats: ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx'],
        public_id: `${Date.now()}`
    })
});

const upload = multer({
    storage,
    limits: { fileSize: 10 * 1024 * 1024 } // 10 MB limit
});

but when try with postman i get error

{
    "status": "error",
    "error": {
        "message": "An unknown file format not allowed",
        "name": "Error",
        "http_code": 400,
        "storageErrors": [],
        "statusCode": 500,
        "status": "error"
    },
    "message": "An unknown file format not allowed"
}

and see below my preset:
preset screenshot

what should i do? thanks

Javascript shipping countdown timer not working

I am having a issue with some javascript code on a category page, here is an example of such a page. I am trying to add a javascript shipping countdown timer that says order within x amount of time and it will be delivered on this date. I found some code online but noticed it only worked on the first div element and not the others.

I looked it up on Google and found it was due to the script using byID and others said it was better to use class so I changed the code to use class and queryselector but now it’s not working. Below is the current code I have:

<div class="delivery-text">Super fast delivery available</div>
function isHoliday(date) {
    const holidays = [
        new Date(2024, 0, 1), // New Year's Day
            new Date(2024, 3, 7), // Good Friday
            new Date(2024, 3, 10), // Easter Monday
            new Date(2024, 4, 1), // Early May Bank Holiday
            new Date(2024, 4, 8), // King Charles Coronation
            new Date(2024, 4, 29), // Spring Bank Holiday
            new Date(2024, 7, 28), // Summer Bank Holiday
            new Date(2024, 11, 25), // Christmas Day
            new Date(2024, 11, 26), // Boxing Day
    ];

    for (let i = 0; i < holidays.length; i++) {
        if (date.getFullYear() === holidays[i].getFullYear() &&
                date.getMonth() === holidays[i].getMonth() &&
                date.getDate() === holidays[i].getDate()) {
            return true;
        }
    }
    return false;
}

function isBusinessDay(date) {
    const dayOfWeek = date.getUTCDay();
    return dayOfWeek > 0 && dayOfWeek < 6;
}

function nextBusinessDay(date) {

    let nextDay = new Date(date);
    nextDay.setUTCDate(date.getUTCDate() + 1);

    while (!isBusinessDay(nextDay) || isHoliday(nextDay)) {
        nextDay.setUTCDate(nextDay.getUTCDate() + 1);
    }

    return nextDay;
}

function countdownToDispatch() {

    const now = new Date();
    let dispatchDate;

    //If it's before 11AM, a business day, and not a holiday, our dispatch date is today!

    if (now.getUTCHours() < 14 && isBusinessDay(now) && !isHoliday(now)) {
        dispatchDate = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 14, 0, 0, 0);
    } else {
        dispatchDate = nextBusinessDay(now);
        dispatchDate.setUTCHours(14, 0, 0, 0);
    }

    const timeUntilDispatch = dispatchDate.getTime() - now.getTime();
    const days = Math.floor(timeUntilDispatch / (1000 * 60 * 60 * 24));
    const hours = Math.floor((timeUntilDispatch % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    const minutes = Math.floor((timeUntilDispatch % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor((timeUntilDispatch % (1000 * 60)) / 1000);

    let timeString = '';

    if (days > 0) {
        timeString += days + ' days ';
    }
    if (hours > 0) {
        timeString += hours + ' hours ';
    }
    if (minutes > 0) {
        timeString += minutes + ' minutes ';
    }
    if (seconds > 0) {
        timeString += seconds + ' seconds ';
    }

    return timeString.trim();
}

function setOrderArrivalDate() {
    const now = new Date();

    let dispatchDate;
    if (now.getUTCHours() < 14 && isBusinessDay(now) && !isHoliday(now)) {
        dispatchDate = now;
    } else {
        dispatchDate = nextBusinessDay(now);
    }

    const arrivalDate = nextBusinessDay(dispatchDate);
    let result = countdownToDispatch();

    const formattedDate = arrivalDate.toLocaleDateString("en-GB", {
        weekday: 'long',
        day: 'numeric',
        month: 'long'
    });

    const finalArrivalDateString = formattedDate.split(' ')[0] + ' ' + ordinalSuffix(arrivalDate.getUTCDate()) + ' ' + formattedDate.split(' ')[2];
    //const deliveryText = document.getElementById('delivery-text');
    const deliveryText = document.getElementsByClassName("delivery-text");
    //const deliveryText = document.querySelectorAll('.delivery-text');
    deliveryText.textContent = 'Order within the next ' + result + ' to receive your order on ' + finalArrivalDateString;

}

function ordinalSuffix(i) {
    const j = i % 10, k = i % 100;
    if (j == 1 && k != 11) {
        return i + "st";
    }
    if (j == 2 && k != 12) {
        return i + "nd";
    }
    if (j == 3 && k != 13) {
        return i + "rd";
    }
    return i + "th";
}

setInterval(setOrderArrivalDate, 1000);

Scrolling Glitch

hi i am creating a website and i am experiencing a scrolling glinch. I cant seem to pin-point the problem and I was hoping someone could help me. Currently its taking me 2 scrolls to get to the bottom of the page when it should only take one smooth scroll. For some reason, it always stops at the “about me” section before I have to scroll again to reach the bottom. Same problem when I scroll from the bottom to the top. How do I solve this? What are some things I should look out for?

Website error video

Sperated Strings not picked up in javascript

I’m Using this code to merge two updates. Col c contains current status of a tenant in each cell its for a different tenant. My team ads in col F the update. At the moment code is running but no issues.

function mergeColumnsCAndF() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

// Get all data in columns C and F
const data = sheet.getRange(1, 3, sheet.getLastRow(), 2).getValues(); // Column C (Status) and Column F (Updates)

// Define categories
const categories = {
problems: “Problems”,
payments: “Payments”,
tenantCommitments: “Tenant Commitments”,
landlordObligations: “Landlord Obligations”,
ebm: “EBM Codes”
};

// Loop through each row and merge updates into the status
const mergedData = data.map(([status, update], index) => {
if (!update.trim()) return [status]; // No update, keep the original status

let updatedStatus = status || ""; // Start with existing status
let extractedCategories = {}; // Object to log categories and updates for debugging

// Normalize update string: remove extra spaces and standardize formatting
const normalizedUpdate = update.replace(/s+:s+/g, ":").trim();

// Split updates from F into individual categories
const updates = normalizedUpdate.split(/(?=b(?:Problems|Payments|Tenant Commitments|Landlord Obligations|EBM Codes):)/i);

// Helper function to update a specific category
function updateCategory(category, newInfo) {
  const regex = new RegExp(`${category}:.*?(\n|$)`, "gi"); // Match category in the existing status
  const cleanedStatus = updatedStatus.replace(regex, "").trim(); // Remove existing category info
  return `${cleanedStatus}n${category}: ${newInfo}`.trim(); // Append new category info
}

// Process each update and match it to its category
updates.forEach((item) => {
  const lowerItem = item.toLowerCase();
  if (lowerItem.includes("problems")) {
    updatedStatus = updateCategory(categories.problems, item.split(":")[1].trim());
    extractedCategories[categories.problems] = item.split(":")[1].trim(); // Log Problems
  } else if (lowerItem.includes("payments")) {
    updatedStatus = updateCategory(categories.payments, item.split(":")[1].trim());
    extractedCategories[categories.payments] = item.split(":")[1].trim(); // Log Payments
  } else if (lowerItem.includes("tenant commitments")) {
    updatedStatus = updateCategory(categories.tenantCommitments, item.split(":")[1].trim());
    extractedCategories[categories.tenantCommitments] = item.split(":")[1].trim(); // Log Tenant Commitments
  } else if (lowerItem.includes("landlord")) {
    updatedStatus = updateCategory(categories.landlordObligations, item.split(":")[1].trim());
    extractedCategories[categories.landlordObligations] = item.split(":")[1].trim(); // Log Landlord Obligations
  } else if (lowerItem.includes("ebm")) {
    updatedStatus = updateCategory(categories.ebm, item.split(":")[1].trim());
    extractedCategories[categories.ebm] = item.split(":")[1].trim(); // Log EBM Codes
  }
});

// Log the extracted categories for debugging
Logger.log(`Row ${index + 1}: Extracted Categories: ${JSON.stringify(extractedCategories)}`);

// Remove duplicate lines from the final status
const uniqueLines = [...new Set(updatedStatus.split("n"))].join("n").trim();

return [uniqueLines]; // Return the updated status

});

// Write merged data back into Column C
sheet.getRange(1, 3, mergedData.length, 1).setValues(mergedData);

// Clear all updates in Column F after processing
sheet.getRange(1, 6, data.length, 1).clearContent();

SpreadsheetApp.getUi().alert(“Columns C have been updated with merged statuses, and Column F has been cleared.”);
}

What is the significance of the spread operator in this code?

I am a React newbie. Please help me understand why a spread operator is used in the following. I’ve tried to run the same code without using it and I get all sorts of errors.

App.js contains:

import { useFormInput } from './useFormInput.js';

export default function Form() {
  const firstNameProps = useFormInput('Mary');
  const lastNameProps = useFormInput('Poppins');

  return (
    <>
      <label>
        First name:
        <input {...firstNameProps} />
      </label>
      <label>
        Last name:
        <input {...lastNameProps} />
      </label>
      <p><b>Good morning, {firstNameProps.value} {lastNameProps.value}.</b></p>
    </>
  );
}

The referenced file contains:

import { useState } from 'react';

export function useFormInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  function handleChange(e) {
    setValue(e.target.value);
  }

  const inputProps = {
    value: value,
    onChange: handleChange
  };

  return inputProps;
}

From the little I understand, the spread operator copies/uses slices of arrays. But, I don’t follow how that applies here.

Detect focus enter direction

I need to detect if an element received focus as a result of the user requesting to focus the next element or previous element ( TAB or SHIFT + TAB navigation ).

Is there any native solution for this ?

Using a keydown listener to check if tab or shift was pressed only works as long as the focus doesn’t leave the “document”.

If the element is the first or last focusable element and tab navigation is used the focus will jump to the browser toolbar and the key down listener will not longer work to detect the focus direction.

For accessibility reasons I need to keep the default focus navigation behavior ( Focus jumping to browser toolbar )

Forwarding a discord message with a bot (Javascript)

Discord recently implemented functionality for forwarding messages from one channel (or server) to another. Is there a way for bots to forward messages?

In particular I would like to write a command, say it’s called !forward, where if I reply to a particular message with !forward, it will then forward that message to a specified channel.

I’ve been running this bot for about a year so I’m not brand new to this, but I can’t seem to find any documentation on how/if it’s possible to forward messages with a bot.

Any guidance is appreciated. Thank you!

How to load an LDR file using THREE.js

I am attempting to display an .ldr file in a web page using THREE.js. An .ldr file is a LEGO version of a .mpd file. The THREE.js documentation says to convert the .ldr file to a packed .mpd file, which I have done successfully.

Note: .ldr is a LEGO LDraw file, and a .mpd is a 3D Models to Print file.

I then used the .ldr example from the LDrawLoader documentation and this works. However, I want the simplest version of displaying the .mpd file. The example code has a preloader, a small GUI, and the option to select from a list of .mpd files.

I have attempted to remove the GUI and preloader but it stops everything from working. I’ve tried the code from the documentation (not the examples page) and a similar set of code from the LDraw forum.

I have had limited experience with THREE.js and anything related to 3D animation.

Here is my current working code:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - LDrawLoader</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link type="text/css" rel="stylesheet" href="main.css">
        <style>
            body {
                color: #444;
            }
            a {
                color: #08f;
            }
        </style>
    </head>

    <body>

        <script type="importmap">
            {
                "imports": {
                    "three": "../build/three.module.js",
                    "three/addons/": "./jsm/"
                }
            }
        </script>

        <script type="module">

            import * as THREE from 'three';

            import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

            import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
            import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';

            import { LDrawLoader } from 'three/addons/loaders/LDrawLoader.js';
            import { LDrawUtils } from 'three/addons/utils/LDrawUtils.js';
            import { LDrawConditionalLineMaterial } from 'three/addons/materials/LDrawConditionalLineMaterial.js';

            let container, progressBarDiv;

            let camera, scene, renderer, controls, gui, guiData;

            let model;

            const ldrawPath = 'models/';

            const modelFileList = {
                'Car': 'car.ldr_Packed.mpd',
                'Block': 'block.ldr_Packed.mpd',
            };

            init();

            function init() {

                container = document.createElement( 'div' );
                document.body.appendChild( container );

                camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
                camera.position.set( 150, 200, 250 );

                //

                renderer = new THREE.WebGLRenderer( { antialias: true } );
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.setAnimationLoop( animate );
                renderer.toneMapping = THREE.ACESFilmicToneMapping;
                container.appendChild( renderer.domElement );

                // scene

                const pmremGenerator = new THREE.PMREMGenerator( renderer );

                scene = new THREE.Scene();
                scene.background = new THREE.Color( 0xdeebed );
                scene.environment = pmremGenerator.fromScene( new RoomEnvironment() ).texture;

                controls = new OrbitControls( camera, renderer.domElement );
                controls.enableDamping = true;

                //

                guiData = {
                    modelFileName: modelFileList[ 'Car' ],
                    displayLines: true,
                    conditionalLines: true,
                    smoothNormals: true,
                    buildingStep: 0,
                    noBuildingSteps: 'No steps.',
                    flatColors: false,
                    mergeModel: false
                };

                window.addEventListener( 'resize', onWindowResize );

                progressBarDiv = document.createElement( 'div' );
                progressBarDiv.innerText = 'Loading...';
                progressBarDiv.style.fontSize = '3em';
                progressBarDiv.style.color = '#888';
                progressBarDiv.style.display = 'block';
                progressBarDiv.style.position = 'absolute';
                progressBarDiv.style.top = '50%';
                progressBarDiv.style.width = '100%';
                progressBarDiv.style.textAlign = 'center';


                // load materials and then the model

                reloadObject( true );

            }

            function updateObjectsVisibility() {

                model.traverse( c => {

                    if ( c.isLineSegments ) {

                        if ( c.isConditionalLine ) {

                            c.visible = guiData.conditionalLines;

                        } else {

                            c.visible = guiData.displayLines;

                        }

                    } else if ( c.isGroup ) {

                        // Hide objects with building step > gui setting
                        c.visible = c.userData.buildingStep <= guiData.buildingStep;

                    }

                } );

            }

            function reloadObject( resetCamera ) {

                if ( model ) {

                    scene.remove( model );

                }

                model = null;

                updateProgressBar( 0 );
                showProgressBar();

                // only smooth when not rendering with flat colors to improve processing time
                const lDrawLoader = new LDrawLoader();

        const loader = new LDrawLoader();

                lDrawLoader.setConditionalLineMaterial( LDrawConditionalLineMaterial );
                lDrawLoader.smoothNormals = guiData.smoothNormals && ! guiData.flatColors;
                lDrawLoader
                    .setPath( ldrawPath )
                    .load( guiData.modelFileName, function ( group2 ) {

                        if ( model ) {

                            scene.remove( model );

                        }

                        model = group2;

                        // demonstrate how to use convert to flat colors to better mimic the lego instructions look
                        if ( guiData.flatColors ) {

                            function convertMaterial( material ) {

                                const newMaterial = new THREE.MeshBasicMaterial();
                                newMaterial.color.copy( material.color );
                                newMaterial.polygonOffset = material.polygonOffset;
                                newMaterial.polygonOffsetUnits = material.polygonOffsetUnits;
                                newMaterial.polygonOffsetFactor = material.polygonOffsetFactor;
                                newMaterial.opacity = material.opacity;
                                newMaterial.transparent = material.transparent;
                                newMaterial.depthWrite = material.depthWrite;
                                newMaterial.toneMapping = false;

                                return newMaterial;

                            }

                            model.traverse( c => {

                                if ( c.isMesh ) {

                                    if ( Array.isArray( c.material ) ) {

                                        c.material = c.material.map( convertMaterial );

                                    } else {

                                        c.material = convertMaterial( c.material );

                                    }

                                }

                            } );

                        }

                        // Merge model geometries by material
                        if ( guiData.mergeModel ) model = LDrawUtils.mergeObject( model );

                        // Convert from LDraw coordinates: rotate 180 degrees around OX
                        model.rotation.x = Math.PI;

                        scene.add( model );

                        guiData.buildingStep = model.userData.numBuildingSteps - 1;

                        updateObjectsVisibility();

                        // Adjust camera and light

                        const bbox = new THREE.Box3().setFromObject( model );
                        const size = bbox.getSize( new THREE.Vector3() );
                        const radius = Math.max( size.x, Math.max( size.y, size.z ) ) * 0.5;

                        if ( resetCamera ) {

                            controls.target0.copy( bbox.getCenter( new THREE.Vector3() ) );
                            controls.position0.set( - 2.3, 1, 2 ).multiplyScalar( radius ).add( controls.target0 );
                            controls.reset();

                        }

                        createGUI();

                        hideProgressBar();

                    }, onProgress, onError );

            }

            function onWindowResize() {

                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();

                renderer.setSize( window.innerWidth, window.innerHeight );

            }

            function createGUI() {

                if ( gui ) {

                    gui.destroy();

                }

                gui = new GUI();

                gui.add( guiData, 'modelFileName', modelFileList ).name( 'Model' ).onFinishChange( function () {

                    reloadObject( true );

                } );

                gui.add( guiData, 'flatColors' ).name( 'Flat Colors' ).onChange( function () {

                    reloadObject( false );

                } );

                gui.add( guiData, 'mergeModel' ).name( 'Merge model' ).onChange( function () {

                    reloadObject( false );

                } );

                if ( model.userData.numBuildingSteps > 1 ) {

                    gui.add( guiData, 'buildingStep', 0, model.userData.numBuildingSteps - 1 ).step( 1 ).name( 'Building step' ).onChange( updateObjectsVisibility );

                } else {

                    gui.add( guiData, 'noBuildingSteps' ).name( 'Building step' ).onChange( updateObjectsVisibility );

                }

                gui.add( guiData, 'smoothNormals' ).name( 'Smooth Normals' ).onChange( function changeNormals() {

                    reloadObject( false );

                } );

                gui.add( guiData, 'displayLines' ).name( 'Display Lines' ).onChange( updateObjectsVisibility );
                gui.add( guiData, 'conditionalLines' ).name( 'Conditional Lines' ).onChange( updateObjectsVisibility );

            }

            //

            function animate() {

                controls.update();
                render();

            }

            function render() {

                renderer.render( scene, camera );

            }

            function onProgress( xhr ) {

                if ( xhr.lengthComputable ) {

                    updateProgressBar( xhr.loaded / xhr.total );

                    console.log( Math.round( xhr.loaded / xhr.total * 100, 2 ) + '% downloaded' );

                }

            }

            function onError( error ) {

                const message = 'Error loading model';
                progressBarDiv.innerText = message;
                console.log( message );
                console.error( error );

            }

            function showProgressBar() {

                document.body.appendChild( progressBarDiv );

            }

            function hideProgressBar() {

                document.body.removeChild( progressBarDiv );

            }

            function updateProgressBar( fraction ) {

                progressBarDiv.innerText = 'Loading... ' + Math.round( fraction * 100, 2 ) + '%';

            }

        </script>       

    </body>
</html>

I have a GitHub repo with different attempts here:

https://github.com/codeadamca/nodejs-three-ldr

The best code is one called working.html.

To summarize, I want to remove the GUI and preloader from the THREE.js LDrawLoader example.

loading content thru PHP to simplify or is there a way to load it in a div?

I have my header/css and part of the body including the <div tag for the cell the content is in as one file and then the footer with the and and segment as another file and then have the following code:
How do I make it so it will load content per a PHP page with the content in it… it’s all supposed to go in one div on the page and then the header and footer (the parts of the page that stay the same which is everything except that div) saved as separate files to minimize loading time…

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

$PageTitle="Havent // Heavent Made // Hellt Mindedt // Manualt";

function customPageHeader(){?>
  <!--Arbitrary HTML Tags-->
<?php }

include_once('file:///home/chronos/u-57608984ca0e6dfae1c20c6c0ed79e71e9626f08/MyFiles/Downloads/header.php');

include_once("content");

include_once('file:///home/chronos/u-57608984ca0e6dfae1c20c6c0ed79e71e9626f08/MyFiles/Downloads/footer.php');
?>

Why am I getting the errors “dyld: Library not loaded:” and “zsh: command not found: electron” when making the electron quick start project?

I am trying to learn how to build an electron app, so I decided to try making the quickstart project found on the official website here.

However, I quickly ran into problems because I keep getting errors, and I cannot even begin to build the app because electron won’t run.

I downloaded the latest LTS version of Node.js, and then I ran the following commands in the terminal:

npm init -y
npm i --save-dev electron
touch main.js

I did not modify the main.js file, so it is blank.
I then changed the default scripts in package.json into:

"start": "electron ."

After this, I then ran npm start, but it gave me the following error:

dyld: Library not loaded: /System/Library/Frameworks/UniformTypeIdentifiers.framework/Versions/A/UniformTypeIdentifiers

and it also said Reason: image not found

I tried deleting all the files and restarting from scratch, thinking that I might have made a mistake somewhere.

I tried putting in console.log("Hello World") in the main.js file, and then running npm start again.

I tried shutting down my computer and turning it on again.

None of these things worked.

I also tried to run electron . directly in the command line, and that’s when I got the error zsh: command not found: electron.

I also tried starting over again and making electron a dependency instead of dev dependency, but I still got all the same errors.

I tried googling different keywords and phrases from the errors I received, but I could not find anything that I could try to use as a possible solution.

The only way I could get my main.js to run was if I put node main.js in the command line, and it properly logged Hello World in the terminal.

I’m not sure if it is relevant, but for reference I am using a 2019 16-inch Macbook Pro on macOS Catalina 10.15.7.

If there is already a similar case out there, I apologize that I couldn’t find it due to my lack of experience. I am an absolute beginner in electron and I’m just starting to figure things out. I would appreciate any help on this. Thank you.

Is it possible to create an npm library that uses service workers without requiring end-user script configuration?

The Problem

I want to create an npm library that uses service workers under the hood, where the end user does not need to configure anything—ideally, not even place or reference a sw.js file.

The main challenge I’m facing is that navigator.serviceWorker.register('somePath') requires the somePath to be relative to the final HTML file where the code is executed. This depends on the framework being used, for example:

  • In Next.js, service workers need to be placed in the public/ folder.
  • In Vite, they belong in the project’s root directory.

Since my library lives in node_modules, I don’t have control over these paths.

What I’d like:

  1. Zero setup: by simply running a function, the library takes care of everything else, including registering service workers. The user does not need to configure any path or add files to any specific location in their project.
  2. Fallback option (if zero setup isn’t possible): Provide a simplified setup process to reduce user effort. For example, I considered using type: 'module' during registration:
navigator.serviceWorker.register('somePath', {
  scope: '/',
  type: 'module',
});

Then my idea was for the user to import the library’s service worker script in their framework-specific file (e.g., public/sw.js in Next.js):

// public/sw.js for Next.js or sw.js for Vite
import { serviceWorkerScript } from 'myLibrary';

serviceWorkerScript();

But even this approach has issues. The import path must be relative to the script and does not support libraries installed in node_modules. So that code will throw an error.

I have also found that bypassing the restriction of placing the script in a separate file (e.g. with a string or Blob) is not a valid option.[ 1 ][ 2 ]

My question:

  1. Is it possible to achieve a zero-setup solution where the service worker script is registered and functional without requiring user intervention?
  2. If not, what’s the simplest way to guide users in configuring the service worker, minimizing complexity and effort?

I’m open to alternative approaches or best practices to handle this scenario efficiently. Any help is appreciated!

ReferenceError: dotenv is not defined in Node.js with PM2

I’m encountering a ReferenceError: dotenv is not defined issue in my Node.js backend application managed by PM2. Here’s the breakdown:

Environment Details:

Node.js version: 18.20.5
PM2 version: 5.x
Backend framework: Express.js
Problem Description:
When I try to run my application with PM2, I see the following error in the logs:

ReferenceError: dotenv is not defined
    at Object.<anonymous> (/root/DevTrust/backend/server.js:20:1)
    at Module._compile (node:internal/modules/cjs/loader:1364:14)

What I've Tried So Far:

Installed dotenv using: npm install dotenv –force
Verified it’s in node_modules using npm list dotenv
Ensured the top of server.js has:
javascript

require('dotenv').config();
Verified .env exists in the backend folder and contains required variables:
makefile


OPENAI_API_KEY=your_actual_api_key
Restarted PM2 with:
bash

pm2 restart backend
pm2 save

Tried running the server directly using node server.js (it works fine).
Logs from PM2:
When running pm2 logs backend –lines 50, I see repeated ReferenceError: dotenv is not defined.

Expected Behavior:
The backend server should load environment variables from the .env file without any errors when started with PM2.

Actual Behavior:
It keeps failing with ReferenceError: dotenv is not defined.

How can I ensure that dotenv is properly loaded and recognized by PM2 when running the backend server?

Any insights or suggestions are appreciated. Thanks in advance!

How to reliably check Casper (CSPR) balance in Electron js application?

I’m building an Electron app (Node 18) to check cryptocurrency balances, including Casper (CSPR). However, I’m getting “No working endpoints found” errors when trying to check CSPR balances.

**Error Message:**
javascript
Testing available endpoints...
Testing endpoint: https://rpc.mainnet.casperlabs.io
Testing endpoint: https://casper-node.services.dev.z7x.org
// ... more endpoints ...
Endpoint https://casper-node.services.dev.z7x.org failed: getaddrinfo ENOTFOUND
Found 0 working endpoints
CSPR balance check failed: Error: No working endpoints found

Here the code to check the CSPR enpoint

async function testEndpoint(url) {
    try {
        console.log(`Testing endpoint: ${url}`);
        const response = await axios.post(`${url}/rpc`, {
            jsonrpc: "2.0",
            id: "0",
            method: "info_get_status",
            params: []
        }, {
            timeout: 10000,
            headers: { 'Content-Type': 'application/json' },
            validateStatus: status => status < 500,
            httpsAgent: new require('https').Agent({
                rejectUnauthorized: false,
                timeout: 10000
            })
        });
        
        if (response.data && !response.data.error) {
            console.log(`Endpoint ${url} is working`);
            return true;
        }
        console.log(`Endpoint ${url} returned invalid data:`, response.data);
        return false;
    } catch (error) {
        console.log(`Endpoint ${url} failed:`, error.message);
        return false;
    }
}

and balance checking function

async function getCSPRBalance(key) {
    try {
        const formattedKey = normalizePublicKey(key);
        
        const endpoints = Array.isArray(config.casper.apiUrl) 
            ? config.casper.apiUrl 
            : [config.casper.apiUrl];
        
        // Test endpoints in parallel
        const endpointTests = endpoints.map(endpoint => testEndpoint(endpoint));
        const results = await Promise.allSettled(endpointTests);
        
        const workingEndpoints = endpoints.filter((endpoint, index) => 
            results[index].status === 'fulfilled' && results[index].value === true
        );
        
        if (workingEndpoints.length === 0) {
            throw new Error('No working endpoints found');
        }

        // Try each working endpoint
        for (const baseUrl of workingEndpoints) {
            try {
                const url = `${baseUrl}/rpc`;
                const rpcKey = `01${formattedKey}`;

                const accountResponse = await axios.post(url, {
                    jsonrpc: "2.0",
                    id: "1",
                    method: "state_get_account_info",
                    params: {
                        public_key: rpcKey
                    }
                });

                // ... rest of balance checking logic ...
            } catch (endpointError) {
                // Continue to next endpoint
            }
        }
    } catch (error) {
        return {
            success: false,
            error: error.message || 'Failed to check CSPR balance',
            address: key
        };
    }
}

the endpoints

const endpoints = [
    'https://rpc.mainnet.casperlabs.io',
    'https://casper-node.services.dev.z7x.org',
    'https://casper-proxy.liquidstaking.com',
    'https://casper-node-proxy.dev.z7x.org',
    'https://node.casper.network.dev.z7x.org'
];

I’ve tried:

Using different Casper RPC endpoints
Adding SSL/TLS error handling
Implementing timeout and retry mechanisms
Disabling SSL verification for testing

The sample public key I’m testing with: 0203d9f49b0d76a3f14482ab11926f0d5f792e933f3df824dc1e0b07104474c4c3b3
Questions:

Are there more reliable Casper RPC endpoints I should be using?
Is there something wrong with my endpoint testing approach?
Are there specific considerations for making RPC calls to Casper nodes from an Electron app?

Environment:

Electron
Node.js 18
axios for HTTP requests
casper-js-sdk for key handling

Any help would be greatly appreciated!