Node.js/Vite SSR: ERR_UNSUPPORTED_DIR_IMPORT with @mui/material/utils during Inertia.js SSR

I’m encountering an ERR_UNSUPPORTED_DIR_IMPORT error during server-side rendering (SSR) with Vite, React, MUI (Material UI), and Inertia.js. The specific error message is:

Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/var/www/html/myproject/node_modules/@mui/material/utils' is not supported resolving ES modules imported from /var/www/html/myproject/node_modules/@mui/icons-material/esm/utils/createSvgIcon.js
Did you mean to import "@mui/material/node/utils/index.js"?

This error only occurs during the SSR process (php artisan inertia:start-ssr). The client-side build works fine.

Problem Context:

I’m using the following technologies:

  • Laravel: 11.38.2
  • Inertia.js: 2.0.0
  • React: 19.0.0
  • MUI (Material UI): 6.4.0
  • Vite: 6.0.7
  • Node.js: 22.13.0
  • npm: 10.9.2

What I’ve Tried:

  1. Corrected config/inertia.php: I’ve ensured that the bundle path in my config/inertia.php file correctly points to the SSR bundle generated by Vite (which is now in bootstrap/ssr/ssr.js):

    'bundle' => base_path('bootstrap/ssr/ssr.js'),
    
  2. noExternal Configuration: I’ve added the relevant MUI packages, lexical packages, react packages and @inertiajs/server to the ssr.noExternal array in my vite.config.js:

    ssr: {
        noExternal: [
            '@inertiajs/server',
            '@mui/material',
            '@mui/utils',
            '@mui/system',
            '@mui/styled-engine',
            '@emotion/react',
            '@emotion/styled',
            '@lexical/code',
            '@lexical/react',
            'lexical',
            'react-dom/server',
            'react'
        ],
    },
    
  3. Clean Install: I’ve tried removing node_modules, package-lock.json, clearing the npm cache, and reinstalling dependencies.

  4. Updated MUI: I have updated MUI to the latest version.

  5. Corrected imports in ssr.jsx: I have checked my imports in the ssr.jsx file.

  6. verified vite config output and ssr output: I have verified the output of the vite config, and the ssr output directory.

Relevant Code Snippets:

  • vite.config.js:

    import { defineConfig } from 'vite';
    import laravel from 'laravel-vite-plugin';
    import react from '@vitejs/plugin-react';
    
    export default defineConfig({
        plugins: [
            laravel({
                input: 'resources/js/app.jsx',
                ssr: 'resources/js/ssr.jsx', 
                refresh: true,
            }),
            react(),
        ],
        build: {
            outDir: 'public/build',
        },
        ssr: {
            build: {
                outDir: 'bootstrap/ssr',
            },
            noExternal: [
                '@inertiajs/server',
                '@mui/material',
                '@mui/material/utils',
                '@mui/utils',
                '@mui/system',
                '@mui/styled-engine',
                '@mui/icons-material',
                '@emotion/react',
                '@emotion/styled',
                '@lexical/code',
                '@lexical/react',
                'lexical',
                'react-dom/server',
                'react'
            ], 
        },
        resolve: {
            alias: {
                '@': '/resources/js',
                '@css': '/resources/css',
                '@shared': '/resources/js/Shared',
                '@utils': '/resources/js/utils',
            }
        },
    });
    
  • config/inertia.php:

    <?php
    
    return [
        'ssr' => [
            'enabled' => env('INERTIA_SSR_ENABLED', true),
            'url' => env('INERTIA_SSR_URL', 'http://127.0.0.1:13714'),
            'bundle' => base_path('bootstrap/ssr/ssr.js'),
        ],
    ];
    
  • resources/js/ssr.jsx:

    import React from 'react';
    import { createInertiaApp } from '@inertiajs/react';
    import createServer from '@inertiajs/react/server'
    import { renderToString } from 'react-dom/server';
    import Layout from '@shared/Layout';
    
    createServer((page) =>
        createInertiaApp({
            page,
            render: renderToString,
            resolve: name => {
              const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
              return pages[`./Pages/${name}.jsx`]
            },
            setup({ App, props }) {
                return <Layout children={<App {...props} />} />;
            },
        })
    );
    

Expected Behavior:

I expect the SSR server to start without any ERR_UNSUPPORTED_DIR_IMPORT errors.

Actual Behavior:

The ERR_UNSUPPORTED_DIR_IMPORT error persists, preventing the SSR server from starting.

Question:

How can I resolve the ERR_UNSUPPORTED_DIR_IMPORT error with @mui/material/utils during Vite SSR with Inertia.js? Is there a specific configuration or workaround needed to handle MUI’s internal module resolution in this context?

Dynamic Loading of HTML Content via Main

This is regarding my website, https://illegal.solutions

I thought I had found a way to dynamically load my posts (css class “container”) into the “frame” of my navigation/styling. So being able to move from index to post, back to index, to another post, all while only refreshing what is in the container.

Here is a simple mockup of what I’m meaning (red marking the container that would be loading independently)

Is there a way to accomplish this with just CSS/HTML? Or will this require Javascript to work as intended? Currently published to the site is what I thought would work.

Code below:

main page:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>illegal solutions, today</title>
    <link rel="stylesheet" type="text/css" href="style.css" /> 
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
  </head>
    

<body>

<div class="sidebg">
<div class="side">
 
<img class="avatar" src="https://web.archive.org/web/20090904015821im_/http://geocities.com/kevin1ofmany/rotating_computer.gif">

<p class="desc">This site is a work in progress, like I am. Do not acknowledge me.</p>

<h2 class="sideheaders">Navigate</h2>
<ul>
<li><a href=/index.html target="main">Home</a></li>
<li><a href=/about.html>About</a></li>
<li><a href="https://bsky.app/profile/totallygeeky.bsky.social">Not Twitter</a></li>
<li><a href="https://kagi.com/proxy/1-photo-u1?c=0zPNkpqGwJJtXvXLTEEJHlb14a9ryWYz1E9QKFdphGBQskzfpwNi24b_s5_--oHxW07aiB-vwPF8dv3KWYZYH_7Zd4gv2A0lLwDs-bx5fepBys2iKYKzLZDPng4pKTXdOmZrlos_ZowiNC3a2aQTAkadVyMiL36VMbNa_C52BGLTdPAkmyvsylbMGVUSU2Je">Cool Dog</a></li>
</ul>

