Error: Element type is invalid. Received a promise that resolves to: undefined. Lazy element type must resolve to a class or function

I am trying to create and publish nextjs ui component Hsciifontpicker inside a [npmjs lib : hsciifontlib].
can I use next/font/local=>localFont function in a npmjs library component ?
Hsciifontpicker.jsx(in npmjs library named hsciifont) code :

// hsciifontlib/src/library/Hsciifontpicker.jsx
"use client";
import localFont from "next/font/local";
import React, { useState } from 'react';
import Select from 'react-select';
import options from './options.json';

const Hsciifontpicker= () => {

const binarywenglosoftw8asc = localFont({ src: "./fonts/hscii/englosoftw8/englosoftw8asc/binarywenglosoftw8asc.woff2", display: "swap", });
const heksenglosoftw8asc = localFont({ src: "./fonts/hscii/englosoftw8/englosoftw8asc/heksenglosoftw8asc.woff2", display: "swap", });

const hsciifont_classnames = {
      binarywenglosoftw8asc: binarywenglosoftw8asc.className,
      heksenglosoftw8asc: heksenglosoftw8asc.className,
}

  const [selectedCategory, setSelectedCategory] = useState(null);
  const [selectedItem, setSelectedItem] = useState(null);  
  let currfontcn = "";

  const handleCategoryChange = (selectedOption) => {
    setSelectedCategory(selectedOption);
    setSelectedItem(null); // Reset the second select
    if (selectedOption) { setBodyFont(selectedOption.value); }
  };

  const handleItemChange = (selectedOption) => {
    setSelectedItem(selectedOption);
    if (selectedOption) { setBodyFont(selectedOption.value); }
  };

  const setBodyFont = (selected_hsciifont_name) => {
    document.body.classList.value = document.body.classList.value.replaceAll(/__className_w+s+antialiased/g,"");
    document.body.classList.value = document.body.classList.value.replaceAll(/antialiaseds+__className_w+/g,"");
    currfontcn = hsciifont_classnames[selected_hsciifont_name];
    document.body.classList.add(currfontcn);
    document.body.classList.add("antialiased");
  };
  const itemOptions = selectedCategory ? selectedCategory.children : [];

  return (
    <div style={{ width: 400, marginBottom: 20, color: 'black', backgroundColor: 'white' }} >
      <Select
        options={options}
        onChange={handleCategoryChange}
        value={selectedCategory}
        placeholder="8aiueohcg lxnguAge(bhαsα).select"
      />
      <Select
        options={itemOptions}
        onChange={handleItemChange}
        value={selectedItem}
        placeholder="8aiueohcg font.select"
        isDisabled={!selectedCategory}
      />

    </div>
  );
};

after adding(bun add hsciifontlib) and using this library in another next js app lifp I am getting error as :

Error: Element type is invalid. Received a promise that resolves to: undefined. Lazy element type must resolve to a class or function.

lifp/src/app/page.js code:

// lifp/src/app/page.js file
import { Hsciifontpicker } from "hsciifontlib";
//import { Hsciifontpicker } from "@/components/hscii/hsciifontpicker";
export default function Home() {
  return (
    <div>
      <main>
      <div>
          <Hsciifontpicker/>
        </div>
        <div>
          <textarea rows={12}/>
        </div>
      </main>
    </div>
  );
}

How do I correctly send a signature to verify in Inngest?

I’m getting an “Invalid x-inngest-signature provided” error when I try to send an event to my Inngest server

Here is my server.js

import { config } from "dotenv";
import express from "express";
import { serve } from "inngest/express";
import { inngest } from "./client.js";
import { matchNotify } from "./functions/matchNotify.js";
import crypto from 'crypto';

config();

const app = express();

// Parse JSON and capture raw body for signature verification
app.use(express.json({
    verify: (req, res, buf) => {
        req.rawBody = buf;
    }
}));

// Serve Inngest
app.use("/api/inngest", serve({
    client: inngest,
    functions: [matchNotify],
    verify: {
        getRawBody: (req) => req.rawBody,
    },
}));

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log (`Server running on http://localhost:${PORT}`);
});

and my notif.dart that sends an event

import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';

import 'package:flutter_dotenv/flutter_dotenv.dart';

String inngestEventKey = dotenv.env['INNGEST_EVENT_KEY'] ?? 'Default Value';

