How to send data to GAS function?

I am using Google Apps Script to write a small web app where I can upload an image (Business Cards) which is then stored in my Google Drive.
The image should be utilized by ChatGPT which extract the information and save them into Google Spreadsheets.

I have this Index.html where I can select and image and upload it. It saved to my Google Drive successfully but I get an error Uncaught at uploadImageToServer (Code:34).

Here is the HTML

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style>
      #status {
        margin-top: 10px;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <form id="uploadForm">
      <input type="file" id="fileInput" accept="image/*">
      <input type="button" value="Upload" onclick="uploadImage()">
    </form>
    <pre id="result"></pre>
    <div id="status"></div>
    <script>
      function uploadImage() {
        const fileInput = document.getElementById('fileInput');
        const file = fileInput.files[0];
        const statusDiv = document.getElementById('status');

        if (!file) {
          alert("Please select a file before uploading.");
          return;
        }

        statusDiv.textContent = "Uploading image, please wait...";

        const reader = new FileReader();

        reader.onload = function(e) {
          const dataUrl = e.target.result;
          console.log("Data URL:", dataUrl);

          if (dataUrl) {
            google.script.run.withSuccessHandler(function(response) {
              document.getElementById('result').textContent = JSON.stringify(response, null, 2);            
            }).uploadImageToServer(dataUrl);

            statusDiv.textContent = "Image uploaded successfully. Processing...";
          } else {
            console.error("Failed to generate Data URL.");
            statusDiv.textContent = "Error uploading image.";
          }
        };

        reader.onerror = function(error) {
          console.error("Error reading file:", error);
          statusDiv.textContent = "Error uploading image.";
        };

        reader.readAsDataURL(file);
    </script>
  </body>
</html>

I put a console.log and Data URL exists but it is somehow not pass to my GAS function uploadImageToServer().

Here is my Code.gs script

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function uploadImageToServer(dataUrl) {
  Logger.log("Upload function started");

  try {
    Logger.log("Received dataUrl: " + dataUrl);

    if (!dataUrl) {
      throw new Error("No dataUrl received");
    }

    const matches = dataUrl.match(/^data:(.+);base64,(.*)$/);
    if (!matches || matches.length !== 3) {
      throw new Error('Could not parse the data URL.');
    }

    const contentType = matches[1];
    const data = matches[2];
    const blob = Utilities.newBlob(Utilities.base64Decode(data), contentType, "uploaded_image");

    const folder = DriveApp.getFolderById('xxx');
    const file = folder.createFile(blob);
    Logger.log("Image uploaded to Google Drive");

    const imageUrl = file.getUrl();
    Logger.log("Image URL: " + imageUrl);

    // Call Google Cloud Vision API
    const apiKey = 'xxx';
    const visionUrl = `https://vision.googleapis.com/v1/images:annotate?key=${apiKey}`;
    const image = UrlFetchApp.fetch(imageUrl).getBlob().getBytes();
    const encodedImage = Utilities.base64Encode(image);
    Logger.log("Encoded image for Vision API");

    const visionPayload = {
      requests: [
        {
          image: {
            content: encodedImage
          },
          features: [
            {
              type: "TEXT_DETECTION"
            }
          ]
        }
      ]
    };

    const visionOptions = {
      method: "post",
      contentType: "application/json",
      payload: JSON.stringify(visionPayload)
    };

    const visionResponse = UrlFetchApp.fetch(visionUrl, visionOptions);
    Logger.log("Vision API response received");

    const visionData = JSON.parse(visionResponse.getContentText());
    Logger.log("Vision API data parsed: " + JSON.stringify(visionData));

    if (!visionData.responses || !visionData.responses[0] || !visionData.responses[0].fullTextAnnotation) {
      throw new Error("No text found by Vision API");
    }

    const text = visionData.responses[0].fullTextAnnotation.text;
    Logger.log("Extracted text: " + text);

    // Call OpenAI API
    const openaiApiKey = 'xxx';
    const openaiUrl = 'https://api.openai.com/v1/engines/davinci/completions';
    const prompt = `Extract the information from this business card text:nn${text}nnThe information should be in JSON format with keys 'Company', 'Name', 'Title', 'Phone', 'Website', 'Email', and 'Address'.`;

    const openaiPayload = {
      prompt: prompt,
      max_tokens: 150,
      n: 1,
      stop: null,
      temperature: 0.5
    };

    const openaiOptions = {
      method: 'post',
      contentType: 'application/json',
      headers: {
        'Authorization': `Bearer ${openaiApiKey}`
      },
      payload: JSON.stringify(openaiPayload)
    };

    const openaiResponse = UrlFetchApp.fetch(openaiUrl, openaiOptions);
    Logger.log("OpenAI API response received");

    const openaiData = JSON.parse(openaiResponse.getContentText());
    Logger.log("OpenAI API data parsed: " + JSON.stringify(openaiData));

    const jsonResponse = openaiData.choices[0].text.trim();
    Logger.log("OpenAI response parsed: " + jsonResponse);

    const parsedData = JSON.parse(jsonResponse);

    if (!parsedData.Company || !parsedData.Name) {
      throw new Error("Parsed data incomplete");
    }
    
    const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    const row = [parsedData.Company, parsedData.Name, parsedData.Title, parsedData.Phone, parsedData.Website, parsedData.Email, parsedData.Address];
    sheet.appendRow(row);
    Logger.log("Data appended to Google Sheet");

    return parsedData;
  } catch (error) {
    Logger.log("Error: " + error.message);
    throw error;
  }
}

Here is the Execution Log when I run this code

12:37:37 AM Notice Execution started
12:37:06 AM Info Upload function started
12:37:06 AM Info Received dataUrl: undefined
12:37:06 AM Info Error: No dataUrl received
12:37:37 AM Error

Error: No dataUrl received
uploadImageToServer @ Code.gs:12

Import a ES6 module in Angular

I’m trying to use H5 to convert C# code into JS and then use the result in an Angular project, but I’m having trouble importing the generated JS module.

I wrote a simple C# class like this:

namespace TW3.Shared {
    public class Class1 {
        public int Sum(int x, int y) {
            return x + y;
        }
    }
}

…and using the following h5.json configuration file:

{
    "module": {
        "type": "ES6",
        "name": "XXX"
    },
    "generateTypeScript": true
}

…I got these 2 files:

// SharedJS.js

/**
 * @compiler H5 24.2.45744+d8342060ba1fec4b36b7d0c2865c74ad945e2889
 */
H5.assemblyVersion("SharedJS","1.0.0.0");
H5.assembly("SharedJS", function ($asm, globals) {
    "use strict";

    (function () {
        var XXX = { };
        H5.define("TW3.Shared.Class1", {
            $metadata : function () { return {"att":1048577,"a":2,"m":[{"a":2,"isSynthetic":true,"n":".ctor","t":1,"sn":"ctor"},{"a":2,"n":"Sum","t":8,"pi":[{"n":"x","pt":System.Int32,"ps":0},{"n":"y","pt":System.Int32,"ps":1}],"sn":"Sum","rt":System.Int32,"p":[System.Int32,System.Int32],"box":function ($v) { return H5.box($v, System.Int32);}}]}; },
            $scope: XXX,
            $module: "XXX",
            methods: {
                Sum: function (x, y) {
                    return ((x + y) | 0);
                }
            }
        });
        export {XXX};
    }) ();

});
// SharedJS.d.ts

namespace TW3.Shared {
    interface Class1 {
        Sum(x: number, y: number): number;
    }
    interface Class1Func extends Function {
        prototype: Class1;
        new (): Class1;
    }
    var Class1: Class1Func;
}

So, what do I need to do in order to call Class1.Sum() inside Angular?

I tried adding the generated .js and .ts files to angular.json:

"scripts": [
  "src/assets/js/SharedJS/h5.js",
  "src/assets/js/SharedJS/h5.meta.js",
  "src/assets/js/SharedJS/SharedJS.js",
  "src/assets/js/SharedJS/SharedJS.meta.js",
  "src/assets/js/SharedJS/SharedJS.d.ts"
]

but if I do that, then I get an error when I try to build the angular project:

X [ERROR] Unexpected "export"

    angular:script/global:scripts.js:51675:8:
      51675 │         export {XXX};
            ╵         ~~~~~~

How to customize elements in a #shadow-root (open)

I am trying to customize a third-party code to match the colors on our Squarespace website. The third party has an open #shadow-root on their Footer, but I’m still unable to customize part of the code. What I’m trying to do is change the background-color to #ff0000;

I’ve tried to target .formFooter in CSS, but from what I’ve tried, it hasn’t worked. Here is their code below through Inspector:

<div>
 #shadow-root (open)
 <style></style>
<div class="formFooter-heightMa sk"></div>
<div class="formFooter f6 branding21 ">∞</div>flex)
== $0
<style id="action-styles">
</style>
</div>
</form>