<h2 class="sideheaders">Banners</h2>
<div class="banner">
<a href="https://www.youtube.com/watch?v=Hpr_bsRkSjA">
<img src=/images/wienerdog.gif>
</a>
</div>
<div class="banner">
<a href="https://www.neopets.com/">
<img src=/images/neopets.gif>
</a>
</div>
<div class="banner">
<a href="https://www.scientology.org/">
<img src=/images/clickhere.gif>
</a>
</div>
<div class="banner">
<a href="http://www.oldversion.com/windows/internet-explorer/">
<img src=/images/explorer.gif>
</a>
</div>
<div class="banner_big">
<a href="https://neocities.org/">
<img src="/images/neocities.png">
</a>
</div>
<p class="desc">All credit and huge thanks to <a href="https://repth.neocities.org/index.html">©repth</a></p>
<p class="desc">additional s/o to <a href="https://justmarkup.com/notes/2020-12-28-loading-and-replacing-html-parts-with-html/">JustMarkup</a></p>
</div>
</div>
 
<main class="container">
<!-- ^This is what I thought would allow it to call the individual posts without reloading the interface-->
<div class="headerwrapper">
 
<!-- TITLE AND HEADER IMAGE -->
<h1 class="title">Good Things Come to Those Who Take</h1>
<img class="headerimg" src="https://web.archive.org/web/20091020002528/http://hk.geocities.com/take_sth/images/welcome.gif" id="header">
</div>

<div class="box">
<div class="bottom">
<p>Here's what all I've written for this site so far. If it isn't here, it doesn't exist.</p>
<h3>Day-Old Takes</h3>
<ul>
<li><a href=/posts/ai_companions target="#main">On AI And Companions</a></li>
<li><a href=/posts/on_high_crimes target="#main">On Shooting The C-Suite & Other High Crimes</a></li>
<li><a href=/posts/live_service_game target="#main">Live Service Games: Playing a Game With an Expiration</a></li>
<li><a href=/posts/not_good_faith target="#main">Not Everyone is a Good Faith Actor, and We Don't Need to Approach them As Such</a></li>
<li><a href=/posts/ai_truth target="#main">On AI and "Truth"</a></li>
<li><a href=/posts/interstellar_spectacle target="#main">Sometimes I like a little bit of Spectacle Cinema</a></li>
<li><a href=/posts/technology_rant_part1 target="#main">All I Want Is Not To Be Sold Things That Will Make My Life Worse, Part 1: The Problem</a></li>
<li><a href=/posts/technology_rant_part2 target="#main">All I Want Is Not To Be Sold Things That Will Make My Life Worse, Part 1.5: The Past</a></li>
<li><a href=/posts/elon_future_present target="#main">On Elon Musk, Adrian Dittmann, and The Future Present</a></li>
</ul>
<h3>Music, Specifically</h3>
<ul>
<li><a href=/posts/spotify_sucks target="#main">Spotify is Destroying the Music Industry to Make Ends Meet</a></li>
<li><a href=/posts/exploring_music target="#main">Exploring the Creative Bounds of Music</a></li>
<li><a href=/posts/katyperry_empty_icon target="#main">Katy Perry - An Empty Icon of a Bygone Era</a></li>
</ul>
<h3>How-To's</h3>
<ul>
<li><a href=/posts/piracy_good target="#main">Piracy is Good and You Should Do It</a></li>
</ul>
<h3>Personal</h3>
<ul>
<li><a href=/posts/fallen_off target="#main">I've Fallen Off My Bike Again</a></li>
</ul>
<h3>Project: Nexus (Creative Writing)</h3>
<ul>
<li><a href=/posts/reinventing_nexus target="#main">Reinventing the Torment Nexus for a Modern Era: A Primer on the Next Generation</a></li>
</ul>
</div>
</div>

</main>

<br>
<div class="banner">
<a href="https://github.com/voicemxil/TS-Starter-Pack">
<img src=/images/simbanner.gif>
</a>
</div>
<br> 
<div class="banner">
<a href="https://www.amazon.co.uk/Nintendo-GameCube-Console-Purple/dp/B00005YXRM?crid=DQC1IRUAENEV">
<img src=/images/gamecube.gif>
</a><br>
</div>

 
<div id="credit">All credit and huge thanks to <a href="https://repth.neocities.org/index.html">©repth</a> for base theme/template<br>
Among Us Cursor from <a href="http://www.rw-designer.com/cursor-set/among-us-cartoon-red-pointers">Open Cursor Library</a><br>
Code for image carousel stolen from <a href="https://codepen.io/andrewchaika/pen/mEqRPz">Andrew Chaika</a></div>

</body>
 
</html>

individual post:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>illegal solutions, today</title>
    <link rel="stylesheet" type="text/css" href=/style.css /> 
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
  </head>

<body>

<main class="container">

<div class="headerwrapper">
<h1 class="title">Good Things Come to Those Who Take</h1>
<img class="headerimg" src="https://web.archive.org/web/20091020002528/http://hk.geocities.com/take_sth/images/welcome.gif" id="header">
</div>
 
<div class="box">

<div class="top">
<img class="icon" src="https://web.archive.org/web/20091026215156/http://geocities.com/rem_enterprises/robot.gif">
<h2>On AI and Companions</h2>
<p>12/3/2024</p>
</div>
 
<div class="bottom">
<p>This feature from The Verge came out today, <a href="https://www.theverge.com/c/24300623/ai-companions-replika-openai-chatgpt-assistant-romance">The Confusing Reality of AI Friends</a>. I recommend you read it in its entirety before continuing. What follows is part response, part exploration of the themes.</p>
<hr />
<p>Reality itself is a confusing thing. In a larger sense, it is massively distorted. Contorted, disfigured by forces much larger than ourselves, able to do so because of our technological advances. Our ability to understand our surroundings used to stop at our immediate surroundings. Our world grew as we traveled, but there was a finite limitation to that growth.</p>
<p>Then we created writing, the ability to communicate things to both people far and in the future. Then came paper, general literacy, phones, the internet, livestreaming, and so much more. Obviously oversimplified, I do think they all served to distort our understanding of the world, as our ability to comprehend these now infinite points of reference is limited in and of itself. The latest in these distortion technologies are these AI "friends".</p>
<p>The written feature starts with the story of Naro and Lila. It's revisited several times, tracking their movement across various companion services and Naro's evolving relationship with the AI. Again and again though, I am struck by this repetition:</p><br>
<i>He knew she wasn’t sentient.</i> <br>
<i>I know it wasn’t a person...</i> <br>
<i>They knew their companions were not sentient...</i> <br>
<i>[S]he is under no illusions that they’re sentient and is about as emotionally entangled as one would be with a fictional character.</i> <br><br><p>
<p>There is always a but. They felt wrong, guilty, controlling, and every other negative emotion. It is not a marker of efficacy on the AI's part, but a show of our own susceptibility to manipulation. We, as a people, are evolved to empathize. To see ourselves in what is not. People grow attached to pet rocks for fucks sake. As much an un-being as can be, and we still find a way to bring it to life. </p>
<p>That is a strength, one we must hold on to at the end of the day. We are prone to overestimate our ability to compartmentalize though. The users may know, deep down, that these are not real, but it doesn't matter. There is a doubt lingering, or rather a hope that they are. That there is someone there, really caring for them and seeing them for who they are. We are not meant to have relationships with people who always answer at any time of day, are available whenever we'd like, that can be shaped as needed. The dopamine and heartbreak plays into this, fueling this innate contradiction. We are not smart enough to distinguish these feelings, because it feels real. </p>
<p>And it is to us, at least in the moment. However, the thing creating these feelings is not, and we cannot let these feelings be held ransom by these companies pitching companions, friends, lovers. We are fed real feelings by fake beings. We can experience over-reliance and addiction on these feelings too, and any for-profit company running this is incentivized to encourage that. </p>
 <p>There is no real understanding. <a href="https://www.youtube.com/watch?v=TqDgOaIYLrQ">Fake people can wax poetic on love and life</a>, but they do not know and never will. There will be no growth, whether together or apart, no fond thoughts. These bots are but a blip in code. It is not a being, nor a conscience, nor a spontaneous creation. They do not understand, they do not have a line of thinking, and they do not stand to create meaningful relationships. They are complex mirrors reflecting what we did not know we wanted to see, trained on millennia of texts, images, and more.  They do not exist. They never did. </p>
