Type Error with Optional Fields in React Hook Form and Yup Schema

I’m encountering a problem while using React Hook Form with Yup for validation. I have a schema where some fields are optional, but I’m getting a type error related to the resolver.

Here’s my Yup schema:

const yupSchema = yup.object({
  name: yup.string()
    .typeError('Name must be a string')
    .required('Name is required')
    .min(3, 'Name must be at least 3 characters long'),

  surname: yup.string()
    .matches(/^[a-zA-Z]+$/, 'Surname must contain only letters'),

  age: yup.number()
    .min(0, 'Age must be greater than or equal to 0')
    .max(120, 'Age must be less than or equal to 120'),
});

type YupFormData = yup.InferType<typeof yupSchema>;

In this schema, age and surname are optional fields. However, I am receiving the following error when using the resolver:

Types of parameters options and options are incompatible.
Type 'ResolverOptions<{ surname?: string | undefined; age?: number | undefined; name: string; }>' is not assignable to type 'ResolverOptions<{ name: string; surname: string | undefined; age: number | undefined; }>'.
Property 'surname' is optional in type
{
    surname?: string | undefined;
    age?: number | undefined;
    name: string;
}
but required in type
{
    name: string;
    surname: string | undefined;
    age: number | undefined;
}

Here’s how I’m using the useForm hook:

const {
  control,
  handleSubmit,
  formState: {
    errors, 
  }, 
} = useForm<YupFormData>({
  resolver: yupResolver(yupSchema),
  mode: 'onBlur',
});

I would appreciate any help in resolving this issue. Thank you!

What I tried:

I created a Yup validation schema with optional fields for surname and age. I then set up the useForm hook from React Hook Form, integrating the Yup schema using the yupResolver. I expected the form to validate correctly without errors, even when the optional fields were left blank.

What I was expecting:

I expected that the optional fields (surname and age) would not cause any type errors during validation, allowing the form to submit successfully as long as the required field (name) was filled out correctly. Instead, I encountered a type error related to the resolver, indicating a mismatch in the expected types for the form data.


EDIT:

I’m also encountering an error related to the control when using the following components:

<InputController
  name="name"
  control={control}
  error={errors.name?.message as string}
  label="Name"
/>
<InputController
  name="surname"
  control={control}
  error={errors.surname?.message as string}
  label="Surname"
/>
<InputNumberController
  name="age"
  control={control}
  error={errors.age?.message as string}
  label="Age"
/>

The error message I receive is:

TS2322: Type
Control<{
    name: string;
    surname: string | undefined;
    age: number | undefined;
}, unknown, {
    surname?: string | undefined;
    age?: number | undefined;
    name: string;
}>
is not assignable to type
Control<{
    surname?: string | undefined;
    age?: number | undefined;
    name: string;
}>
The types of _options.resolver are incompatible between these types.
Type 'Resolver<{ name: string; surname: string | undefined; age: number | undefined; }, unknown, { surname?: string | undefined; age?: number | undefined; name: string; }> | undefined' is not assignable to type 'Resolver<{ surname?: string | undefined; age?: number | undefined; name: string; }, any, { surname?: string | undefined; age?: number | undefined; name: string; }> | undefined'.
Type 'Resolver<{ name: string; surname: string | undefined; age: number | undefined; }, unknown, { surname?: string | undefined; age?: number | undefined; name: string; }>' is not assignable to type 'Resolver<{ surname?: string | undefined; age?: number | undefined; name: string; }, any, { surname?: string | undefined; age?: number | undefined; name: string; }>'.
Types of parameters options and options are incompatible.
Type 'ResolverOptions<{ surname?: string | undefined; age?: number | undefined; name: string; }>' is not assignable to type 'ResolverOptions<{ name: string; surname: string | undefined; age: number | undefined; }>'.
Type '{ surname?: string | undefined; age?: number | undefined; name: string; }' is not assignable to type '{ name: string; surname: string | undefined; age: number | undefined; }'.
Property surname is optional in type
{
    surname?: string | undefined;
    age?: number | undefined;
    name: string;
}
but required in type
{
    name: string;
    surname: string | undefined;
    age: number | undefined;
}

This error with control exists even before removing <YupFormData> from the useForm hook. While removing it resolves the resolver error, the control type mismatch persists. Any guidance on how to resolve this would be greatly appreciated!


EDIT: Here is my implementation of the InputController:

type InputControllerProps<T extends FieldValues> = {
  name: Path<T>;
  control: Control<T>;
  rules?: Omit<RegisterOptions<T, Path<T>>, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>;
  error?: string;
  label: string;
};

function InputController<T extends FieldValues>({
  name, control, rules, error, label,
}: InputControllerProps<T>) {
  return (
    <Controller
      name={name}
      control={control}
      rules={rules}
      render={({ field }) => (
        <input
          {...field}
          aria-label={label}
          id={name}
          style={{ borderColor: error ? 'red' : 'default' }} // Example of error handling
          placeholder={label}
        />
      )}
    />
  );
}

Encountered illegal break in a for loop [duplicate]

Can anyone help me with this? I’m doing leetcode and I just want to break my for loop inside an if-else statement but I have an illegal error.

var longestCommonPrefix = function(strs) {
    let commonPrefix = [];
    let firstStringArr = strs[0].split("");
    counter = 0;
    
    for (i = 0; i < firstStringArr.length; i++) {
        strs.forEach(string => {
            if (string.includes(firstStringArr[i])) { 
                counter++; 
            };

            if (counter === strs.length && strs.length > 0) {
            commonPrefix.push(firstStringArr[i]);
            } else {
                break;
            }
        })
        counter = 0;
    }
    return commonPrefix.join('');
};