And here is their style:

.formFooter {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
    background-color: #0A1551;

Issues in Chrome setting scrollLeft when devicePixelRatio is not an integer

When I set element.scrollLeft while the devicePixelRatio is 1.25 (on Windows > Display > Scale = 125%), Chrome seems to round my values to what appear to be multiples of 0.8. Firefox does not exhibit the same behavior.

Here is an example script:

element.scrollLeft = 1;
console.log(element.scrollLeft); // 0.8
element.scrollLeft = 2;
console.log(element.scrollLeft); // 2.4
element.scrollLeft = 3;
console.log(element.scrollLeft); // 3.2
element.scrollLeft = 4;
console.log(element.scrollLeft); // 4

This rounding is causing me issues in some code I am developing. The goal is to maintain the visual position of something in a scrolled container while that container is moving. For example, if the box moves 10 pixels to the right on the screen, scroll it the same amount, so that the contents look like they haven’t moved. Kind of like looking out of a window.

The code works well at a devicePixelRatio of 1 or 2, but not at 1.25. The rounding causes the element’s position to jitter back-and-forth a fraction of a pixel.

I know that sub-pixel precision is expected in Element.scrollLeft, as part of the spec. I would like to know how to to account for it in some way, so that I can set the scrollLeft and know that it is maintaining my contents’ position.


GIF: https://imgur.com/a/UYE2KsH

Here is a CodeSandbox with a demo of the technique: https://codesandbox.io/p/sandbox/hardcore-lichterman-xydrpy

Verify the sequence of Time in JavaScript Selenium

I have a list of time as folllowing,
‘a day ago,
10 days ago,
3 months ago,
6 months ago’.

How to verify that these dates are ascending? in javascript Selenium

I cant think of trying anything, I have some ideas for dd/mm/yyyy or mm/dd/yyyy. But this Text format of the time made me confused.

Quantity field doesn’t work in a custom plugin for WooCommerce and Elementor

I’m making a plugin for Elementor. It must show a product from WooCommerce on the page. Picture, name, price, quantity window, +/- buttons, add to cart button for each product. The quantity window does not work, the quantity 1 initial digit is indicated there, it accepts it, and that’s it. If I enter the number 3, it will not record anything and add 1.

Build

  1. custom-product-widget.php
  2. script.js
  3. style.css
  4. folder “widgets”:
    • class-custom-product-widget.php

The main pludin file custom-product-widget.php:

<?php
/*
Plugin Name: Custom Product Widget for Elementor v1.00000000
Description: Додає віджет для Elementor, який відображає WooCommerce продукти.
Version: 1.00000000
Author: blvckfamily
*/

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

// Connecting the necessary files
function cpw_enqueue_scripts() {
    wp_enqueue_style( 'cpw-style', plugin_dir_url( __FILE__ ) . 'style.css' );
    wp_enqueue_script( 'cpw-script', plugin_dir_url( __FILE__ ) . 'script.js', array('jquery'), null, true );
}
add_action( 'wp_enqueue_scripts', 'cpw_enqueue_scripts' );

// Widget registration
function cpw_register_widget() {
    require_once( plugin_dir_path( __FILE__ ) . 'widgets/class-custom-product-widget.php' );
    ElementorPlugin::instance()->widgets_manager->register_widget_type( new Custom_Product_Widget() );
}
add_action( 'elementor/widgets/widgets_registered', 'cpw_register_widget' );

The script.js file:

jQuery(function($) {
    $('.product-card').each(function() {
        var minusBtn = $(this).find('.minus'),
            plusBtn  = $(this).find('.plus'),
            qtyInput = $(this).find('.qty'),
            addToCartBtn = $(this).find('.add-to-cart');

        function updateAddToCartButton(qtyInput) {
            qtyInput.closest('.product-card').find('.add-to-cart').attr('data-quantity', qtyInput.val());
        }

        minusBtn.on('click', function () {
            var currentVal = parseInt(qtyInput.val());
            if (currentVal > 1) {
                qtyInput.val(currentVal - 1);
                updateAddToCartButton(qtyInput);
            }
        });

        plusBtn.on('click', function () {
            var currentVal = parseInt(qtyInput.val());
            qtyInput.val(currentVal + 1);
            updateAddToCartButton(qtyInput);
        });

        qtyInput.on('input', function () {
            updateAddToCartButton(qtyInput);
        });

        addToCartBtn.on('click', function() {
            var productId = $(this).data('product-id');
            var quantity = $(this).siblings('.quantity-box').find('.qty').val();
            $.ajax({
                url: wc_add_to_cart_params.ajax_url,
                type: 'POST',
                data: {
                    action: 'woocommerce_ajax_add_to_cart',
                    product_id: productId,
                    quantity: quantity
                },
                success: function(response) {
                    if (response.error && response.product_url) {
                        window.location = response.product_url;
                    } else {
                        $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $this]);
                    }
                }
            });
        });
    });
});