Future<void> sendNotification(
  String userId,
  String matchedId,
) async {
  final event = {
    "name": "match.created",
    "data": {"matchedUserId": userId, "matchingUserId": matchedId},
  };

  final jsonBody = jsonEncode(event);

  final keyBytes = utf8.encode(inngestEventKey);
  final bodyBytes = utf8.encode(jsonBody);
  final hmacSha256 = Hmac(sha256, keyBytes);
  final digest = hmacSha256.convert(bodyBytes);
  final signature = digest.toString().toLowerCase(); // hex output

  final response = await http.post(
    Uri.parse(
        'https://cryptic-depths-95477-ba7e4f659ba0.herokuapp.com/api/inngest'),
    headers: {
      'Content-Type': 'application/json',
      'x-inngest-signature': signature, // Sending the signature here
    },
    body: jsonBody,
  );

  if (response.statusCode == 202 || response.statusCode == 200) {
    if (kDebugMode) {
      print("Event sent successfully");
    }
  } else {
    if (kDebugMode) {
      print("Failed to send event: ${response.body}");
    }
  }
}

I’ve compared the output of signature on both sides and they matched, I’ve compared the event_key and signing_key and both are correct on both sides, I’ve tried debugging with ChatGPT and not found the solution

Sentry Logger [warn]: Discarded session because of missing or non-string release

As per the Sentry setup guide for a React FE project

Sentry setup guide in React

import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: "SOME_SENTRY_DNS",
  // Setting this option to true will send default PII data to Sentry.
  // For example, automatic IP address collection on events
  sendDefaultPii: true
});

const container = document.getElementById(“app”);
const root = createRoot(container);
root.render(<App />);

I’ve adjusted that to

const SENTRY_DSN = process.env.REACT_APP_SENTRY_DSN;
const SENTRY_ENV = process.env.REACT_APP_SENTRY_ENVIRONMENT || "development";

Sentry.init({
  dsn: SENTRY_DSN,
  environment: SENTRY_ENV,
  sendDefaultPii: true,
  debug: true,
  autoSessionTracking: false,
  beforeSend(event) {
    console.log("Sentry about to send event:", event);
    return event;
  },
});

but still keep getting

Sentry Logger [warn]: Discarded session because of missing or non-string release

enter image description here

APEX Interactive Grid data not being captured by JavaScript function

I’m having trouble capturing data from multiple Interactive Grids in Oracle APEX Oracle APEX 24.2.3 using JavaScript. When I try to save the data, I’m getting undefined values for all records.

Here’s my current JavaScript code:

function getIGData(staticId) {
    console.log('Getting data for region:', staticId);
    var region = apex.region(staticId);
    if (!region) {
        console.error('Region not found:', staticId);
        return [];
    }
    
    var grid = region.widget();
    if (!grid) {
        console.error('Grid widget not found for region:', staticId);
        return [];
    }
    
    var view = grid.interactiveGrid("getViews").grid;
    var model = view.model;
    var records = [];

    model.forEach(function(record) {
        var r = record;
        console.log('Raw record data:', r);
        
        var recordData = {
            QUESTION: r.QUESTION,
            RESPONSE: r.RESPONSE || r["INITIAL ANSWER"],
            COMMENTS: r.COMMENTS,
            ACTUAL_ANSWER: r.ACTUAL_ANSWER,
            FORECAST_ANSWER: r.FORECAST_ANSWER,
            SUBQUESTION_ANSWER: r.SUBQUESTION_ANSWER
        };

        console.log('Processed record data:', recordData);
        
        if (recordData.QUESTION && recordData.RESPONSE) {
            records.push(recordData);
        }
    });

    console.log('Data from ' + staticId + ':', JSON.stringify(records));
    return records;
}

