feat(notifications): add localStorage debug config for notification API base URL
Introduce NotificationDebugConfig so register/refresh use getNotificationApiBaseUrl() (APP_SERVER by default, optional LAN/ngrok override) and configurable testMode without rebuilds.
This commit is contained in:
@@ -16,6 +16,10 @@ import type { PushNotificationSchema } from "@capacitor/push-notifications";
|
|||||||
import { DailyNotification } from "@/plugins/DailyNotificationPlugin";
|
import { DailyNotification } from "@/plugins/DailyNotificationPlugin";
|
||||||
import { REMINDER_ID_DAILY_REMINDER } from "./reminderIds";
|
import { REMINDER_ID_DAILY_REMINDER } from "./reminderIds";
|
||||||
import { configureNativeFetcherIfReady } from "./nativeFetcherConfig";
|
import { configureNativeFetcherIfReady } from "./nativeFetcherConfig";
|
||||||
|
import {
|
||||||
|
getNotificationApiBaseUrl,
|
||||||
|
getTestMode,
|
||||||
|
} from "./NotificationDebugConfig";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended type for DailyNotification that includes the actual Swift implementation
|
* Extended type for DailyNotification that includes the actual Swift implementation
|
||||||
@@ -555,12 +559,13 @@ export async function refreshNotifications(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/notifications/refresh", {
|
const baseUrl = getNotificationApiBaseUrl();
|
||||||
|
const res = await fetch(`${baseUrl}/notifications/refresh`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
platform: Capacitor.getPlatform(),
|
platform: Capacitor.getPlatform(),
|
||||||
testMode: true,
|
testMode: getTestMode(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Lightweight debug configuration for notification backend testing.
|
||||||
|
* Persists overrides in localStorage; production defaults apply when unset.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { APP_SERVER } from "@/constants/app";
|
||||||
|
|
||||||
|
const LOG = "[NotificationDebug]";
|
||||||
|
const STORAGE_KEY_BACKEND_URL = "notificationDebug.backendBaseUrl";
|
||||||
|
const STORAGE_KEY_TEST_MODE = "notificationDebug.testMode";
|
||||||
|
|
||||||
|
/** Trim whitespace, drop trailing slash; empty input becomes null. */
|
||||||
|
export function normalizeNotificationBackendUrl(url: string): string | null {
|
||||||
|
const trimmed = url.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return trimmed.replace(/\/$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStorage(key: string): string | null {
|
||||||
|
if (typeof localStorage === "undefined") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(key);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeStorage(key: string, value: string | null): void {
|
||||||
|
if (typeof localStorage === "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (value === null) {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Quota / privacy mode — ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Backend URL override, or null when using the default app server. */
|
||||||
|
export function getBackendBaseUrl(): string | null {
|
||||||
|
const raw = readStorage(STORAGE_KEY_BACKEND_URL);
|
||||||
|
if (raw === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return normalizeNotificationBackendUrl(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setBackendBaseUrl(url: string): void {
|
||||||
|
const normalized = normalizeNotificationBackendUrl(url);
|
||||||
|
if (normalized === null) {
|
||||||
|
writeStorage(STORAGE_KEY_BACKEND_URL, null);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`${LOG} backend URL cleared (using default)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writeStorage(STORAGE_KEY_BACKEND_URL, normalized);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`${LOG} backend URL set to ${normalized}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When never configured via debug UI/console, matches prior hardcoded `testMode: true`.
|
||||||
|
*/
|
||||||
|
export function getTestMode(): boolean {
|
||||||
|
const raw = readStorage(STORAGE_KEY_TEST_MODE);
|
||||||
|
if (raw === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return raw === "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setTestMode(enabled: boolean): void {
|
||||||
|
writeStorage(STORAGE_KEY_TEST_MODE, enabled ? "true" : "false");
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`${LOG} test mode ${enabled ? "enabled" : "disabled"}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base URL for `/notifications/*` API calls.
|
||||||
|
* Uses debug override when set; otherwise the built-in app server (production default).
|
||||||
|
*/
|
||||||
|
export function getNotificationApiBaseUrl(): string {
|
||||||
|
const override = getBackendBaseUrl();
|
||||||
|
if (override) {
|
||||||
|
return override;
|
||||||
|
}
|
||||||
|
return normalizeNotificationBackendUrl(APP_SERVER) ?? APP_SERVER;
|
||||||
|
}
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
import { Capacitor } from "@capacitor/core";
|
import { Capacitor } from "@capacitor/core";
|
||||||
import { logger } from "@/utils/logger";
|
import { logger } from "@/utils/logger";
|
||||||
import { getOrCreateDeviceId } from "./deviceId";
|
import { getOrCreateDeviceId } from "./deviceId";
|
||||||
|
import {
|
||||||
|
getNotificationApiBaseUrl,
|
||||||
|
getTestMode,
|
||||||
|
} from "./NotificationDebugConfig";
|
||||||
import { NativeNotificationService } from "./NativeNotificationService";
|
import { NativeNotificationService } from "./NativeNotificationService";
|
||||||
import { WebPushNotificationService } from "./WebPushNotificationService";
|
import { WebPushNotificationService } from "./WebPushNotificationService";
|
||||||
|
|
||||||
@@ -24,14 +28,15 @@ import { WebPushNotificationService } from "./WebPushNotificationService";
|
|||||||
*/
|
*/
|
||||||
export async function registerToken(fcmToken: string): Promise<void> {
|
export async function registerToken(fcmToken: string): Promise<void> {
|
||||||
const deviceId = await getOrCreateDeviceId();
|
const deviceId = await getOrCreateDeviceId();
|
||||||
const res = await fetch("/notifications/register", {
|
const baseUrl = getNotificationApiBaseUrl();
|
||||||
|
const res = await fetch(`${baseUrl}/notifications/register`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
deviceId,
|
deviceId,
|
||||||
fcmToken,
|
fcmToken,
|
||||||
platform: Capacitor.getPlatform(),
|
platform: Capacitor.getPlatform(),
|
||||||
testMode: true,
|
testMode: getTestMode(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
|||||||
@@ -13,6 +13,14 @@
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export {
|
||||||
|
getBackendBaseUrl,
|
||||||
|
getNotificationApiBaseUrl,
|
||||||
|
getTestMode,
|
||||||
|
normalizeNotificationBackendUrl,
|
||||||
|
setBackendBaseUrl,
|
||||||
|
setTestMode,
|
||||||
|
} from "./NotificationDebugConfig";
|
||||||
export { NotificationService, registerToken } from "./NotificationService";
|
export { NotificationService, registerToken } from "./NotificationService";
|
||||||
export { NativeNotificationService } from "./NativeNotificationService";
|
export { NativeNotificationService } from "./NativeNotificationService";
|
||||||
export { WebPushNotificationService } from "./WebPushNotificationService";
|
export { WebPushNotificationService } from "./WebPushNotificationService";
|
||||||
|
|||||||
Reference in New Issue
Block a user