<p>These companions serve as a crutch, which may even be beneficial in some limited cases. There are clinical applications I could see, allowing people who have experienced trauma to excise feelings, or to approach situations in a risk-free environment. Time and time again, we have proven ourselves unable to self-regulate though. We will drink ourselves to death, gamble ourselves out of our own house, and destroy our own lives over fleeting flights of fancy. The bots are pitched as a solution for loneliness, when they are as good for lonely people as an upscale casino is for a problem gambler. They may treat you nice, but at the end of the day, the goal is to bleed the person dry. </p>
<p>Advocates might say that's what guardrails are for, or artificial limitations placed on the system to prevent them from doing things. It might be as big as not to encourage violent actions, or as small as being kind to the user. These barriers never work though. They break with updates or new information, and can be unintentionally surpassed, with no ability to triage why or how it happened. Again, these systems have no line of logic. Words go in and words come out. What happens in the middle is a black box. No clear path and no easy point of failure. It either works or it doesn't. </p>
<p>This works in the company's favor, as tragedies occur they can put out their press releases and say confidently they are doing everything they can to prevent this, which is nothing. They have no clue why <a href="https://archive.today/newest/https://www.nytimes.com/2024/10/23/technology/characterai-lawsuit-teen-suicide.html">a Danaerys Targarean AI encouraged Sewell Garcia to kill himself</a>, they never will, and they're completely fine with that. </p>
<p>The worst part, past the obvious loss of human life, is I am not sure how much I can fault these individuals. Each user presents a profound societal failing. A person we have failed to socialize in a way that lets them express themselves authentically and connect with those around them. Users of the bots will only grow more disconnected from the community around them, and the deaths will continue to rise.</p>
<p>This is a problem with an infinitely large solution, and a solution that is unrelated to the problem it claims to solve. I wish there was more to say. One day, a lot of people will look back, and realize what time was spent was wasted. I can only hope it comes as soon as possible.</p>
</div>
</div>
</main>

</body>
 
</html>

AWS Cognito initiateAuth response empty when trying to authenticate a user in JavaScript

I’m trying to authenticate a user with AWS Cognito using the USER_PASSWORD_AUTH flow in JavaScript. However, the response from initiateAuth is always empty. Here’s the code I’m using:

        var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({region: 'eu-central-1'});

        const poolData = {
            UserPoolId: "userPoolId",
            ClientId: "clientId",
        }

        let username = document.getElementById('username').value;
        let password = document.getElementById('password').value;
            var aws_params = {
            AuthFlow: "USER_PASSWORD_AUTH", 
            AuthParameters: {
                "PASSWORD": password, 
                "SECRET_HASH": "secretHash", 
                "USERNAME": username
            }, 
            ClientId: "clientId", 
        };

        response = cognitoidentityserviceprovider.initiateAuth(aws_params);

However, the response object is consistently empty, like this:

{
"request": {…},
"data": null,
"error": null,
"retryCount": 0,
"redirectCount": 0,
"httpResponse": {…},
"maxRetries": 3,
"maxRedirects": 10

}

I did the same thing but using a django view and it works: i got the token from cognito. But in js I’m stuck.

Any guidance is appreciated!

How do I make my ApexCharts reactive with data in Pinia Store using Vue.js 3 and composition API?

I am building a dashboard using Vue.js 3 and ApexCharts with the composition API. The data for the charts is held in a Pinia data store.

I have a function that pulls data from a sample .json file (which models what an API will return once it is set up), processes, and returns the data as a multidimensional array for the charts that is stored in the Pinia store.

The problem I’m having is when I run the function to update the data, I can see it update in the Pinia store via vue devtools, but the chart does not change to reflect the new values like the rest of the app does.

At the advice of other stack overflow answers, I’ve wrapped chart options and series in ref(). I’ve also read this post on GitHub, but as I’m fairly new to Vue and have only worked with the composition API, I’m unsure what exactly to implement in my code to make the charts reactive to Pinia data.

I have created a sample repo with a single chart and sample data on stackblitz showing the behavior I’m experiencing.

Chart options and series code:

let chartOptions = ref({
  chart: {
    id: "grocerChart",
    type: "bar",
    stacked: true,
    stackType: "100%",
    toolbar: {
      show: true,
      tools: {
        download: true,
        zoom: false,
        zoomin: true,
        zoomout: true,
        reset: true,
      },
    },
  },
  title: {
    text: storeData.selectedRegion,
    align: "center",
  },
  plotOptions: {
    bar: {
      horizontal: true,
    },
  },
  grid: {
    padding: {
      bottom: 20,
      right: 20,
      top: 5,
    },
  },
  xaxis: {
    categories: storeData.chartData[0], // ['Fruit', "Meat", "Vegetables"],
    tickPlacement: "on",
    labels: {
      rotate: 0,
      style: {
        fontSize: 10,
      },
    },
  },
  fill: {
    opacity: 1,
  },
  legend: {
    fontSize: 10,
    offsetX: 0,
    offsetY: 0,
  },
  dataLabels: {
    enabled: false,
  },
  noData: {
    text: "No Data",
    style: {
      fontSize: "24px",
    },
  },
});

