Why declare the function as async when the other function inside the function block is itself an asynchronous function

const fs = require('fs').promises

const filePath = './me.txt';
async function  readFileAsync(){
 try{
    const data=  await fs.readFile(filePath,'utf-8')
    console.log(data)
 }
 catch(err){
    console.log(err)
 }

}
readFileAsync()

taking the above code as an example.We know fs.readFile() is an async function and returns a promise and await will return the resolved value of the promise.Then why do we need to declare the readFileAsync with the async keyword?

React Hook “useGetCatalogueDataByIdQuery” is called conditionally. React Hooks must be called in the exact same order in every component render

I have this component where i don’t want to all api unless Catalogue id exists

const GeneralInfoForm = ({ currentStep, setCurrentStep }: GeneralInfoFormValues) => {
  const user = getCurrentUser();
  const dispatch= useAppDispatch()
  // Mutation hook for adding catalogue info
  const [addCatalogueInfoMutation, { isLoading }] = useAddCatalogueInfoMutation();
  const CatalogueIdFromStore=useAppSelector((state)=>state.catalogueId.id)
  const { data} = CatalogueIdFromStore && useGetCatalogueDataByIdQuery({ catalogueId:CatalogueIdFromStore,queryParams:'' });
  console.log(data,"from general info")

but it says

React Hook "useGetCatalogueDataByIdQuery" is called conditionally. React Hooks must be called in the exact same order in every component render.eslintreact-hooks/rules-of-hooks
(alias) useGetCatalogueDataByIdQuery<UseQueryStateDefaultResult<QueryDefinition<any, BaseQueryFn<FetchArgs, BaseQueryApi, DefinitionType>, "brand" | "draftsTask" | "allEmployees", any, "baseApi">>>(arg: any, options?: (UseQuerySubscriptionOptions & UseQueryStateOptions<...>) | undefined): UseQueryHookResult<...>
import useGetCatalogueDataByIdQuery

how can i solve this problem?

Cannot perform CRUD (DELETE operation) on MongoDB (MERN stack)

I’m working on a MERN stack “to-do list” application which performs CRUD operations. I could successfully implement “adding task to the database” functionality. However, for “removing task” I’m facing with Internal Server Error that I can’t fix although I’ve done research and tried multiple solutions.

I’m sharing related code snippets and I hope someone can help me a bit.

In my client folder, Task.jsx component:

function Task({ task }) {
    const { _id, taskId, title, description, completed } = task;
    const { userToken, dispatch } = useContext(TaskContext);

    const handleRemove = async (e) => {
        e.preventDefault();
        console.log("Task ID to remove:", _id);
    
        try {
            const res = await axios.get("/task/removeTask", {
                headers: {
                    Authorization: `Bearer ${userToken}`
                },
                params: {
                    _id: taskId
                }
            });
            console.log("Task deletion response:", res.data);
            dispatch({
                type: "REMOVE_TASK",
                _id
            });
        } catch (error) {
            console.error("Error removing task:", error);
            // Handle error state or display an error message to the user
        }
    }

taskReducer.js file:

function taskReducer(tasks, action) {
    console.log("taskreducer");
    switch (action.type) {
        // eslint-disable-next-line no-lone-blocks
        case "ADD_TASK": {
            return [
                ...tasks,
                {
                    _id: action._id,
                    title: action.title,
                    description: action.description,
                    completed: false
                }
            ]
        }
        case "SET_TASK": {
            return action.payload
        }
        case "REMOVE_TASK": {
            console.log("Tasks before removal:", tasks);
            const updatedTasks = tasks.filter((task) => task._id !== action._id);
            console.log("Tasks after removal:", updatedTasks);
            return updatedTasks;
        }

In my server folder, taskController.js file:

import taskModel from "../models/taskModel.js";
import userModel from "../models/userModel.js";
import dotenv from "dotenv";
import mongoose from "mongoose";
dotenv.config();

const addTask = async (req, res) => {
    const { _id, title, description } = req.body;
    const userId = req.user.id;

    const user = await userModel.find({_id: userId});
    if (!user) {
        return res.status(404).json({ message: "User not found" });
    }

    const taskId = _id ? mongoose.Types.ObjectId(_id) : new mongoose.Types.ObjectId();

    console.log("Task to be saved:", { taskId, title, description, completed: false, userId });

    const newTask = new taskModel({ _id: taskId, title, description, completed: false, userId })

    newTask.save()
        .then((savedTask) => {
            return (res.status(200).json({ message: "Task added successfully", task: savedTask }))
        })
        .catch((error) => {
            return (
                res.status(500).json({ message: error.message })
            )
        }
        )
}

const removeTask = (req, res) => {
    const { _id } = req.body;
    const taskId = req.task._id;

    console.log("Task ID to remove:", _id); // Log the ID being used for deletion

    taskModel.findByIdAndDelete({ _id: taskId })
        .then((deletedTask) => {
            if (!deletedTask) {
                return res.status(404).json({ message: "Task not found" });
            }
            console.log("Deleted task:", deletedTask); // Log the deleted task
            return res.status(200).json({ message: "Task deleted successfully" });
        })
        .catch((error) => {
            console.error("Error deleting task:", error); // Log any errors
            return res.status(500).json({ message: "Internal server error" });
        });
}

const getTask = (req, res) => {
    taskModel.find({ userId: req.user.id })
        .lean() // Convert Mongoose documents to plain JavaScript objects
        .then((data) => res.status(200).json(data))
        .catch((error) => res.status(501).json({ message: error.message }))
}

export { addTask, getTask, removeTask }

taskRouter.js file:

router.post("/addTask", requireAuth, addTask)
router.get("/getTask", requireAuth, getTask)
router.get("/removeTask", requireAuth, removeTask)

Only removeTask function doesn’t work.

When I add a task, this is the response I’m getting on my browser console:

XHR OPTIONS http://localhost:8000/api/task/addTask[HTTP/1.1 204 No Content 6ms]

XHR POST http://localhost:8000/api/task/addTask[HTTP/1.1 200 OK 468ms]

When I click on the delete button to remove a task, this is the response:

Task ID to remove: 662e7dc365cc6fb9a0e14ed7 // matches the database

XHR OPTIONS http://localhost:8000/api/task/removeTask[HTTP/1.1 204 No Content 10ms]

XHR GET http://localhost:8000/api/task/removeTask[HTTP/1.1 500 Internal Server Error 1ms]

Error removing task: message: “Request failed with status code 500”, name: “AxiosError”, code: “ERR_BAD_RESPONSE”, config: {…}, request: XMLHttpRequest, response: {…} }

​I’ve also tried router.delete("/removeTask") and axios.delete("/task/removeTask") instead of GET method but nothing changed.

I hope you can enlight me a bit about the issue because I’m stucked up on this for a couple of days. Thanks.

Error on Amadeus when trying to access my user token using JavaScript on a React Native App

Amadeus get token api error in JavaScript

Hello, I want to use the getToken Api provided by Amadeus using fetch in JavaScript in a React Native App. What I’am doing is the following:

(LOOK AT THE IMAGE TO SEE THE CODE IM USING)

Code im using

But I’m getting the following error:
{"code": 38187, "error": "invalid_request", "error_description": "Mandatory grant_type form parameter missing", "title": "Invalid parameters"}, I know that the AMADEUS_CLIENT_ID, AMADEUS_CLIENT_SECRET and BASE_GENERATE_TOKEN_AMADEUS_URL has the correct value

I don’t understand why I’m getting this error since I passing "grant_type": "client_credentials"
Can anyone please enlighten me with this problem??

Invalid site key or not loaded in api.js, Google reCAPTCHA Enterprise

Everytime I tried to render the reCAPTCHA manually using the render function I get the following error

Error: Invalid site key or not loaded in api.js: "6Lf....."

It works fine doing it the way shown in the docs

<head>
  <script src="https://www.google.com/recaptcha/enterprise.js?render=6L..."></script>
  <!-- Your code -->
</head>
<script>
  function onClick(e) {
    e.preventDefault();
    grecaptcha.enterprise.ready(async () => {
      const token = await grecaptcha.enterprise.execute('6L...', {action: 'LOGIN'});
    });
  }
</script>

But whenever I try:

<script src="https://www.google.com/recaptcha/enterprise.js?render=explicit&onload=onRecaptchaLoadCallback"></script>

// recaptcha.js
function onRecaptchaLoadCallback(){
 grecaptcha.enterprise.render('recaptcha', {
        sitekey: "6L...",
        badge: 'inline',
        size: "invisible",
        callback: function () {
            console.log('recaptcha callback');
            }
    })
}

// executed upon form onsubmit
function onClick(e) {
  e.preventDefault();
  grecaptcha.enterprise.ready(async () => {
    const token = await grecaptcha.enterprise.execute('KEY_ID', {action: 'LOGIN'});
    
  });
}

I get the above-stated error. I have already double-checked the keys and tried creating a new key, but it did not work. Any ideas as to why it doesn’t work when trying to render manually?

Ignore largely differing electronics input values

I have a physical, draggable device connected to a Raspberry Pi, which upon movement outputs its current position as keyboard input. The physical device can “have a position” in the range from 91 pixels to 955 pixels.

The pixels are supposed to control an image on a screen. The image should scroll up/down smoothly based on the handle’s position/generated values. See below picture for visualization.

Visualization of setup

This works OK when dragging the handle downwards; the values are fairly sequential. But when dragging the handle it upwards, the electronics output random/jumpy values.

I need help with the maths to normalize the values and ignore large diffs in JavaScript.

I.e. the values might go smoothly from 92, 94, 96, 100, 105… for a while, and then suddenly jump to 847.

I can’t fix the electronics unfortunately, so I need a programmatic solution.

Here’s a real example of keyboard output received from the electronic device:

const values = [
  92,
  94,
  96,
  100,
  102,
  105,
  107,
  112,
  123,
  134,
  116,
  114, // Last acceptable position
  847, // Huge diff compared to previous value
  299,
  628, // Huge diff again
  559, // Not as big of a diff compared to the previous value, but too big compared to 114 which was the last acceptable value
  395,
  788,
  189,
  948,
  135, // ≈ 20 px difference to 114 would be OK
  907,
  190,
  853,
  134,
  981,
  34,
  940,
  64,
  899,
  214,
  168,
  174,
  182,
  187,
  189,
  191,
  193,
  195,
  198,
  200,
  204,
  209,
  211,
  214,
  217,
  220,
  222,
  225,
  231,
  229,
  232,
  225,
  233,
  230,
  245,
  241,
  237,
  241,
  239,
  242,
  57,
  275,
  125,
  242,
  238,
  245,
  240,
  243,
  230,
  244,
  233,
  360,
  241,
  248,
  240,
  249,
  251,
  260,
  32,
  1007,
  68,
  1018,
  243,
  711,
  498,
  440,
  765,
  199,
  951,
  121,
  932,
  148,
  274,
  271,
  214,
  271,
  285,
  267,
  351,
  246,
  376,
  102,
  412,
  61,
  580,
  0,
  336,
  270,
  391,
  269,
  279,
  282,
  284,
  288,
  291,
  293,
  298,
  305,
  309,
  311,
  313,
  318,
  322,
  324,
  330,
  332,
  337,
  332,
  339,
  980,
  120,
  835,
  370,
  557,
  667,
  273,
  909,
  77,
  761,
  324,
  873,
  104,
  1005,
  156,
  799,
  418,
  509,
  715,
  229,
  366,
  369,
  410,
  369,
  365,
  374,
  376,
  381,
  383,
  387,
  392,
  394,
  398,
  405,
  408,
  410,
  418,
  427,
  433,
  437,
  439,
  441,
  228,
  660,
  562,
  362,
  849,
  120,
  999,
  25,
  993,
  60,
  916,
  70,
  900,
  81,
  884,
  191,
  879,
  196,
  873,
  101,
  1007,
  168,
  781,
  444,
  479,
  749,
  198,
  961,
  101,
  959,
  103,
  956,
  40,
  946,
  48,
  934,
  56,
  808,
  268,
  918,
  68,
  904,
  78,
  886,
  460,
  472,
  480,
  489,
  497,
  499,
  501,
  509,
  520,
  526,
  528,
  530,
  536,
  544,
  551,
  565,
  558,
  556,
  558,
  532,
  558,
  556,
  584,
  500,
  558,
  551,
  540,
  612,
  559,
  579,
  581,
  583,
  581,
  590,
  596,
  598,
  600,
  606,
  615,
  622,
  626,
  628,
  632,
  646,
  659,
  962,
  687,
  699,
  705,
  710,
  714,
  720,
  729,
  740,
  757,
  753,
  775,
  748,
  757,
  204,
  775,
  789,
  802,
  811,
  813,
  815,
  818,
  827,
  830,
  832,
  836,
  841,
  845,
  847,
  850,
  852,
  842,
  852,
  828,
  851,
  849,
  852,
  849,
  852,
  850,
  852,
  850,
  853,
  851,
  864,
  829,
  852,
  850,
  852,
  850,
  852,
  854,
  852,
  861,
  326,
  871,
  129,
  880,
  887,
  894,
  899,
  903,
  905,
  908,
  910,
  912,
  915,
  919,
  921,
  927,
  932,
  934,
  939,
  944,
  947,
  949,
  954,
  978,
  923,
  1002,
  872,
  965,
  877,
  964,
  912,
  987,
  957,
  966,
  973,
  962,
  978,
  939,
  1021,
  723,
  989,
  899,
  1023,
  961,
  963,
  959,
  1020,
  957,
  962,
  960,
  968,
  944,
  980,
  961,
  963,
  961]

I tried calculating the difference between the previous position and the received value, and skipping it if it was too big (i.e. over 20 pixels). This works OK when dragging the handle downwards because the received input is within the limit, but not with the dataset received when going upwards.

The jump in values becomes too big at some point, and then the graphic becomes “stuck” because the handle has been dragged too rapidly and it’s (seemingly) impossible to determine its new “real” location.

I.e. if looking at the above data set, 114 would have been the “last acceptable position” (index 11 in the array) and then the new acceptable position would be 135 (index 20) and then I suppose somewhere around 168 after that.

The handle is user-controlled (i.e. a human being dragging the handle), so there’s no way to programmatically “stop” it or alter its position, or put any resistance on it.

I’ve also tried to use the mean value from the last 3 and 5 values, but that didn’t seem like the best approach because sometimes there are too many incorrect consecutive values (10-ish), which distorts the last known “real” position. Or should I just increase the amount of values included in the mean? How then to handle “edge cases” like when the draggable handle is at the very top/bottom and there are no previous values to refer to?

Any help/ideas/creative approaches are much welcome!

Image uploading issue to the backend using Axios and FormData in React Native

I’m using Axios for backend requests to upload form data, including images. I’ve wrapped the image data as an object with properties like uri, name, etc. However, upon making the request, the response shows null for the image path and URL and the rest data is uploaded successfully. I dont have the access for backend but on postman the image is uploading.Could anyone provide guidance on how to troubleshoot this issue?

        const data = new FormData();
        // const fileUri = Platform.OS === 'ios' ? image.replace('file://', '') : image;
        const fileExtension = getFileExtension(image) || 'jpg'; // Default extension 'jpg'
        const fileName = `imageMed.${fileExtension}`;
        data.append('file', {
            uri: image,
            name: fileName,
            type: `image/${fileExtension}`,
        });

        data.append('name', MedicineName);
        data.append('dosage', dose);
        data.append('start_time', `${Newdate} ${Newtime}`);
        data.append('number_of_days', days);
        data.append('frequency', freNumber);
        data.append('days_of_the_week', '1,2,3');
        data.append('st_notification', !isNotify ? 0 : 1);
        data.append('st_critical', !priority ? 0 : 1);
        data.append('default_icon', selectedImage);
        data.append('medicine_schedules', 'test_string');

        let config = {
            method: 'post',
            maxBodyLength: Infinity,
            url: 'https://api-patient-dev.easy-health.app/medicines',
            headers: {
                'Content-Type': 'multipart/form-data',
                'Authorization': `Bearer ${access_token}`,
            },
            data: data
        };
        console.log(data);
        axios.request(config)
            .then((response) => {
                console.log(JSON.stringify(response.data));
                renderAlarmComponents(response.data, userId);
            })
            .catch((error) => {
                console.log(error);
            })
            .finally(() => {
                setShowLoader(false);
                // navigation.navigate('Dashboard', {
                //     isChanged: true,
                // });
            });
    }

Page can’t render normally animated image with lib GSAP

I did animation when scrolling for a picture, cut out a lot of frame-by-frame pictures and made animation, but here’s the problem, when loading the page there is no picture, it appears only if scrolled, and disappears back if scrolled back up, please help…

i think it’s solution in render(), but i don’t know how to solve this. I’m thinking of making it render not only by scrolling, but also just like that when the page loads.

<div class="hero">
                    <div id="home">
                        <canvas></canvas>
                    </div>
                    <div class="about"></div>
                </div>
function sequence_animation() {
        const canvas = document.querySelector('#home>canvas');
        const context = canvas.getContext('2d');
    
        canvas.width = 1500;
        canvas.height = 700;
    
        let imagesLoaded = 0;
        const frameCount = 19;
        const images = [];
        const imageSeq = {
            frame: 0,
        };
    
        function files(index) {
            var data = `
            ../assets/img/animation/1.png
                ../assets/img/animation/1.png
                ../assets/img/animation/1-2.png
                ../assets/img/animation/2.png
                ../assets/img/animation/2-2.png
                ../assets/img/animation/3.png
                ../assets/img/animation/3-2.png
                ../assets/img/animation/4.png
                ../assets/img/animation/4-2.png
                ../assets/img/animation/5.png
                ../assets/img/animation/5-2.png
                ../assets/img/animation/6.png
                ../assets/img/animation/6-2.png
                ../assets/img/animation/7.png
                ../assets/img/animation/7-2.png
                ../assets/img/animation/8.png
                ../assets/img/animation/8-2.png
                ../assets/img/animation/9.png
                ../assets/img/animation/9-2.png
                ../assets/img/animation/10.png
            `;
            return data.split('n')[index].trim();
        }
    
        for (let i = 0; i < frameCount; i++) {
            const img = new Image();
            img.src = files(i);
            images.push(img);
            img.onload = () => {
                imagesLoaded++;
                if (imagesLoaded === frameCount) {
                    render();
                }
            };
        }
    
        window.addEventListener('resize', function () {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            render();
        });
    
        gsap.to(imageSeq, {
            frame: frameCount - 1,
            snap: 'frame',
            ease: 'none',
            scrollTrigger: {
                scrub: 1,
                pin: false,
                trigger: '.header__list-item.message',
                start: 'left %',
            },
            onUpdate: render,
        });
    
        function render() {
            scaleImage(images[imageSeq.frame | 0], context);
        }
    
        function scaleImage(img, ctx) {
            var canvas = ctx.canvas;
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
        }
    }
    
    sequence_animation();
})
canvas {
    margin: 0 auto;
    margin-top: -189px;
    display: block;
    aspect-ratio: 16 / 9;
}