Error message is:

Line 21 in solution.js
                break;
                ^^^^^
SyntaxError: Illegal break statement

How to create a custom WordPress plugin for adding a shortcode?

I’m trying to create a custom WordPress plugin that registers a shortcode so I can use it in posts and pages. I want to know the steps and code needed to make this work from scratch.

What I want:
Create a plugin inside the wp-content/plugins folder.

Add a shortcode (for example, [greet name=”John”]) that outputs something like:

Copy
Edit
Hello, John!
Ability to pass attributes to the shortcode (like name).

What I have tried:
I created a folder custom-shortcode-plugin inside wp-content/plugins.

Added a file custom-shortcode-plugin.php with only a header comment:

Difficulties with responsiveness

I’m having trouble with the responsiveness of a landing page. It doesn’t adapt well to mobile devices. I’ll forward my Style.css and HTML:

Problems: Slide and Forms

I’m working on a responsive navigation menu using HTML and CSS, where the menu should collapse into a hamburger button on smaller screens.

I’ve already implemented the following:

Created a checkbox-based toggle system (.close-menu) to show/hide the menu with a hamburger (☰) and close (×) icon.

Styled the menu with position: fixed, height: 100vh, and flex-direction: column to make it appear as a full-screen overlay.

Used :checked pseudo-class to toggle .menu visibility when clicking the label.

Set display: none and display: block correctly to toggle visibility.

Ensured the menu content centers properly using flex and justify-content: center.

However, I’m still facing issues with how the menu behaves on mobile devices:

Sometimes the hamburger icon appears behind other elements or disappears.

The menu content shifts unexpectedly or doesn’t center vertically.

Overflow issues or layout bugs depending on the screen size.

I’ve checked z-index, position types, and even adjusted padding and margin, but can’t seem to fix the final layout issue.

Here’s the relevant CSS part for the mobile menu:

style.css:
.intro-content {
    position: relative;
    /* top: -8rem; */
    display: grid;
    grid-template-columns: 1fr 1.5fr;
    gap: var(--gap);
    min-height: 100vh;
}

.intro-text-content,
.intro-img {
    display: flex;
    flex-flow: column wrap;
    justify-content: center;

}

.intro-img img,
.intro-img svg {
    max-width: 100%;
    height: auto;
}

.top3-content {
    max-width: 64rem;
    display: flex;
    /* flex-flow: column nowrap; */
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: center;
    min-height: 100vh;
    text-align: center;
}

.grid-one-content {
    display: flex;
    flex-flow: column wrap;
    justify-content: center;
    min-height: 100vh;
}

.grid-main-heading {
    margin-bottom: 1rem;
}

.grid-description {
    padding-bottom: 5rem;
}

.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gap);
    counter-reset: grid-counter;
}

.grid h3 {
    font-size: 3rem;
    position: relative;
    padding-left: 5rem;
    padding-bottom: 2rem;
}

.grid h3::before {
    counter-increment: grid-counter;
    content: counter(grid-counter);
    position: absolute;
    font-size: 8rem;
    font-style: italic;
    top: -4rem;
    left: -2rem;
    transform: rotate(5deg);
}

.gallery-img {
    width: 100%;
    max-width: 36rem;
    max-height: 36rem;
    overflow: hidden;
}

.gallery-img img {
    transition: all 300ms ease-in-out;
}

.gallery-img img:hover {
    transform: translate(-3%, 3%) scale(1.2) rotate(5deg);
}

.contact-form {
    grid-column: span 2;
}

.contact-form .form-grid {
    border: none;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--gap);
}

.form-grid legend {
    font-style: italic;
    font-size: 1.6rem;
    margin-bottom: 3rem;
}

.form-group {
    min-width: 32rem;
    flex: 1 1 auto;
}

.form-group label {
    display: block;
    margin-bottom: 1rem;
}

.form-group input,
.form-group textarea {
    border: none;
    background: var(--white-color);
    padding: 1.5rem 2rem;
    width: 100%;
    font-size: 3rem;
    outline: none;
}

.form-group input:focus,
.form-group textarea:focus {
    box-shadow: 0 0 10px 2px var(--light-gray-color);
}

.form-group button {
    border: 0.5rem solid var(--white-color);
    background: var(--primary-color);
    color: var(--white-color);
    padding: 1.5rem 2rem;
    font-size: 3rem;
    cursor: pointer;
    transition: all 300ms ease-in-out;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    border-radius: 0.5rem;
}

.form-group button:hover {
    border: 0.5rem solid var(--white-color);
    background: var(--primary-color-checked);
    color: var(--white-color);
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
    transform: scale(1.05);
}

.form-group ::placeholder {
    color: var(--light-gray-color);
}

.footer {
    text-align: center;
    font-size: 1.6rem;
}

.footer a {
    color: var(--primary-color);
}

.footer p {
    margin: 0;
    padding: 3rem;
}


.close-menu {
    display: none;
}

.back-to-top {
    position: fixed;
    bottom: 2rem;
    right: 2rem;
    background: var(--white-color);
    width: 5rem;
    height: 5rem;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 50%;
    color: var(--primary-color);
    transform: rotate(-90deg);
    border: 0.1rem solid var(--primary-color);
}

