Getting Flask-MDEditor to work with Bootstrap 5

I am trying to get the Flask-MDEditor extension working with Bootstrap. I have been able to get the demo version (sans-Bootstrap) working but cannot get it to work properly within my project.

I am using Flask 2.3.3, Bootstrap 5.3.2, and Flask-MDEditor 0.1.5. Besides this issue with Flask-MDEditor, my project works otherwise and does not throw any errors.

I am a bit of a noob when it comes to JS and CSS, so any help is appreciated.

The basic implementation seems to work until rendering time. Placing the editor field inside of a form in the modal div seems to break the modal, as it never appears when called; placing it in a form outside of the modal works.

Inspecting the code in the browser (Firefox) reveals an error that repeats 4 times: `Uncaught TypeError: Element.prototype.querySelectorAll is undefined`. Following that error takes me to Bootstrap’s `selector-engine.js`. After that, I do not know what to check or what should happen.

Disabling the Bootstrap CSS allows the editor to be displayed properly both inside and outside the modal div but does not get rid of the JS errors: disabling Bootstrap’s JS does.

I’ve checked that the CSS and JS for the mdeditor field are after the CSS and JS for Bootstrap.

Execute JavaScript DOM with .NET

I have an HTML string that contains JavaScript code in the <script> tag. This string is passed to a C# program. I’ve read a lot about executing JS in C# (Jint, etc.), but I haven’t found a solution with which I can apply commands to the DOM part.
In general, JS will be composed before applying certain styles to HTML elements, and I plan to remove all JS from the string after its execution. Maybe there are alternatives to the solution?

Executing JS DOM in a C# program

How to count all objects with specific key recursive?

How i can count all objects that have specific key but if object can be nested and I do not know max depth of object because everytime is differente?

for exmaple once can be like this:

{
    "coins_series": [
        {
            "series": 1,
            "coins": [
                {
                    "_id": "65c8c78845d911984d98f6be",
                    "currency": "EUR",
                    "reverse_id": "SVN200701001REG",
                    "obverse_id": [
                        "EUR199901001FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 0.01,
                    "diameter": 16.25,
                    "thickness": 1.67,
                    "weight": 2.3
                },
                {
                    "_id": "65c8c78845d911984d98f6bf",
                    "currency": "EUR",
                    "reverse_id": "SVN200701002REG",
                    "obverse_id": [
                        "EUR199901002FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 0.02,
                    "diameter": 18.75,
                    "thickness": 1.67,
                    "weight": 3.06
                },
                {
                    "_id": "65c8c78845d911984d98f6c0",
                    "currency": "EUR",
                    "reverse_id": "SVN200701005REG",
                    "obverse_id": [
                        "EUR199901005FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 0.05,
                    "diameter": 21.25,
                    "thickness": 1.67,
                    "weight": 3.92
                },
                {
                    "_id": "65c8c78845d911984d98f6c1",
                    "currency": "EUR",
                    "reverse_id": "SVN200701010REG",
                    "obverse_id": [
                        "EUR200702010FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 0.1,
                    "diameter": 19.75,
                    "thickness": 1.93,
                    "weight": 4.1
                },
                {
                    "_id": "65c8c78845d911984d98f6c2",
                    "currency": "EUR",
                    "reverse_id": "SVN200701020REG",
                    "obverse_id": [
                        "EUR200702020FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 0.2,
                    "diameter": 22.25,
                    "thickness": 2.14,
                    "weight": 5.74
                },
                {
                    "_id": "65c8c78845d911984d98f6c3",
                    "currency": "EUR",
                    "reverse_id": "SVN200701050REG",
                    "obverse_id": [
                        "EUR200702050FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 0.5,
                    "diameter": 24.25,
                    "thickness": 2.38,
                    "weight": 7.8
                },
                {
                    "_id": "65c8c78845d911984d98f6c4",
                    "currency": "EUR",
                    "reverse_id": "SVN200701100REG",
                    "obverse_id": [
                        "EUR200702100FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 1,
                    "diameter": 23.25,
                    "thickness": 2.33,
                    "weight": 7.5
                },
                {
                    "_id": "65c8c78845d911984d98f6c5",
                    "currency": "EUR",
                    "reverse_id": "SVN200701200REG",
                    "obverse_id": [
                        "EUR200702200FRO"
                    ],
                    "country": "SVN",
                    "commemorative": false,
                    "series": 1,
                    "min_year": 2007,
                    "denomination": 2,
                    "diameter": 25.75,
                    "thickness": 2.2,
                    "weight": 8.5
                }
            ]
        }
    ],
    "country": "SVN"
}

and other time can be like this:

{
    "series": 2,
    "coins": [
        {
            "_id": "65c8c78845d911984d98f724",
            "currency": "EUR",
            "reverse_id": "VAT200502001REG",
            "obverse_id": [
                "EUR199901001FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 0.01,
            "diameter": 16.25,
            "thickness": 1.67,
            "weight": 2.3
        },
        {
            "_id": "65c8c78845d911984d98f725",
            "currency": "EUR",
            "reverse_id": "VAT200502002REG",
            "obverse_id": [
                "EUR199901002FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 0.02,
            "diameter": 18.75,
            "thickness": 1.67,
            "weight": 3.06
        },
        {
            "_id": "65c8c78845d911984d98f726",
            "currency": "EUR",
            "reverse_id": "VAT200502005REG",
            "obverse_id": [
                "EUR199901005FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 0.05,
            "diameter": 21.25,
            "thickness": 1.67,
            "weight": 3.92
        },
        {
            "_id": "65c8c78845d911984d98f727",
            "currency": "EUR",
            "reverse_id": "VAT200502010REG",
            "obverse_id": [
                "EUR199901010FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 0.1,
            "diameter": 19.75,
            "thickness": 1.93,
            "weight": 4.1
        },
        {
            "_id": "65c8c78845d911984d98f728",
            "currency": "EUR",
            "reverse_id": "VAT200502020REG",
            "obverse_id": [
                "EUR199901020FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 0.2,
            "diameter": 22.25,
            "thickness": 2.14,
            "weight": 5.74
        },
        {
            "_id": "65c8c78845d911984d98f729",
            "currency": "EUR",
            "reverse_id": "VAT200502050REG",
            "obverse_id": [
                "EUR199901050FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 0.5,
            "diameter": 24.25,
            "thickness": 2.38,
            "weight": 7.8
        },
        {
            "_id": "65c8c78845d911984d98f72a",
            "currency": "EUR",
            "reverse_id": "VAT200502100REG",
            "obverse_id": [
                "EUR199901100FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 1,
            "diameter": 23.25,
            "thickness": 2.33,
            "weight": 7.5
        },
        {
            "_id": "65c8c78845d911984d98f72b",
            "currency": "EUR",
            "reverse_id": "VAT200502200REG",
            "obverse_id": [
                "EUR199901200FRO"
            ],
            "country": "VAT",
            "commemorative": false,
            "series": 2,
            "min_year": 2005,
            "max_year": 2005,
            "denomination": 2,
            "diameter": 25.75,
            "thickness": 2.2,
            "weight": 8.5
        }
    ]
}

some other time can be different format. I need to count all objects with commemorative key each time without specific data structure.

CKEditor Webpack config errors

I’m trying to create webpack config for CKEditor 5. I’m trying to create custom build.
Here is my webpack.mix.js

const mix = require('laravel-mix');
require('laravel-mix-purgecss');


const { styles } = require( '@ckeditor/ckeditor5-dev-utils' );

const webpack = require('webpack');
/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js').vue()
        .postCss('resources/css/app.css', 'public/css', [
        require('postcss-import'),
        require('tailwindcss'),
        require('autoprefixer'),
        ])
    .webpackConfig(require('./webpack.config'));
const CKEditorWebpackPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin')
const CKEStyles = require('@ckeditor/ckeditor5-dev-utils').styles
const CKERegex = {
    svg: /ckeditor5-[^/\]+[/\]theme[/\]icons[/\][^/\]+.svg$/,
    css: /ckeditor5-[^/\]+[/\]theme[/\].+.css/
}

Mix.listen('configReady', webpackConfig => {
    const rules = webpackConfig.module.rules
    const targetSVG = /(.(png|jpe?g|gif|webp)$|^((?!font).)*.svg$)/
    const targetCSS = /.css$/

    // exclude CKE regex from mix's default rules
    // if there's a better way to loop/change this, open to suggestions
    for (const rule of rules) {
        if (rule.test.toString() === targetSVG.toString()) {
            rule.exclude = CKERegex.svg
        } else if (rule.test.toString() === targetCSS.toString()) {
            rule.exclude = CKERegex.css
        }
    }
});

mix.webpackConfig({
    module: {
        rules: [
            {
                test: /ckeditor5-[^/\]+[/\]theme[/\]icons[/\][^/\]+.svg$/,

                use: [ 'raw-loader' ]
            },
            {
                test: /ckeditor5-[^/\]+[/\]theme[/\].+.scss$/,

                use: [
                    {
                        loader: 'style-loader',
                        options: {
                            injectType: 'singletonStyleTag',
                            attributes: {
                                'data-cke': true
                            }
                        }
                    },
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: styles.getPostCssConfig( {
                                themeImporter: {
                                    themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' )
                                },
                                minify: true
                            } )
                        }
                    }
                ]
            }
        ]
    },
    }
);

But after all I get only

CKEditorError: svg is null
Read more: https://ckeditor.com/docs/ckeditor5/latest/support/error-codes.html#error-svg is null

XML parsing error: incorrect
Line 1, character 1:

I’m trying to add custom CkEditor 5 build for my vue js|Laravel application

How do I make Reactjs access deeply nested data from a json response? I’m getting a TypeError when I try to access them

I am currently learning react and I’m trying to use real-world APIs’ as a data source for my react app. I am using an API which provides a json response as follows.
json response from the API
When I try to console.log the info, I am able to print it out, but using it in the app is giving me this error
error message while trying to fetch data.
for example, I am trying to fetch JSON.data.cards[0].groupedCard.cardGroupMap.RESTAURANT.cards[0].card.card.info.id But the app is complaining that it’s not defined.

While I was going through other responses, I did figure out to have an await for the promise to resolve and then set it to the variable.

const data = await fetch(“LINK_TO_API”);
const json = await data.json();

I am able to access the data through console.log, but not able to use it within my application.

WebFlux websockets send back to javascript client text in Uint8Array/arraybuffer, client also send in Uint8Array

i can send from client side to WebFlux and see the string bug how can i send back to client side and that the client side be able to parse it is something i can’t figure out .
this is what have as server using java spring WebFlux ;

 public Mono<Void> handle(WebSocketSession session) {

        Flux<WebSocketMessage> output2 = session.receive()
                .doOnNext(message -> {
                        logger.info("Recived from client:"+message.getPayloadAsText());
                })
                .map(value -> session.textMessage("Echo " + value.getPayloadAsText()));

        return session.send(output2);

    }

And this is the client :

var WebSocket = WebSocket || window.WebSocket || window.MozWebSocket; 


_stringConvertToArray = function(strData) {
if (!strData)
    {
        return null;
    }

    var arrData = new Uint16Array(strData.length);
    for (var i = 0; i < strData.length; i++) {
        arrData[i] = strData.charCodeAt(i);
    }
    return arrData;
};
_stringConvertToUint8Array = function (strData) {
        
    // View the byte buffer as an array of 8-bit unsigned integers
    var arrData = new Uint8Array(strData.length);
    for (var i=0;i<strData.length;++i) {
        arrData[i] = strData.charCodeAt(i);
    }
    // Log the binary array
    console.log("SEND ARRAY BUFFER: " + arrData.buffer);
    return arrData;
};

var connection = new WebSocket("ws://localhost:8001/test");
connection.binaryType = "arraybuffer";
connection.onopen = function(evt) {
    console.log("Send Binary WS was opened.");
};

connection.onmessage = (function(evt) {
        console.log(evt.currentTarget.binaryType);
        var binaryUint8 = new Uint8Array(evt.data);
        var binaryStr = '';
        for (var i = 0; i < binaryUint8.length; i++) {
            binaryStr += String.fromCharCode(binaryUint8[i]);
        }
        console.log("recived from server:"+binaryStr);
        

        connection.onerror = function(evt) {
            //this.m_loginObj.serverofflineLabel = 180;
            conosle.log("connection Error was fired");
            
        };

        connection.onclose = function(evt) {
            conosle.log("connection websocket instance closed.");
            connection = null;
        };
               
 })



var sendMassage = function(reqJson)
{

    if (this.connection.readyState == WebSocket.OPEN)
    {
        var buf = reqJson;//Encode(reqJson);
        var binary = this._stringConvertToUint8Array(buf);
        this.connection.send(binary.buffer);
    }
    else
    {
        var warningStr = "send binary websocket instance wasn't ready...try again in few seconds";
        console.log(warningStr);
        this.init();
        
            
    }
};

in the function : connection.onmessage i keep getting empty data .

How to remove, local storage EXPO_CONSTANTS_INSTALLATION_ID?

I have an react native expo web app. And I have implemented the local storage token.

But when I am on the login page and I do a refresh every time there will created a local storage with key:

EXPO_CONSTANTS_INSTALLATION_ID

and value:

4002984a-d469-4d34-9f06-9d9d1c8033a3

and after refresh the application redirects to the main page. But without data(blank page). Because no user is logged in.

So, I don’t know where this value comes from?

Question: how to get rid of the automatically generated key, value from localstorage?

Why is the wrap=hard attribute not functioning as expected in a textarea element?

I do need the line breaks, but even with wrap=”hard”, defining cols, the value is still a single line.

<!DOCTYPE html>
<html>
<body>

<h1>The textarea wrap attribute</h1>

<textarea id="usrtxt" rows="2" cols="5" name="usrtxt" wrap="hard" style="overflow-wrap: break-word; width: 100px;">
At W3Schools you will find free Web-building tutorials.
</textarea>

<!-- A div to display the textarea content -->
<div id="textareaContent"></div>

<script>
// Function to display textarea content
function showTextareaContent() {
  var textarea = document.getElementById('usrtxt');
  var displayArea = document.getElementById('textareaContent');
  displayArea.innerText = textarea.value;
}

// Event listener for the textarea input
document.getElementById('usrtxt').addEventListener('input', showTextareaContent);

// Initialize the display area with the current content of the textarea
showTextareaContent();
</script>

</body>
</html>

JavaScriptEngineSwitcher loading resource javascript file failing

I have a .NET 8 Core C# MVC project to provide the content as website and a class library to host the logic.

I’m trying to run ua-parser-js through JavaScriptEngineSwitcher as I couldnt find a C# based project like this which was recently updated.

I installed the nuget packages to my class library and added the JsEngineSwitcher to the available services in my MVC projects Program.cs file.

builder.Services.AddJsEngineSwitcher(options =>
{
    options.AllowCurrentProperty = false;
    options.DefaultEngineName = JintJsEngine.EngineName;
}).AddJint();

In my Controller I load the injected Service as below

var jsEngineSwitcher = _serviceProvider.GetService<IJsEngineSwitcher>();
var engine = jsEngineSwitcher.CreateDefaultEngine();

I’m passing the UA and the engine to my class library method where I am trying to load the JS file. The JS file is added as a embedded ressource in the root folder of the class library.

engine.ExecuteResource("<class library name>.ua-parser.min.js", typeof(Program).Assembly);

Unfortunately this fails with

System.NullReferenceException: 'Resource with name '<class library name>.ua-parser.min.js' is null.'

I checked if the JS file is really exiting as a ressource by below code, and it does have “.ua-parser.min.js”

System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();

The sample projects in the github repo seem not to load any JS and I wasn’t able to find a recent example except this.

Anyone having an idea what I am doing wrong?

Why are my convolutional layers not providing expected output using TensorFlowJS?

I’m using a CNN with TensorFlowJS to classify images and show the output of the conv2d layers. Visualising the conv2d layer output works well in python. However, in JS the output is the same as the input image except that it is slightly darker. For some reason the convolution isn’t functioning properly. Any ideas why?
”’

// Get first 2 convolutional layers
const conv2d_0 = model2.getLayer(index = 1);
const conv2d_1 = model2.getLayer(index = 2);

// Convert detected face image into tensor
var image_tensor = tf.browser.fromPixels(cropped_face);

// Resize image to be of requirered resolution
image_tensor = tf.image.resizeBilinear(image_tensor,[48,48]);

// Average depth channel to create gray scale image
image_tensor = tf.mean(image_tensor,axis = 2);

// Normalize values between 0-1
image_tensor = normalize(image_tensor);

// Expand tensor dimensions to fit CNN
image_tensor = tf.expandDims(image_tensor,0);
image_tensor = tf.expandDims(image_tensor,3);

// Apply first 2 conv2d layers to image tensor
var output1 = conv2d_0.apply(image_tensor);
var output2 = conv2d_1.apply(output1);

// Turn tensor into array
var array = nj.array(output2.arraySync());

// Slice array, resulting array of shape (1,46,46,1)
var sliced = array.slice(null,null,null,[44,null,45]);

//Turn Array back into tensor
var sliced_tensor = tf.tensor(sliced.reshape(46,46).tolist());

// Display output of first 2 layers as an image
tf.browser.toPixels(sliced_tensor,canvasBottom);

”’

Leaflet with Nuxt, marker does not stay where it should when zooming map, but only after updating marker

I have Nuxt app with Leaflet. I use custom div marker with leaflet. When I create this marker for the first time, everything is fine. But when I update the marker, in reality, delete and create new one. When dragging when map, marker is fine, when I “zoom” the map, the marker does not stay where it should, but is fixed to the “screen” position, instead to the geographical position. Can anyone at least direct me to the solution?

Adding marker:

addMarkerToMap(markerData: MyMarker) {
const myCustomColour = markerData.state?.color ?? "black";
let markerHtmlStyles = `
    background-color: ${myCustomColour};
    width: 2rem;
    height: 2rem;
    display: block;
    left: -1rem;
    top: -1rem;
    position: relative;
    border-radius: 3rem 3rem 0;
    transform: rotate(45deg);`;

const colorIcon = L.divIcon({
    iconAnchor: [0, 24],
    popupAnchor: [0, -36],
    html: `<span id="${markerData.id}" style="${markerHtmlStyles}"></span>`,
});
const marker = L.marker([markerData.lat, markerData.lng], {
    draggable: false,
    title: markerData.state?.title ?? "Unknown state",
    alt: markerData.state?.title ?? "Unknown state",
    icon: colorIcon,
});
marker.addTo(this.map);
return marker;
}

How I update the marker:

for (let i = 0; i < this.project!.markers.length; i++) {
    if (this.project!.markers[i].mapMarker) {
        await this.project!.markers[i].mapMarker.remove();
        this.project!.markers[i].mapMarker = null;
    }
    await this.$nextTick(); // Don't know if this has any effect with leaflet, but I've tried everything
    this.project!.markers[i].mapMarker = this.addMarkerToMap(
        this.project!.markers[i]
    );
}

An import works in Code, but does not work in `yarn start`

In MS Code this import is not highlighted as an error:

import { keccak256 } from "ethers/lib/utils";

but when I try to yarn start, it produces errors.

[1] ✘ [ERROR] Could not resolve "ethers/lib/utils"
[1] 
[1]     ../util/eth.ts:1:26:
[1]       1 │ import { keccak256 } from "ethers/lib/utils";
[1]         ╵                           ~~~~~~~~~~~~~~~~~~
[1] 
[1]   The path "./lib/utils" is not exported by package "ethers":
[1] 
[1]     ../node_modules/ethers/package.json:67:13:
[1]       67 │   "exports": {
[1]          ╵              ^
[1] 
[1]   You can mark the path "ethers/lib/utils" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.

I don’t understand what imports in package.json mean and how to use it together with Code, in such a way that both code and yarn start would be satisfied.

Adding spinner after someone clicks submit HTML/CSS/JS

I know this is a hot mess, but I just need to add a spinner after someone clicks ok, and it errors our or completes. I have no idea how to do front end, I just figured out azure functions like yesterday. I can’t believe this thing even works…

I am not sure exactly how to add the spinner or how to make it go away once the script is over.

I looked at a bunch of examples, but I’m stumped.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>GDAP Request </title>
    <style>
      form {
        max-width: 400px;
        margin: 0 auto;
      }
      input[type="text"],
      textarea {
        width: 100%;
        padding: 12px;
        border: 1px solid #ccc;
        border-radius: 4px;
        box-sizing: border-box;
        margin-top: 6px;
        margin-bottom: 16px;
        resize: vertical;
      }
      input[type="submit"] {
        background-color: #4caf50;
        color: white;
        padding: 12px 20px;
        border: none;
        border-radius: 4px;
        cursor: pointer;
      }
      input[type="submit"]:hover {
        background-color: #45a049;
      }
    </style>
  </head>
  <body>
    <h2 style="text-align: center;">GDAP Request</h2>

    <form id="contactForm">
      <label for="TenantID">Enter Tenant ID Here</label>
      <input
        type="text"
        id="TenantID"
        name="TenantID"
        placeholder="TenantID..."
        required
      />

      <label for="ClientContact">Email Address for Global Admin</label>
      <input
        type="text"
        id="ClientContact"
        name="ClientContact"
        placeholder="Client email..."
        required
      />

      <label for="gdapconfig">Select Permisions given to REMOVED</label>
        <select name="gdapconfig" id="gdapconfig"> 
            <option value="0">Support Only</option> 
            <option value="1">Cloudmore Basic</option> 
            <option value="2">Assisted GDAP</option> 
            <option value="3">Global Admin + Assist</option> 
        </select>


      <input type="submit" value="Submit" />
    </form>

    <script>
      document
        .getElementById("contactForm")
        .addEventListener("submit", function (event) {
          event.preventDefault();
          const formData = new FormData(this);
          const object = {};
          formData.forEach((value, key) => {
            object[key] = value;
          });
          const jsonData = JSON.stringify(object);

          let test = fetch(
            "https://fa-cus-afa-gdap-02.azurewebsites.net/api/gdapCreateRow?code=REMOVED-LdRyJ9Ac2LAzFujwNOSQ==",
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
              },
              body: jsonData,
            }
          )
            .then((response) => {
              if (!response.ok) {
                throw new Error("Network response was not ok");

              }
              return response.json();
            })
            .then((data) => {
              alert("Client Add Complete.");
              var requestOptions = {
                  method: "POST",
                  redirect: "follow",
                };

                fetch(
                  "https://5f6fc7f3-d8a5-4d06-ad4a-67460f3fa3eb.webhook.cus.azure-automation.net/webhooks?token=REMOVED%2b%2bnFKr2GWrtHU1E4%3d",
                  requestOptions
                )
                  .then((response) => response.text())
                  .then((result) => console.log(result))
                  .catch((error) => console.log("error", error));
            })
            .catch((error) => {
              console.error(
                "There was an error sending the message:",
                jsonData
              );
              alert(
                "Client Add Complete.",
                test
              );
              var requestOptions = {
                  method: "POST",
                  redirect: "follow",
                };

                fetch(
                  "https://5f6fc7f3-d8a5-4d06-ad4a-67460f3fa3eb.webhook.cus.azure-automation.net/webhooks?token=REMOVED%2b%2bnFKr2GWrtHU1E4%3d",
                  requestOptions
                )
                  .then((response) => response.text())
                  .then((result) => console.log(result))
                  .catch((error) => console.log("error", error));
            });
        });
    </script>
  </body>
</html>

Testing concurrency with Typescript/JS

I’m working on a TS application and I need to test some concurrent code and how it interacts with a database (the code deals with idepotency). I want to verify that multiple requests that modify the same resource would apply the changes correctly or fail, rather than experience lost updates or processing them twice.

I quite a lot of experience testing this in Java (as it has a ton of concurrency primitives like semaphores, barriers, and other things to control concurrency and parallelism), but I’m struggling to figure out how to do this in TS.

For example, in Java I would start 2 threads passing a CyclicBarrier with 2 parties. Both threads would execute up to the barrier, wait for eachother, and then continue. In this way I could often ensure that the code worked as expected. If I couldn’t ensure 100% that the code would be run in parallel, I would run the same time multiple times or with more threads to increase the chances of parallel execution.

I cannot find any concurrency primitives in JS that would allow me to do something similar. The best I’ve found is to do a busy wait on a shared value. Some blogs suggest to use worker threads.

Any suggestions how this is usually done? This is a difficult topic, so links to blogs, articles & books are appreciated!