how d loading the github file to my application i created using django framework

This view fetches repositories of the authenticated user from GitHub

Retrieve the access token from the session after OAuth authentication

def github_repositories(request):
access_token = request.session.get(‘github_access_token’)

# Check if the access token exists
if access_token:
    # Set up the headers for GitHub API request
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Accept': 'application/vnd.github.v3+json'
    }
    
    # Make a GET request to GitHub API to fetch user repositories
    response = requests.get('  https://api.github.com/orgs/ORG/repos', headers=headers)
    
    # Check the response status code
    if response.status_code == 200:
        # Parse the JSON response to extract repositories
        repositories = response.json()
        # Pass repositories to the template
        return render(request, 'dashboard.html', {'repositories': repositories})
    else:
        # Handle API request errors
        return HttpResponse('Error fetching repositories', status=response.status_code)
else:
    # Redirect the user to log in with GitHub if the access token is not found
    return redirect('github_login')

iam execting solutions responses from you also you may email me through [email protected]

How can I correctly print the value of request.endpoint in Flask?

A student here, currently learning Flask and learning how to use request.endpoint.

When I attempt to print it, it shows ‘static’ instead. I’d like it to print the current route, for example: ‘index’ or ‘login’

Here’s an example from my console:

127.0.0.1 - - [28/Apr/2024 11:12:35] "GET /static/css/style.css HTTP/1.1" 304 -
before_request
static 