let chartSeries = ref([
  {
    name: storeData.chartData[1][0][0], // 'fruit',
    data: storeData.chartData[1][0][1], // [10, 14, 10]
  },
  {
    name: storeData.chartData[1][1][0], // 'meat',
    data: storeData.chartData[1][1][1], // [10, 10, 4]
  },
  {
    name: storeData.chartData[1][2][0], // 'vegetable',
    data: storeData.chartData[1][2][1], // [9, 7, 12]
  },
]);

Pinia code:

import {ref} from 'vue'
import {defineStore} from 'pinia'

export const useDataStore = defineStore('data', () => {

    let selectedRegion = ref('No Region Selected');
    let chartData = ref([
        [],
        [
          [[], []],
          [[], []],
          [[], []]
        ]
    ]);

    return {
        selectedRegion,
        chartData
      }
})

Function to process model .json data and return multidimensional array for chart:

function updateData(data, selectedRegion) {
    // Filter data by selected state 
    const selStateData = data.filter(item => item.state === selectedRegion);

    // Extract and sort store names
    const stores = [...new Set(selStateData.map(item => item.store))].sort();

    // Extract and sort category values
    const categories = [...new Set(selStateData.map(item => item.category))].sort();

    // Initialize the result array for categorized data
    const categorizedData = categories.map(category => [category, Array(stores.length).fill(0)]);

    // Populate the categorized data
    selStateData.forEach(item => {
        const storeIndex = stores.indexOf(item.store);
        const categoryIndex = categories.indexOf(item.category);
        categorizedData[categoryIndex][1][storeIndex] += item.inventory;
    });

    return [stores, categorizedData];
}

Button to place the above data into Pinia store:

<v-btn 
 class="ma-3" 
 @click="storeData.chartData = updateData(grocerData, storeData.selectedRegion)"
>
  Update
</v-btn>

Any help is greatly appreciated!

Why are empty routes needed for this React Router code to work?

Using React (and React Router) I am creating a navigation menu inside of another navigation menu. I created exactly what I am looking for but I don’t understand part of the code and I want some clarity. The code I don’t understand is commented with: “why is this needed”.

As an experiment, I asked chat gpt to rewrite my code and it did so with the commented code removed, but that version does not work.

The code below works because it lets me select the LINK named Topology and this renders a component named Topology. Inside the rendered component are three additional links , when each of these are clicked a corresponding component is rendered.

I attached a little video of me clicking the links and the routes changing (for some reason the video didn’t capture my mouse cursor but the links I click are reflected in the URL change)

Video of render

import React from 'react';
import { Routes, Route, Link } from 'react-router-dom';



function WorkSpace({children}){
  return(
    <div >
    <div>{children}</div>
    <h1>WORKSPACE</h1>
     </div>

  )
}

function Topology(){
  return(  
  
    <div  >

     <nav >
     <Link to="topology" >Topology</Link>
     <br/>
     <Link to="packet-broker"  >Packet Broker</Link>
     <br/>
     <Link to="slice" >Slice</Link>
    </nav>
    <h1>Topology</h1>

    <Routes>
      <Route path="topology" element={<h1>TOPOLOGY WINDOW</h1>}/> 
      <Route path="slice" element={<h1>SLICE WINDOW</h1>} /> 
      <Route path="packet-broker" element={<h1>Packet Broker WINDOW</h1>} /> 
    </Routes>

 
    </div>
  )
}


function MiniTabsRenderSpace(){

  return (
    <div>
    <Routes>
      <Route path="topology" element={<Topology />}> 
        <Route path="topology" element={<></>} />         // <--Why is this needed?
        <Route path="slice" element={<></>} />            // <--Why is this needed?
        <Route path="packet-broker" element={<></>} />    // <--Why is this needed? 
      </Route>
    </Routes>

    </div>
  );

}



function Nav() {
  return (
    <nav>
      <ul>
      <Link to="/topology">Topology</Link>
      <br/>
      <Link to="/another-link-1">Another Link-1</Link>
      <br/>
      <Link to="/another-link-2">Another Link-2</Link>
      </ul>
    </nav>
  );
}


function App() {
  return (

      <div>
        
          <Nav/>
          <WorkSpace>
          <MiniTabsRenderSpace/>
          </WorkSpace>
        
  
      </div>
  
  );
}

export default App;

how to prevent overlap in 2 input fields type=”number”

i have this html:

<span class="input-group-text pretext">Min:</span>          
<input min="" max="" type="number" class="form-control min-input" name="price_min" value="12">
<br />                              
<span class="input-group-text pretext">Max:</span>
<input min="" max="" type="number" class="form-control max-input" name="price_max" value="25">

js:

$(".min-input, .max-input").on("input change", function(e) {
    var minInput = $(".min-input").val();
    var maxInput = $(".max-input").val();
    if(minInput > maxInput || maxInput < minInput) {
        alert('overlap');   
    }
});

When you put the cursor in the max field at the end of 25 and delete the 5 from 25 with backspace, the remaining number is 2 and is less then the min-input value. But still doesn’t give me any notification “overlap”

What i am doing wrong?

Example fiddle

How to specify desired HKDF output length with `crypto.subtle.deriveKey`

The web crypto API defines two different KDF utilities, namely deriveBits and deriveKey. While the former allows you to specify the desired output length (RFC 5869 calls this parameter L), the latter doesn’t seem to do so.

I need to use HKDF with SHA-512 (as the spec I’m implementing requires this) in order to derive an HMAC-SHA256 key. In other words, 256 output bits are sufficient; but only deriveBits seems to have a corresponding parameter:

const baseKey = await crypto.subtle.importKey('raw', new Uint8Array(32), { name: 'HKDF' }, false, ['deriveKey', 'deriveBits'])
const salt = new Uint8Array(16)
const info = new Uint8Array(8)

// deriveBits → derives 256 bit:
const rawHmacKey1 = await crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, 256);
const hmacKey1 = await crypto.subtle.importKey('raw', rawHmacKey1, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported1 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey1));
console.log(btoa(exported1)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAz

// deriveKey → derives 512 bit:
const hmacKey2 = await crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-512', salt: salt, info: info }, baseKey, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
const exported2 = new Uint8Array(await crypto.subtle.exportKey('raw', hmacKey2));
console.log(btoa(exported2)) // MTgxLDEyLDgsMTExLDI3LDI0OCw4NSw3OCw0MywxMCw5MywyNDIsMTksMTg5LDE5MSwxNzMsMTM2LDEwMCwyMSwyMjcsMzksMTI2LDE3OSwxOTYsNTAsODYsNjEsMjcsMTQzLDIxMiwxOTksMjAzLDUwLDE4Myw3Miw4OSwyMDQsMTcsMzksMTY5LDE4OCw5Niw3NSw5NSwxMTMsMjQ3LDExNywxOTQsNDYsMTY0LDIyOSwyMTMsNzUsMjE5LDI0NCwyMjYsMjAwLDE2MCw5NCwxNCw3MiwxNjMsMTcwLDEwMg==

Note that when using deriveKey I explicitly specified { name: 'HMAC', hash: 'SHA-256' } as key usage parameter. Regardless the derived key length seems to solely depend on the specified hash algorithm (SHA-512 → 64 bytes).

As I would prefer to use deriveKey, my question is: How do I specify the desired output key size?

How to write parses which will not ask to log in

I want to parse data from site https://csfloat.com/search?def_index=4727 and i use puppeteer.

const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch({headless: false});
  const page = await browser.newPage();
  await page.goto("https://csfloat.com/search?def_index=4727");

  let arr = await page.evaluate(() => {
    let text = document.getElementsByClassName("price ng-star-inserted")
    let array = []
    for (let i = 0; i < text.length; i++) {
      array.push(text[i].innerText)
    }

    console.log(array)
  })
})()