function saveAllResponses() {
    console.log('saveAllResponses function called');
    var allData = [];
    var regionIds = ["region-question-1", "region-question-2", "region-question-3", "region-question-4", "region-question-5"];
    
    regionIds.forEach(function(regionId) {
        var data = getIGData(regionId);
        console.log('Data from ' + regionId + ':', data);
        allData = allData.concat(data);
    });

    console.log('All data:', JSON.stringify(allData));
    console.log('P22_ID_RISK:', $v("P22_ID_RISK"));
    console.log('P22_SUPPLIER:', $v("P22_SUPPLIER"));
    console.log('P22_SUBTYPE:', $v("P22_SUBTYPE"));
    console.log('P22_EVALUATOR:', $v("P22_EVALUATOR"));
    console.log('P22_SUPPLIER_ID:', $v("P22_SUPPLIER_ID"));

    if (allData.length > 0) {
        apex.server.process(
            "SAVE_ALL_RESPONSES",
            {
                x01: JSON.stringify(allData),
                p_id_risk: $v("P22_ID_RISK"),
                p_supplier: $v("P22_SUPPLIER"),
                p_subtype: $v("P22_SUBTYPE"),
                p_evaluator: $v("P22_EVALUATOR"),
                p_supplier_id: $v("P22_SUPPLIER_ID")
            },
            {
                success: function(pData) {
                    console.log('Server response:', pData);
                    if (pData && pData.success) {
                        apex.message.showPageSuccess(pData.message);
                    } else {
                        apex.message.showErrors([{
                            type: "error",
                            location: ["page"],
                            message: pData && pData.message ? pData.message : "Unknown error occurred",
                            unsafe: false
                        }]);
                    }
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.error("AJAX error:", textStatus, errorThrown);
                    console.log("Response Text:", jqXHR.responseText);
                    apex.message.showErrors([{
                        type: "error",
                        location: ["page"],
                        message: "Error saving responses: " + errorThrown,
                        unsafe: false
                    }]);
                },
                dataType: "json"
            }
        );
    } else {
        console.log("No data to save");
        apex.message.showErrors([{
            type: "error",
            location: ["page"],
            message: "No data to save. Please ensure at least one question is answered.",
            unsafe: false
        }]);
    }
}

Also I have an Application Process called SAVE_ALL_RESPONSES

DECLARE
    l_data CLOB := wwv_flow.g_x01;
    l_id_risk NUMBER := :P22_ID_RISK;
    l_supplier VARCHAR2(100) := :P22_SUPPLIER;
    l_subtype VARCHAR2(100) := :P22_SUBTYPE;
    l_evaluator VARCHAR2(100) := :P22_EVALUATOR;
    l_supplier_id NUMBER := :P22_SUPPLIER_ID;
    l_success BOOLEAN := TRUE;
    l_message VARCHAR2(4000) := 'Responses saved successfully.';
    l_rows_updated NUMBER := 0;
BEGIN
    apex_debug.message('Received data: ' || l_data);

    IF l_data IS NULL OR l_data = '[]' THEN
        l_success := FALSE;
        l_message := 'No data received from the frontend.';
    ELSE
        APEX_JSON.PARSE(l_data);
        
        FOR i IN 1..APEX_JSON.GET_COUNT(p_path => '.') LOOP
            DECLARE
                l_question VARCHAR2(4000) := APEX_JSON.GET_VARCHAR2(p_path => '[%d].QUESTION', p0 => i);
                l_answer VARCHAR2(4000) := APEX_JSON.GET_VARCHAR2(p_path => '[%d].ANSWER', p0 => i);
            BEGIN
                UPDATE RMA_USER_EVALUATIONS
                SET ANSWER = l_answer
                WHERE ID_RISK = l_id_risk
                AND SUPPLIER = l_supplier
                AND SUBTYPE = l_subtype
                AND QUESTION = l_question;

                IF SQL%ROWCOUNT = 0 THEN
                    -- If no row was updated, it means the row doesn't exist, so we insert it
                    INSERT INTO RMA_USER_EVALUATIONS (
                        ID_RISK, SUPPLIER, SUBTYPE, QUESTION, ANSWER, 
                        EVALUATOR, SUPPLIER_ID
                    ) VALUES (
                        l_id_risk, l_supplier, l_subtype, l_question, l_answer,
                        l_evaluator, l_supplier_id
                    );
                END IF;

                l_rows_updated := l_rows_updated + 1;
            EXCEPTION
                WHEN OTHERS THEN
                    l_success := FALSE;
                    l_message := 'Error saving response for question ' || l_question || ': ' || SQLERRM;
                    apex_debug.error(l_message);
                    EXIT;
            END;
        END LOOP;

        IF l_success THEN
            COMMIT;
            l_message := l_message || ' (' || l_rows_updated || ' rows updated/inserted)';
        ELSE
            ROLLBACK;
        END IF;
    END IF;

    APEX_JSON.OPEN_OBJECT;
    APEX_JSON.WRITE('success', l_success);
    APEX_JSON.WRITE('message', l_message);
    APEX_JSON.CLOSE_OBJECT;