It seems that it’s not capturing the correct route; instead, it’s picking up routes for my JavaScript or CSS files and that applies to every route. I’d like it to print the current route, for example: ‘index’ or ‘login’ instead of ‘static’

How can I correctly print request.endpoint, but without excluding my CSS and JS routes?”

Parts of my code:

main.py

@app.before_request
def before_request():
    print("before_request")

    if 'username' not in session:
        print(request.endpoint) 

@app.route('/', methods = ['GET', 'POST'])
def index():
    if 'username' in session:
        username = session['username']
        print(username)

    title = "Curso Flask"
    return render_template('index.html', title = title,) 

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    
    <title>{%block title%} {%endblock%}</title>

<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

</head>
<body>
    <h1>Hola mundo desde mi base.html</h1>

    <!--Ejemplo de flash message para recibir el response de un mensaje-->
    {% with messages = get_flashed_messages() %}
        {% if messages %}
            <ul>
                {% for message in messages %}
                    <li>{{message}}</li>
                {%endfor%}
            </ul>
        {%endif%}
    {%endwith%}

    {% block content %}
    
    {% endblock %}

    <script type="text/javascript" src="{{ url_for('static', filename='js/jquery.js') }}"></script>
</body>
</html>

Index.html

{% extends 'base/base.html'%}