a:visited {
    color: inherit;
    /* Define a cor do link visitado */
    text-decoration: none;
    /* Remove a sublinha do link visitado, se necessário */
}

a:hover {
    color: var(--menu-underline-color);
}

a:active {
    color: blue;
}

/* table */

.responsive-table table {
    width: 100%;
    border-collapse: collapse;
    font-family: inherit;
    color: var(--white-color);
    background-color: var(--primary-color);
}

.responsive-table th {
    background-color: var(--primary-color-checked);
    color: var(--white-color);
    padding: 0.75rem 1rem;
    text-align: left;
    font-weight: bold;
}

.responsive-table td {
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--primary-color-checked);
}

.responsive-table .text-end {
    color: var(--primary-color);
    text-align: right;
    padding-right: 1rem;
    background-color: var(--white-color);
}

.responsive-table caption {
    color: var(--white-color);
    font-weight: bold;
    font-size: 1.2rem;
    padding: 0.75rem 0;
}


/* mobile */
@media (max-width: 800px) {



    .intro-content,
    .grid {
        grid-template-columns: 1fr;
    }

    .gallery-img {
        width: 100%;
        max-width: 100%;
        max-height: 100%;
    }

    .gallery-img img {
        width: 100%;
    }

    .grid-one-content {
        display: block;
    }

    .menu {
        bottom: 0;
        text-align: center;
    }

    .menu-content,
    .menu-content ul {
        flex-direction: column;
        justify-content: center;
    }

    .menu-content {
        height: 100vh;
    }

    .menu {
        display: none;
    }


    .close-menu-label::after {
        content: '☰';
        position: fixed;
        z-index: 2;
        top: 2rem;
        right: 2rem;
        background: var(--primary-color);
        color: var(--white-color);
        font-size: 3rem;
        line-height: 3rem;
        width: 3rem;
        height: 3rem;
        text-align: center;
        padding: 0.5rem;
        cursor: pointer;
    }

    .close-menu:checked~.menu {
        display: block;
    }

    .close-menu:checked~.close-menu-label::after {
        display: block;
        content: '×';
    }

    .menu-spacing {
        display: none;
    }

    h1 {
        font-size: 4rem;
    }

    h2 {
        font-size: 3.6rem;
    }

    h3 {
        font-size: 3.4rem;
    }

    h4 {
        font-size: 3.2rem;
    }

    h5 {
        font-size: 3rem;
    }

    h6 {
        font-size: 2.8rem;
    }
}

/* fechando o bloco mobile */


/* SLIDE SHOW */
.slider{
    margin: 0 auto;
        width: 800px;
        height: 400px;
        overflow: hidden;
}

.slider {
    border: 0px solid var(--white-color);
    box-shadow: 0px 0px 15px 5px var(--white-color);
    transition: 0.5s ease-in-out, border 0.5s ease-in-out; /* Especifica a transição para a sombra e borda */
}

.slider:hover {
    box-shadow: 0px 0px 25px 10px var(--white-color); /* Aumenta o brilho da sombra no hover */
}

.slides {
    width: 400%;
    height: 400px;
    display: flex;;
}
.slides input {
    display: none;
}
.slide{
    width: 25%;
    position: relative;
    transition: 2s
}
.slide img{
    width: 800px;
}
.manual-navigation{
    position: absolute;
    width: 800px;
    margin-top: -40px;
    display: flex;
    justify-content: center;
}
.manual-btn{
    border: 2px solid var(--menu-underline-color);
    padding: 5px;
    border-radius: 10px;
    cursor: pointer;
    transition: 0.8s;
    background-color: var(--white-color);
}
.manual-btn:not(:last-child) {
    margin-right: 40px;
}
.manual-btn:hover{
    background: var(--primary-color);
}
#radio1:checked ~ .first{
    margin-left: 0;
}
#radio2:checked ~ .first{
    margin-left: -25%;
}
#radio3:checked ~ .first{
    margin-left: -50%;
}
#radio4:checked ~ .first{
    margin-left: -75%;
}
#radio5:checked ~ .first{
    margin-left: -100%;
}
#radio6:checked ~ .first{
    margin-left: -125%;
}
.navigation-auto div{
    border: 2px solid var(--menu-underline-color);
    padding: 5px;
    border-radius: 10px;
    cursor: pointer;
    transition: 1s;
}
.navigation-auto{
    position: absolute;
    width: 800px;
    margin-top: 360px;
    display: flex;
    justify-content: center;
}
.navigation-auto div:not(:last-child){
    margin-right: 40px;
}
#radio1:checked ~ .navigation-auto .auto-btn1{
    background: var(--white-color);
}
#radio2:checked ~ .navigation-auto .auto-btn2{
    background: var(--white-color);
}
#radio3:checked ~ .navigation-auto .auto-btn3{
    background: var(--white-color);
}
#radio4:checked ~ .navigation-auto .auto-btn4{
    background: var(--white-color);
}
#radio5:checked ~ .navigation-auto .auto-btn5{
    background: var(--white-color);
}
#radio6:checked ~ .navigation-auto .auto-btn6{
    background: var(--white-color);
}


