An error occurred while retrieving the token. FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope
http://localhost:3000/firebase-cloud-messaging-push-scopewith script http://localhost:3000/firebase-messaging-sw.js: A bad HTTP response code (404) was received when fetching the script. messaging/failed-service-worker registration.
at register defaults registerDefaultSw.ts:43:1 at async updateSwReg updateSwReg.ts:28:1
at async getToken$1 getToken.ts:43:1
at async fetchToken firebase.js:25:1`
Due to the homepage/basename of the react js project, I am getting an error when trying to reach the public folder firebase-messaging-sw.js file.
You need to changing default path of service worker in getToken
sth like this :
export const askForNotification = async () => {
const tempMessaging = await messaging();
if (tempMessaging) {
const newSw = await navigator.serviceWorker.register(
'/homepage/basename/firebase-messaging-sw.js'
);
return getNotificationPermission(
async () => await getToken(tempMessaging, { vapidKey, serviceWorkerRegistration:newSw })
);
}
};
Related
I'm attempting to set up push notifications using Twilio Conversations and Firebase Cloud Messaging on a Next.js 12 app. The documentation is written with the assumption of using Firebase 8 syntax, but I'm using Firebase 9 in this scenario. I've been struggling to get push notifications to work while the page is open. I have the service worker set up (per Firebase docs) but it doesn't seem to be recognizing that a new message is being received from Twilio in order to actually show the notification.
Docs I've followed:
https://www.twilio.com/docs/conversations/javascript/push-notifications-web
https://firebase.google.com/docs/cloud-messaging/js/client
What I've tried
On my backend, I pass the Push Credential SID when I construct a new ChatGrant:
const chatGrant = new ChatGrant({
pushCredentialSid: process.env.TWILIO_PUSH_CREDENTIAL_SID,
serviceSid: CONVERSATIONS_SID
});
In the frontend, I followed the Twilio documentation to set up Firebase:
init.ts
import { getMessaging, getToken, onMessage } from "firebase/messaging";
import { initializeApp } from "firebase/app";
import { Client } from "#twilio/conversations";
// Omitted
const firebaseConfig = {};
export function getPermission(client: Client) {
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
getToken(messaging, { vapidKey:"KEY" })
.then((data) => {
console.log({ data });
client.setPushRegistrationId("fcm", data).catch((error) => {
console.error({ error });
});
onMessage(messaging, (payload) => {
console.log({ payload });
client.handlePushNotification(payload).catch((error) => {
console.error(error);
// test
});
});
})
.catch((error) => {
console.error(error);
// test
});
}
I call getPermission from this file once when the conversation app loads.
// chatClient is stored in a ref so it doesn't recalculate/refetch/reauthorize all the time
const chatClient = useRef(null);
// [Other code]
chatClient.current = new ConversationClient(data.chatAccessToken);
chatClient.current.on("connectionStateChanged", async (state) => {
switch (state) {
case "connected": {
// Only get permission once the chat client is fully set up
getPermission(chatClient.current);
// ..........
And my service worker firebase-messaging-sw.js:
importScripts('https://www.gstatic.com/firebasejs/9.14.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/9.14.0/firebase-messaging-compat.js');
if (!firebase.apps.length) {
firebase.initializeApp({
// CONFIG GOES HERE
});
}
const messaging = firebase.messaging();
//background notifications will be received here
messaging.onBackgroundMessage(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Background Message Title';
const notificationOptions = {
body: 'Background Message body.',
icon: '/android-chrome-192x192.png'
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
What's happening
In the service worker, messaging.onBackgroundMessage never appears to be invoked. I don't know where this issue is derived from - is Twilio not passing message info to Firebase? Or is Firebase not listening to when Twilio sends it the information? Has that changed from v8 to v9?
In init.ts, onMessage is never invoked. Same deal here, is Twilio not passing the right information to Firebase, or did I misconfigure something?
I'm not getting any console errors or warnings, and the network tab is not pointing out anything super helpful.
I got this to work by using the example code (from docs) and configuring my Next.js application to compile the TypeScript into JavaScript. This helped a lot: https://github.com/vercel/next.js/issues/33863#issuecomment-1140518693
I try to use a brand new feature released in NextJS v.12.1 https://deepinder.me/nextjs-on-demand-isr. The API itself works fine. I can reach it. But in exchange it returns 500 error that says res.unstable_revalidate is not a function. It does not work either over dev (next server && next dev) run or production one (next build && next start).
This is the api endpoint:
// ./api/misc/revalidate
const revalidateCache = async (_, res) => {
console.log(res.unstable_revalidate, 'TEST REVALIDATE'); // res.unstable_revalidate is undefined here :(
try {
await res.unstable_revalidate('/');
return res.json({ revalidated: true });
} catch (err) {
return res.status(500).send(`Error revalidating: ${err}`);
}
};
export default revalidateCache;
This is the invoke:
// ./apps/client/services/server
const getRevalidate = async () => {
await fetch('/api/misc/revalidate');
};
export default getRevalidate;
View layer that I call from:
// .src/pages/index.js
// ...some code here
const HomePage = ({ page, legacy }) => {
const handleClick = () => {
getRevalidate();
};
return (
<div className={styles.homeRoot}>
<button onClick={handleClick}>REVALIDATE</button>
</div>
);
};
UPD:
I use express to handle API abstration.
import express from 'express';
import revalidateCacheApi from './api/misc/revalidate';
export default app => {
// ...some code here
app.use('/api/misc/revalidate', revalidateCacheApi);
};
NVM. It was an issue with my local server. I use advanced set up with two independent instances (:3000 and :4000) spinning in the memory.
The way I designed API above suppose to call it over :4000 server. Which is in fact Express server (obviously does not has NextJS internal API to purge the cache).
So I moved the call to the pages/api/revalidate and up to :3000 server.
Works fine:
// ./src/pages/server/revalidate.js
const getRevalidate = async () => {
await fetch('/api/revalidate');
};
export default getRevalidate;
Describe the bug
I have built an application with NextJS that has an internal API and I use the getStaticProps methods to query the API.
You can find the deployed app here: https://tailor-challenge.vercel.app/
And also the github repository here: enter link description here
The application works perfectly in development mode and the deploy I made in Vercel also works. But when I run the next build command I get the following error:
Build error occurred
FetchError: request to http://localhost:3000/api/restaurants failed, reason: connect ECONNREFUSED 127.0.0.1:3000
at ClientRequest.<anonymous> (/home/silinde87/Jobs/tailor/TailorChallenge/node_modules/node-fetch/lib/index.js:1461:11)
at ClientRequest.emit (node:events:376:20)
at Socket.socketErrorListener (node:_http_client:474:9)
at Socket.emit (node:events:376:20)
at emitErrorNT (node:internal/streams/destroy:188:8)
at emitErrorCloseNT (node:internal/streams/destroy:153:3)
at processTicksAndRejections (node:internal/process/task_queues:80:21) {
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED'
}
info - Collecting page data .npm ERR! code 1
npm ERR! path /home/silinde87/Jobs/tailor/TailorChallenge
npm ERR! command failed
npm ERR! command sh -c next build
NextJS internal API
/api/restaurants/index.js
export default function handler(req, res) {
const { method } = req;
switch (method) {
case 'GET':
getRestaurants();
break;
default:
res.status(405).end(`Method ${req.method} Not Allowed`);
}
function getRestaurants() {
const restaurants = data;
res.status(200).json(restaurants);
}
}
/api/restaurants/[id].js
export default function handler(req, res) {
const { id } = req.query;
const { method } = req;
switch (method) {
case 'GET':
getRestaurantById();
break;
default:
res.status(405).end(`Method ${req.method} Not Allowed`);
}
function getRestaurantById() {
const restaurants = data.find((el) => el.id.toString() === id.toString());
if (restaurants) res.status(200).json(restaurants);
else res.status(405).end(`There is no Restaurant with id: ${id}`);
}
}
Pages from NextJS
pages/index.js <-- Where I fetch the restaurants list
export async function getStaticProps() {
const res = await fetch(`${process.env.NEXT_PUBLIC_NEXTAUTH_URL}/api/restaurants`);
const restaurants = await res.json();
if (!restaurants) {
return {
notFound: true,
};
}
return {
props: {
restaurants,
},
};
}
pages/[id].js
// Return a list of possible value for id
export async function getStaticPaths() {
const res = await fetch(`${process.env.NEXT_PUBLIC_NEXTAUTH_URL}/api/restaurants`);
const restaurants = await res.json();
let paths = restaurants.map(({ id }) => {
return {
params: {
id: id.toString(),
},
};
});
return { paths, fallback: false };
}
// Fetch necessary data for the restaurant details using params.id
export async function getStaticProps({ params }) {
const res = await fetch(`${process.env.NEXT_PUBLIC_NEXTAUTH_URL}/api/restaurants/${params.id}`);
const restaurantData = await res.json();
return {
props: {
restaurantData,
},
};
}
I took this quote from the official documentation, link below:
Note: You should not use fetch() to call an API route in >getStaticProps. Instead, directly import the logic used inside >your API route. You may need to slightly refactor your code for >this approach.
Fetching from an external API is fine!
https://nextjs.org/docs/basic-features/data-fetching
Basically because the code inside getStaticProps or getStaticPaths is never executed in the browser, so you can safely call the data source directly there.
Also the failure happens because the app is not running when building, so the localhost api is not available. You can confirm this by running the app via ’yarn dev’ or ’npm run dev’ in another terminal window, and building the app in another terminal window. This way it should build just fine, but it's not recommended way of doing it. I would refactor the code so that there is no fetch to the api of this app in those getStaticProps and getStaticPaths functions.
Same goes for getServerSideProps, that is also just run on the server, so you shouldn't be doing fetches to the api there either. Only the browser should do fetches to the api, for example if you want the user to be able to post some data to the app.
I have a nextjs app with a strapi api deployed with heroku and the frontend with firebase. I use an environnement variable to fetch my api. It worked well in localhost but not with Heroku. I get the error: Only absolute URLs are supported**
I tried to hardcode my api URL, but I guess this is not the very best solution
Does someone ever meet that kind of problem ?
> Build error occurred
TypeError: Only absolute URLs are supported
at getNodeRequestOptions (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/node_modules/next/dist/compiled/node-fetch/index.js:1:64341)
at /Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/node_modules/next/dist/compiled/node-fetch/index.js:1:65715
at new Promise (<anonymous>)
at fetch (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/node_modules/next/dist/compiled/node-fetch/index.js:1:65650)
at fetchAPI (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/.next/server/pages/books/[name].js:7040:26)
at getProducts (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/.next/server/pages/books/[name].js:7053:26)
at getStaticPaths (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/.next/server/pages/books/[name].js:6997:60)
at buildStaticPaths (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/node_modules/next/dist/build/utils.js:17:86)
at Object.isPageStatic (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/node_modules/next/dist/build/utils.js:24:555)
at execFunction (/Users/mac/Documents/Website/strapi/strapi-starter/strapi-starter-next-ecommerce/frontend/node_modules/jest-worker/build/workers/processChild.js:155:17) {
type: 'TypeError'
}
api.js
export function getStrapiURL(path) {
return `https://intense-beyond-59367.herokuapp.com${path}`;
}
// Helper to make GET requests to Strapi
export async function fetchAPI(path) {
const requestUrl = getStrapiURL(path);
const response = await fetch(requestUrl);
const data = await response.json();
return data;
}
export async function getCategories() {
const categories = await fetchAPI("/categories");
return categories;
}
export async function getCategory(slug) {
const categories = await fetchAPI(`/categories?slug=${slug}`);
return categories?.[0];
}
export async function getProducts() {
const products = await fetchAPI("/books");
return products;
}
export async function getProduct(name) {
const products = await fetchAPI(`/books?name=${name}`);
return products?.[0];
}
I am losing my hope at solving a Network Error in my Firebase/React app. The error Uncaught Error: Network Error at auth.esm.js:255 shows up in the console sometimes, and at other times it simply won't show and the user gets logged in with Google successfully.
While searching for an answer, I couldn't find anything conclusive (be it in Stack Overflow or Github issues). The Firebase documentation only shows Thrown if a network error (such as timeout, interrupted connection or unreachable host) has occurred about this.
Below is my piece of code for the log in component.
useEffect(() => {
auth
.getRedirectResult()
.then(function (result) {
if (result.credential) {
const token = result.credential.accessToken
setIdToken(token)
history.push('/')
}
const user = result.user
setUsername(user.displayName)
})
.catch(function (error) {
var errorCode = error.code
var errorMessage = error.message
console.log('errorCode and errorMessage: ', errorCode, errorMessage)
})
}, [])
function handleSignInWithGoogle() {
signInWithGoogle()
setLoading(true)
}
//then, inside of my return statement
<button onClick={() => handleSignInWithGoogle()}> Sign in with Google </button>
And this is what inside of my Firebase file
firebase.initializeApp(firebaseConfig)
export const firestore = firebase.firestore()
export const auth = firebase.auth()
export const provider = new firebase.auth.GoogleAuthProvider()
export const signInWithGoogle = () => auth.signInWithRedirect(provider)
Its possible you have some debugger on the code or any blocking process.
Aparently firebase has a timeout and after that time pass (few seconds on my case) it doesnt allow you, as soon as took out the debugger that was blocking the first start it got solved.