{% block title %} {{ title }} {%endblock%}

{% block content %}
    <h2>Hola mundo desde mi index.html</h2>

    <!--Esto es para importar el macro-->
    {% from "_macro.html" import show_list_h %}

    <!--Esto es para llamar al macro-->
    {{ show_list_h('Hola mundo desde mi macro')}}

{% endblock %}

There’s more, but I condensed it to what I think is most relevant.

okay so i created this season greetings website and used github to host it live,but it displays a github page i don’t seem to understand

[first step
output
where where the problem is ](https://stackoverflow.com)
so when I pass through the first the stage, get my output and send it to someone through the WhatsApp link, it always show the GitHub part
I just want it to display the output to whomever clicks the link sent via WhatsApp, or does this have to do with the fact GitHub can't handle it, maybe I need to host it? like domain stuff and the rest
I was expecting it to showcase when I send it via WhatsApp, to display what came out as the output

Why isn’t value assigned and cleared here?

I’m trying Svelte 5 for the first time today.

This is a reproduction of this issue.

As you can see if I select a date from the picker the {value} is not assigned and the same if I press the “Clear” button.

Why?

Relevant code

<script lang="ts">
    type Props = {
        value?: Date | null;
        id?: string;
        onchange?: (e: Date | undefined) => void;
    };

    let {
        value = $bindable(),
        id,
        onchange,
    }: Props = $props();

    $effect(() => {
        console.log('value in $effect:', value);
    });

    $inspect(value);

    const format = (date: typeof value): string => {
        if (!date) return '';

        if (date instanceof Date && isNaN(date.getTime())) return '';

        return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, -8);
    };

    function handleOnChange(e: Event) {
        const dateValue = new Date((e.target as HTMLInputElement).value);

        console.log('handleOnChange:', dateValue);

        value = dateValue;

        if (onchange) onchange(dateValue);
    }

    function handleClear() {
        console.log('handleClear :');

        value = undefined;

        if (onchange) onchange(value);

        (document.getElementById(id) as HTMLInputElement).value = '';
    }