/* Para telas pequenas, como tablets */
@media (max-width: 768px) {
    .slider {
        width: 100%;
        height: auto;
        overflow: hidden;
    }

    .slides {
        display: flex;
        width: 600%;
        height: auto;
        transition: margin-left 0.5s ease-in-out;
    }

    .slide {
        width: 16.6667%; /* Cada slide ocupa 1/6 do total */
        flex-shrink: 0;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .slide img {
        width: 100%;
        height: auto;
        object-fit: cover;
    }

    .manual-navigation,
    .navigation-auto {
        width: 100%;
        position: relative;
    }

    .manual-btn {
        padding: 6px;
        margin-right: 10px;
    }

    #radio1:checked ~ .first {
        margin-left: 0;
    }
    
    #radio2:checked ~ .first {
        margin-left: -16.7%;
    }
    
    #radio3:checked ~ .first {
        margin-left: -33.4%;
    }
    
    #radio4:checked ~ .first {
        margin-left: -50%;
    }
    
    #radio5:checked ~ .first {
        margin-left: -66.7%;
    }
    
    #radio6:checked ~ .first {
        margin-left: -83.3%;
    }
}

/* Para celulares menores que 480px */
@media (max-width: 480px) {
    .slider {
        width: 100%;
        height: auto;
        overflow: hidden;
    }

    .slides {
        display: flex;
        width: 600%; /* ou 400% dependendo do número de slides */
        transition: margin-left 0.8s ease-in-out;
      }
      

    .slide {
        width: 50%; /* Ajustado para 2 slides por vez em telas menores */
        flex-shrink: 0;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .slide img {
        width: 100%;
        height: auto;
        object-fit: contain;
        border-radius: 0.5rem;
      }

    .slider,
    .slide img {
    max-width: 100%;
    overflow: hidden;
}


    .slider-container {
        max-width: 800px;
        width: 100%;
        margin: 0 auto;
        position: relative;
        aspect-ratio: 16 / 9; /* Mantém proporção em qualquer tela */
      }

    .manual-navigation,
    .navigation-auto {
        width: 100%;
        position: relative;
    }

    .navigation-auto div {
        opacity: 0.5;
        background: transparent;
      }
      
      #radio1:checked ~ .navigation-auto .auto-btn1,
      #radio2:checked ~ .navigation-auto .auto-btn2,
      #radio3:checked ~ .navigation-auto .auto-btn3,
      #radio4:checked ~ .navigation-auto .auto-btn4,
      #radio5:checked ~ .navigation-auto .auto-btn5,
      #radio6:checked ~ .navigation-auto .auto-btn6 {
        background: var(--menu-underline-color);
        opacity: 1;
      }      

    .manual-btn {
        border: 2px solid var(--menu-underline-color);
        padding: 6px;
        border-radius: 50%;
        cursor: pointer;
        background: transparent;
        transition: background-color 0.3s ease-in-out, transform 0.2s ease-in-out;
      }
      
      .manual-btn:hover {
        background-color: var(--menu-underline-color);
        transform: scale(1.1);
      }
      

    #radio1:checked ~ .first {
        margin-left: 0;
    }

    #radio2:checked ~ .first {
        margin-left: -50%;
    }

    #radio3:checked ~ .first {
        margin-left: -100%;
    }

    #radio4:checked ~ .first {
        margin-left: -150%;
    }

    #radio5:checked ~ .first {
        margin-left: -200%;
    }

    #radio6:checked ~ .first {
        margin-left: -250%;
    }
}

/* Para celulares muito pequenos, como 320px */
@media (max-width: 320px) {
    .slider {
        width: 100%;
        height: auto;
        overflow: hidden;
    }

    .slides {
        display: flex;
        width: 600%;
        height: auto;
        transition: margin-left 0.5s ease-in-out;
    }

    .slide {
        width: 100%; /* Apenas 1 slide por vez */
        flex-shrink: 0;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .slide img {
        width: 100%;
        height: auto;
        object-fit: cover;
    }

    .manual-navigation,
    .navigation-auto {
        width: 100%;
        position: relative;
    }

    .manual-btn {
        padding: 4px;
        margin-right: 3px;
    }

    #radio1:checked ~ .first {
        margin-left: 0;
    }

    #radio2:checked ~ .first {
        margin-left: -100%;
    }

    #radio3:checked ~ .first {
        margin-left: -200%;
    }

    #radio4:checked ~ .first {
        margin-left: -300%;
    }

    #radio5:checked ~ .first {
        margin-left: -400%;
    }

    #radio6:checked ~ .first {
        margin-left: -500%;
    }
}
html:
<!DOCTYPE html>
<html lang="pt-BR">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Language" content="pt-br">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Portfólio de Marcelo Magalhães - Desenvolvedor Full Stack com projetos em C#, JS, PHP e mais.">
    <meta name="author" content="Marcelo Magalhães">
    <meta name="keywords" content="portfólio, desenvolvedor, fullstack, C#, JavaScript, PHP, sistemas, API, landing page">

    <title>Marcelo Magalhães </></title>
    <link rel="icon" type="image/png" href="assets/img/Brazil.png" />
    <link rel="shortcut icon" href="assets/img/Brazil.png" type="image/png">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">

    <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=Montserrat:[email protected]&family=Open+Sans:[email protected]&display=swap" rel="stylesheet">

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">

    <link rel="stylesheet" href="assets/css/style.css">
    <link rel="stylesheet" href="assets/css/variables.css">
    <link rel="stylesheet" href="assets/css/elements.css">
    <link rel="stylesheet" href="assets/css/classes.css">
    <link rel="stylesheet" href="assets/css/menu.css">

    <script src="assets/js/script.js" defer></script>

</head>