EXCEPTION
    WHEN OTHERS THEN
        apex_debug.error('Unexpected error: ' || SQLERRM);
        APEX_JSON.OPEN_OBJECT;
        APEX_JSON.WRITE('success', FALSE);
        APEX_JSON.WRITE('message', 'Unexpected error: ' || SQLERRM);
        APEX_JSON.CLOSE_OBJECT;
END;

My setup:

  • I have 5 Interactive Grids on my page, with IDs: region-question-1, region-question-2, region-question-3, region-question-4, region-question-5
  • Each grid has columns: QUESTION, RESPONSE (or INITIAL ANSWER), COMMENTS, ACTUAL_ANSWER, FORECAST_ANSWER, SUBQUESTION_ANSWER
  • I’m using a Dynamic Action on a button click to trigger the save function

Expected behavior:
The function should collect data from all grids and send it to the server for processing.

Actual behavior:
The function is not capturing any data from the grids. All record data is coming back as undefined.

So the region 1 should insert the answers in the rows where the question 1 in the table is:

ID_RISK SUBTYPE QUESTION ANSWER COMMENTS SUPPLIER ID SUPPLIER_ID IMPACT ACTUAL_ANSWER FORECAST_ANSWER IMPACT_ACTUAL IMPACT_FORECAST COMMENT_WHEN_CLOSED USER_CLOSED SUBQUESTION_ANSWER ADDITIONAL_INPUT
643 Tropical Storm / Hurricane 1. Impact on operations/production GG Cables and Wires Mexico 881 22352710
643 Tropical Storm / Hurricane 2. Impact on deliveries for BMW GG Cables and Wires Mexico 882 22352710
643 Tropical Storm / Hurricane 3. Status for infrastructure or equipment compromised GG Cables and Wires Mexico 883 22352710
643 Tropical Storm / Hurricane 4. Effective countermeasures are in place to mitigate the risk GG Cables and Wires Mexico 884 22352710
643 Tropical Storm / Hurricane 5. Estimated time for restoration of operations GG Cables and Wires Mexico 885 22352710

So if the user answer like this:example of answer

at the end the table in the DB should look like enter image description here

Nextjs 15 tailwind PWA: env(safe-area-inset-*) not working

I am trying to add padding to the bottom of my pwa to prevent items going behind the phone navigation. I have tried different solutions from others (custom css, adding a custom plugin to tailwind.config.css, etc…) but its not working. when i do “npm run dev” the padding is applied at the bottom. but when i make a change and save my code, the padding is gone. it also does not show up running “npm run build;npm run start”

tailwind.config.ts:

...snip...
theme: {
    data: {
      checked: 'ui~="checked"',
    },
    padding: { safe: "env(safe-area-inset-bottom)" },
    extend: {
      colors: {
...snip...

layout.tsx:

...snip...
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, user-scalable=0, viewport-fit=cover"
        />
        <link rel="apple-touch-icon" href="/images/icon-192.png" />
        <link href="/images/icon-192.png" rel="icon" sizes="192x192" />
        <link href="/images/icon-512.png" rel="icon" sizes="512x512" />
        <link rel="manifest" href="/manifest.json" />
      </head>
      <body className="bg-gray-100 pb-safe">
        {/* <div className="flex flex-col "> */}
        <div className="h-96 bg-black"></div>
        <div className="h-96 bg-black"></div>
        <div className="h-96 bg-black"></div>
        <div className="h-96 bg-black"></div>
        {/* </div> */}
      </body>
    </html>
...snip...

How to allow my Polotno custom editor to edit individual parts of SVG’s

I am making a custom Polotno editor for editing heraldry blazons using React JS and open source Polotno code. In the original Polotno editor they show off on their website (https://studio.polotno.com), uploading an SVG file and selecting it on the canvas allows editing of its individual colors using squares on the top toolbar. In my own custom editor, I am struggling to achieve this.

I am using React js and have also installed Polotno modules with npm install polotno. Currently, I have a working template of the editor that uses local svg files I store on my pc. I can drag them onto the canvas, but the color picking boxes do not appear on the top toolbar even upon clicking them, therefore I cannot edit their colors.

I have read the polotno documentation (https://polotno.com/docs) and used chatGPT to no avail.

here is my src folder

src
│   App.css
│   App.js
│   App.test.js
│   Editor.js
│   index.css
│   index.js
│   logo.svg
│   reportWebVitals.js
│   Sections.js
│   setupTests.js
│
└───utils

Here is App.js

// src/App.js
import React from "react";
import Editor from "./Editor";

function App() {
  return <Editor />;
}

export default App;

Here is editor.js

// src/Editor.js

import React from "react";
import { PolotnoContainer, SidePanelWrap, WorkspaceWrap } from "polotno";
import { Toolbar } from "polotno/toolbar/toolbar";
import { PagesTimeline } from "polotno/pages-timeline";
import { ZoomButtons } from "polotno/toolbar/zoom-buttons";
import { SidePanel } from "polotno/side-panel";
import { Workspace } from "polotno/canvas/workspace";

import { createStore } from "polotno/model/store";

import { sections } from "./Sections"; // <-- Import the organized sections

import "@blueprintjs/core/lib/css/blueprint.css";

const store = createStore({
  key: "YOUR_API_KEY", // go to https://polotno.com/cabinet/ and generate a free API key
  showCredit: true,
});

store.addPage();

const Editor = () => {
  console.log("Custom Tabs loading:");

  return (
    <PolotnoContainer style={{ width: "100vw", height: "100vh" }}>
      <SidePanelWrap>
        <SidePanel store={store} sections={sections} defaultSection="Gabarits" />
      </SidePanelWrap>
      <WorkspaceWrap>
        <Toolbar store={store} downloadButtonEnabled />
        <Workspace store={store} />
        <ZoomButtons store={store} />
        <PagesTimeline store={store} />
      </WorkspaceWrap>
    </PolotnoContainer>
  );
};

export default Editor;

Sections.js contains long code specifying my side pannels, their subsections, and content. It is probably irrelevant. If you require the contents of any other files, I can add them.

I am suspecting that the relevant functionality lies within node-modules/polotno/… as this is where most of the editor’s native imports come from. The folder is huge though, and so far the few files mentioning svgs have been of little help.

Is there some useEffect and useState behavior that explains why only one of these instances work?

I’m using useEffect to fetch data. This data is passed to a state, then used as a prop for a component to render/populate accordingly. Here is the code that works:

const [projects, setProjects] = useState([]);

useEffect(() => {
  const q = query(collection(db, "projects"), orderBy("update", "desc"));
  const unsubscribe = onSnapshot(q, (QuerySnapshot) => {
    const fetched = [];
    QuerySnapshot.forEach((doc) => {
      fetched.push({ ...doc.data(), id: doc.id });
    });
    const sortedProjects = fetched.sort((a, b) => a.update - b.update);
    setProjects(sortedProjects);
  });
  return () => unsubscribe;
}, []);

The code above correctly fetches the data and then passes it to a component that then uses map to display a list of the projects. In terms of streamlining, I wanted to see if I could do the same with the resume data. Here is the code for that:

const [edu, setEducation] = useState([]);

useEffect(() => {
  const q = query(
    collection(db, "resume/resume/education"),
    orderBy("startDate")
  );
  const unsubscribe = onSnapshot(q, (QuerySnapshot) => {
    const fetched = [];
    QuerySnapshot.forEach((doc) => {
      fetched.push({ ...doc.data(), id: doc.id });
    });
    const sortedEdu = fetched.sort(
      (a, b) => a.startDate.nanoseconds - b.startDate.nanoseconds
    );
    setEducation(sortedEdu);
  });
  return () => unsubscribe;
}, []);

This one, for some reason, does not work. I checked that data is being retrieved (it is), and the useEffect and useState appear to be working as they should. I even added a log in to the component, and indeed, the data shows up from that end, but I’m still getting a map error, saying the array is undefined, and preventing the react from rendering. I also know that these components work when I try and input data directly. What could be happening to cause this?

I’ve literally copy/pasted then tweaked values, and still get the same problem. For clarity’s sake, here is the component in question:

export const ResumeItemLister = ({ items, sectionTitle }) => {
  return (
    <div>
      <h2 className="text-xl text-left">{sectionTitle}</h2>
      <hr />
      <table>
        {items.map(({ title, location, date, bullets }) => (
          <tr className="pt-10">
            <div className="grid grid-cols-3">
              <td className="text-left">{date}</td>
              <td className="col-span-2">
                <div className="text-left">
                  {title ? (
                    <p>
                      <bold className="font-bold">{title}</bold>, {location}
                    </p>
                  ) : (
                    <p>{location}</p>
                  )}
                  <ul>
                    {bullets.map((text) => (
                      <li className="list-disc list-inside"> {text}</li>
                    ))}
                  </ul>
                </div>
                <br />
              </td>
            </div>
          </tr>
        ))}
      </table>
    </div>
  );
};

This works, as long as I explicitly set the items in the parent component. Using the fetched state however, I get:

Uncaught TypeError: Cannot read properties of undefined (reading 'map')

I understand this means items is undefined, but as mentioned, that isn’t the case. Any help is deeply appreciated

launchWebAuthFlow in Chrome extension: OAuth2 window and popup close after user clicks username

Chrome extension using manifest v3 with popup written with React.

service-worker.js

async function startJoltAuth(sendResponse, force_refresh = false) {
    var manifest = chrome.runtime.getManifest();
    var scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
    var clientId = encodeURIComponent(MyClientId);
    const chromeRuntimeChromium = 'https://' + chrome.runtime.id + '.chromiumapp.org'
    var redirectUri = encodeURIComponent(chromeRuntimeChromium);
    var url = 'https://accounts.google.com/o/oauth2/v2/auth' +
        '?client_id=' + clientId +
        '&response_type=code' +
        '&access_type=offline' +
        '&redirect_uri=' + redirectUri +
        '&scope=' + scopes;
    if (force_refresh) {
        url += '&prompt=consent'
    }
    chrome.identity.launchWebAuthFlow(
        {
            'url': url,
            'interactive': true
        },
        async function (redirectedTo) {
            let message = { type: "auth_tokens" }
            if (chrome.runtime.lastError) {
                // Example: Authorization page could not be loaded, or "user did not approve access"
                message.body = {
                    error: chrome.runtime.lastError.message
                }
                sendResponse(message)
                return;
            }
            const authorizationCode = extractCodeFromRedirectUri(redirectedTo);
            const tokens = await getTokensUsingCode(authorizationCode);
            if (tokens) {
                const expires_in = +(tokens.expires_in ?? (3599 - 5 * 60)) * 1000
                const expire_date = new Date(new Date() - (-expires_in)).toISOString()
                message.body = {
                    access_token: tokens.access_token,
                    refresh_token: tokens.refresh_token,
                    id_token: tokens.id_token,
                    expire_date,
                    login_type: "google"
                }
            } else {
                console.log("Failed to exchange authorization code for tokens.");
                message.body = {
                    error: "Failed to exchange authorization code for tokens."
                }
            }

            sendResponse(message)
        }
    );
}

function extractCodeFromRedirectUri(redirectUrl = "") {
    const params = new URL(redirectUrl).search;
    const tokenParams = new URLSearchParams(params);
    return tokenParams.get("code");
}

async function getTokensUsingCode(code) {
    //fetch and return tokens from 'https://oauth2.googleapis.com/token'
    ...
}

chrome.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {        
        if (request.func == "startJoltAuth") {
            startJoltAuth(sendResponse, request.force_refresh).then(() => {
                // response sent within startJoltAuth already
            })
        }
        // indicates that sendResponse will be used to reply to the sender of the message
        // and that sendResponse was used asynchronously
        return true 
    }
);

auth.js (imported within App.tsx)

async function fullLogin(session_info, force_refresh = false) {
  if (!force_refresh) {
    force_refresh = session_info ? false : true
  }
  const response = await chrome.runtime.sendMessage({
    func: "startJoltAuth", force_refresh
  })
  if (response.body.error) {
    return { error: response.body.error }
  }
  const signupResponse = await signup(response.body)
  ...
  return {
    new_session_info: result,
    prev_session_info: session_info
  }
}

manifest.json: Note that MyChromeExtensionClientId is different from MyClientId because it is registered as a Chrome extension. Chrome store makes me do this, iirc, otherwise I’d use MyClientId.

{
  ...
  "manifest_version": 3,
  "oauth2": {
    "client_id": MyChromeExtensionClientId,
    "scopes": [
      "https://www.googleapis.com/auth/presentations",
      "https://www.googleapis.com/auth/userinfo.email",
      "https://www.googleapis.com/auth/userinfo.profile",
      "openid"
    ]
  },
  "permissions": ["tabs", "identity", "identity.email", "storage"],
  "background": {
    "service_worker": "service_worker.js"
  }
  ...
}

Following this post for guidance, MyClientId is registered as a Web Application instead of a Chrome extension. This is so that launchWebAuthFlow works with Google OAuth2.

When a user opens the extension’s popup (main application) and clicks “Sign up with Google”, the Google OAuth window opens.

Bug:
Sometimes, right when a user clicks a username in the auth window, the auth window closes and the extension closes. What we expect is for them to be prompted to the next screen where they accept the permissions (the flow we are all familiar with in a Google auth flow).

I did a demo for a class of pre-service teachers who all downloaded the extension. About half of them experienced the bug. Most of the users who experienced the bug were eventually able to complete the sign-in, with the max number of attempts being something like 12 (12 times re-opening the extension and trying to sign in). The bug seemed to occur on Mac.

We have been unable to reproduce the bug on anyone’s computer while using “Inspect”.

Extension link:
https://chromewebstore.google.com/detail/jolt-education-test/domhnpgbfcjbnedflfkalafpfjphokfk

Ublock Origin replace-node-text

I’m on a website with an overly sensitive profanity filter that sticks periods in the middle of words like doc.u.ments or as.sas.sin. There is no option to turn off the profanity filter. I wanted to use something like Ublock Origin to remove the periods in the middle of words. I am not sure what the best approach is.

I tried this first:
##+js(replace-node-text, #text, “.”, “”)

Which cleaned up the periods in the middle of words, but it also removed all of the regular end of sentence periods as well.

So then I tried this:
##+js(replace-node-text, #text, /[.][a-z]+/, “”)

but this just turned doc.u.ments into: doc.ments, not what I wanted. I was wondering if anyone had any ideas.

Demuxing an RTP audio stream using WebRTC API

I am developing a voice chat application.
After the server receives an RTP packet from a client, it sends this packet unmodified to all the other clients. Each client has a different SSRC.

The following code works (i.e. all audio streams received from server are played correctly):

function join_vc(offer){
    const rtc_conn = new RTCPeerConnection({
        bundlePolicy: 'max-compat'
    })

    rtc_conn.ontrack = (ev) => {
        const vc_audio = $("#vc_audio")[0]
        vc_audio.srcObject = ev.streams[0]
        vc_audio.play()
    }

    rtc_conn.onicegatheringstatechange = (state) => {
        if(rtc_conn.iceGatheringState === "complete"){
            const answer = rtc_conn.localDescription
            vc_sock.send(JSON.stringify(answer))
        }
    }

    await rtc_conn.setRemoteDescription(offer)

    const media = await navigator.mediaDevices.getUserMedia({audio: true})
    console.log("tracks", await navigator.mediaDevices.enumerateDevices())
    media.getTracks().forEach(track => {rtc_conn.addTrack(track, media)})

    const answer = await rtc_conn.createAnswer()
    await rtc_conn.setLocalDescription(answer)

}

However, the streams are played as one, and I couldn’t find a way to separate them. The RTCPeerConnection instance has a single RTCReceiver, which has a single RTCTransport.

Is there a way to separate multiplexed streams (to enable client-side muting / volume adjustment) by SSRCs using WebRTC API? Re-negotiating all RTCPeerConnections whenever a new participant joins a voice channel seems expensive; keeping separate connections is even more expensive (O(N^2)).

I tried using transformers, but they are not available for Chrome.

React – Updating an object inside an array that’s been filtered

I’m working on this Frontend Mentor challenge and I have most of the functionality down. I can filter the data by it’s isActive property to display the correct items based on whether they’re active or not. What I can’t figure out is how to update an individual item’s isActive status and have it rerender the app upon toggle to move the item into the correct filter.

Here is the code for App.jsx:

   function App() {
  const [data, setData] = useState([]);
  const [filteredData, setFilteredData] = useState(data);
  const [activeFilter, setActiveFilter] = useState("All");

  // Fetch and set the data.
  useEffect(() => {
    fetch("../data.json")
      .then((response) => response.json())
      .then((data) => setData(data))
      .catch((error) => console.error("error", error));
  }, []);

  // Filter the data
  useEffect(() => {
    if (activeFilter === "All") {
      setFilteredData(data);
    } else if (activeFilter === "Active") {
      setFilteredData(data.filter((item) => item.isActive === true));
    } else {
      setFilteredData(data.filter((item) => item.isActive === false));
    }
  }, [activeFilter, data]);

  return (
    <div className="w-full h-full bg-linear-to-b from-[#040918] to-[#091540] py-6 px-3 flex flex-col text-white">
      {/* Header */}
      <Header />

      {/* Options */}
      <Options activeFilter={activeFilter} setActiveFilter={setActiveFilter} />

      {/* Cards */}
      {filteredData &&
        filteredData.map((item) => (
          <Card
            logo={item.logo}
            name={item.name}
            description={item.description}
            isActive={item.isActive}
            key={item.name}
            setFilteredData={setFilteredData}
            filteredData={filteredData}
          />
        ))}
    </div>
  );
}

and here is the Card.jsx with the toggle switch

  const Card = ({
  logo,
  name,
  description,
  isActive,
  filteredData,
  setFilteredData,
}) => {
  const [activeState, setActiveState] = useState(isActive);

  function handleClick() {
    setActiveState(!activeState);
  }

  return (
    <div className="bg-neutral-700 p-4 rounded-xl border border-neutral-600 mt-4">
      <div className="flex items-start gap-4">
        {/* Logo */}
        <img src={logo} alt="Extension Image" />

        {/* Name and Description */}
        <div className="flex flex-col gap-2 mb-8">
          <h2 className="font-semibold text-xl">{name}</h2>
          <p className="text-sm font-light">{description}</p>
        </div>
      </div>

      {/* Remove Button */}
      <div className="flex justify-between items-center">
        <div className="border border-neutral-600 rounded-full px-3 py-1 flex items-center justify-center">
          <button>Remove</button>
        </div>

        {/* Is Active Toggle */}
        <div className="flex items-center justify-center">
          <label
            htmlFor={`${name}Toggle`}
            className="flex items-center cursor-pointer "
          >
            <div className="relative">
              <input
                id={`${name}Toggle`}
                type="checkbox"
                className="sr-only"
                onClick={handleClick}
              />
              <div
                className={`flex items-center ${
                  activeState ? "bg-red-400 " : "bg-gray-600 "
                } w-11 h-6 rounded-full transition-all px-[2px]`}
              >
                <div
                  className={`bg-white w-5 h-5 rounded-full ${
                    activeState ? "translate-x-5" : "translate-x-0"
                  } transition-all`}
                ></div>
              </div>
            </div>
          </label>
        </div>
      </div>
    </div>
  );
};

I was attempting to figure out same way inside the Card’s handleclick function that would match the name of the specific card with the item’s name in filteredData and….flip it’s isActive status? I couldn’t figure how to get that to work and I’m not even sure that’s the best way to do it.

In FE existing screen, I have added field CGT,it’s dropdown yes or no,it has to be no by default,when changed to yes,3 extra fields has to be enabled

I have added old html and javascript code as my organisation uses that, but when I’m hovering on that drop-down option in frontend it’s directly becoming 0, and when I click on yes the enabled fields are also becoming 0.
But I want CGT as default ‘no’ even when I hover, what should I change in my fieldset.suggest.
I have tried using strict, position: absolute, selected,but not able to bypass the error

How to style unselected line points in Mapbox draw gl?

Initially, when drawing a line in Mapbox GL Draw, the vertex points are only visible when the line is selected. However, I want the points to remain visible even when the line is unselected, and to style them based on a condition (a custom user property) — for example, making them red or blue. I have already figured out how to apply styling to all points.

  {
    id: "gl-draw-all-points",
    type: "circle",
    paint: {
      "circle-color": ["case", ["==", ["get", "special"], "true"], red, blue],
      "circle-radius": 4,
      "circle-stroke-width": 2,
      "circle-stroke-color": white,
    },
  },

Currently, I don’t apply a filter to my layer, which allows me to style all circles (vertices) globally. However, the problem is that I need to style the points conditionally. With my current setup, the points always appear blue, even when some vertices have the special property set.
Meanwhile, I have another styling approach that correctly applies conditional styling based on properties.

  {
    id: "gl-draw-waypoints",
    type: "circle",
    filter: ["all", ["==", "$type", "Point"], ["==", "meta", "vertex"]],
    paint: {
      "circle-color": ["case", ["==", ["get", "special"], "true"], red, blue],
      "circle-radius": ["case", ["==", ["get", "special"], "true"], 8, 5],
      "circle-stroke-color": white,
      "circle-stroke-width": 2,
    },
  },