The style.css file:

.custom-product-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
}

.product-card {
    text-align: center;
    padding: 10px;
    border: 1px solid #eee;
    margin-bottom: 15px;
}

.product-card img {
    max-width: 100%;
    height: auto;
}

.product-card h3 {
    font-size: 16px;
    margin: 10px 0;
}

.product-card .quantity-box {
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 10px 0;
}

.product-card .quantity-box input {
    width: 50px;
    text-align: center;
    margin: 0 10px;
}

.product-card .add-to-cart {
    background-color: #000;
    color: #fff;
    padding: 10px 20px;
    text-transform: uppercase;
    border: none;
    cursor: pointer;
}

.product-card .add-to-cart:hover {
    background-color: #333;
}

.quantity-box button {
    background-color: #ddd;
    border: none;
    padding: 0 10px;
    cursor: pointer;
}

.quantity-box button:hover {
    background-color: #ccc;
}

/* Remove arrows from number input */
.quantity-box input[type="number"] {
    -moz-appearance: textfield;
    -webkit-appearance: none;
    appearance: none;
}

.quantity-box input[type="number"]::-webkit-inner-spin-button,
.quantity-box input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

In the folder “widgets”, the file “class-custom-product-widget.php”:

<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

class Custom_Product_Widget extends ElementorWidget_Base {