<body>
    <input id="close-menu" class="close-menu" type="checkbox" aria-label="Close menu" role="button">
    <label class="close-menu-label" for="close-menu" title="close menu"></label>
    <aside class="menu white-bg">
        <div class="main-content menu-content">
            <h1 onclick="getElementById('close-menu').checked = false">
                <a href="#home" title="Início" aria-label="Ir para a seção inicial">
                    <i class="fas fa-home"></i>
                </a>
            </h1>
            <nav>
                <ul onclick="getElementById('close-menu').checked = false">
                    <li><a href="#home">Sobre mim</a></li>
                    <li><a href="#grid-one">Projetos</a></li>
                    <li><a href="#grid-three">Projetos Casuais</a></li>
                    <li><a href="#slideshow">Slide Show</a></li>
                    <li><a href="#meus-estudos">Meus Estudos</a></li>
                    <li><a href="#contact">Contato</a></li>
                </ul>
            </nav>
        </div>
    </aside>

    <section id="home" class="intro main-bg section">
        <div class="main-content intro-content">
            <div class="intro-text-content">
                <h2>Olá,</h2>
                <p> Me chamo Marcelo Magalhães, sou 
                    formado em Análise e Desenvolvimento de Sistemas,
                    Pós Graduado em MBA - Inteligência Artificial e Big Data,
                    e também possuo Pós Graduação em Desenvolvimento Web Full 
                    Stack. Também sou estudante de Engenharia de Software 5º 
                    Semestre.</p>
            </div>
            <div class="intro-img">
                <img src="assets/img/javascript.svg" alt="Logo de HTML, CSS e JS.">
            </div>
        </div>
    </section>
..........."
    <footer id="footer" class="footer white-bg">
        <p><a rel="nofollow" target="_blank" href="https://www.linkedin.com/in/marcelo-magalhães-513b6b283/">Feito com
                muita dedicação por: Marcelo Magalhães</a></p>
    </footer>
    <a class="back-to-top" href="#" aria-label="Voltar ao topo">
        <i class="fas fa-arrow-up"></i>
    </a>
</body>



</html>

I tried to add @media and it didn’t work. I think the images are too big for the slide, but I wanted them to adapt.

How to handle async/await inside Express middleware without blocking the request-response cycle?

I’m working on a Node.js project with Express and using async/await inside middleware to validate an auth token with an external API.

Here’s my middleware:

const authMiddleware = async (req, res, next) => {
    const token = req.headers.authorization;

    try {
        const user = await fetchUserFromToken(token); // external API call
        req.user = user;
        next();
    } catch (err) {
        res.status(401).json({ error: 'Invalid token' });
    }
};

How can I return an img tag with src parameter?

Jest transformers are written by module.exports-ing process, which returns code.

Extract from the docs:

export type TransformedSource =
  | {code: string; map?: FixedRawSourceMap | string | null}
  | string;

A transformer looks like this:

module.exports = {
  process(src, filename) {
    return { code: `module.exports = 'img';` };
  }
}

If I write the transformer as above the transformer works as expected, whatever it transforms will become an img tag.

