How to Use GraalVM to Execute JavaScript Code Making REST Calls Using Java?

I’m trying to use GraalVM to execute JavaScript code that makes a REST call using Java. Below is the code I am working with:

JavaScript Code:

import axios from "axios";
const API_URL = "https://jsonplaceholder.typicode.com/posts";
const fetchPosts = async () => {
try {
const response = await axios.get(API_URL);
console.log("Posts:", response.data);
} catch (error) {
console.error("Error fetching posts:", error);
}
};
// Call the function
fetchPosts();

Bundled JavaScript using es bundle
Java Code to Execute the ES Bundled Code:

public static void main( String[] args )
{
String jscode = null;
try {
jscode = new String(Files.readAllBytes(Paths.get("/tmp/main.js")));
} catch (IOException e) {
throw new RuntimeException(e);
}
try (Context context = Context.create()) {
Value value = context.eval("js", jscode);
value.execute();
}
}

pom.xml:

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<graaljs.version>24.1.1</graaljs.version>

<dependency>
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>polyglot</artifactId>
  <version>${graaljs.version}</version>
</dependency>
<dependency>
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>js</artifactId>
  <version>${graaljs.version}</version>
  <type>pom</type>
</dependency>
<dependency> <!-- all tools we include in Oracle GraalVM -->
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>tools</artifactId>
  <version>${graaljs.version}</version>
  <type>pom</type>
</dependency>


<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>3.8.1</version>
  <scope>test</scope>
</dependency>

When I run the above code, I encounter the following error:

Error fetching posts: AxiosError: There is no suitable adapter to dispatch the request since :
adapter xhr is not supported by the environment
adapter http is not available in the build
adapter fetch is not supported by the environment

Could someone please help me figure out how to properly use GraalVM to execute JavaScript code that makes a REST call in Java?

Thank you in advance!

How can I create hyperlinkOrPicture column types on SharePoint Lists with Microsoft Graph API or Sharepoint API?

Background

I am working on a script in JavaScript that generates new columns for a given Sharepoint List. I have been referencing the Graph API which defines the column types and what should be present in the payload for the POST requests to create new columns. To format the request I have referred to the following: https://learn.microsoft.com/en-us/graph/api/list-post-columns?view=graph-rest-1.0&tabs=http.

The following code from my script that is working for almost all types: (text, dateTime, boolean, choice, currency, etc…)

const graphApiUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/columns`;
const response = await fetch(graphApiUrl, {
    method: "POST",
    headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
    },
    body: JSON.stringify(graphPayload),
});

if (!response.ok) {
    const errorDetails = await response.text();
    logError(`Failed to create column "${field.name}": ${response.statusText}nDetails: ${errorDetails}`);
    return; 
}

const responseData = await response.json();

Unfortunately, I am having an issue with the hyperlinkOrPicture columns… For instance the following combinations of payloads do not work:

// payload for hyperlink column
{ 
   name: 'URL', 
   hyperlinkOrPicture: { isPicture: false } 
}
// payload for picture column 
{
  name: 'Files (Image Files Only)',
  hyperlinkOrPicture: { isPicture: true }
}

The following error occurs:

ERROR: Failed to create column "URL": Bad Request
Details: {"error":{"code":"invalidRequest","message":"Invalid request","innerError":{"date":"2025-01-03T21:32:54","request-id":"ad66da6b-c273-409a-801c-aabe918c80e2","client-request-id":"ad66da6b-c273-409a-801c-aabe918c80e2"}}}

# similar for the second column

The above formatting comes from the documentation:

Graph API hyperlinkOrPicture JSON

Research and Attempt at Solution

Bad Graph API Documentation

Before resorting to making a post on here, I did my best to research as much as possible: both from other posts, and Microsoft’s API documentation. I knew there was a possibility that the API documentation was missing something because the Graph documentation in particular for Lists related requests is very minimal in detail, and tends to just include examples without a thorough breakdown of all the fields that are necessary in the body of the requests. I noticed this when working on the second part of my script which was to insert items into the columns I generated.

Example: Inserting a new Item to a “choice” column type with multipleSelects enabled.

If we look at the documentation it is very minimal and does not provide any example for all possible fields: https://learn.microsoft.com/en-us/graph/api/listitem-create?view=graph-rest-1.0&tabs=http

I had to resort to another post that mentioned how to have this done.

Answer to choice column with multiple choices enabled

Thus, I was hoping that something like this was the case for the hyperlinkOrPicture columns – which in the Sharepoint API are referred to as different types: https://learn.microsoft.com/en-us/previous-versions/office/sharepoint-csom/ee540543(v=office.15). It states that there is a ‘URL’ Field, with a value of 11, and a ‘File’ field with a value of 18. Clearly, there is a disconnect here and cause of confusion.

Using Sharepoint API Instead

After not finding anything on the Graph API documentation as to why hyperlinkOrPicture column type happens to be the only column type that is not being created properly, even though I am following the formatting, I decided to try the Sharepoint API. However, I have been having a difficult time setting that up and having an issue with the token that I am using. Even though I have Sites.FullControl.All Application Access, and have followed the instructions in this post from MicroSoft to setup app-only token access: https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread, by including a certificate to my registered app on azure, I am still getting an error that says the following:

ERROR: Failed to create SharePoint column "URL": Unauthorized
Unsupported app only token.

I am not sure why this is only an issue with SharePoint API when Graph API is working just fine with similar permissions.

I am using the following payload according to SharePoint API documentation to create the new column:

const isPicture = field.type === 'multipleAttachments';
const sharePointPayload = {
    __metadata: { type: "SP.Field" },
    Title: columnName,
    FieldTypeKind: 11,
    Required: false,
    EnforceUniqueValues: false,
    UrlFormat: isPicture ? 1 : 0, // 0 for Hyperlink, 1 for Picture
    Description: columnPayload.description,
};

Request is below…

const sharePointApiUrl = `${SITE_URL}/_api/web/lists(guid'${listId}')/fields`;

try {
    const response = await fetch(sharePointApiUrl, {
        method: "POST",
        headers: {
            Authorization: `Bearer ${sharePointAccessToken}`,
            Accept: "application/json;odata=verbose",
            "Content-Type": "application/json;odata=verbose",
        },
        body: JSON.stringify(sharePointPayload),
    });

    if (!response.ok) {
        const errorDetails = await response.text();
        logError(
            `Failed to create SharePoint column "${columnName}": ${response.statusText}n${errorDetails}`
        );
    }

    log(`SharePoint column "${columnName}" created successfully.`);

} catch (error) {
    logError(`Error creating SharePoint column "${columnName}": ${error.message}`);
}

I am not completely certain if the above is the correct payload for creating a hyperlinkOrPicture column type in SharePoint Lists. I would not be able to know since I am getting the previous error I mentioned with regard to the token.

If someone could come up with a solution by using just the Graph API, that would be the best; however, I would also like to know what I may be doing wrong in the setup process to have SharePoint API requests working.

Compare dependencies changes using two lock file

In a project that is broken but no changes in my source code, I suspect something changed in my dependency tree.

I have both lock file, I have tried to do like this:

grep 'version:' yarn.lock > yarn-versions.txt
grep 'version:' yarn-old.lock > yarn-old-versions.txt
diff yarn-versions.txt yarn-old-versions.txt

And this is the result of the diff:

❯ diff yarn-versions.txt yarn-old-versions.txt
156d155
<   version: 0.0.0-use.local
317c316
<   version: 0.6.5
---
>   version: 0.6.2
319c318
<   version: 0.6.5
---
>   version: 0.6.2
321c320
<   version: 0.6.5
---
>   version: 0.6.2
323c322
<   version: 0.6.5
---
>   version: 0.6.2
325c324
<   version: 0.6.5
---
>   version: 0.6.2
327c326
<   version: 0.6.5
---
>   version: 0.6.2
329c328
<   version: 0.6.5
---
>   version: 0.6.2
331c330
<   version: 0.6.5
---
>   version: 0.6.2
843d841
<   version: 9.1.0
1079d1076
<   version: 6.4.2
1181c1178
<   version: 2.22.17
---
>   version: 2.22.12
1673d1669
<   version: 1.1.1
1676d1671
<   version: 4.0.2
1854d1848
<   version: 1.8.2
1970d1963
<   version: 0.2.10

Not very easy to read, I must be not the first one to have this need.

I use yarn 4.3.1, how can I know all dependencies that have been modified/added/deleted?

Comapre dependencies changes using two lock file

In a project that is broken but no changes in my source code, I suspect something changed in my dependency tree.

I have both lock file, I have tried to do like this:

grep 'version:' yarn.lock > yarn-versions.txt
grep 'version:' yarn-old.lock > yarn-old-versions.txt
diff yarn-versions.txt yarn-old-versions.txt

And this is the result of the diff:

❯ diff yarn-versions.txt yarn-old-versions.txt
156d155
<   version: 0.0.0-use.local
317c316
<   version: 0.6.5
---
>   version: 0.6.2
319c318
<   version: 0.6.5
---
>   version: 0.6.2
321c320
<   version: 0.6.5
---
>   version: 0.6.2
323c322
<   version: 0.6.5
---
>   version: 0.6.2
325c324
<   version: 0.6.5
---
>   version: 0.6.2
327c326
<   version: 0.6.5
---
>   version: 0.6.2
329c328
<   version: 0.6.5
---
>   version: 0.6.2
331c330
<   version: 0.6.5
---
>   version: 0.6.2
843d841
<   version: 9.1.0
1079d1076
<   version: 6.4.2
1181c1178
<   version: 2.22.17
---
>   version: 2.22.12
1673d1669
<   version: 1.1.1
1676d1671
<   version: 4.0.2
1854d1848
<   version: 1.8.2
1970d1963
<   version: 0.2.10

Not very easy to read, I must be not the first one to have this need.

I use yarn 4.3.1, how can I know all dependencies that have been modified/added/deleted?

Can I reference form state from outside form using PrimeVue Forms

I’m trying to use PrimeVue Forms and I have validation working using Valibot (though I think this question is agnostic of what validation framework I’m using).

In my template, I have the following:

    <Form
      v-slot="form"
      :initialValues="location"
      :resolver
      @submit="formSubmit"
      class="h-full flex flex-col justify-between"
    >
      <!-- Form -->
      <div class="flex flex-col overflow-auto gap-4">
        <!-- Details  -->
        <Panel :header="label('details')">
          <div class="flex flex-col gap-4">
            <!-- Name  -->
            <div class="flex flex-col">
              <IftaLabel>
                <InputText name="name" type="text" placeholder="" fluid />
                <label>{{ label("floor_name") }}</label>
              </IftaLabel>
              <div class="text-xxs text-right mt-1" v-if="form?.name?.invalid">{{ form.name.error?.message }}</div>
            </div>
          </div>
        </Panel>
      </div>
      <!-- Footer -->
      <div class="safe bottom mt-4">
        <div class="flex gap-2 justify-between">
          <div></div>
          <div class="flex gap-2">
            <Button icon="fa-sharp fa-light fa-xmark" :label="label('discard')" severity="warn" @click="discard(form)" />
            <Button icon="fa-sharp fa-light fa-floppy-disk" :label="label('save')" type="submit" :disabled="!form.valid" />
          </div>
        </div>
      </div>
    </Form>

My question is this – can I reference the state of the form from JavaScript outside the scope of the form itself? For example, could I have a computed value that determines if the form is dirty or not? I’m using the following to determine if the form is dirty from functions called from the form, but can’t work out how to get field dirty states from outside the form.

const discard = async (form) => {
  console.log(
    "Dirty",
    Object.keys(form).reduce((result, key) => result || form[key].dirty === true, false)
  );
};

Are there any UI libraries built on top of shadcn-ui with extended components?

I am exploring the shadcn-ui library for my project and am impressed with its design and components. However, I am curious to know if there are any third-party UI libraries or component collections built on top of shadcn-ui that provide additional or extended components.

For instance, I am looking for components or features that are not currently part of the official shadcn-ui library.

Any suggestions or recommendations would be greatly appreciated. If you’ve used such libraries, please share your experience and let me know how well they integrate with shadcn-ui.

Error decrypting AES-encrypted text from file through stdin and pipe to stdout in Node.js

Let’s say we have a file named foobar.enc and a script called decrypt-from-stdin-to-stdout.js. the file foobar.enc contains an AES-encrypted text. This text is unencrypted as follows: “foobar”.

The script is being called in this way:

cat foobar.enc | node decrypt-from-stdin-to-stdout.js

Expected output on console should be: “foobar”
But it is “fooba” instead.

Im am working with Windows 10 Professional and Cygwin and Node v20.9.0. Another test with same input file and script on a native Debian system yields the same strange result.

So what is the problem with the script?
This is the script:

const crypto = require('crypto');
const zlib = require('zlib');


function createCipherKeyBuffer(passwordStr) {
  return crypto.createHash('sha256').update(passwordStr).digest();
}


const stdoutStream = process.stdout;
const stdinStream = process.stdin;

let decipherStream;
let initVectBufferCreated = false;


stdinStream.on('data', inputBuffer => {
  if (inputBuffer.length >= 16 && !initVectBufferCreated) {
    const initVectBuffer = inputBuffer.subarray(0, 16);
    initVectBufferCreated = true;

    const unzipStream = zlib.createUnzip();

    const cipherKeyBuffer = createCipherKeyBuffer('power237');
    decipherStream = crypto.createDecipheriv('aes256', cipherKeyBuffer, initVectBuffer);

    /*stdinStream.on('end', () => {
      console.error('stdinStream on end');
    });*/

    decipherStream.write(inputBuffer.subarray(16, inputBuffer.length));
    decipherStream
      .pipe(unzipStream)
      .pipe(stdoutStream);

  } else if (inputBuffer.length < 16) {
    console.error('input too small');
    process.exit(1);

  } else {
    decipherStream.write(inputBuffer);
  }
});

Some hints:

I know using passwords in source code is a bad habit. But this code is not for production purposes but only for test. I would just like to understand the main problem.

When I use a larger text like “foobarbazboz”, everything is working fine.
The file foobarbazboz.enc contains the encrypted text.

Calling like:

cat foobarbazboz.enc | node decrypt-from-stdin-to-stdout.js

This outputs (as expected):

“foobarbazboz”

This is the Base64-encoded data for the file foobar.enc:

9BoTOZenA+Ynw0m9/Qzqij9Wzw/VkkuVGXR/jm2+YneeQ08L75ylM6gk+EmhwYJE

And this is the Base64-encoded data for the file foobarbazboz.enc:

zKTsPq7wvdW7dxSj/tNTtC9R7sAvPhrBsgbFDcvSE7CgvGY7DWyBsDtroOh1gOVwUhCv3TbBCb8Ar+UU3DeDAw==

Since the both input files contains binary (encrypted) data and because I want to avoid external resources, I have decided to encode them with Base64 and print them here.
I am sorry for that circumstance. So please first decode the strings and write them to the test files mentioned above.

You can decode them like as follows:

echo "9BoTOZenA+Ynw0m9/Qzqij9Wzw/VkkuVGXR/jm2+YneeQ08L75ylM6gk+EmhwYJE" | base64 -d > foobar.enc
echo "zKTsPq7wvdW7dxSj/tNTtC9R7sAvPhrBsgbFDcvSE7CgvGY7DWyBsDtroOh1gOVwUhCv3TbBCb8Ar+UU3DeDAw==" | base64 -d > foobarbazboz.enc

Can anyone explain this TypeScript error?

I do not undestand of TS error

Here is an example of code

interface initParams {
    withoutAuth?: any;
    scripts?: any; // ссылка на файл, который выдает скрипты
    setProxy: any;
}

class LoaderService {
    bar1: any;

    constructor() {

    }
}
class ServerBaseService<T extends LoaderService> {
    constructor(
        private readonly _createClass: { new(): T },

        private readonly isKube: boolean,
    ) {
 
    }
}

class HttpLoaderService extends LoaderService {
    constructor({ withoutAuth, scripts, setProxy }: initParams) {
        super()
    }

}

class ServerHTTPService<T extends HttpLoaderService> extends ServerBaseService<T> {
    constructor(
        private readonly _createClasss: new () => T, //{ new(): T }
        private readonly withoutAuth: boolean,
        private readonly setProxy: boolean,
        private readonly isKubee: boolean
    ) {
        super(_createClasss, isKubee) //_createClasss,  // будет вызван конструктор ServerBaseService
    }
}

class AuthLoaderService extends HttpLoaderService {
}

class AuthenticationServerService extends ServerHTTPService<AuthLoaderService> {

    constructor({ withoutAuth, setProxy, isKube }: { withoutAuth: boolean, setProxy: boolean, isKube: boolean }) {
        super(AuthLoaderService,withoutAuth,setProxy,isKube)

    }

}

TS playground

Why here is an error

Argument of type 'typeof AuthLoaderService' is not assignable to parameter of type 'new () => AuthLoaderService'.
  Types of construct signatures are incompatible.
    Type 'new ({ withoutAuth, scripts, setProxy }: initParams) => AuthLoaderService' is not assignable to type 'new () => AuthLoaderService'

In AuthenticationServerService when calling super it refer on ServerHTTPService constructor.
But error message is refer on HttpLoaderService constructor signature.
Why???
Can anybody explain this error?

Details disclosure using Ctrl+F in Firefox

The <details> element is searchable in Chrome. In other words, I can have something like this:

<details>
  <summary>John Doe</summary>
  <div>123 Main Street</div>
  <div>Springfield, OK</div>
  <div>73000</div>
</details>

Then if I Ctrl+F for “Main Street” Chrome will automatically open the details for me.

However, Firefox doesn’t do this!

How to I get the same behavior in Firefox? Even a custom solution? Basically I want content to be hidden by default, but so I can toggle it open and also use Ctrl+F to find it.

FCM Cloud Messaging – Provide Credentials Manually

In attempting to follow the instructions detailed at https://firebase.google.com/docs/cloud-messaging/migrate-v1?authuser=2#provide-credentials-manually, I’m getting

Error sending message: Error: exec is not supported

I think the issue lies in something needing to be changed for the manual approach, but aside from adding the headers section to the message I don’t know what to do.

Regarding the code below, assume that getAccessToken() is implemented and verified to be working properly, and I’m aware that registrationToken is defined such that an invalid token error should be rendered, the entire issue is that I’m not getting to that error as expected.

const { JWT } = require('google-auth-library');
const admin = require('firebase-admin');

exports = async function(){

  var accessToken = getAccessToken();

  admin.initializeApp();

  // This registration token comes from the client FCM SDKs.
  const registrationToken = 'YOUR_REGISTRATION_TOKEN';
  
  const message = {
    headers: {
      'Authorization': 'Bearer ' + accessToken
    },
    notification: {
      title: 'Test title',
      body: 'You need to X!'
    },
    token: registrationToken
  };
  
  // Send a message to the device corresponding to the provided
  // registration token.
  admin.messaging().send(message)
    .then((response) => {
      // Response is a message ID string.
      console.log('Successfully sent message:', response);
    })
    .catch((error) => {
      console.log('Error sending message:', error);
    });
  
};

Why Click event does not work in audio tag [duplicate]

I want to fire a function name shake dots when clicked in audio apparently it does not fire here is the code

   <div class="lyric-word">
                  <span class="sho">.</span>
                  <span class="sho">.</span>
                  <span class="sho">.</span>
                  <span class="sho">.</span>
                  <span class="sho">.</span>
                  <span class="sho">.</span>
            </div>      
<div class="btm">
            <audio id="thisaudio" onclick="shakeDots()" src="https://pagalworld.com.mx/wp-content/uploads/2023/02/Until-I-Found-You.mp3"
                  controls controlsList="nodownload noplaybackrate"></audio>
      </div>

JS

   function shakeDots() {
            const $click= document.querySelectorALL('.shok');
            $click.classList.add('shak'); 
            console,log("Clicked")
        }

Thanks

In OpenTelemetry typescript, can you exclude instruments from view?

Let’s say I have something like this:

const fooView = new View({
      instrumentName: "*_foo",
      // options for foo instruments
    });

const barView = new View({
      instrumentName: "*_bar",
      // options for bar instruments
    });

Then I also want to have something like this:

const defaultView = new View({
      // do something here to capture all instruments EXCEPT foo and bar ones
    });

And just for full context, these will then be used like this:

var meterProvider = new MeterProvider({
      views: [fooView, barView, defaultView],
      // other options here
    });

My question is: how do I define defaultView to achieve this? The problem is instrumentName is not a standard regexp. And the view documentation from here doesn’t mention any way of excluding specific names. Is there a workaround for this?

Resizing KonvaJS Dynamically Similar to Canvas

I have a need to adjust the KonvaJS Container/Stage in a similar way to a canvas element. I’ve provided an example below showcasing my exact need. In this code the source of the image to select is the canvas, and so I need the canvas and the Konva elements to dynamically update to the screen size and perfectly align while still maintaining dimensions of 1000×1000.

However, for some reason the Konva container’s (select-container) width is not adjusting the same way as the canvas does with the same css. In addition, it seems that the stage is not adjusting to the fit within the container. Is there any built in solution to fix my issue?

<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/[email protected]/konva.min.js"></script>
    <meta charset="utf-8" />
    <title>Canvas to Konva Object</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        overflow: hidden;
        background-color: #f0f0f0;
      }
      .over-container {
            top: 100%;
            display: flex;
            flex-wrap: nowrap; /* Prevent wrapping */
            flex-direction: column;
            width: 100%;
            height: 100vh;
            align-items: center;
            margin-top: 35px;
        }

        #canvas-container {
            position: relative;
            width: 100%;
            overflow: hidden;
            /* Aspect Ratio */
            padding-top: 100%;
            display: flex;
            justify-content: center;
        }

        #select-container {
            cursor: crosshair;
            position: absolute;
            top: 0;
            left: 50%;
            transform: translate(-50%);
            max-width: calc(100vw - 10px); /* Subtracting 5px margin on both sides */
            /* Set explicitly or let JavaScript control */
            border: 1px solid #571bfa;
            flex: 1;
        }

        #canvas {
            cursor: crosshair;
            position: absolute;
            top: 0;
            left: 50%;
            transform: translate(-50%);
            /* Adjust size based on viewport */
            max-width: calc(100vw - 10px); /* Subtracting 5px margin on both sides */
            touch-action: none; 
            image-rendering: pixelated; 
            flex: 1;
            border: 1px solid #000;
        }
    </style>
  </head>
  <body>
    <div class="over-container" id="Ocontainer">
        <div id="canvas-container">
            <canvas id="canvas"></canvas>
            <div id="select-container"></div>
        </div>
    </div>
    <script>
        var width = 1000;
        var height = 1000;

        // Get the canvas and set dimensions
        var canvas = document.getElementById('canvas');
        canvas.width = width;
        canvas.height = height;

        var ctx = canvas.getContext('2d');
        ctx.fillStyle = 'blue';
        ctx.fillRect(50, 50, 300, 200);
        ctx.fillStyle = 'orange';
        ctx.fillRect(400, 100, 200, 300);

        // Create Konva stage and layer
        var stage = new Konva.Stage({
            container: 'select-container',
            width: width,
            height: height,
        });

        var layer = new Konva.Layer();
        stage.add(layer);

        var selectionRectangle = new Konva.Rect({
            fill: 'rgba(0, 0, 255, 0.5)',
            visible: false,
            listening: false,
        });
        layer.add(selectionRectangle);

        var x1, y1, x2, y2, selecting = false, activeObject = null;
        var copiedObject = null;
        var objects = [];
        var transformers = []; // Keep track of transformers for cleanup

        // Helper function to create a transformer for a given object
        function createTransformer(object) {
            const transformer = new Konva.Transformer({
            nodes: [object],
            });
            layer.add(transformer);
            transformer.update();
            transformers.push(transformer); // Keep track of the transformer
            return transformer;
        }

        stage.on('mousedown touchstart', (e) => {
            if (e.target !== stage) return;

            e.evt.preventDefault();
            x1 = stage.getPointerPosition().x;
            y1 = stage.getPointerPosition().y;
            selecting = true;

            selectionRectangle.setAttrs({
            visible: true,
            x: x1,
            y: y1,
            width: 0,
            height: 0,
            });
        });

        stage.on('mousemove touchmove', (e) => {
            if (!selecting) return;

            e.evt.preventDefault();
            x2 = stage.getPointerPosition().x;
            y2 = stage.getPointerPosition().y;

            let width = Math.abs(x2 - x1);
            let height = Math.abs(y2 - y1);

            // Check if Shift key is held
            if (e.evt.shiftKey) {
            // Force square by setting width and height to the smaller of the two
            const sideLength = Math.min(width, height);
            width = sideLength;
            height = sideLength;

            // Adjust x2 and y2 to maintain the square shape
            if (x2 < x1) x2 = x1 - width; // Adjust for leftward movement
            else x2 = x1 + width; // Adjust for rightward movement

            if (y2 < y1) y2 = y1 - height; // Adjust for upward movement
            else y2 = y1 + height; // Adjust for downward movement
            }

            selectionRectangle.setAttrs({
            x: Math.min(x1, x2),
            y: Math.min(y1, y2),
            width: width,
            height: height,
            });

            layer.batchDraw();
        });

        stage.on('mouseup touchend', () => {
            if (!selecting) return;
            selecting = false;
            selectionRectangle.visible(false);

            const box = selectionRectangle.getClientRect();
            const sx = box.x;
            const sy = box.y;
            const sw = box.width;
            const sh = box.height;

            if (sw === 0 || sh === 0) return;

            // Get the selected area from the visible canvas
            const imageData = ctx.getImageData(sx, sy, sw, sh);

            // Remove the selected portion from the canvas
            ctx.clearRect(sx, sy, sw, sh);

            // Create an off-screen canvas to crop the image data
            const tempCanvas = document.createElement('canvas');
            tempCanvas.width = sw;
            tempCanvas.height = sh;
            const tempCtx = tempCanvas.getContext('2d');
            tempCtx.putImageData(imageData, 0, 0);

            // Create a Konva.Image from the cropped area
            const image = new Konva.Image({
                x: sx,
                y: sy,
                image: tempCanvas,
                draggable: true,
            });
            layer.add(image);
            objects.push(image);

            // Create a transformer for this object
            createTransformer(image);

            activeObject = image;
            layer.batchDraw();
        });

        window.addEventListener('keydown', (e) => {
            if (e.ctrlKey && e.key === 'c' && activeObject) {
                // Copy the active object
                const clonedCanvas = document.createElement('canvas');
                clonedCanvas.width = activeObject.image().width;
                clonedCanvas.height = activeObject.image().height;
                const clonedCtx = clonedCanvas.getContext('2d');
                clonedCtx.drawImage(activeObject.image(), 0, 0);

                copiedObject = {
                    x: activeObject.x() + 10,
                    y: activeObject.y() + 10,
                    image: clonedCanvas,
                    rotation: activeObject.rotation(),
                    scaleX: activeObject.scaleX(),
                    scaleY: activeObject.scaleY(),
                };
            }
            if (e.ctrlKey && e.key === 'v' && copiedObject) {
                // Paste the copied object
                const newCopy = new Konva.Image({
                    x: copiedObject.x,
                    y: copiedObject.y,
                    image: copiedObject.image,
                    draggable: true,
                    rotation: copiedObject.rotation,
                    scaleX: copiedObject.scaleX,
                    scaleY: copiedObject.scaleY,
                });
                layer.add(newCopy);
                objects.push(newCopy);

                // Create a transformer for the new copy
                createTransformer(newCopy);

                activeObject = newCopy;
                layer.batchDraw();
            }
        });

        stage.on('click tap', (e) => {
            if (activeObject && e.target === stage) {
            // Apply all objects back to the canvas
            objects.forEach((obj) => {
                const image = obj.image(); // Get the underlying image
                const rotation = obj.rotation(); // Rotation angle in degrees

                // Use getClientRect to get transformed position
                const clientRect = obj.getClientRect();
                const boundingBoxCenterX = clientRect.x + clientRect.width / 2;
                const boundingBoxCenterY = clientRect.y + clientRect.height / 2;

                // Use the original image dimensions
                const originalWidth = image.width;
                const originalHeight = image.height;

                // Use scaleX and scaleY for scaling
                const scaledWidth = originalWidth * obj.scaleX();
                const scaledHeight = originalHeight * obj.scaleY();

                // Save the canvas context state
                ctx.save();

                // Translate to the bounding box center
                ctx.translate(boundingBoxCenterX, boundingBoxCenterY);

                // Rotate the canvas context around the center of the bounding box
                ctx.rotate((rotation * Math.PI) / 180);

                // Draw the object onto the canvas using the original dimensions and scaling
                ctx.drawImage(
                image,
                -scaledWidth / 2, // Center the image horizontally
                -scaledHeight / 2, // Center the image vertically
                scaledWidth,
                scaledHeight
                );

                // Restore the canvas context state
                ctx.restore();
            });

            // Destroy all Konva objects and transformers
            objects.forEach((obj) => obj.destroy());
            transformers.forEach((transformer) => transformer.destroy());
            transformers = [];

            // Reset state variables
            objects = [];
            activeObject = null;

            // Redraw the layer
            layer.batchDraw();
            }
        });

        const selectContainer = document.getElementById('select-container');
        const canvasContainer = document.getElementById('canvas-container');
        let imageSize = 1000;

        resizeCanvas();
        window.addEventListener('resize', resizeCanvas);
        window.addEventListener('load', resizeCanvas);
        document.body.addEventListener('resize', function(event) {
            document.body.style.zoom = 1;
        });

        function resizeCanvas() {
            const screenWidth = window.innerWidth;
            const screenHeight = window.innerHeight;
            const spaceToBottom = window.innerHeight - (canvasContainer.offsetTop + canvasContainer.offsetHeight);
            const topElementsHeight = screenHeight;

            canvas.width = Math.round(imageSize);
            canvas.height = Math.round(imageSize);

            canvas.style.maxHeight = topElementsHeight + 'px';
            canvas.style.height = topElementsHeight - spaceToBottom + 'px';

            selectContainer.style.setProperty('width', Math.round(imageSize) + 'px', 'important');
            selectContainer.style.setProperty('height', Math.round(imageSize) + 'px', 'important');

            selectContainer.style.setProperty('max-height', topElementsHeight + 'px', 'important');
            selectContainer.style.setProperty('height', topElementsHeight - spaceToBottom + 'px', 'important');


            const newWidth = Math.round(imageSize);
            const newHeight = Math.round(imageSize);

            stage.width(newWidth);
            stage.height(newHeight);
            stage.batchDraw();

            redrawCanvas();
        }

        function redrawCanvas() {
            // Clear the main canvas and set the background to white
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = 'blue';
            ctx.fillRect(50, 50, 300, 200);
            ctx.fillStyle = 'orange';
            ctx.fillRect(400, 100, 200, 300);
        }
    </script>
  </body>
</html>

Cannot get seconds from Timestamp object from Firestore

I am creating a Todo app in Angular using Firestore as my backend. I am really new to Firebase and I am having trouble storing and fetching dates.

When I get the dates from firebase and console.log them i get something like this: date: _Timestamp { seconds: 1736290800, nanoseconds: 0 }

I understand that to get a human readable date out of this i need to access the seconds part of this and convert it. I have tried to use date.seconds and date.getSeconds() but .seconds gives me this error:

[ERROR] TS2339: Property ‘seconds’ does not exist on type ‘Date’. [plugin angular-compiler]

src/app/pages/todolist/todolist.component.ts:79:47:
  79 │         console.log("date: ",todo.deadlineDate.seconds);

And date.getSeconds() is not recognized as a function.

It seems like the date retrieved from firebase is not recognized as a Timestamp object.

I have tried making a Timestamp object of the variable using Timestamp.fromDate() but it did not work.

I am using Angular 18 with AngularFirestore and the dates are from user input with MatDatePickerModule and MatNativeDateModule and is stored as a Date in the object sent to firebase.

Appreciate if someone would have a solution to this.