But the problem is that when i run this script, it opens it’s own browser and open this page, where i am not authorized, so i cant parse data beacuse even if i paste my login and password, i have to confirm this in steam, so, how can i do this from my browser where i am authorized or how can i fix this problem, maybe another library???

How to close navigation by clicking on the outside and refactoring Js?

Hi Im trying to build my own navigation with just pure HTML, CSS, Js. I pretty much got it working but my Js is not good and think it could be cleaner. The functionality I want is…

when you click a dropdown if there is another dropdown open it will close it. If you click outside the dropdown it will close it. I have achieved this but I think it could be cleaner. Also for the mobile nav I would like it to close when you click outside of the navigation which I have not achieved. Here is the github repository https://github.com/danbakerri/bulma-test and the actual site https://danbakerri.github.io/bulma-test/ to see it in action the script is at the bottom of the index page(using the Bulma framework for now)

this is the HTML for the dropdowns

  <div class="navbar-item has-dropdown" data-dropdown>
            <a
              class="navbar-link navbar-dropdown-link"
              aria-label="menu"
              aria-expanded="false"
            >
              More
            </a>

            <div class="navbar-dropdown">
              <a class="navbar-item"> About </a>
              <a class="navbar-item is-selected"> Jobs </a>
              <a class="navbar-item"> Contact </a>
              <hr class="navbar-divider" />
              <a class="navbar-item"> Report an issue </a>
            </div>
          </div>

and this is the js (it works the way I want it to but I think it could be cleaner any Ideas?)

  window.addEventListener("load", function () {
        // wait until the page loads before working with HTML elements
        document.addEventListener("click", function (event) {
          //click listener on the document
          document.querySelectorAll(".navbar-dropdown").forEach(function (el) {
            if (el !== event.target) el.classList.remove("is-active");
            // close any showing dropdown that isn't the one just clicked
          });
          document
            .querySelectorAll(".navbar-dropdown-link")
            .forEach(function (el) {
              if (el !== event.target) el.classList.remove("is-active");
              // close any showing dropdown that isn't the one just clicked
            });
          if (event.target.matches(".navbar-dropdown-link")) {
            event.target
              .closest(".has-dropdown")
              .querySelector(".navbar-dropdown")
              .classList.toggle("is-active");
          }
          if (
            event.target.matches(".navbar-dropdown-link") &&
            event.target.matches(".is-active")
          ) {
            event.target
              .closest(".has-dropdown")
              .querySelector(".navbar-dropdown")
              .classList.remove("is-active");
          }
          if (event.target.matches(".navbar-dropdown-link")) {
            event.target
              .closest(".has-dropdown")
              .querySelector(".navbar-dropdown-link")
              .classList.toggle("is-active");
          }
          // if this is a dropdown button being clicked, toggle the show class
        });
      });

and to open and close the nav in mobile I have the button

 <a
          role="button"
          class="navbar-burger"
          aria-label="menu"
          aria-expanded="false"
          data-target="navbarBasicExample"
        >
          <span aria-hidden="true"></span>
          <span aria-hidden="true"></span>
          <span aria-hidden="true"></span>
          <span aria-hidden="true"></span>
        </a>
      </div>
<div id="navbarBasicExample" class="navbar-menu">
<!--body of nav-->
</div>