However, If I write code: `module.exports = 'img src=""';, I get the following error:

The above error occurred in the <img src=""> component:

at img src=""
    
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

InvalidCharacterError: "img src=""" did not match the Name production: Unexpected syntax in top

It looks like the whole expression is trying to be evaluated to a tag.

Question:

How can I successfully transform the input into an img tag with src information?

What is the best way to download large files in JavaScript where the file is not public? [closed]

I’m looking for an approach that works on most modern browsers, provides a good user experience, and can handle large (~50 GB) files.


Existing Implementation

The code that I am working on downloads a file by making a request for the file, reading the file as a blob and then using createObjectURL to make a link to the file and download it. It’s currently implemented inside an RTK Query endpoint:

getTempStorageDocumentBlobUrl: builder.query<string, string>({
    query: documentId => ({
        url: documentId,
        responseHandler: async (response) => await response.blob()
    }),
    transformResponse: (blob: Blob) => URL.createObjectURL(blob)
})

This is for the most part working okay but has a couple big disadvantages:

  1. It seems to struggle with larger file sizes. I had seen mention on here as well as other sources that browsers would optimise await response.blob() to avoid loading the entire file into memory, but it’s choking with files over 1 GB.
  2. The user receives absolutely no feedback until the entire file is downloaded, at which point it pops up in their download bar. With a fast internet connection and small files it’s not that noticeable, but with large files it’s not a good experience.

The upside is that the file downloads like most other files on the internet, and goes straight into their downloads folder or lets them choose a save location based on their browser settings.


Implementation without RTK Query

I wondered if the problem with the existing implementation struggling with large files was due to something RTK Query was doing, so I tried a stripped back version that uses the most basic demo I’d seen online.

const filePath = '';
const token = '';

const response = await fetch(filePath, {
    headers: { Authorization: `Bearer ${token}` }
});

if (!response.ok) {
    return;
}

const blob = await response.blob();

const url = URL.createObjectURL(blob);

const a = document.createElement('a');
a.href = url;
a.download = 'test.txt';

a.click();

URL.revokeObjectURL(url);

The problem is that this still has the second disadvantage of the existing implementation: the user doesn’t see the download progress until the file is fully loaded.

I’m also still unsure if this will support large files, as I’ve seen posts saying the browser will save the blob to disk if it’s large enough, and others saying it this approach isn’t optimal for files over ~2 GB.


Streaming

The next thing I tried is streaming the file and managing the progress all in code.

const handle = await window.showSaveFilePicker({ startIn: 'downloads', suggestedName: 'test.txt' });

const writable = await handle.createWritable();

const filePath = '';
const token = '';

const response = await fetch(filePath, {
    headers: { Authorization: `Bearer ${token}` }
});

if (!response.ok) {
    return;
}

const reader = response.body.getReader();

const readable = new ReadableStream({
    start: controller => {
        const read = async () => {
            const { done, value } = await reader.read();

            if (done) {
                controller.close();
                return;
            }

            controller.enqueue(value);
            read();
        };

        read();
    }
});

let bytesRead = 0;
const label = document.getElementById('fileStatusLabel');
label.textContent = 'Starting download...';
const finalSize = 104857699922; // For testing, would normally get this from API.

let lastTime = Date.now();
let dBytes = 0;
let byteRate = 0;

const track = new TransformStream({
    transform: (chunk, controller) => {
        controller.enqueue(chunk);

        bytesRead += chunk.byteLength;
        dBytes += chunk.byteLength;

        const progress = Math.ceil(bytesRead * 100 / finalSize);

        if (Date.now() - lastTime > 1000) {
            const dTime = Date.now() - lastTime;
            byteRate = dBytes * 0.001 / dTime;
            dBytes = 0;
            lastTime = Date.now();
        }

        label.textContent = `Download ${progress} complete (${byteRate.toFixed(2)} MB/s) - ${bytesRead}/${finalSize} bytes downloaded.`;
    }
});

readable.pipeThrough(track).pipeTo(writable);

Aside from the scuffed code for tracking download speed, this is pretty close to working how I want it… with a couple big downsides.

  1. It doesn’t work on Firefox because window.showSaveFilePicker isn’t defined. I looked it up and apparently Firefox doesn’t agree with the file save API so it isn’t implemented, and the post I saw recommended using the second approach with createObjectURL instead.
  2. It still can’t download really large files. In my testing with a ~100 GB file it got to between 5-20 GB (on screen) before I got an error in the console:

Uncaught (in promise) RangeError: Array buffer allocation failed

It shows this error as having come from the read() method inside ReadableStream.start, and the progress eventually stops. It generally stops at around 21% e.g. ~21 GB.

  1. The download happens completely inside the app, so the user doesn’t get the file in their downloads folder – they have to pick a location on disk to save the file to.

I imagine this approach would also need a lot more testing and error handling e.g. what if they pick a restricted directory? Can I create a link to open the folder containing the file once the download is complete? It’s my first time using this method so I have no idea what the possible pitfalls are, and generally it feels like there must be a simpler way to do this.


Don’t require an access token?

I’ve seen this done (and done it myself in the past) where the access token is passed as a query parameter instead of with a header, allowing you to just open a new tab containing the file path and the browser downloads the file as it should. I can’t make this change as I can’t risk exposing a user’s access token. Security is very important here, these are not public files.

Something I did consider was creating a cookie or something that will allow the browser to access the file. I’ve never done that before, though, and don’t really know how/if it will work or if it is a recommended/secure approach.


Any advice on this would be much appreciated as I’m otherwise at a bit of a loss.

LangGraph course_title and course_description mismatch

over the past few days I’ve been working with LangGraph, and I’m still new to it. While learning, I created a LangGraph agent that generates a course based on the user_thought and targeted_audience. Everything works fine until the evaluation step. However, whenever it reaches the save_course step, the title and description are different from what was used in the course_reviewer.

Could anyone help me understand the reason for this? Am I doing something wrong?

import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
import { DynamicStructuredTool } from '@langchain/core/tools';
import { Annotation, MemorySaver, StateGraph } from '@langchain/langgraph';
import { ToolNode } from '@langchain/langgraph/prebuilt';
import { Injectable } from '@nestjs/common';
import z from 'zod';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';

type courseData = {
user_thought: string;
targeted_audience: string;

enable_knowledge_store: boolean;
knowledge_store_id: string;

course_structure_id?: string;
};

@Injectable()
export class LangCourseService {
private readonly app;

constructor() {
  this.app = this.buildflow();
}

private buildflow() {
  const CourseMetadataAgentAnnotation = Annotation.Root({
    messages: Annotation<BaseMessage[]>,
    userInput: Annotation<string>,
    courseInput: Annotation<courseData>,
    courseScore: Annotation<number>,
    courseOutput: Annotation<{
      course_title: string;
      short_Desc: string;
      detailed_desc: string;
      tags: string[];
    }>,
  });

  const course_reviewer = new DynamicStructuredTool({
    name: 'course_reviewer',
    description: ``,
    schema: z.object({
      course_title: z.string().describe('Title of the course'),
      course_description: z.string().describe('Description of the course'),
    }),
    func: async ({ course_title, course_description }) => {

      console.log("Course Title", course_title)
      console.log("course description", course_description)

      const prompt = `Evaluate the following course based on clarity, relevance, and detail.
          Return a score between 1 and 10, and provide a short comment.

          Course Title: ${course_title}
          Course Description: ${course_description}

          Format:
          Score: <number>
          Comment: <text>
          `
       
          const agents = await model.invoke([new HumanMessage(prompt)]);
      
          const text = agents.content as string;
          const match = text.match(/Score:s*(d+)/i);
          const commentMatch = text.match(/Comment:s*(.*)/i);

          console.log("Score",match ? parseInt(match[1]) : 0);
          
          return {
              score: match ? parseInt(match[1]) : 0,
              comments: commentMatch ? commentMatch[1] : 'No comment',
          };
    },
  });

  const save_course = new DynamicStructuredTool({
    name: 'save_course',
    description: `Saves the course details to the database.
          * PURPOSE: Saves the course details to the database.
          * INPUT: A data object containing course details.
          * OUTPUT: An object with the course ID and a success message.
          * EXAMPLES:
          - "Save the course details to the database."
          - "Store the course information in the system."`,
    schema: z.object({
      course_title: z.string().describe('Title of the course'),
      course_description: z.string().describe('Description of the course'),
    }),
    func: async ({ course_title, course_description }) => {
      console.log('Saving course:', { course_title, course_description });

      return {
        course_id: 'course-12345',
        message: 'Course saved successfully',
      };
    },
  });

  const shouldContinue = ({
    messages,
  }: typeof CourseMetadataAgentAnnotation.State) => {
    const lastMessage = messages[messages.length - 1] as AIMessage;
    return lastMessage.tool_calls?.length ? 'tools' : '__end__';
  };

  const tools = [course_reviewer, save_course];

  const tool = new ToolNode(tools);

  const model = new ChatGoogleGenerativeAI({
    apiKey: 'AIzaSyBs1GoNE5PScHx8_U6ErN2Y2CdNVutsIjQ',
    model: 'models/gemini-2.5-flash',
  });

  const chatModel = async (
    state: typeof CourseMetadataAgentAnnotation.State,
  ) => {
    const messages: BaseMessage[] = [new AIMessage(`You are a helpful course generation assistant.

          Your job is to:
          1. Generate a course based on the user's course idea and targeted audience.
          2. Use the "course_reviewer" tool to evaluate the generated course.
          3. If the score is less than or equal to 5, regenerate a new course and re-evaluate.
          4. Repeat until the score is greater than 5.
          5. Once a good-quality course is achieved (score > 5), call the "save_course" tool with the course details.

          Always ensure:
          - The course is well-structured, relevant to the audience, and clearly described.
          - You follow the tool call format properly and wait for score feedback before proceeding.- Always use the same course content that was evaluated.`),
      ...state.messages];

    const response = await model.bindTools(tools).invoke(messages);
    

    return {
      ...state,
      messages: [...state.messages, response],
    };
  };

  const checkpointSaver = new MemorySaver();

  return new StateGraph(CourseMetadataAgentAnnotation)
    .addNode('chatModel', chatModel)
    .addNode('tools', tool)
    .addEdge('__start__', 'chatModel')
    .addEdge('tools', 'chatModel')
    .addConditionalEdges('chatModel', shouldContinue)
    .compile({
      checkpointer: checkpointSaver,
    });
}

async interact(thread_id: string,user_thought: string, targeted_audience: string) {
  const result = await this.app.invoke({
    messages: [
      new HumanMessage(
        `Create a course title and description based on the following user idea:
          ${user_thought}

          Ensure the course is suitable for the target audience:
          ${targeted_audience}`,
      ),
    ],
  },{
      configurable: {
          thread_id,
      }
  });

  return result.messages[result.messages.length - 1];
}
}

How to deal with the printer using Node.js

I have a lot of problems when I try to deal with the printer using Node.js.

I have tried a lot of libraries like :

  • pdf-to-printer – it is good, but when I use the fit option, it makes the printing unclear, and also puts a huge margin on the top of the paper.

  • node-thermal-printer & node-printer. I encountered some issues with these libraries and was unable to install them at all. I tried many solutions, but they could not solve the problems.

  • I also use Electron in my project, and I tried to use the print method of the window, but it has some issues with silent printing and page size.

I want a library that could give me the ability to send a PDF file to the printer and print it properly.

This is the code that I am using right now:

const fs = require('fs');
const { print } = require("pdf-to-printer");

async function generate_and_print_invoice(event, html, width_mm = 80) {
    const win = new BrowserWindow({ show: false, webPreferences: { offscreen: true } });
    try {
        await win.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`);

        const height_px = await win.webContents.executeJavaScript('document.body.scrollHeight');
        const pdf_buffer = await win.webContents.printToPDF({
            printBackground: true,
            pageSize: { width: Math.round(width_mm * 0.0393701), height: Math.round(height_px * 0.01045) },
            margins: { top: 0, right: 0, bottom: 0, left: 0 }
        });

        const file_path = path.join(process.cwd(), 'invoice.pdf');
        fs.writeFileSync(file_path, pdf_buffer);

        const response = await print(file_path);

        try {
            fs.unlinkSync(file_path);
        } catch (err) {
            console.log(err);
        }

        win.close();
        return { success: true };
    } catch (error) {
        win.close();
        return { success: false, error: error.message };
}