    public function get_name() {
        return 'custom_product_widget';
    }

    public function get_title() {
        return __( 'Custom Product Widget', 'cpw' );
    }

    public function get_icon() {
        return 'eicon-product-grid';
    }

    public function get_categories() {
        return [ 'general' ];
    }

    protected function _register_controls() {
        // Add controls here if needed
    }

    protected function render() {
        $args = array(
            'post_type' => 'product',
            'posts_per_page' => 10
        );
        $products = new WP_Query( $args );
        if ( $products->have_posts() ) {
            echo '<div class="custom-product-grid">';
            while ( $products->have_posts() ) {
                $products->the_post();
                global $product;
                ?>
                <div class="product-card">
                    <?php if ( has_post_thumbnail() ) { ?>
                        <img src="<?php echo esc_url( get_the_post_thumbnail_url() ); ?>" alt="<?php the_title(); ?>" />
                    <?php } ?>
                    <h3><?php the_title(); ?></h3>
                    <div class="quantity-box">
                        <button type="button" class="minus">-</button>
                        <input type="number" class="input-text qty text" step="1" min="1" value="1" />
                        <button type="button" class="plus">+</button>
                    </div>
                    
                    <a href="<?php echo esc_url( $product->add_to_cart_url() ); ?>" class="add-to-cart button">
                        <?php echo esc_html( $product->add_to_cart_text() ); // Button "Add to cart" ?>
                    </a>

                </div>
                <?php
            }
            echo '</div>';
            wp_reset_postdata();
        }
    }
}

I’ve done so many things, even tried searching stackoverflow.

`drawArrays` not working when mode is POINTS

