diff --git a/firebase.json b/firebase.json
index cc63270c..6235787e 100644
--- a/firebase.json
+++ b/firebase.json
@@ -44,15 +44,6 @@
"value": "same-origin"
}
]
- },
- {
- "source": "/@(service-worker|firebase-messaging-sw).js",
- "headers": [
- {
- "key": "Cache-Control",
- "value": "no-cache, no-store, must-revalidate"
- }
- ]
}
]
},
diff --git a/functions/src/prerender.ts b/functions/src/prerender.ts
index 0c6ac700..6b6c7eac 100644
--- a/functions/src/prerender.ts
+++ b/functions/src/prerender.ts
@@ -4,33 +4,34 @@ import express from 'express';
import { getFirestore } from 'firebase-admin/firestore';
import * as functions from 'firebase-functions';
import fetch from 'node-fetch';
-import url, { URL } from 'url';
const app = express();
-const getSiteDomain = async () => {
- const doc = await getFirestore().collection('config').doc('site').get();
- return doc.data().domain;
-};
-
const getRendertronServer = async () => {
const doc = await getFirestore().collection('config').doc('rendertron').get();
return doc.data().server;
};
-/**
- * generateUrl() - Piece together request parts to form FQDN URL
- * @param {Object} request
- */
-const generateUrl = async (request) => {
- // Why do we use config site.domain instead of the domain from
- // the request? Because it'll give you the wrong domain (pointed at the
- // cloudfunctions.net)
- return url.format({
- protocol: request.protocol,
- host: await getSiteDomain(),
- pathname: request.originalUrl,
- });
+const normalizeHost = (h: string) =>
+ h.replace(/^https?:\/\//, '').replace(/\/+$/, '');
+
+const resolveHost = (req): string => {
+ // 1. Prefer Hosting/CDN header
+ const headerHost =
+ req.get('x-forwarded-host') || req.get('host') || req.hostname;
+
+ if (headerHost) {
+ return normalizeHost(headerHost);
+ }
+
+ // 2. Fallback to Firebase config
+ const cfgHost = functions.config()?.site?.domain as string | undefined;
+ if (cfgHost) {
+ return normalizeHost(cfgHost);
+ }
+
+ // 3. Last fallback (safe default for dev)
+ return 'localhost:5000';
};
/**
@@ -55,38 +56,35 @@ const checkForBots = (userAgent) => {
//
// The trick is on L66, pwaShell(): You must update that file! Open for explainer.
app.get('*', async (req, res) => {
- // What say you bot tester?
+ const host = resolveHost(req);
const botResult = checkForBots(req.headers['user-agent']);
+
if (botResult) {
- // Get me the url all nice
- const targetUrl = generateUrl(req);
-
- // Did you read the README? You should have set rendertron document
- // to where ever you deployed https://github.com/GoogleChrome/rendertron on AppEngine
- fetch(`${await getRendertronServer()}/render/${targetUrl}`)
- .then((res) => res.text())
- .then((body) => {
- // We set Vary because we only want to cache this result for the bots
- // which we know based on the user-agent. Vary is very useful.
- // Reading about Vary header:
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary
- // https://www.fastly.com/blog/best-practices-using-vary-header/
- res.set('Cache-Control', 'public, max-age=300, s-maxage=600');
- res.set('Vary', 'User-Agent');
-
- res.send(body.toString());
- });
- } else {
- // 1. Umm, Justin, why not just point to index.html?
- // 2. Umm, Justin, why not just fetch() index.html from the domain?
- //
- // Valid things to ask internet peoples
- // 1. function doesn't know about the public hosting as far as I can tell (docs don't offer opinion/example)
- // 2. Could fetch and return...but I found copy+paste the index.html PWA shell into file returns faster
- // const indexHTML = fs.readFileSync('./index.html').toString();
- const path = new URL('./index.html', import.meta.url).pathname;
- res.sendFile(path);
+ // Bot path via Rendertron (you can keep your caching here if you want)
+ const targetUrl = `https://${host}${req.originalUrl}`;
+ const rendertron = await getRendertronServer();
+
+ const botResp = await fetch(`${rendertron}/render/${targetUrl}`);
+ const body = await botResp.text();
+
+ res.set('Cache-Control', 'public, max-age=300, s-maxage=600');
+ res.set('Vary', 'User-Agent');
+ return res.send(body.toString());
}
+
+ // ✅ Non-bot path: fetch the current Hosting HTML so it’s never stale
+ const htmlResp = await fetch(`https://${host}/index.html`, {
+ // prevent node-fetch from reusing cached responses
+ headers: { 'Cache-Control': 'no-cache' }
+ });
+ const html = await htmlResp.text();
+
+ // No-cache for HTML so users revalidate on each load
+ res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
+ res.set('Pragma', 'no-cache');
+ res.set('Expires', '0');
+
+ return res.status(htmlResp.status || 200).send(html);
});
export const prerender = functions.https.onRequest(app);
diff --git a/public/data/meet-the-talent.json b/public/data/meet-the-talent.json
index 2e9f261e..0aae31ba 100644
--- a/public/data/meet-the-talent.json
+++ b/public/data/meet-the-talent.json
@@ -38,6 +38,44 @@
"name": "X/Twitter"
}
]
+ },{
+ "fullName": "Jaydip Umaretiya",
+ "location": "Surat, Gujarat, India",
+ "bio": "Experienced Android developer with 10+ years of expertise in building native mobile and TV applications, including digital signage solutions. Proficient in Kotlin, Java, Jetpack Compose, and native libraries, with strong skills in creating modern, responsive UIs. Well-versed in Kotlin Multiplatform (KMP) and Compose Multiplatform (CMP) to deliver scalable cross-platform solutions. Adept at project leadership, team mentoring, and managing complex, high-impact applications. Committed to innovation, exceeding client expectations, and fostering long-term partnerships.",
+ "email": "jaynumaretiya@gmail.com",
+ "phone": "+91-9510086772",
+ "imageUrl": "https://www.jaydip.tech/static/media/img-mobile.ec99727dfdae5c2cdd64.png",
+ "website": "https://jaydip.tech/",
+ "skills": [
+ "Android",
+ "Kotlin",
+ "Jetpack Compose",
+ "Android TV Development",
+ "Kotlin MultiPlatform",
+ "Compose MultiPlatform"
+ ],
+ "links": [
+ {
+ "icon": "website",
+ "link": "https://jaydip.tech/",
+ "name": "Portfolio"
+ },
+ {
+ "icon": "github",
+ "link": "https://github.com/jaydipumaretiya",
+ "name": "Github"
+ },
+ {
+ "icon": "linkedin",
+ "link": "https://www.linkedin.com/in/jaydipumaretiya",
+ "name": "LinkedIn"
+ },
+ {
+ "icon": "twitter",
+ "link": "https://x.com/jaydipumaretiya",
+ "name": "X/Twitter"
+ }
+ ]
}
]
}
\ No newline at end of file
diff --git a/rollup.config.ts b/rollup.config.ts
index 86d335a3..6ba4d656 100644
--- a/rollup.config.ts
+++ b/rollup.config.ts
@@ -13,22 +13,6 @@ import { compileBufferTemplate, production } from './utils/build';
const { ROLLUP_WATCH } = process.env;
export default [
- {
- input: 'src/firebase-messaging-sw.ts',
- treeshake: production,
- output: {
- file: 'dist/firebase-messaging-sw.js',
- sourcemap: production,
- },
- plugins: [
- nodeResolve(),
- typescript({
- noEmitOnError: true,
- sourceMap: production,
- }),
- production && terser(),
- ],
- },
{
treeshake: production,
output: {
diff --git a/src/firebase-messaging-sw.ts b/src/firebase-messaging-sw.ts
deleted file mode 100644
index 8759ca55..00000000
--- a/src/firebase-messaging-sw.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/* eslint spaced-comment: ["error", "always", { "markers": ["/"] }] */
-/* eslint-env serviceworker */
-
-///
This helps us avoid overcrowding and ensures that everyone gets the most out of the sessions they’re truly passionate about.
+🚫 Coupon code? Seriously?!
+🎟️ અમારી ટિકિટની કિંમત પહેલાંથી જ community ને ધ્યાનમાં રાખીને રાખવામાં આવી છે — it's already a highly subsidized price considering the amazing value you get!
+💬 Coupon code માંગીને શરમાવશો નહીં — એક દિવસ પિઝ્ઝા પાર્ટી ના ખર્ચે, તમારું ભવિષ્ય સુધારવાની તક છે.
+👉 Knowledge મા investment કરશો, regret નહીં થાય.
+