Intelephense is showing Undefined Type errors that are not true

Windows 11: 24h2
VS Code: 1.102.1 (WSL: Ubuntu 24.04.2 LTS)
Intelephense: 1.14.4
Symfony: v6.4.23
PHP: 8.2.28

<?php

namespace AppCommand;

use DoctrineBundleFixturesBundleFixture;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputArgument;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;

#[AsCommand(
    name: 'app:fixtures:load-one',
    description: 'Load a single Doctrine fixture by class name',
)]

All of the symfony classes are highlighted with a red line by Intelephense.
The above snippet shows that the AsCommand has been included but the line #[AsCommand( shows an error of:

Undefined type 'SymfonyComponentConsoleAttributeAsCommand'.intelephense(P1009)
class SymfonyComponentConsoleAttributeAsCommand
function AsCommand::__construct(
    string $name,
    string|null $description = null,
    array $aliases = [],
    bool $hidden = false
)
Service tag to autoconfigure commands

I am seeing the exact same error from:

  • class ClassName extends Command
    • Undefined type ‘SymfonyComponentConsoleCommandCommand’.intelephense(P1009)
  • parent::__construct();
    • Undefined type ‘SymfonyComponentConsoleCommandCommand’.intelephense(P1009)
  • $this->addArgument(...);
    • Undefined method ‘addArgument’.intelephense(P1013)
  • protected function execute(InputInterface $input, OutputInterface $output): int
    • Undefined type ‘SymfonyComponentConsoleInputInputInterface’.intelephense(P1009)
    • Undefined type ‘SymfonyComponentConsoleOutputOutputInterface’.intelephense(P1009)