</script>

<div>
    {value}

    <button type="button" onclick={handleClear}>Clear</button>

    <input
        type="datetime-local"
        {id}
        value={format(value)}
        onchange={handleOnChange}
    />
</div>

Content Security Policy blocking localhost in Firefox

OS etc Developing on Lubuntu 20.04 inside Virtualbox 5.2.42 on host Ubuntu 18.04.6 LTS

I’m serving a site on localhost using the php development server:

php -S 0.0.0.0:8080 -t /home/alan/DEV/

index.html is

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
  <div id="main"></div>
  <script src="/main.js"></script>
  <script src="/script.js"></script>
</body>
</html>

Chromium has no problem viewing the page at localhost:8080. Until recently, neither did Firefox.

However, I just tried to connect on Firefox 122.0.1 . Nothing of the page is displayed, and I get these errors in the browser console:

Content-Security-Policy: The page's settings blocked the loading of a resource at data: ("media-src"). localhost:8080
Content-Security-Policy: The page's settings blocked the loading of a resource at http://localhost:8080/main.js ("script-src-elem"). localhost:8080
Content-Security-Policy: The page's settings blocked the loading of a resource at http://localhost:8080/script.js ("script-src-elem"). localhost:8080

Looking at about:config in Firefox, and searching on content-security, I see the following:

extensions.webextensions.base-content-security-policy:

script-src 'self' https://* http://localhost:* http://127.0.0.1:* moz-extension: blob: filesystem: 'unsafe-eval' 'wasm-unsafe-eval' 'unsafe-inline';

extensions.webextensions.base-content-security-policy.v3:

script-src 'self' 'wasm-unsafe-eval';

extensions.webextensions.default-content-security-policy:

script-src 'self' 'wasm-unsafe-eval';

extensions.webextensions.default-content-security-policy.v3:

script-src 'self'; upgrade-insecure-requests;

I tried adding <meta http-equiv="Content-Security-Policy" content="default-src 'self'"> to the head of my index.html file, but it made no difference (except it partially screwed up the page layout on Chromium).

Notification.requestPermission() on Angular 17 standalone + PWA + Firebase chrome/safari compatibility

I’m trying to set up Firebase Cloud Messaging but I’m having compatibility issues with Safari I don’t know if it’s due to the script or the test http-server I’m running it on.
Since @angular/fire is not yet standalone compatible I opted for direct interaction of Firebase interconnected with the pwa worker (@angular/pwa).

I created a firebase-setup.ts on which to include the dedicated code… the problem with Safari desktop (17.4.1) is that I get the notification acceptance request popup randomly… doing many page refreshes … at you want by clicking cmd+enter … absurd.

