Im trying to get the data from the generated firebase dynamic link.
I passed Id while generating the dynamic link. I need to get the particular id from the generated dynamic link. Can you please help me.
Where it generates link as :https://thejyotistore.page.link/jNngseAasXzE5SuSA
const ShareLink = ({
fallbackUrl, id, product }) =>
{
const buildLink = async () =>
{
let link = await axios({
method: "POST",
url:
`https://firebasedynamiclinks
.googleapis.com/v1/shortLinks?
key=AIzaSyDNZvtkjAqf8c9esg
gSEzV2 L7. 3vEUv1FfQ`,
headers: {
"Content-Type":
"application/json",
},
data: {
dynamicLinkInfo: {
domainUriPrefix: `https://thejyotistore.page.link`,
link: `https://youtube.com/${id}`,
androidInfo: {
androidPackageName: "com.jyotistore.main",
},
},
},
});
if (link.status === 200 && link.data.hasOwnProperty("shortLink")) {
console.log(link.data.shortLink);
return link.data.shortLink;
}
};
const shareLink = async () =>
{
let shareUrl;
try {
shareUrl = await buildLink();
console.log(shareUrl);
} catch (error) {
console.log(error);
}
try {
if (shareUrl !== "") {
const result = await Share.share({
message: `Hey, ${"\n \n"}I would like to invite you to check out this New App from Jyoti Store. ${"\n \n"} ${product}Download the App now: ${"\n \n"} ${shareUrl}`,
});
}
} catch (error) {
console.log(error);
}
};
I'm trying to pass in fetch which apparently isn't defined in my api libraries when using ssr:
<script context="module">
import setup from '$api/create-api';
import Jobs from '$api/jobs';
export async function load({ fetch }) {
setup(fetch);
const jobs = await Jobs.getAll();
return {
props: { jobs }
};
}
</script>
create-api.js
import { browser } from '$app/env';
let fetch = fetch || null;
async function api(path, body = {}, opts = {}) {
path = import.meta.env.VITE_API_ENDPOINT + path;
body = JSON.stringify(body);
const method = opts.method || 'GET';
const headers = {};
if (browser) {
const token = localStorage.getItem('token');
headers.Authorization = token ? 'Bearer ' + token : '';
}
const res = await fetch(path, {
method: opts.method || 'GET',
body: method === 'GET' ? null : body,
headers
});
if (res.ok) {
return await (opts.raw ? res.text() : res.json());
}
throw res;
}
export default api;
export const setup = (f) => {
fetch = f;
};
jobs.js
import api from './create-api';
class Jobs {
static async getAll() {
return await api('/jobs');
}
static async getAllMine() {
return await api('/jobs/me');
}
static async create(job) {
return await api('/jobs', job, { method: 'POST' });
}
static async update(job) {
return await api('/jobs/' + job.id, job, { method: 'PUT' });
}
static async deleteById(id) {
return await api('/jobs/' + id, {}, { method: 'DELETE' });
}
static async getById(id) {
console.log(id);
return await api('/jobs/' + id, {}, { method: 'GET' });
}
}
export default Jobs;
It seems you have to use the fetch passed into the script module for some reason. I tried installing node-fetch but got a ton of errors.
I used to send push notifications with only text messages in them. The payload structure was different at the time, and the function "sendToDevices(token,payload)" was utilized. But now I want to send a push notice to several devices with images in it, thus I'm using the "sendMulticast(payload)" function. It works up to Firebase, which means I can see the console message "push notification send" in the Firebase console, but no notification is sent.
Also, I tested the payload in the console and everything seemed to be working.
Old Code and its payload
exports.sendPushNotificationToAllDevices = functions.https.onRequest((request, response) => {
const domain = request.body.Domain;
if (typeof domain == "undefined" || domain == null || domain == "") {
response.status(400).send("Domain is empty.");
return;
}
const url = domain + '/Users';
admin.database().ref(url).once('value')
.then(snapshot => {
let tokens = [];
let counter = 0;
const count = snapshot.numChildren();
snapshot.forEach(function (data) {
counter++;
const token = data.val().FirebaseToken;
if (typeof token !== "undefined" && token !== null && token != "") {
tokens.push(token);
}
});
let uniqeTokens = [...new Set(tokens)];
if (uniqeTokens.length > 0) {
const payload = getNotificationPayload(request);
console.log(uniqeTokens.length);
const tokensChunk = chunk(uniqeTokens,999);
tokensChunk.forEach(function(tokens){
sendPushNotificationTo(tokens, payload); // sendToDevice() function is used.
});
}
});
response.status(200).send("sending");
});
Old Payload Structure
return {
notification: {
title: notificationTitle,
body: notificationBody,
clickAction: clickAction,
sound: 'default'
},
data: notificationData
};
New Code Structure
exports.sendPushNotificationToAllDevices = functions.https.onRequest((request, response) => {
const domain = request.body.Domain;
if (typeof domain == "undefined" || domain == null || domain == "") {
response.status(400).send("Domain is empty");
return;
}
const url = domain + '/Users';
admin.database().ref(url).once('value')
.then(snapshot => {
let tokens = [];
let counter = [];
const count = snapshot.numChildren();
snapshot.forEach(function (data){
counter++;
const token = data.val().FirebaseToken;
if (typeof token !== "undefined" && token !== null && token != "") {
tokens.push(token);
}
});
let uniqueTokens = [...new Set(tokens)];
if (uniqueTokens.length > 0) {
var payload = getNotificationPayload(request);
const tokensChunk = chunk(uniqueTokens, 999);
tokensChunk.forEach(function(tokens){
payload['tokens'] = tokens;
sendPushNotificationTo(payload); // sendMulticast() function is used.
});
}
});
response.status(200).send("Sending");
});
New Payload Structure
let message = {
notification: {
title: notificationTitle,
body: notificationBody,
clickAction: clickAction,
sound: 'default',
},
data: notificationData,
android: {
notification: {
sound: 'default'
}
},
apns: {
payload: {
aps: {
'mutable-content': 1,
sound:sound,
}
}
}
};
if (typeof clickAction === 'string' || clickAction !== "") {
message["android"]["notification"]["click_action"] = clickAction;
}
if (typeof imageUrl === 'string' || imageUrl !== "") {
message["android"]["notification"]["imageUrl"] = imageUrl;
message["apns"]["fcm_options"]["image"] = imageUrl;
}
return message;
Payload structure was not correct for new function "sendMulticast()" .
required payload structrue
let message = {
notification: {
title: notificationTitle,
body: notificationBody,
// clickAction: clickAction,
// sound: 'default',
},
data: notificationData,
android: {
notification: {
sound: 'default'
}
},
apns: {
payload: {
aps: {
"mutable-content": 1,
sound:'default',
}
}
}
};
if (typeof clickAction === 'string' || clickAction !== "") {
message["android"]["notification"]["click_action"] = clickAction;
}
if (typeof imageURL !== "undefined" && imageURL !== null && imageUrl !== "") {
message["android"]["notification"]["imageUrl"] = imageUrl;
}
return message;
ClickAction and Sound is not supported by sendMulticast(), send() etch kind of function
I'm working with next.js and apollo client to get an access token with a refresh token from the server and I searched the web and find apollo-link-token-refresh that does something like silent refresh, so I follow along with example and was happy that after 2 days I finish my project Authentication but no it didn't work. is there any problem in my code?
const refreshLink = new TokenRefreshLink({
accessTokenField: "token",
isTokenValidOrUndefined: () => {
if (!cookie.get("JWT")) {
return true;
}
if (token && jwt.decode(token)?.exp * 1000 > Date.now()) {
return true;
}
},
fetchAccessToken: async () => {
if (!cookie.get("JWT")) {
return true;
}
const response = await fetch(`${NEXT_PUBLIC_SERVER_API_URL}`, {
method: "POST",
headers: {
authorization: token ? "JWT " + token : "",
"content-type": "application/json",
},
body: JSON.stringify({
query: `
mutation {
refreshToken(refreshToken: "${cookie.get("JWTRefreshToken")}") {
token
payload
refreshToken
refreshExpiresIn
}
}
`,
}),
});
return response.json();
},
handleFetch: (newToken) => {
cookie.remove("JWT", { path: "" });
cookie.set("JWT", newToken, {
expires: data.tokenAuth.payload.exp,
secure: process.env.NODE_ENV !== "production",
path: "",
});
},
handleResponse: (operation, accessTokenField) => (response) => {
if (!response) return { newToken: null };
return { newToken: response.data?.refreshUserToken?.token };
},
handleError: (error) => {
console.error("Cannot refresh access token:", error);
},
});
function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === "undefined",
link: authLink.concat(refreshLink).concat(
new HttpLink({
uri: process.env.NEXT_PUBLIC_SERVER_API_URL,
credentials: "same-origin",
}),
),
cache
})
)
A noticed that onUploadProgress from axios are not being called at all on my Nuxt.js Project. After some debugging I found out it is related to the "#nuxtjs/pwa" and "#nuxtjs/firebase" modules. I use firebase auth, and the PWA module uses a service worker to take care of SSR auth and inject the auth token on outgoing requests.
This modules are interfering somehow on the axios onUploadProgress. I use axios to upload files to other Apis.
Once I remove the "#nuxtjs/pwa" module the onUploadProgress from axios gets called normally.
Does anyone have an idea how to fix that?
The versions of the modules:
"#nuxtjs/axios": "^5.13.6",
"#nuxtjs/firebase": "^7.6.1",
"#nuxtjs/pwa": "^3.3.5",
nuxt.config.js
firebase: {
....
services: {
auth: {
ssr: true,
persistence: 'local',
initialize: {
onAuthStateChangedAction: 'auth/onAuthStateChangedAction',
subscribeManually: false,
},
},
firestore: true,
functions: true,
},
}
pwa: {
meta: false,
icon: false,
workbox: {
importScripts: ['/firebase-auth-sw.js'],
dev: process.env.NODE_ENV === 'development',
},
},
Axios upload
const asset = await $axios.post(uploadUrl, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (progressEvent) => {
console.log('onUploadProgress');
const prog = parseInt(
Math.round((progressEvent.loaded / progressEvent.total) * 100)
);
progress(prog);
},
});
the console.log isn't called at all.
firebase-auth-sw
const ignorePaths = ["\u002F__webpack_hmr","\u002F_loading","\u002F_nuxt\u002F"]
importScripts(
'https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js'
)
importScripts(
'https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js'
)
firebase.initializeApp({"apiKey":"AIzaSyDUjfwaCRNG72CaPznknOfbNLySkFQvfrs","authDomain":"j-a-developer-web-site.firebaseapp.com","projectId":"j-a-developer-web-site","storageBucket":"j-a-developer-web-site.appspot.com","messagingSenderId":"393360816421","appId":"1:393360816421:web:75c43cac27032d924502cc"})
// Initialize authService
const authService = firebase.auth()
/**
* Returns a promise that resolves with an ID token if available.
* #return {!Promise<?string>} The promise that resolves with an ID token if
* available. Otherwise, the promise resolves with null.
*/
const getIdToken = () => {
return new Promise((resolve) => {
const unsubscribe = authService.onAuthStateChanged((user) => {
unsubscribe()
if (user) {
// force token refresh as it might be used to sign in server side
user.getIdToken(true).then((idToken) => {
resolve(idToken)
}, () => {
resolve(null)
})
} else {
resolve(null)
}
})
})
}
const fetchWithAuthorization = async (original, idToken) => {
// Clone headers as request headers are immutable.
const headers = new Headers()
for (let entry of original.headers.entries()) {
headers.append(entry[0], entry[1])
}
// Add ID token to header.
headers.append('Authorization', 'Bearer ' + idToken)
// Create authorized request
const { url, ...props } = original.clone()
const authorized = new Request(url, {
...props,
mode: 'same-origin',
redirect: 'manual',
headers
})
return fetch(authorized)
}
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url)
const expectsHTML = event.request.headers.get('accept').includes('text/html')
const isSameOrigin = self.location.origin === url.origin
const isHttps = (self.location.protocol === 'https:' || self.location.hostname === 'localhost' || self.location.hostname === '127.0.0.1')
const isIgnored = ignorePaths.some(path => {
if (typeof path === 'string') {
return url.pathname.startsWith(path)
}
return path.test(url.pathname.slice(1))
})
// https://github.com/nuxt-community/firebase-module/issues/465
if (!expectsHTML || !isSameOrigin || !isHttps || isIgnored) {
event.respondWith(fetch(event.request))
return
}
// Fetch the resource after checking for the ID token.
// This can also be integrated with existing logic to serve cached files
// in offline mode.
event.respondWith(
getIdToken().then(
idToken => idToken
// if the token was retrieved we attempt an authorized fetch
// if anything goes wrong we fall back to the original request
? fetchWithAuthorization(event.request, idToken).catch(() => fetch(event.request))
// otherwise we return a fetch of the original request directly
: fetch(event.request)
)
)
})
// In service worker script.
self.addEventListener('activate', event => {
event.waitUntil(clients.claim())
})
sw
const options = {"workboxURL":"https://cdn.jsdelivr.net/npm/workbox-cdn#5.1.4/workbox/workbox-sw.js","importScripts":["/firebase-auth-sw.js"],"config":{"debug":true},"cacheOptions":{"cacheId":"J.A-Developer-Web-Site-dev","directoryIndex":"/","revision":"qIA7lTEhJ6Mk"},"clientsClaim":true,"skipWaiting":true,"cleanupOutdatedCaches":true,"offlineAnalytics":false,"preCaching":[{"revision":"qIA7lTEhJ6Mk","url":"/?standalone=true"}],"runtimeCaching":[{"urlPattern":"/_nuxt/","handler":"NetworkFirst","method":"GET","strategyPlugins":[]},{"urlPattern":"/","handler":"NetworkFirst","method":"GET","strategyPlugins":[]}],"offlinePage":null,"pagesURLPattern":"/","offlineStrategy":"NetworkFirst"}
importScripts(...[options.workboxURL, ...options.importScripts])
initWorkbox(workbox, options)
workboxExtensions(workbox, options)
precacheAssets(workbox, options)
cachingExtensions(workbox, options)
runtimeCaching(workbox, options)
offlinePage(workbox, options)
routingExtensions(workbox, options)
function getProp(obj, prop) {
return prop.split('.').reduce((p, c) => p[c], obj)
}
function initWorkbox(workbox, options) {
if (options.config) {
// Set workbox config
workbox.setConfig(options.config)
}
if (options.cacheNames) {
// Set workbox cache names
workbox.core.setCacheNameDetails(options.cacheNames)
}
if (options.clientsClaim) {
// Start controlling any existing clients as soon as it activates
workbox.core.clientsClaim()
}
if (options.skipWaiting) {
workbox.core.skipWaiting()
}
if (options.cleanupOutdatedCaches) {
workbox.precaching.cleanupOutdatedCaches()
}
if (options.offlineAnalytics) {
// Enable offline Google Analytics tracking
workbox.googleAnalytics.initialize()
}
}
function precacheAssets(workbox, options) {
if (options.preCaching.length) {
workbox.precaching.precacheAndRoute(options.preCaching, options.cacheOptions)
}
}
function runtimeCaching(workbox, options) {
const requestInterceptor = {
requestWillFetch({ request }) {
if (request.cache === 'only-if-cached' && request.mode === 'no-cors') {
return new Request(request.url, { ...request, cache: 'default', mode: 'no-cors' })
}
return request
},
fetchDidFail(ctx) {
ctx.error.message =
'[workbox] Network request for ' + ctx.request.url + ' threw an error: ' + ctx.error.message
console.error(ctx.error, 'Details:', ctx)
},
handlerDidError(ctx) {
ctx.error.message =
`[workbox] Network handler threw an error: ` + ctx.error.message
console.error(ctx.error, 'Details:', ctx)
return null
}
}
for (const entry of options.runtimeCaching) {
const urlPattern = new RegExp(entry.urlPattern)
const method = entry.method || 'GET'
const plugins = (entry.strategyPlugins || [])
.map(p => new (getProp(workbox, p.use))(...p.config))
plugins.unshift(requestInterceptor)
const strategyOptions = { ...entry.strategyOptions, plugins }
const strategy = new workbox.strategies[entry.handler](strategyOptions)
workbox.routing.registerRoute(urlPattern, strategy, method)
}
}
function offlinePage(workbox, options) {
if (options.offlinePage) {
// Register router handler for offlinePage
workbox.routing.registerRoute(new RegExp(options.pagesURLPattern), ({ request, event }) => {
const strategy = new workbox.strategies[options.offlineStrategy]
return strategy
.handle({ request, event })
.catch(() => caches.match(options.offlinePage))
})
}
}
function workboxExtensions(workbox, options) {
}
function cachingExtensions(workbox, options) {
}
function routingExtensions(workbox, options) {
}
store's index.js
export const state = () => ({});
export const actions = {
async nuxtServerInit({ dispatch, commit }, { res }) {
// initialize the store with user if already authenticated
if (res && res.locals && res.locals.user) {
const {
allClaims: claims,
idToken: token,
...authUser
} = res.locals.user;
await dispatch('auth/onAuthStateChangedAction', {
authUser,
claims,
token,
});
}
},
};