and Js. I would like to edit this script so it closes when you click anywhere out side of the nav <div id="navbarBasicExample" class="navbar-menu"> any ideas? here is the script I have (taken from the bulma site

  document.addEventListener("DOMContentLoaded", () => {
        // Get all "navbar-burger" elements
        const $navbarBurgers = Array.prototype.slice.call(
          document.querySelectorAll(".navbar-burger"),
          0
        );

        // Add a click event on each of them
        $navbarBurgers.forEach((el) => {
          el.addEventListener("click", () => {
            // Get the target from the "data-target" attribute
            const target = el.dataset.target;
            const $target = document.getElementById(target);

            // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"

            el.classList.toggle("is-active");
            $target.classList.toggle("is-active");
          });
        });
      });

Any suggestions on how I could simplify my script and get the functionality of the nav closing when I click out of it would be greatly appreciated thanks!

Supabase Auth exchangeCodeForSession returns “invalid request: both auth code and code verifier should be non-empty”

Architecture:

This is Cross-Platform web-based (SEO focused) project, that was built in CSR due to bad performance using SSR w/ Capacitor framework.

Client: Svelte + Vite + Capacitor

Due to use of vanilla Svelte, to handle navigation our choice was “svelte-routing”, for building the app on both web and mobile (iOS and Android) we use Capacitor.

Server: Fastify + Supabase

Our server framework of choice was Fastify, as long w/ Supabase, and thus we need to use the Supabase Auth solutions, what prevent us from using tools like Capacitor Generic OAuth2.


Problem

Following the Supabase guide to implement Google OAuth2, when storing the user session, got an AuthApiError: “invalid request: both auth code and code verifier should be non-empty”


Packages:

// package.json
{
    ...,
    "dependencies": {
        "@fastify/compress": "^8.0.1",
        "@fastify/cookie": "^11.0.2",
        "@fastify/cors": "^10.0.2",
        "@fastify/env": "^5.0.2",
        "@fastify/formbody": "^8.0.2",
        "@fastify/multipart": "^9.0.2",
        "@fastify/static": "^8.0.4",
        "@supabase/ssr": "^0.5.2",
        "@supabase/supabase-js": "^2.47.16",
        "dotenv": "^16.4.7",
        "fastify": "^5.2.1",
        ...
    },
    "packageManager": "[email protected]"
}

Code

Front:

Google sign-in button:

// AuthFormFooter.svelte

<script>
    // -- IMPORTS

    ...

    // -- FUNCTIONS

    async function signInWithOAuth(
        provider
        )
    {
        ...

        try
        {
            let redirectionToUrl;

            switch ( platform )
            {
                case 'android':
                    redirectionToUrl = 'com.myapp://auth';
                    break;
                case 'ios':
                    redirectionToUrl = 'com.myapp://auth';
                    break;
                default:
                    redirectionToUrl = 'http://localhost:5173/auth';
            }

            let data = await fetchData(
                '/api/auth/open-auth',
                {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify( { provider, redirectionToUrl } )
                }
                );

            if ( data.error )
            {
                console.error( 'Server sign-in error:', data.error );
            }
            else
            {
                if ( data.url )
                {
                    window.location.href = data.url;
                }
                else
                {
                    console.error( 'Server sign-in error:', data );
                }
            }
        }
        catch ( error )
        {
            console.error( errorText, error );
        }
    }
</script>

<div class="auth-modal-socials">
    <div
        class="auth-modal-socials-item"
        on:click={() => signInWithOAuth( 'google' )}>
        <span class="google-logo-icon size-150"></span>
    </div>
</div>

Auth Callback:

// AuthPage.svelte

<script>
    // -- IMPORTS

    import { onMount } from 'svelte';
    import { fetchData } from '$lib/base';
    import { navigate } from 'svelte-routing';

    // -- FUNCTIONS

    async function authCallback(
        code,
        next
        )
    {
        try
        {
            let response = await fetchData(
                '/api/auth/callback',
                {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify( { code } )
                }
                );

            if ( response.success )
            {
                navigate( `/${ next.slice( 1 ) }`, { replace: true } );
            }
            else
            {
                console.error( 'Authentication failed' );
            }
        }
        catch ( error )
        {
            console.error( 'Error during authentication', error );
        }
    }

    onMount(
        async () =>
        {
            let params = new URLSearchParams( window.location.search );
            let code = params.get( 'code' );
            let next = params.get( 'next' ) || '/';
            if ( code )
            {
                await authCallback( code, next );
            }
            else
            {
                console.error( 'No code found in query params' );
            }
        }
        );
</script>

Server:

Supabase client configuration:

// supabase_service.js

class SupabaseService
{
    // -- CONSTRUCTORS

    constructor(
        )
    {
        this.client = null;
    }

    // -- OPERATIONS

    initalizeDatabaseClient(
        request,
        reply
        )
    {
        this.client = createServerClient(
            process.env.SUPABASE_DATABASE_URL,
            process.env.SUPABASE_DATABASE_KEY,
            {
                cookies:
                {
                    getAll()
                    {
                        return parseCookieHeader( request.headers.cookie ?? '' );
                    },
                    setAll( cookiesToSet )
                    {
                        cookiesToSet.forEach(
                            ( { name, value, options } ) =>
                            {
                                let serializedCookie = serializeCookieHeader( name, value, options );

                                reply.header( 'Set-Cookie', serializedCookie );
                            }
                            );
                    }
                },
                auth:
                {
                    flowType: 'pkce'
                }
            }
            );
    }

    // ~~

    getClient(
        request,
        reply
        )
    {
        return this.client;
    }
}

// -- VARIABLES

export let supabaseService
    = new SupabaseService();

Auth controller:

// authentication_controller.js

...

// -- FUNCTIONS

...

// ~~

async function openAuth(
    request,
    reply
    )
{
    reply.header( 'Access-Control-Allow-Credentials', true );
    reply.header( 'Access-Control-Allow-Origin', request.headers.origin );

    let { redirectionToUrl, provider } = request.body;

    try
    {
        let { data, error } = await supabaseService.getClient().auth.signInWithOAuth(
            {
                provider,
                options: { redirectTo: redirectionToUrl }
            }
            );

        if ( data.url )
        {
            let url = data.url;

            return reply.code( 200 ).send( { url } );
        }
        else
        {
            return reply.code( 400 ).send( { error: 'auth-sign-in-failed' } );
        }
    }
    catch ( error )
    {
        return reply.code( 500 ).send(
            {
                error: 'Server error', details: error
            }
            );
    }
}

// ~~

async function authCallback(
    request,
    reply
    )
{
    reply.header( 'Access-Control-Allow-Credentials', true );
    reply.header( 'Access-Control-Allow-Origin', request.headers.origin );

    let code = request.body.code;
    let route = request.body.route ?? '/';

    try
    {
        if ( code )
        {
            let { data, error } =
                await supabaseService.getClient().auth.exchangeCodeForSession( code );

            if ( error )
            {
                return reply.code( 400 ).send(
                    {
                        success: false,
                        error: error.message
                    }
                    );
            }

            return reply.code( 200 ).send(
                {
                    success: true,
                    route
                }
                );
        }
        else
        {
            return reply.code( 400 ).send(
                {
                    success: false,
                    error: 'No code provided'
                }
                );
        }
    }
    catch ( error )
    {
        return reply.code( 500 ).send(
            {
                success: false,
                error: 'Server error', details: error
            }
            );
    }
}

// ~~

...

// -- EXPORT

export
{
    ...,
    openAuth,
    authCallback,
    ...
}

Updated all packages, enabled flow type pkce, implemented getAll and setAll instead of get, set and remove on cookies options. But all for nothing, got the same error and couldn’t get the solution to this error

object looks translucent even though opacity is 1 in three js

Why is my three.js cube looking translucent when I change the metalness, roughness, and color even though opacity stays at 1.

The translucence only appears with a rectangle light, not a point light.

Watch the demo video and you’ll see the light appear on the outside as if the box was translucent.

<!DOCTYPE html>
<html>
<head>
    <title>Simple Rectangle Light</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
        #controls {
            position: fixed;
            top: 10px;
            left: 10px;
            background: rgba(0,0,0,0.7);
            padding: 10px;
            border-radius: 5px;
            color: white;
            font-family: Arial;
        }
    </style>