firebase-setup.ts

import { initializeApp } from 'firebase/app';
import { getMessaging, getToken } from 'firebase/messaging';

const firebaseConfig = {
  ...
};

const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);

navigator.serviceWorker
  .getRegistration('./ngsw-worker.js')
  .then((registration) => {
    requestPermission(registration);
  });

async function requestPermission(
  registration: ServiceWorkerRegistration | undefined,
) {
  return new Promise((resolve) => {
    const timeoutId = setInterval(() => {
      if (Notification.permission === 'granted') {
        handleComplete(Notification.permission);
      }
    }, 3000);

    const handleComplete = (permission: NotificationPermission) => {
      clearInterval(timeoutId);
      resolve(permission);

      if (permission === 'granted') {
        getToken(messaging, {
          vapidKey: '...',
          serviceWorkerRegistration: registration,
        })
          .then((currentToken) => {
            if (currentToken) {
              console.log(currentToken);
            } else {
              console.log(
                'No registration token available. Request permission to generate one.',
              );
            }
          })
          .catch((err) => {
            console.log('Error token ', err);
          });
      }
    };

    Notification.requestPermission(handleComplete)?.then?.(handleComplete);
  });
}

main.ts

import '../firebase-setup'

app.component.ts

import { SwPush } from '@angular/service-worker';

export class AppComponent implements OnInit {
  swPush = inject(SwPush)

    ngOnInit(): void {
      this.subscribePush()
    }

    subscribePush(): void {
      this.swPush.messages.subscribe(
        (res: any) => {
          console.log(res, ' Message to show into notification')
        }
      )
    }
}