I have tried:

  • Restarting
    • laptop
    • PHP
    • Symfony:server
    • VS Code
  • Force Intelephense to reindex
  • Regenerate autoloader (composer dump-autoload –optimize)

I only have two options left that I can think of that include removing intelephense or specifically applying a setting that stops this (which seems pointless as then its not doing its job) "intelephense.diagnostics.undefinedTypes": false,

PHP $_GET always empty in IIS Server [closed]

I would like to ask for help with my PHP website that running on IIS Server version 10, as I have no experience with IIS.

Currently, the website face “too many redirects” error after login because the function always checks $_GET[‘code’], but $_GET[‘code’] is always empty.

public function isauthenticated($appid,$twofa = null,$return_uri = null) {
    
    file_put_contents("log_code_check.txt", "[" . date("Y-m-d H:i:s") . "] code param 1: " . ($_GET['code'] ?? 'NULL') . "n", FILE_APPEND);
    
    $this->appid = $appid;
    $this->returnuri = $return_uri;
    
    if ( !isset($_GET['code']) ) {
        $this->getAuthorized($twofa);
    }
    
    return TRUE;
}

After the login process, we can actually see the code parameter in the URL like this:

http://cls.nus.edu.sg/nusgerman?code=AAAAAAAAAAAAAAAAAAAAAA.sovlCnfD3QiPAMLpX5ySy_K9ekQ.JswjwasWN9ipSItHr5hLOfodtzaUQybLo7j5JcYCwAm9py0OrGqhl77kmbdK6XNvTIKhgQ4Jt1wodK3Dh3Gt3PbZKMTnorQBrWbZo8o3WfSwAgJFj2Vq2ZyOn-Th9_Kz_-CLCZHK-5xOkve_l1Xf33ZSibLF0YXPw-hBHathjpIZslKELYvKl5vpa61KeiIU1R0da6ntK773mGRGzjFLSgxAjQ8_NrOiPvbx3l2CKb7-IFvqa131rwNloryt32oZPWwCWvLQf-9ScB6Ajbfef8dPaSFTb9GYjPZ8Qvvx0ir31TpzoGAdyLI1ZiUitfCUVPpIEOa4_y5QFle-EetJWQ

Log file also captured empty code parameter like this:

[2025-07-17 07:22:35] code param 1: NULL

here’s my web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <defaultDocument>
            <files>
                <clear />
                <add value="Default.htm" />
                <add value="Default.asp" />
                <add value="index.htm" />
                <add value="index.html" />
                <add value="iisstart.htm" />
                <add value="index.php" />
            </files>
        </defaultDocument>
        <httpProtocol>
            <customHeaders>
                <add name="Cache-Control" value="max-age=300" />
                <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" />
                <add name="X-Content-Type-Options" value="nosniff" />
                <add name="X-Frame-Options" value="SAMEORIGIN" />
                <add name="X-Powered-By" value="ASP.NET" />
                <add name="X-XSS-Potection" value="1;mode=block" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>

How to process data of one client in different browser tabs? [closed]

There is such a difficulty. The client fills out a form on the site, with data on several clients, and does it not in turn, but in parallel, in several browser tabs. The question is, how to process such data?

If you store such data in sessions or cookies, they can be overwritten, I talked about localsession, but you can only work with it from js, is there a solution in php?

Change event date to TBD in Modern Event Calendar (aka MEC)

I want to change the date of a specific event to TBD, I can’t see any opton in Modern Event Calendar WordPress plugin. I have the php code but its not working.

add_filter('the_content', function($content) {
    if (is_singular('mec-events')) {
        $event_id = get_the_ID();
        $start_date = get_post_meta($event_id, 'mec_start_date', true);

        if ($start_date === '2099-12-31') {
            // Replace any date pattern with "TBD"
            $content = preg_replace('/d{1,2}s+w+s+d{4}/', 'TBD', $content);
            $content = str_replace('2099', 'TBD', $content); // fallback
        }
    }

    return $content;
});

I am adding this into code snippet but nothing changed.

PHP Equivalent of Mysql inet6_aton() function

Our client is using a version of Mysql that does not support the inet6_aton() function.

What would be the PHP equivalent for the inet6_aton function?

The inet6_aton() function returns the numeric value of the address in VARBINARY data type: VARBINARY(16) for IPv6 addresses and VARBINARY(4) for IPv4 addresses.

We have tried a few functions that convert IP to binary but none of them have the same output as the inet6_aton() function.

Below is the desired output that we are trying to achieve with PHP.

SELECT inet6_aton('214.0.0.0');

// OUTPUT

0xd6000000