Browse Source

feat: implement AuthBridge for managing HABIB_TOKEN and HABIB_COINS from window

master
mortezaei 2 months ago
parent
commit
a2f66835a9
  1. 10
      src/app/api/proxy/route.ts
  2. 25
      src/app/layout.tsx
  3. 74
      src/lib/auth-bridge.ts
  4. 6
      src/lib/http.ts
  5. 12
      src/types/window.d.ts

10
src/app/api/proxy/route.ts

@ -103,11 +103,17 @@ function getRequestHeaders(request: NextRequest, targetUrl: URL) {
const value = request.headers.get(header); const value = request.headers.get(header);
if (value) { if (value) {
headers.set(header, value);
if (header === "token") {
// Convert token header to Authorization
headers.set("authorization", `Token ${value}`);
} else {
headers.set(header, value);
}
} }
} }
if (authKey) {
// Override with authKey if set and no authorization header exists
if (authKey && !headers.has("authorization")) {
headers.set("authorization", `token ${authKey}`); headers.set("authorization", `token ${authKey}`);
} }

25
src/app/layout.tsx

@ -29,8 +29,8 @@ const amiri = Amiri({
}); });
export const metadata: Metadata = { export const metadata: Metadata = {
title: "ازدواج حبیب",
description: "سامانه ازدواج اسلامی حبیب",
title: "Habib Marriage",
description: "Islamic Marriage Platform",
viewport: { viewport: {
width: "device-width", width: "device-width",
initialScale: 1, initialScale: 1,
@ -55,6 +55,27 @@ export default function RootLayout({
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
window.onFlutterResponse = window.onFlutterResponse || function() {}; window.onFlutterResponse = window.onFlutterResponse || function() {};
// Save to sessionStorage when injected
Object.defineProperty(window, 'HABIB_TOKEN', {
set: function(value) {
this._habib_token = value;
if (value) sessionStorage.setItem('habib_token', value);
},
get: function() {
return this._habib_token || sessionStorage.getItem('habib_token');
}
});
Object.defineProperty(window, 'HABIB_COINS', {
set: function(value) {
this._habib_coins = value;
if (value) sessionStorage.setItem('habib_coins', String(value));
},
get: function() {
return this._habib_coins || parseInt(sessionStorage.getItem('habib_coins') || '0');
}
});
// Performance monitoring // Performance monitoring
window.addEventListener('load', function() { window.addEventListener('load', function() {
var perfData = performance.getEntriesByType('navigation')[0]; var perfData = performance.getEntriesByType('navigation')[0];

74
src/lib/auth-bridge.ts

@ -0,0 +1,74 @@
class AuthBridge {
private token: string | null = null;
private coins: number = 0;
private isReady = false;
private readyCallbacks: Array<() => void> = [];
constructor() {
this.init();
}
private init() {
if (typeof window !== 'undefined') {
const win = window as any;
if (win.HABIB_TOKEN) {
this.token = win.HABIB_TOKEN;
this.coins = win.HABIB_COINS || 0;
this.isReady = true;
this.notifyReady();
} else {
this.waitForInjection();
}
}
}
private waitForInjection() {
let attempts = 0;
const maxAttempts = 50;
const checkInterval = setInterval(() => {
const win = window as any;
if (win.HABIB_TOKEN) {
this.token = win.HABIB_TOKEN;
this.coins = win.HABIB_COINS || 0;
this.isReady = true;
clearInterval(checkInterval);
this.notifyReady();
} else if (++attempts >= maxAttempts) {
clearInterval(checkInterval);
console.warn('⚠️ Token not received from Flutter');
this.isReady = true;
this.notifyReady();
}
}, 100);
}
private notifyReady() {
this.readyCallbacks.forEach(cb => cb());
this.readyCallbacks = [];
}
public onReady(callback: () => void) {
if (this.isReady) {
callback();
} else {
this.readyCallbacks.push(callback);
}
}
public getToken(): string | null {
return this.token;
}
public getCoins(): number {
return this.coins;
}
public isAuthenticated(): boolean {
return !!this.token;
}
}
export const authBridge = new AuthBridge();

6
src/lib/http.ts

@ -1,4 +1,5 @@
import axios, { type InternalAxiosRequestConfig } from "axios"; import axios, { type InternalAxiosRequestConfig } from "axios";
import { authBridge } from "./auth-bridge";
const PROXY_PATH_PARAM = "__proxyPath"; const PROXY_PATH_PARAM = "__proxyPath";
const LOCALHOST_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1"]); const LOCALHOST_HOSTNAMES = new Set(["localhost", "127.0.0.1", "::1"]);
@ -59,6 +60,11 @@ export const http = axios.create({
}); });
http.interceptors.request.use((config) => { http.interceptors.request.use((config) => {
const token = authBridge.getToken();
if (token) {
config.headers.Authorization = `Token ${token}`;
}
if (isLocalhost() && config.url && !isAbsoluteUrl(config.url)) { if (isLocalhost() && config.url && !isAbsoluteUrl(config.url)) {
config.params = withProxyPathParam(config.params, config.url); config.params = withProxyPathParam(config.params, config.url);
config.url = ""; config.url = "";

12
src/types/window.d.ts

@ -0,0 +1,12 @@
declare global {
interface Window {
HABIB_TOKEN?: string;
HABIB_COINS?: number;
onFlutterResponse?: (data: any) => void;
HabibApp?: {
postMessage: (message: string) => void;
};
}
}
export {};
Loading…
Cancel
Save