With the following code:

// where gl is WebGL2RenderingContext, but I tried WebGLRenderingContext as well.
gl.drawArrays(gl.POINTS, 0, points.length / 2);
#version 300 es

in vec2 position;

void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}

My canvas isn’t rendering any of the points on the canvas whatsoever. However, when mode, the first argument, is gl.LINES, the interconnected points render just fine. I also noticed this issue only happens in hardware acceleration mode in browsers for certain GPUs—it worked fine on Linux but not on Windows.

How can I render the points correctly?

cypress javascript function for sorting based on event priority then event date and time

I need to validate sorting of an Event column with this value:
Event Name
Event date
Event time
your text
Order of column when sorted is based on priority of event name ( I > U > P)
then date and time should be sorted correctly based on ascending/descending.

I need a javascript code to run in Cypress to validate if sorting is correct based on event priority then date/time.
Chatgpt gave me some but it did not work

function validateEvents(events, priorityOrder, sortOrder = 'desc') {
const getDate = (dateStr) => new Date(dateStr);

// Compare function for date and time sorting
const compareDates = (a, b) => {
const dateA = getDate(a.date);
const dateB = getDate(b.date);
if (dateA.getTime() === dateB.getTime()) {
  return sortOrder === 'asc' ? a.time.localeCompare(b.time) : b.time.localeCompare(a.time);
}
return sortOrder === 'asc' ? dateA - dateB : dateB - dateA;
};

let previousPriorityIndex = -1;

// Group by event name and check priority and sorting
for (const event of events) {
const currentPriorityIndex = priorityOrder.indexOf(event.name);

// Ensure event names follow the priority order
if (currentPriorityIndex < previousPriorityIndex) {
  return false;
}

previousPriorityIndex = currentPriorityIndex;

// Sort events within the same name group
const groupedEvents = events.filter(e => e.name === event.name).sort(compareDates);

// Ensure events are in correct date/time order
if (!groupedEvents.every((e, i) => e === event)) {
  return false;
}
}
return true;
}

// Usage in Cypress test
cy.get('selector-for-events').then(($elements) => {
const events = [...$elements].map(el => ({
name: el.querySelector('.event-name').innerText.trim(),
date: el.querySelector('.event-date').innerText.trim(),
time: el.querySelector('.event-time').innerText.trim()
 }));

 const priorityOrder = ['I', 'U', 'P']; // Define the priority order
 const sortOrder = 'desc'; // or 'asc'

  expect(validateEvents(events, priorityOrder, sortOrder)).to.be.true;
});`

HTML Canvas Arc only drawing outer sliver of circle

I am working on a visualizer to show the area on a graph that is currently being checked for points from a starting points POV, and within a limited FOV. I am trying to show this with canvas arc, however, instead of filling in the arc area, it is filling in the outermost sliver of the arc.

I have tried drawing lines using the rad angle, and those are successful, it is only the arc that does not appear to work correctly. I would expect that it would complete the arc within the two angles, instead of seemingly subtracting the area of the triangle within the arc.

let startingLocation = {x:0,y:0};
let angle = 18.43494882292201;
let fovAngle = 30;
let r = 100;
//Convert start and end angles to radians
let theta = angle * (Math.PI / 180);
let theta2 = (angle + fovAngle) * (Math.PI / 180);

//Draw start to end arc area
ctx.moveTo(startingLocation.x, startingLocation.y);
ctx.beginPath();
ctx.fillStyle = 'green';
ctx.arc(startingLocation.x, startingLocation.y, r, theta, theta2, false);
ctx.fill();
ctx.closePath();

JSFiddle

Passport JS authenticates if the user goes back on navigation history even without selecting account

When the user have logged In the app before(gave consent), in the next time while logging in the user can be authenticate without even selecting the account. How to prevent it? Bug occurs on step 2:

Step 1 – User Click On Log In Button and is redirected to azure page

//

Step 2 – If User click on the navigation back(in red) then it is authenticated even before putting its data

Console after navigating back
You can notice that even though the button was directed to microsoft, when navigating back the google passport-js that I also have setted takes controls and authenticate the user twice. How could I avoid? The opposite happens as well(google login then microsoft takes control and authenticate it)

PASSPORT.JS:

require('dotenv').config();
const passport = require('passport');
const { getOrCreateUser } = require('../controllers/User');
const AzureAdOAuth2Strategy = require('passport-azure-ad-oauth2');
const GitHubStrategy = require('passport-github2').Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const jwt = require('jsonwebtoken');

// Azure Strategy
passport.use(
  new AzureAdOAuth2Strategy(
    {
      clientID: process.env.AZURE_CLIENT_ID,
      clientSecret: process.env.AZURE_CLIENT_SECRET,
      callbackURL: 'http://localhost:80/auth/azure/callback',
      tenantId: process.env.AZURE_TENANT_ID,
      scope: 'openid profile email',
    },
    async (accessToken, refreshToken, params, profile, done) => {
      const decodedProfile = jwt.decode(params.id_token, '', true) || profile;
      const user = await getOrCreateUser({
        azureId: decodedProfile.oid,
        name: decodedProfile.given_name,
      });
      return done(null, { profile: user });
    }
  )
);

// GitHub Strategy
passport.use(
  new GitHubStrategy(
    {
      clientID: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET,
      callbackURL: `http://localhost:80/auth/github/callback`,
    },
    async (accessToken, refreshToken, profile, done) => {
      const user = await getOrCreateUser({
        githubId: profile.id,
        name: profile.username,
      });
      console.log(user);
      return done(null, { profile: user });
    }
  )
);