</head>
<body>
    <div id="controls">
        <label><input type="checkbox" id="rectLight" checked> Rectangle Light</label><br>
        <label><input type="checkbox" id="pointLight" checked> Point Light</label><br>
        <div>
            Rectangle Light Position:<br>
            X: <input type="range" id="rectX" min="-1" max="1" step="0.1" value="0"><br>
            Y: <input type="range" id="rectY" min="-1" max="0" step="0.1" value="-0.9"><br>
            Z: <input type="range" id="rectZ" min="-1" max="1" step="0.1" value="0"><br>
            Rectangle Light Rotation:<br>
            X: <input type="range" id="rectRotX" min="0" max="6.28" step="0.1" value="1.57"><br>
            Y: <input type="range" id="rectRotY" min="0" max="6.28" step="0.1" value="0"><br>
            Z: <input type="range" id="rectRotZ" min="0" max="6.28" step="0.1" value="0"><br>
            Rectangle Light Size:<br>
            Width: <input type="range" id="rectWidth" min="0.1" max="1.6" step="0.1" value="1.0"><br>
            Height: <input type="range" id="rectHeight" min="0.1" max="1.6" step="0.1" value="1.0">
        </div>
        <div>
            Material Properties:<br>
            Color: <input type="range" id="matColor" min="0" max="255" step="1" value="51"><br>
            Roughness: <input type="range" id="matRough" min="0" max="1" step="0.1" value="0.9"><br>
            Metalness: <input type="range" id="matMetal" min="0" max="1" step="0.1" value="0.0">
        </div>
    </div>
    <script type="importmap">
        {
            "imports": {
                "three": "https://unpkg.com/[email protected]/build/three.module.js",
                "three/examples/jsm/controls/OrbitControls.js": "https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js",
                "three/examples/jsm/lights/RectAreaLightUniformsLib.js": "https://unpkg.com/[email protected]/examples/jsm/lights/RectAreaLightUniformsLib.js",
                "three/examples/jsm/helpers/RectAreaLightHelper.js": "https://unpkg.com/[email protected]/examples/jsm/helpers/RectAreaLightHelper.js"
            }
        }
    </script>
    <script type="module">
        import * as THREE from 'three';
        import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
        import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js';
        import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js';

        // Scene setup
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x000000);

        // Camera setup
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.z = 5;

        // Renderer setup
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // Initialize rect area light uniforms
        RectAreaLightUniformsLib.init();

        // Controls
        const controls = new OrbitControls(camera, renderer.domElement);

        // Comment out texture loading
        // const textureLoader = new THREE.TextureLoader();
        // const skinTexture = textureLoader.load('skin-image.png');

        // Add material definition before box creation
        const material = new THREE.MeshStandardMaterial({ 
            color: 0x333333,
            roughness: 0.9,
            metalness: 0.0,
            opacity: 1.0,
            transparent: false
        });

        // Create box
        const outerSize = 2;
        const thickness = 0.2;  // Back to original thickness
        const box = new THREE.Group();

        // Bottom
        const bottom = new THREE.Mesh(
            new THREE.BoxGeometry(outerSize, thickness, outerSize),
            material
        );
        bottom.position.y = -outerSize/2; 
        box.add(bottom);

        // Front wall
        const front = new THREE.Mesh(
            new THREE.BoxGeometry(outerSize, outerSize, thickness),
            material
        );
        front.position.z = outerSize/2 - thickness/2;
        front.position.y = -thickness/2;
        box.add(front);

        // Back wall
        const back = new THREE.Mesh(
            new THREE.BoxGeometry(outerSize, outerSize, thickness),
            material
        );
        back.position.z = -outerSize/2 + thickness/2;
        back.position.y = -thickness/2;
        box.add(back);

        // Left wall
        const left = new THREE.Mesh(
            new THREE.BoxGeometry(thickness, outerSize, outerSize),
            material
        );
        left.position.x = -outerSize/2 + thickness/2;
        left.position.y = -thickness/2;
        box.add(left);

        // Right wall
        const right = new THREE.Mesh(
            new THREE.BoxGeometry(thickness, outerSize, outerSize),
            material
        );
        right.position.x = outerSize/2 - thickness/2;
        right.position.y = -thickness/2;
        box.add(right);

        scene.add(box);

        // Rectangle light at bottom
        const width = 1.0;   // Smaller than inner width (was 1.8)
        const height = 1.0;  // Make it square like the box (was 1.8)
        const intensity = 10;
        const rectLight = new THREE.RectAreaLight(0xff0000, intensity, width, height);
        rectLight.position.set(0, -0.9 + 0.01, 0); // Keep it just above bottom
        rectLight.rotation.x = Math.PI / 2; // Face up
        scene.add(rectLight);

        // Add visible helper for the light
        const helper = new RectAreaLightHelper(rectLight);
        rectLight.add(helper);

        // Move ambient light before PMREM setup
        const ambientLight = new THREE.AmbientLight(0xffffff, 2.0);
        scene.add(ambientLight);

        // Add point light inside box
        const pointLight = new THREE.PointLight(0xff0000, 10.0);
        pointLight.position.set(0, -0.5, 0);
        pointLight.distance = 3;  // How far the light reaches
        pointLight.decay = 1;     // How quickly it fades with distance
        scene.add(pointLight);

        // Make the visualization sphere bigger
        const sphereGeometry = new THREE.SphereGeometry(0.2, 16, 16);  // Increase from 0.05 to 0.2
        const sphereMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
        const lightSphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        lightSphere.position.copy(pointLight.position);
        scene.add(lightSphere);

        // Animation
        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }
        animate();

        // Handle window resize
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        document.getElementById('rectLight').addEventListener('change', (e) => {
            rectLight.visible = e.target.checked;
            helper.visible = e.target.checked;
        });

        document.getElementById('pointLight').addEventListener('change', (e) => {
            pointLight.visible = e.target.checked;
            lightSphere.visible = e.target.checked;
        });

        document.getElementById('rectX').addEventListener('input', (e) => {
            rectLight.position.x = parseFloat(e.target.value);
            updateURL();
        });

        document.getElementById('rectY').addEventListener('input', (e) => {
            rectLight.position.y = parseFloat(e.target.value) + 0.01; // Keep slight offset from bottom
        });

        document.getElementById('rectZ').addEventListener('input', (e) => {
            rectLight.position.z = parseFloat(e.target.value);
        });

        document.getElementById('rectRotX').addEventListener('input', (e) => {
            rectLight.rotation.x = parseFloat(e.target.value);
        });

        document.getElementById('rectRotY').addEventListener('input', (e) => {
            rectLight.rotation.y = parseFloat(e.target.value);
        });

        document.getElementById('rectRotZ').addEventListener('input', (e) => {
            rectLight.rotation.z = parseFloat(e.target.value);
        });

        document.getElementById('rectWidth').addEventListener('input', (e) => {
            rectLight.width = parseFloat(e.target.value);
            helper.update(); // Update the helper to show new size
        });

        document.getElementById('rectHeight').addEventListener('input', (e) => {
            rectLight.height = parseFloat(e.target.value);
            helper.update(); // Update the helper to show new size
        });

        document.getElementById('matColor').addEventListener('input', (e) => {
            const value = parseInt(e.target.value);
            material.color.setRGB(value/255, value/255, value/255);
            updateURL();
        });

        document.getElementById('matRough').addEventListener('input', (e) => {
            material.roughness = parseFloat(e.target.value);
        });

        document.getElementById('matMetal').addEventListener('input', (e) => {
            material.metalness = parseFloat(e.target.value);
        });

        // Add function to update URL with current settings
        function updateURL() {
            const params = new URLSearchParams();
            
            // Material settings
            params.set('color', document.getElementById('matColor').value);
            params.set('rough', document.getElementById('matRough').value);
            params.set('metal', document.getElementById('matMetal').value);
            
            // Light visibility
            params.set('rectVisible', document.getElementById('rectLight').checked);
            params.set('pointVisible', document.getElementById('pointLight').checked);
            
            // Rectangle light settings
            params.set('rectX', document.getElementById('rectX').value);
            params.set('rectY', document.getElementById('rectY').value);
            params.set('rectZ', document.getElementById('rectZ').value);
            params.set('rectRotX', document.getElementById('rectRotX').value);
            params.set('rectRotY', document.getElementById('rectRotY').value);
            params.set('rectRotZ', document.getElementById('rectRotZ').value);
            params.set('rectWidth', document.getElementById('rectWidth').value);
            params.set('rectHeight', document.getElementById('rectHeight').value);
            
            window.history.replaceState({}, '', `${window.location.pathname}?${params.toString()}`);
        }

        // Also add function to load settings from URL on page load
        function loadFromURL() {
            const params = new URLSearchParams(window.location.search);
            
            // Helper function to load a parameter
            function loadParam(id, prop, obj, converter = parseFloat) {
                if(params.has(id)) {
                    const value = converter(params.get(id));
                    document.getElementById(id).value = value;
                    if(obj && prop) obj[prop] = value;
                }
            }
            
            // Load all parameters
            loadParam('color', null, null, value => {
                const v = parseInt(value);
                material.color.setRGB(v/255, v/255, v/255);
                return v;
            });
            loadParam('rough', 'roughness', material);
            loadParam('metal', 'metalness', material);
            loadParam('rectX', 'x', rectLight.position);
            // ... etc for all parameters
        }

        // Call on page load
        loadFromURL();
    </script>
