Getting 404 for when building an Signed Web Bundle and Isolated Web App in the browser

I am able to successfully build a Signed Web Bundle (SWBN) and Isolated Web App (IWA) (see https://github.com/WICG/webpackage/tree/main and https://github.com/WICG/isolated-web-app) in node, deno, and bun runtime environments with the same source code using Web Cryptography API, see https://github.com/guest271314/webbundle and https://github.com/guest271314/telnet-client.

Now I am working on building a Signed Web Bundle and Isolated Web App in the browser https://github.com/guest271314/webbundle/tree/browser.

We do not have Node.js fs module in the browser, which the working code uses. The closest we have in the browser is WICG File System API.

I had to modify https://github.com/guest271314/webbundle/blob/browser/wbn-bundle.js to comment the Node.js fs module code.

Right now I am writing the files to the SWBN using TextEncoder. I’ve also included the same files locally and set recPath to the file:/// location of assets.

The IWA installs on chrome://web-app-internals. The structure of the SWBN doesn’t appear to be an issue.

I am getting 404 when writing the files directly to addAsset() as Uint8Array and launching the IWA from chrome://apps

This <ID> page can’t be found

No webpage was found for the web address: isolated-app://<ID>/

What do I need to adjust in https://github.com/guest271314/webbundle/blob/browser/wbn-bundle.js for the IWA to successfully launch?

Where sholud I further precess on after reading file with a try-catch block in Node.js?

When reading a file with Node.js promise API, I need to use try-catch block. While I can’t decide where should I place the further processing code, directly inside try block or outside the try-catch block. Here is one example:

import { readFile } from 'node:fs/promises';

try {
  const JSONString = await readFile("./config.json", "utf-8");
  // further processing directly inside try block
  const object = JSONString === ""? {}: JSON.parse(JSONString);
  ...
} catch(e) {
  console.error(e.message);
}

import { readFile } from 'node:fs/promises';

let JSONString = "";
try {
  JSONString = await readFile("./config.json", "utf-8");
} catch(e) {
  console.error(e.message);
}
// further processing outside try-catch block
const object = JSONString === ""? {}: JSON.parse(JSONString);
...

Why doesn’t JSDOM’s Object.getOwnPropertyNames(window) include DOM objects?

I created a repository for the node.js side of this question. Here’s the entire index.js file:

import { JSDOM } from 'jsdom';

JSDOM.fromFile('template.html', {
    url: 'http://localhost',
    runScripts: 'dangerously',
    resources: 'usable',
    pretendToBeVisual: true,
}).then(({ window }) => {
    console.log(`Object.getOwnPropertyNames(window).filter((k) => k === "HTMLElement").length`, Object.getOwnPropertyNames(window).filter((k) => k === "HTMLElement").length);
    
    console.log(`window.HTMLElement`, window.HTMLElement);
    console.log(`Object.getOwnPropertyDescriptor(window, 'HTMLElement')`, Object.getOwnPropertyDescriptor(window, 'HTMLElement'));
    console.log(`Object.getPrototypeOf(window.constructor).name`, Object.getPrototypeOf(window.constructor).name);
});

Note the 0 in this code’s output and the error at the bottom:

Object.getOwnPropertyNames(window).filter((k) => k === "HTMLElement").length 0
window.HTMLElement [class HTMLElement extends Element]
Object.getOwnPropertyDescriptor(window, 'HTMLElement') {
  value: [class HTMLElement extends Element],
  writable: true,
  enumerable: false,
  configurable: true
}
Object.getPrototypeOf(window.constructor).name EventTarget
undefined:1
console.log(HTMLElement);
            ^

ReferenceError: HTMLElement is not defined

If I run those same console.logs in the browser, it prints 1 and does not error:

console.log(`Object.getOwnPropertyNames(window).filter((k) => k === "HTMLElement").length`, Object.getOwnPropertyNames(window).filter((k) => k === "HTMLElement").length);

console.log(`window.HTMLElement`, window.HTMLElement);
console.log(`Object.getOwnPropertyDescriptor(window, 'HTMLElement')`, Object.getOwnPropertyDescriptor(window, 'HTMLElement'));
console.log(`Object.getPrototypeOf(window.constructor).name`, Object.getPrototypeOf(window.constructor).name);

const indirectEval = eval;
indirectEval(`console.log(HTMLElement);`);

As far as I can tell, these properties have the same descriptors and both windows have the same prototype (name). I’m not aware of anything else that could because this difference in behavior.

Why does this code work differently in JSDOM?


Miscellaneous information

As far as I know, the template.html file is irrelevant to my question, but here’s how it looks:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>title</title>
  </head>
  <body>
    <p>Hello world</p>
  </body>
</html>

I am using jsdom 24.0.0 and node v20.10.0.

Is it possible to replace a word document loop tag for a new loop tag (DocxTemplater)?

I want to replace some variable tags inside a Word Document using the DocxTemplater library. E.g. I have a loop tag as follows:

{#gid_123}
    ...content...
{/gid_123}

And I just want to replace the tags with new IDs:

{#gid_999}
    ...content...
{/gid_999}

I am able to replace expressions that are not loops, but I just cannot get the loop tags to be replaced even tho I am using a custom parser function.

My implementation looks as follows:

let doc = new DocxTemplater(zip, {
    paragraphLoop: true,
    linebreaks: true,
    parser(expression) {
        // The default regex is used to match the groups variables.
        let variablesRegex = /(?<type>gid)_(?<id>d+)/g
        let variablesMatches = expression.match(variablesRegex) ?? []
        // If no group variables are found, the regex is changed to match the rest of the variables.
        if (variablesMatches.length === 0) {
            variablesRegex.lastIndex = 0
            variablesRegex = /(?<type>qid|tax|fee)_(?<id>d+)(?:_(?<property>description|amount|percentage))?/g
            variablesMatches = expression.match(variablesRegex) ?? []
        }
        return {
            get: function (scope, context) {
                let newExpression = expression
                if (variablesMatches.length === 0)
                    return `{${newExpression.trim()}}`
                for (let match of variablesMatches) {
                    variablesRegex.lastIndex = 0
                    let {symbol = null, type, id, property} = variablesRegex.exec(match).groups
                    let newId = null
                    let newTag = null
                    let isTaxOrFee = ['tax', 'fee'].includes(type)
                    let isGroup = type === 'gid'
                    let isQuestion = type === 'qid'
                    // ?: tax, fee, qid (questions) and qid (question groups) are the only available variables to replace.
                    if (!isTaxOrFee && !isGroup && !isQuestion)
                        throw new Error(`Invalid variable type ${type}`)
                    if (isTaxOrFee) {
                        newId = tax_fee_id_relations.find(rel => rel.old_tax_or_fee_id === Number(id))?.tax_or_fee_id
                        newTag = `${type}_${newId}_${property}`
                    } else if (isQuestion) {
                        newId = question_id_relations.find(rel => rel.old_question_id === Number(id))?.new_question_id
                        newTag = `${type}_${newId}`
                    } else if (isGroup) {
                        let isOpeningTag = context.meta.part.raw.startsWith('#')
                        newId = group_id_relations.find(rel => rel.old_group_id === Number(id))?.new_group_id
                        // newTag = `${type}_${newId}`
                        newTag = isOpeningTag ?
                            `#${type}_${newId}` :
                            `/${type}_${newId}`
                    }
                    newExpression = newExpression.replaceAll(match, newTag)
                }
                return `{${newExpression.trim()}}`
            },
        }
    },
})

I have tried implementing a custom parsing method that identifies the tags I want to replace, creates the new tag and returns it inside the get() function, but that is just not working. The resulting document has blank spaces where the new loop tags should be.

I want to get a new document with the new tags for all the loops inside the document.

NextJS Error: Functions cannot be passed directly to Client Components when passing a higher-order function to form action

I’m studying the official dashboard tutorial of NextJS and this part (along with the updateInvoice part) got me curious:

https://nextjs.org/learn/dashboard-app/mutating-data#deleting-an-invoice

I played with two approaches to passing the deleteInvoice function to the form action, one with the bind method (the one used in the tutorial) and another with a higher-order function that wraps deleteInvoice.

The bind version worked perfectly:

const deleteInvoiceWithId = deleteInvoice.bind(null, id)
return (
    <form action={deleteInvoiceWithId}>
     // other code
    </form>
);

While the higher-order function version :

const deleteInvoiceWithId = async () => deleteInvoice(id)
return (
    <form action={deleteInvoiceWithId}>
     // other code
    </form>
);

threw Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with “use server”.

My question is, I’m obviously creating and passing a new function to the form action in either case, but why does the bind case work while the higher-order function version fail? What is the fundamental difference between the 2 approaches?

How to validate an object dynamically using Joi in nodejs

import Joi from "joi";


export const getFileLinkSchema = Joi.object({
    userId : Joi.string().required(), //TODO: Need to update
    fileId : Joi.string().required(),
    shareType : Joi.string().required(),
    shareAttributes: Joi.object({
        time: Joi.object({
            expiration:Joi.string()
        }).when('shareType',{is:"time",then:Joi.required()}),
        geoFence: Joi.object({
            latitude: Joi.number().required(),
            longitude: Joi.number().required()
        }).when('shareType',{is:"geoFence",then:Joi.required()})
    }).required()
});

The above is the schema i need to validate. Here if the shareType is time then i need the details in the shareAttribute if the shareType is “geoFence” then i need the latitude and longitude details. How to validate this using joi in nodejs

I tried the when() from joi but couldn’t get the expected outcome

Using Twitter Widget to display tweets and add hidden text behind the tweet

This is a bit of a weird question. I am working on an app in HTML/CSS/Javascript and displaying tweets using the Twitter widget. Everything is working fine and I will post my code below.

The challenge I am encountering is this:

When displaying posts with sensitive content, the widget shows a “not found” image instead of the post. As far as I know, there’s no way of capturing those and linking to the post instead. However, for the user experience, I’d like to be able to allow them to click a link to view the post. My idea for achieving this is to have some text (“click here to see the post”) that takes them to the actual post on twitter, since I do have the post ID. I want to place this text so that if the tweet is not sensitive content and does appear, it will overlay the text, effectively hiding it…and then the user will only see that text if they get the “not found” image.

However I am completely stumped on getting the text to show up. Wherever I try to add it, the column styling gets completely screwed up, or the text ends up replacing the “not found” image. It’s tricky because once I pass the post ID and the parent div to the widget, it auto-generates the rest of the code and I can’t manipulate it from there.

Wondering if anyone has ideas for how to get around this. See below for code – not sure why it isn’t working when I run it here, guessing it has to do with the widget dependency.

const populatePosts = () => {
  // Post data
  let postList = [{
      post_id: "1754905910126968944",
      post_type: "TW",
    },
    {
      post_id: "1755026979865424073",
      post_type: "TW",
    },
    {
      post_id: "1756059288865521797",
      post_type: "TW",
    },
  ];

  // TWEETS \
  let post_id;

  if (postList.length > 0) {
    // set up the variables
    var subs;
    var col1 = "",
      col2 = "",
      col3 = "";
    var column_index = 1;

    // loop through the results to build the three column strings
    for (subs = 0; subs < postList.length; subs++) {
      if (column_index == 1) {
        col1 +=
          "<div class='embed-responsive' id='tweetArea" + subs + "'></div>";
      } else if (column_index == 2) {
        col2 +=
          "<div class='embed-responsive' id='tweetArea" + subs + "'></div>";
      } else if (column_index == 3) {
        col3 +=
          "<div class='embed-responsive' id='tweetArea" + subs + "'></div>";
      }
      column_index += 1;
      if (column_index == 4) {
        column_index = 1;
      }
    }

    // write out the column html code
    document.getElementById(`tweetCol1`).innerHTML = col1;
    document.getElementById(`tweetCol2`).innerHTML = col2;
    document.getElementById(`tweetCol3`).innerHTML = col3;

    // loop through the results to display the tweets
    for (subs = 0; subs < postList.length; subs++) {
      // get the post id
      post_id = postList[subs];

      // build the twitter area name
      let twitter_area = "tweetArea" + subs;

      // display the tweets
      twttr.widgets
        .createTweet(
          postList[subs].post_id,
          document.getElementById(twitter_area), {}
        )
        .then(function(e1) {
          // If any of the tweets return "undefined", that means it's been deleted. Update the counter so we can display a message to the user about how many tweets have been deleted
          if (e1 === undefined) {
            postsCounter += 1;
          }
          // If counter is > 0, display deleted posts summary
          // Grab the deleted summary div from the DOM
          let deletedSummaryDivPositive = $(`#deleted-post-summary-text`);
          if (postsCounter > 0) {
            $(deletedSummaryDivPositive).text(
              `We detected ${postsCounter} post(s) that were deleted or are no longer available.`
            );
            $(deletedSummaryDivPositive).show();
          } else {
            $(deletedSummaryDivPositive).hide();
          }
        })
        .catch(function(e2) {});
    }
  }
};
<!-- Twitter widget -->
<script sync src="https://platform.twitter.com/widgets.js"></script>

<!-- tweets container -->
<div class="container-fluid tweets-container" id="tweets-container">
  <div class="row">
    <div class="col-md-12">
      <div class="row">
        <div class="col-md-3" id="tweetCol1"></div>

        <div class="col-md-1"></div>

        <div class="col-md-3" id="tweetCol2"></div>

        <div class="col-md-1"></div>
        <div class="col-md-3" id="tweetCol3"></div>
      </div>
    </div>
  </div>
</div>
<!-- /tweets container -->

Get url’s HTML with JavasScript

Im creating an application that needs a way to get a urls HTML then put the return into a textarea for editing and copying.

The textarea part I could do myself. Right now I need to send a request and get a urls HTML.

Ive treid HttpRequest() and fetch but dont know where to go with them. I would also be open to ajax or jquery.

Getting Error while working with Charts in React Native

Im trying to make a Donut Chart in react native app and I have tried Libreries like Victory-native and react-native-gifted-charts. None of these works for me. They all are giving similar kind of error like that none of these file exist:Error Screenshot

Error screenshot 2

import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
import { BarChart, LineChart, PieChart, PopulationPyramid } from "react-native-gifted-charts";

const App = () => {
  const data=[ {value:50}, {value:80}, {value:90}, {value:70} ]
  return (
    <View>
      <BarChart data = {data} horizontal />
    </View>
  )
}

export default App
const styles = StyleSheet.create({})

Internally-used function in Blockly

If you go to the Blockly demo, take out the random colour block, and then click the JavaScript tab, you will see the following code generated:

function colourRandom() {
  var num = Math.floor(Math.random() * Math.pow(2, 24));
  return '#' + ('00000' + num.toString(16)).substr(-6);
}


colourRandom();

It creates its own function, colourRandom. Now if you go back to the Blocks tab and create a variable named colourRandom, the same name as the function, drag out a set colourRandom to block, and go back to the Javascript tab, the colourRandom function changes its name to colourRandom2.

var colourRandom;

function colourRandom2() {
  var num = Math.floor(Math.random() * Math.pow(2, 24));
  return '#' + ('00000' + num.toString(16)).substr(-6);
}


colourRandom2();

colourRandom = 0;

I would like to create my own function like this. How do you this? Here’s what looks to be the code that creates the random colour block. (line 37)

Picture of Blocks

ComamnderJS – Prompt for missing args/options with Inquirer

I’m trying to implement prompting users for missing required args/mandatory options.

I thought I could use a preSubcommand hook, change process.argv with prompts, and then allow commander to parse the updated argv.

My hook gets executed before any exit however, After the complete of my hook’s callback, I will get this error: error: required option '--foo' not specified.

It seems that parsing continues after the hook on the old process.argv.

For example my-cli subcommand --foo bar will work fine.
my-cli subcommand will prompt for foo and push it to process.argv inside the hook but then exit with the error above.

Any ideas? I tried to suppress this error with exitOverride and re-calling parse afterwards, but my callback is not being reached. Surrounding in try-catch doesn’t work either.

Here’s my code:

program
        .name('cli')
        .description('foo')
        .version(version, '-v, --version')
        .addCommand(sub)
        .hook('preSubcommand', async (program, subcommand) => {
            await promptForMissingArgs(program, subcommand);
            console.log('here');
            console.log(process.argv);
            program.parse(process.argv); // called again with correct process.argv but still exits
        })
        .exitOverride((exitCode) => {
            console.log(`Exiting with code ${exitCode.exitCode}`); // not reached
            //  if (exitCode.exitCode !== 0) {
            //     program.parse(process.argv);
            //  }
        });
    // parse command line arguments and execute command
    try {
        program.parse(process.argv);
    } catch (error) {
        console.log('here'); // doesn't reach here
        console.error(error);
    }```

How to make an API call

I am developing a web application and I need to make calls to an API from the client side using JavaScript. I’ve been researching how to do this, but I’m a little confused about the different methods available (like fetch, XMLHttpRequest, etc.) and how to use them correctly.

I was wondering if someone could provide me with a clear explanation and practical example of how to make an API call using JavaScript. I’m particularly interested in knowing how to handle API responses (e.g. how to access the returned JSON data) and how to handle potential errors.

Any code examples, tutorials or resources you can recommend would be very helpful. Thanks in advance for any help you can provide.

Object properties added to object are undefined [duplicate]

Either an object – or its properties added to an object – are logging as expected but nevertheless undefined.

My function iterates an array of objects, checking each object (via API call) for various statuses, which are returned as a status object. I have been able to either add the status object to the array item object or the status object’s properties to the array item object, but then I can’t access those values.

Here’s the code:

function checkItems(theItemsData) {
    theItemsData.forEach((itemObj, ix) => {
        let itemStatus = {};
        checkItemStatus(itemObj, ix) /* API call, returns status object */
            .then((statusObj) => {
                // itemObj.itemStatus = statusObj; // it's there, no prob               
                // itemObj = Object.assign(itemObj, statusObj); // not nested obj but ok
                Object.assign(itemObj, statusObj); // √ => not nested obj but ok
            })
    })

    console.log(`theItemsData: `, theItemsData); // √

The checkItemStatus function (4th line of code above) returns an object (statusObj) which I need to EITHER add as an new property (object) in each itemObj in theItemsData – i.e., v1:

theItemsData = [
    {
        "somePropertyAlreadyInTheItemObj": "abc",
        "someOtherPropertyAlreadyInTheItemObj": "xyz",
        "statusObj": { "statusMessage": "blah blah blah", "someBoolean": true } // the statusObj
    }
]

… OR add the properties within the statusObj as properties of the itemObj, i.e., v2:

theItemsData = [
    { // itemObj
        "somePropertyAlreadyInTheItemObj": "abc",
        "someOtherPropertyAlreadyInTheItemObj": "xyz",
        "statusMessage": "blah blah blah",
        "someBoolean": true
    }
]

I can achieve either of these … and theItemsData[] logs as desired outside the forEach loop … HOWEVER, in subsequent code – e.g., using v2:

console.log(`itemObj.statusMessage: `, itemObj.statusMessage); // NOPE
console.log(`itemObj.someBoolean: `, itemObj.someBoolean); // NOPE
console.log(`itemObj.somePropertyAlreadyInTheItemObj: `, itemObj.somePropertyAlreadyInTheItemObj); // SURE, NO PROBLEM, GOT IT

… or using v1 (nested object), these fail:

console.log(itemObj.statusObj.statusMessage: , itemObj.statusObj.statusMessage); // NOPE

In summary, either the properties added to the itemObj or added as a nested object added to itemObj are undefined … please, what am I missing here?

Thank you in advance for any help and clarification.

NextJS, POST Method from client to server gives status of 405 (Method Not Allowed)

I have a NextJS 13 project where I am trying to pass information from a client page to a server page with a function. I this error on my client page:

Failed to load resource: the server responded with a status of 405 (Method Not Allowed)
SyntaxError: The string did not match the expected pattern.

Here is a minimal file of my client page
app/test/page.tsx

export default function Test() {

   const [selectedOptions, setSelectedOptions] = useState(Array(questions.length).fill(''));

   const kickFromExam = () => {
       const userEmail = session?.user?.email;
       
       fetch('/api/data', {
           method: 'POST',
           headers: {
               'Content-type': 'application/json',
           },
           body: JSON.stringify({ userEmail, selectedOptions }),
        })
        
    };

    useEffect(() => {
      if (prevTime === 0) {
          
           (async () => {
             await kickFromExam();
           })();
       }  
    });

}

Here is a minimal file of my server page
app/api/data/route.ts

 import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from "../../../lib/prisma";

interface PutInDbParams {
    userEmail: string;
    selectedOptions: string[];
}

export default async function handler(req: Request, res: NextApiResponse) {
    

    try {
        const { userEmail, selectedOptions } = await req.json() as PutInDbParams;

        const updatedUser = await prisma.[name].update({
            where: { email: userEmail },
            data: {
                answers: {
                    push: selectedOptions,
                },
            },
        });

        res.status(200).json({ message: 'Data updated successfully', data: updatedUser });
    } catch (error) {
        console.error("Error:", error);
        res.status(500).json({ message: 'Error updating data' });
    }
}

Any help would be greatly appreciated. I am unsure why I am getting the Syntaz error since the selectedOptions from my useState is very cleary an array of strings: ['a', 'b', 'c']

Explanation on access an object property that does not exist on an DOM element

I am a beginner on JavaScript, looking for a explanation on accessing to an object property that does not exist on an DOM element.

I am working on a todo apps. Below is my current code but it is not completed.
There’s an empty todosArray, then todoObj with two properties (todo, completed) will be added to the array when users add an item.

Later in the code where item can be removed or crossed out if users clicked on the item. In this click addEventListener, a variable clickedEl is created in the else if statement and it accessed/copied(?) the completed property from the todosArray. This is where I do not understand.

How is the clickedEl has access to the completed property? What is actually happening here?

// Variables 
const form = document.querySelector('form');
const formInput = document.querySelector('input[type=text]');
const ul = document.querySelector('ul');
const addBtn = document.querySelector('input[type=submit]');
const todosArray = [];

// Add item 
function addTodo(item) {
    const todoObj = {
        todo: item,
        completed: false
    };

    todosArray.push(todoObj);
    
    // Save to localStorage
    localStorage.setItem('todosArray', JSON.stringify(todosArray));
    
    formInput.value = '';
};

// Add task to todo list
form.addEventListener('submit', function (e) {
    e.preventDefault();
    
    if (formInput.value === '') {
        alert('Please add a task.');
    }
    else {
        const newLi = document.createElement('li');
        newLi.innerHTML = formInput.value;
        ul.append(newLi);
        const removeBtn = document.createElement('button');
        newLi.append(removeBtn);
        removeBtn.innerHTML = 'Remove';

        addTodo(formInput.value);
    };
});

// Remove/complete list item
ul.addEventListener('click', function (e) {
    if (e.target.textContent === 'Remove') {
        e.target.parentElement.remove();
    }
    else if (e.target.tagName === 'LI') {

        const clickedEl = e.target //li
        //console.log('clickedEl: ', clickedEl)
        if (clickedEl.completed === true) {
            clickedEl.style.textDecoration = 'none';
        }
        else {
            
            clickedEl.style.textDecoration = 'line-through';
            clickedEl.completed = true;
        }
    }
});

// Retrieve from localStorage
if (localStorage.getItem('todosArray')) {
    const todosList = JSON.parse(localStorage.getItem('todosArray'));

    for (let i = 0; i < todosList.length; i++){
        const newLi = document.createElement('li');
        newLi.textContent = todosList[i].todo;
        ul.append(newLi);
        const removeBtn = document.createElement('button');
        newLi.append(removeBtn);
        removeBtn.textContent = 'Remove';

        console.log(todosList[i]);
    }
}

I talked to a mentor but I was not able to understand his explanation. Also, googled quit a bit, but most results are related to property accessors.