// Google Strategy
passport.use(
  new GoogleStrategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: `http://localhost:80/auth/google/callback`,
    },
    async (accessToken, refreshToken, profile, done) => {
      const user = await getOrCreateUser({
        googleId: profile.id,
        name: profile.name.givenName,
      });
      return done(null, { profile: user });
    }
  )
);

passport.serializeUser((user, done) => {
  done(null, user);
});

passport.deserializeUser((user, done) => {
  done(null, user);
});

module.exports = passport;

APP.JS:

app.use(
  express.urlencoded({
    extended: true,
  })
);
app.use(express.json({ limit: '10kb' }));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());

// Passport Initialization
app.use(
  session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: { maxAge: 1000 * 60 * 60 * 24 * 7 }, // 3 Days
  })
);
app.use(passport.initialize());
app.use(passport.session());

app.use('/', routes);

module.exports = app;

Auth Route:

const router = require('express').Router();
const passport = require('../config/passport');
const User = require('../models/User');

// Azure Auth
router.get(
  '/azure',
  passport.authenticate('azure_ad_oauth2', {
    scope: ['profile', 'email'],
    prompt: 'select_account',
  })
);
router.get(
  '/azure/callback',
  passport.authenticate('azure_ad_oauth2', {
    prompt: 'select_account',
    failureRedirect: '/error',
  }),
  async (req, res) => {
    res.redirect(`${process.env.APP_URL}`);
  }
);

// GitHub Auth
router.get(
  '/github',
  passport.authenticate('github', { scope: ['user'], prompt: 'select_account' })
);
router.get(
  '/github/callback',
  passport.authenticate('github', {
    prompt: 'select_account',
    failureRedirect: '/error',
  }),
  async (req, res) => {
    res.redirect(`${process.env.APP_URL}`);
  }
);

// Google Auth
router.get(
  '/google',
  passport.authenticate('google', {
    scope: ['profile'],
    prompt: 'select_account',
  })
);
router.get(
  '/google/callback',
  passport.authenticate('google', {
    scope: ['profile'],
    prompt: 'select_account',
    failureRedirect: '/error',
  }),
  async (req, res) => {
    res.redirect(`${process.env.APP_URL}`);
  }
);

router.get('/profile', async (req, res) => {
  if (req.isAuthenticated()) {
    res
      .status(200)
      .json({ status: 'success', message: 'Profile Info!', user: req.user });
  } else
    res.status(401).json({
      status: 'error',
      message: 'You Need To Be Logged In To Access Profile Info!',
    });
});