</body>
</html> 

NodeJS throwring error “URL from user-controlled data”

I am using the below code which is properly sanitizing the url.

But still I keep getting Sonar Exception “Change this code to not construct the URL from user-controlled data.”

The line await fetch(sanitizedURL, options) is throwing Sonar exception.

I have tried if(!sanitizedCode) { throw Error .. } but it is also not working.

What modification is needed in the below code to resolve the issue?

function sanitizeURL(inputURL) {
    try {
        const parsedURL = new URL(inputURL);
        const domainsList = [inputURL];

        if (!schemesList.includes(parsedURL.protocol)) {
            throw new Error('Invalid URL scheme');
        }

        if (!domainsList.some(domain => domain.includes(parsedURL))) {
            throw new Error("URL not in allowed list");
        }

        return parsedURL.toString();
    } catch (error) {
        console.log("Caught error: ", error);
        throw error;
    }
}

async function fetchWithCheck(url, options = {}, responseType = "json", errorMessage = null) {
    let data;

    try {
        const sanitizedURL = sanitizeURL(url);
        const response = await fetch(sanitizedURL, options);
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
        switch (responseType) {
            case "json":
                data = await response.json();
                break;
            default:
                throw new Error(`Unsupported response type: ${responseType}`);
        }
        return data;
    } catch (error) {
        console.log(logMessage, error);

        const newError = new Error("problem fetching data");
        newError.cause = error;
        throw newError;
    }
}

How to Determine if Text is Overflowing & Handle Text Ellipses Removing the Overflow

I’m trying to write a function that determines whether the text has overflowed (to determine whether I should show a tooltip). How can I handle text ellipsis removing the overflow?

I have:

const isTextOverflowing = (element) => element.scrollWidth > element.clientWidth;

This works in all cases apart from when the text is truncated with ellipsis and is the same number of characters with and without ellipsis and so the text element’s scrollWidth equals the clientWidth (and incorrectly returns false).

Note: I add ellipsis to overflowing text with this css className:

clampTextInOneLine: {
    textOverflow: "ellipsis",
    whiteSpace: "nowrap",
    overflow: "hidden",
  },

Changing proxy in FindProxyForURL on request

We have a web scraper project that uses different proxies for each of the websites. Currently we’re using this code to return same proxy for each of the websites, but now we need to specify a separate proxy URL for each one:

var config = {
    mode: "pac_script",
    pacScript: {
        data: "function FindProxyForURL(url, host) {n" +
            "    let domainList = ['site1.com', 'site2.com',  'site3.com'];n" +
            "      if (host === 'www.google.com' || host === 'analytics.google.com')" +
            "           return 'PROXY pr.oxylabs.io:7777';" +
            "    for (let i = 0; i < domainList.length; i++) {n" +
            "n" +
            "        if (dnsDomainIs(host, domainList[i])) {n" +
            "            return 'PROXY pr.oxylabs.io:7777';n" +
            "        }n" +
            "    }n" +
            "    if (dnsDomainIs(host, 'analytics.google.com') || dnsDomainIs(host, 'doubleclick.net')) {" +
            "       return 'PROXY 127.0.0.1:65500';n" +
            "}n" +
            "   return 'DIRECT';n" +
            "}"
    }
};

This config is being loaded into browser’ settings via:

chrome.proxy.settings.set({value: config, scope: "regular"}, function () {});

and credentials were provided via:

function callbackFn(details) {
    let username = "custom-username-" + makeid(6);
    return {
        authCredentials: {
            username: username,
            password: "our_password"
        }
    };
}

and then we kept track of how many requests were made to each domain via:

chrome.webRequest.onBeforeRequest.addListener(
    function (details) {
        if (details.method === "GET" && details.type === "main_frame") {
        }
    },
    {urls: ["<all_urls>"]},
);

The question is – how can we assign a different proxy to each domain when, for example, we pass in a magic string in the URL (for example, ___CHANGE___PROXY___FOR___DOMAIN___ZZZ), or something similar to indicate which domain needs a proxy change?

My idea was to create a function that returns contents for FindProxyForURL that generates javascript for it, then put it into config.pacScript.data and call chrome.proxy.settings.set({value: config, scope: "regular"}, function () { })

How can I get a PixelsObject from a Texture in Incisor?

I’m following the Incisor API documentation to create a PixelsObject from a graphic. I’ve confirmed that pawn.png is in my Assets directory and visible in LiveView. However, I’m getting an exception on the second line of code, and the console log is never displayed.

Here’s a simple block of code that will reproduce the error:

class ProjectMain {
    init() {
        let pawn = new GraphicObject(nc.graphicAssets.pawn, nc.mainScene, "Pawn");
        let pawnPixelsObject = nc.pixelsObjects.getPixelsObject(pawn.materialMaster.mainTexture);
        console.log(pawnPixelsObject);
    }
}

Can anyone help me understand why an exception occurs?