router.get('/logout', (req, res) => {
  req.logout((err) => {
    if (err) {
      console.error('Error Logging Out: ', err);
      return res
        .status(500)
        .json({ status: 'error', message: 'Internal Server Error' });
    }

    req.session.destroy((err) => {
      if (err) {
        console.error('Error Destroying Session: ', err);
        return res
          .status(500)
          .json({ status: 'error', message: 'Internal Server Error' });
      }

      res
        .clearCookie('connect.sid')
        .status(200)
        .json({ status: 'success', message: 'Logged Out Successfully!' });
    });
  });
});
module.exports = router;

I tried to modify the prompt to select_account, consent and login but no success… Tried state: true as well

Using node to call win32api and focus a window

I want to focus and application to further automate input from my node application.

My approach is to use koffi (basically newer version off ffi-napi) to call the win32api and focus that window.

I can open and focus the notepad, but I didnt manage to do it for any other app.

This is my working example for the notepad app:

const koffi = require('koffi');

const user32 = koffi.load('user32.dll');
const FindWindowA = user32.func('__stdcall', 'FindWindowA', 'long', ['string', 'string']);

const ShowWindow = user32.func('__stdcall', 'ShowWindow', 'bool', ['long', 'int']);
const SetForegroundWindow = user32.func('__stdcall', 'SetForegroundWindow', 'bool', ['long']);
const BringWindowToTop = user32.func('__stdcall', 'BringWindowToTop', 'bool', ['long']);
const SetFocus = user32.func('__stdcall', 'SetFocus', 'long', ['long']);

const window = FindWindowA('Notepad', null);
console.log(window);

ShowWindow(window, 9);
SetForegroundWindow(window);
BringWindowToTop(window);
SetFocus(window);

Which will return a handle for the notepad app and focuses it after.
I could not manage to make it work with any other program. I understand that browsers etc. have changing titles.
I want to do it for the Riot Client but cannot seem to find the program class or title, or at least to get a valid handle of it.

I read this question: Setting focus to a Windows application from Node-JS
The example provided does not work (transpiled to koffi syntax) in the same way. Only by switching the input parameters, and only for Notepad.

What can be the error here? I assume that the Riot Client title or class will be constant.

StorageApiError: new row violates row-level security policy

Using the Supabase Storage API, I am calling:

const createBucketRes = await supabase.storage.createBucket('avatars')

But I am getting the error

StorageApiError: new row violates row-level security policy

I am able to use the dashboard to create a bucket and set policies there, but then what is the purpose of having the API?

Reference: https://supabase.com/docs/guides/storage/quickstart?queryGroups=language&language=javascript

Mysterious text appearing on screen next to my log in/sign up form [duplicate]

I keep seeing “if ($_SERVER[“REQUEST_METHOD”] == “POST”) { if ($username && !$password) { echo ”; } }” next to my form and I have no idea how to fix it since I just began learning to code using VS Code.

Tried to create a “check if username and password are in database” type of thing and I was not expecting some of the code (that snippet is not even in my code) to be visible.

How to handle number input with locale-specific formatting in JavaScript without external libraries?

I want users to enter numbers and currency values in an input field using their own locale-specific formatting. For example:

  • In the Netherlands: 1.234,56 for one thousand two hundred thirty-four and 56 cents.
  • In the US: 1,234.56 for the same value.

The input should be displayed exactly as entered by the user, but I need to normalize this value in JavaScript (e.g., convert it to a standard format like 1234.56 for backend processing). Ideally, this should work automatically based on the user’s locale, but if necessary, I can ask them to specify their preferred format beforehand.

I’m looking for a simple and elegant solution—preferably something that’s already built into JavaScript since this seems like a common issue many developers might face. I would like to avoid large code blocks or complex solutions. Any guidance on how to achieve this efficiently would be appreciated.

“SyntaxError: Unexpected identifier ‘assert'” on JSON import in Node v22

A Node program of mine that worked fine in Node v21 now immediately crashes with a syntax error in Node v22. The line that triggers the error looks like this:

import config from "./some-config-file.json" assert { type: "json" };

and the error says:

SyntaxError: Unexpected identifier 'assert'
    at compileSourceTextModule (node:internal/modules/esm/utils:337:16)
    at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:166:18)
    at callTranslator (node:internal/modules/esm/loader:436:14)
    at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:442:30)
    at async ModuleJob._link (node:internal/modules/esm/module_job:106:19)

Why am I getting this error in code that previously worked, and how should I fix it?