Rename service worker runtime and scope route persistence
This commit is contained in:
@@ -29,7 +29,7 @@ The library provides an `App` component that manages the application shell, rout
|
|||||||
```jsx
|
```jsx
|
||||||
import { App } from '@reliancy/bface/ui/App';
|
import { App } from '@reliancy/bface/ui/App';
|
||||||
import { CONFIG_KEYS } from '@reliancy/bface/platform/env';
|
import { CONFIG_KEYS } from '@reliancy/bface/platform/env';
|
||||||
import { registerServiceWorker } from '@reliancy/bface/platform/sw-register';
|
import { sw } from '@reliancy/bface/platform/worker';
|
||||||
|
|
||||||
async function handleInit(services, { initialProfile } = {}) {
|
async function handleInit(services, { initialProfile } = {}) {
|
||||||
// Application profile (camelCase or snake_case field names are accepted where noted in env mapping)
|
// Application profile (camelCase or snake_case field names are accepted where noted in env mapping)
|
||||||
@@ -49,7 +49,7 @@ async function handleInit(services, { initialProfile } = {}) {
|
|||||||
// await loadModule(moduleName, services);
|
// await loadModule(moduleName, services);
|
||||||
}
|
}
|
||||||
|
|
||||||
await registerServiceWorker();
|
await sw.registerServiceWorker();
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
@@ -65,12 +65,11 @@ function MyApp() {
|
|||||||
|
|
||||||
- **`services.api_client`** — HTTP client (`get`, `post`, …)
|
- **`services.api_client`** — HTTP client (`get`, `post`, …)
|
||||||
- **`services.storage`** — storage module (`getProvider`, …)
|
- **`services.storage`** — storage module (`getProvider`, …)
|
||||||
- **`services.api_router`** — placeholder for service-worker API routing (when available)
|
|
||||||
- **`services.ui_router`** — UI routing helpers
|
- **`services.ui_router`** — UI routing helpers
|
||||||
- **`services.menu`** — menu registration and queries
|
- **`services.menu`** — menu registration and queries
|
||||||
- **`services.env`** — `initEnv`, `getConfig`, `setConfig`, `CONFIG_KEYS`, tracing helpers, etc.
|
- **`services.env`** — `initEnv`, `getConfig`, `setConfig`, `CONFIG_KEYS`, tracing helpers, etc.
|
||||||
|
|
||||||
Service worker registration is **not** on `services`; import `registerServiceWorker` from `@reliancy/bface/platform/sw-register` (or the package root) and call it from `onInit` when you are ready.
|
Service worker registration is **not** on `services`; import `sw` from `@reliancy/bface/platform/worker` (or the package root) and call `sw.registerServiceWorker()` from `onInit` when you are ready. Service-worker API interception belongs in app/module `sw.js` files that run inside the worker.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
async function handleInit(services) {
|
async function handleInit(services) {
|
||||||
@@ -138,7 +137,7 @@ const menuItems = queryMenuItems('/primary');
|
|||||||
### Exports (`package.json` → `exports`)
|
### Exports (`package.json` → `exports`)
|
||||||
|
|
||||||
- **`@reliancy/bface`** — main entry: platform, `App`, UI components index, general settings, security, and data helpers
|
- **`@reliancy/bface`** — main entry: platform, `App`, UI components index, general settings, security, and data helpers
|
||||||
- **`@reliancy/bface/platform/*`** — platform modules (`env`, `api`, `storage`, `menu`, `sw-register`, `compat`, `host`, …)
|
- **`@reliancy/bface/platform/*`** — platform modules (`env`, `api`, `storage`, `menu`, `worker`, `compat`, `host`, …)
|
||||||
- **`@reliancy/bface/ui/*`** — UI entry points such as `App` and `components`
|
- **`@reliancy/bface/ui/*`** — UI entry points such as `App` and `components`
|
||||||
|
|
||||||
Security and data types are re-exported from the root entry; there are no separate `exports` subpaths for `./security/*` or `./data/*` today—import them from `@reliancy/bface` or add deep links if your bundler resolves source.
|
Security and data types are re-exported from the root entry; there are no separate `exports` subpaths for `./security/*` or `./data/*` today—import them from `@reliancy/bface` or add deep links if your bundler resolves source.
|
||||||
@@ -149,7 +148,7 @@ Security and data types are re-exported from the root entry; there are no separa
|
|||||||
- **`platform/api.js`** — API client
|
- **`platform/api.js`** — API client
|
||||||
- **`platform/storage.js`** — storage abstraction (localStorage, IndexedDB, OPFS)
|
- **`platform/storage.js`** — storage abstraction (localStorage, IndexedDB, OPFS)
|
||||||
- **`platform/menu.js`** — menu model and queries
|
- **`platform/menu.js`** — menu model and queries
|
||||||
- **`platform/sw-register.js`** — service worker registration and cache helpers
|
- **`platform/worker.js`** — browser worker/runtime helpers, currently exposed through the `sw` namespace
|
||||||
- **`platform/compat.js`** — environment detection and compatibility
|
- **`platform/compat.js`** — environment detection and compatibility
|
||||||
- **`platform/host.js`** — host detection (e.g. Electron)
|
- **`platform/host.js`** — host detection (e.g. Electron)
|
||||||
|
|
||||||
@@ -195,7 +194,7 @@ Here's a complete example of using the library in a project:
|
|||||||
// app.jsx
|
// app.jsx
|
||||||
import { App } from '@reliancy/bface/ui/App';
|
import { App } from '@reliancy/bface/ui/App';
|
||||||
import { CONFIG_KEYS } from '@reliancy/bface/platform/env';
|
import { CONFIG_KEYS } from '@reliancy/bface/platform/env';
|
||||||
import { registerServiceWorker } from '@reliancy/bface/platform/sw-register';
|
import { sw } from '@reliancy/bface/platform/worker';
|
||||||
|
|
||||||
async function loadProfile() {
|
async function loadProfile() {
|
||||||
// Load your app profile (from JSON, API, etc.)
|
// Load your app profile (from JSON, API, etc.)
|
||||||
@@ -225,7 +224,7 @@ async function handleInit(services, { initialProfile } = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. Register service worker
|
// 4. Register service worker
|
||||||
await registerServiceWorker();
|
await sw.registerServiceWorker();
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ export * from './platform/compat.js';
|
|||||||
export * from './platform/env.js';
|
export * from './platform/env.js';
|
||||||
export * from './platform/menu.js';
|
export * from './platform/menu.js';
|
||||||
export * from './platform/storage.js';
|
export * from './platform/storage.js';
|
||||||
export * from './platform/sw-register.js';
|
export * from './platform/worker.js';
|
||||||
export * from './data/index.js';
|
export * from './data/index.js';
|
||||||
|
|
||||||
// Re-export UI components
|
// Re-export UI components
|
||||||
|
|||||||
+28
-2
@@ -7,11 +7,20 @@
|
|||||||
* added when needed.
|
* added when needed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getConfig, setConfig } from './env.js';
|
import { CONFIG_KEYS, getConfig, setConfig } from './env.js';
|
||||||
import { getDesktopBridgeSafe, getHostKind, isElectronHost } from './host.js';
|
import { getDesktopBridgeSafe, getHostKind, isElectronHost } from './host.js';
|
||||||
|
|
||||||
// Config key for last visited route path
|
// Config key for last visited route path
|
||||||
const LAST_PATH_CONFIG_KEY = 'router.lastPath';
|
const LAST_PATH_CONFIG_KEY = 'router.lastPath';
|
||||||
|
const DEFAULT_APP_NAME = 'default';
|
||||||
|
|
||||||
|
async function getScopedLastPathConfigKey() {
|
||||||
|
const appName = await getConfig(CONFIG_KEYS.APP_NAME, DEFAULT_APP_NAME);
|
||||||
|
const normalizedAppName =
|
||||||
|
typeof appName === 'string' && appName.trim() ? appName.trim() : DEFAULT_APP_NAME;
|
||||||
|
|
||||||
|
return `${LAST_PATH_CONFIG_KEY}.${normalizedAppName}`;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Theme Detection (System Color Scheme)
|
// Theme Detection (System Color Scheme)
|
||||||
@@ -650,10 +659,21 @@ export async function getRouterPath(defaultPath = '/') {
|
|||||||
|
|
||||||
// If URL is empty or '/', check config for last visited path
|
// If URL is empty or '/', check config for last visited path
|
||||||
try {
|
try {
|
||||||
const lastPath = await getConfig(LAST_PATH_CONFIG_KEY, null);
|
const scopedLastPathKey = await getScopedLastPathConfigKey();
|
||||||
|
const lastPath = await getConfig(scopedLastPathKey, null);
|
||||||
if (lastPath && typeof lastPath === 'string' && lastPath !== '/') {
|
if (lastPath && typeof lastPath === 'string' && lastPath !== '/') {
|
||||||
return lastPath;
|
return lastPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep the old unscoped key only for the default app so existing installs
|
||||||
|
// continue to reopen their last route after the namespaced migration.
|
||||||
|
const appName = await getConfig(CONFIG_KEYS.APP_NAME, DEFAULT_APP_NAME);
|
||||||
|
if (appName === DEFAULT_APP_NAME) {
|
||||||
|
const legacyLastPath = await getConfig(LAST_PATH_CONFIG_KEY, null);
|
||||||
|
if (legacyLastPath && typeof legacyLastPath === 'string' && legacyLastPath !== '/') {
|
||||||
|
return legacyLastPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[Compat] Failed to get last path from config:', error);
|
console.warn('[Compat] Failed to get last path from config:', error);
|
||||||
}
|
}
|
||||||
@@ -694,7 +714,13 @@ export async function setRouterPath(path, replace = false, options = {}) {
|
|||||||
|
|
||||||
// Save to config for persistence (works on all platforms)
|
// Save to config for persistence (works on all platforms)
|
||||||
try {
|
try {
|
||||||
|
const scopedLastPathKey = await getScopedLastPathConfigKey();
|
||||||
|
await setConfig(scopedLastPathKey, fullPath);
|
||||||
|
|
||||||
|
const appName = await getConfig(CONFIG_KEYS.APP_NAME, DEFAULT_APP_NAME);
|
||||||
|
if (appName === DEFAULT_APP_NAME) {
|
||||||
await setConfig(LAST_PATH_CONFIG_KEY, fullPath);
|
await setConfig(LAST_PATH_CONFIG_KEY, fullPath);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[Compat] Failed to save path to config:', error);
|
console.warn('[Compat] Failed to save path to config:', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Service Worker Registration
|
* Browser worker/runtime helpers.
|
||||||
|
* Keep the top-level module compact, then expose focused namespaces that we
|
||||||
|
* can later split into separate files without changing the import surface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isElectronHost, isTauriHost } from './host.js';
|
import { isElectronHost, isTauriHost } from './host.js';
|
||||||
@@ -8,14 +10,12 @@ import { getConfig, isDevelopment, CONFIG_KEYS } from './env.js';
|
|||||||
const SW_PATH = '/sw.js';
|
const SW_PATH = '/sw.js';
|
||||||
const SW_SCOPE = '/';
|
const SW_SCOPE = '/';
|
||||||
const DEV_SW_RESET_KEY = '__bface_dev_sw_reset__';
|
const DEV_SW_RESET_KEY = '__bface_dev_sw_reset__';
|
||||||
/**
|
|
||||||
* Clear all caches
|
async function clearAllCaches() {
|
||||||
*/
|
|
||||||
export async function clearAllCaches() {
|
|
||||||
if ('caches' in window) {
|
if ('caches' in window) {
|
||||||
try {
|
try {
|
||||||
const cacheNames = await caches.keys();
|
const cacheNames = await caches.keys();
|
||||||
await Promise.all(cacheNames.map(name => {
|
await Promise.all(cacheNames.map((name) => {
|
||||||
console.log('[SW] Clearing cache:', name);
|
console.log('[SW] Clearing cache:', name);
|
||||||
return caches.delete(name);
|
return caches.delete(name);
|
||||||
}));
|
}));
|
||||||
@@ -29,14 +29,11 @@ export async function clearAllCaches() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function unregisterAllServiceWorkers() {
|
||||||
* Unregister all service workers
|
|
||||||
*/
|
|
||||||
export async function unregisterAllServiceWorkers() {
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
try {
|
try {
|
||||||
const registrations = await navigator.serviceWorker.getRegistrations();
|
const registrations = await navigator.serviceWorker.getRegistrations();
|
||||||
await Promise.all(registrations.map(reg => {
|
await Promise.all(registrations.map((reg) => {
|
||||||
console.log('[SW] Unregistering service worker:', reg.scope);
|
console.log('[SW] Unregistering service worker:', reg.scope);
|
||||||
return reg.unregister();
|
return reg.unregister();
|
||||||
}));
|
}));
|
||||||
@@ -50,25 +47,19 @@ export async function unregisterAllServiceWorkers() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function clearAllStorage() {
|
||||||
* Clear all storage (localStorage, sessionStorage, IndexedDB)
|
|
||||||
*/
|
|
||||||
export async function clearAllStorage() {
|
|
||||||
try {
|
try {
|
||||||
// Clear localStorage
|
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
console.log('[Storage] localStorage cleared');
|
console.log('[Storage] localStorage cleared');
|
||||||
|
|
||||||
// Clear sessionStorage
|
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
console.log('[Storage] sessionStorage cleared');
|
console.log('[Storage] sessionStorage cleared');
|
||||||
|
|
||||||
// Clear IndexedDB databases
|
|
||||||
if ('indexedDB' in window) {
|
if ('indexedDB' in window) {
|
||||||
const databases = await indexedDB.databases();
|
const databases = await indexedDB.databases();
|
||||||
await Promise.all(databases.map(db => {
|
await Promise.all(databases.map((db) => {
|
||||||
if (db.name) {
|
if (db.name) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve) => {
|
||||||
const deleteReq = indexedDB.deleteDatabase(db.name);
|
const deleteReq = indexedDB.deleteDatabase(db.name);
|
||||||
deleteReq.onsuccess = () => {
|
deleteReq.onsuccess = () => {
|
||||||
console.log(`[Storage] IndexedDB database "${db.name}" deleted`);
|
console.log(`[Storage] IndexedDB database "${db.name}" deleted`);
|
||||||
@@ -76,10 +67,11 @@ export async function clearAllStorage() {
|
|||||||
};
|
};
|
||||||
deleteReq.onerror = () => {
|
deleteReq.onerror = () => {
|
||||||
console.warn(`[Storage] Failed to delete IndexedDB database "${db.name}"`);
|
console.warn(`[Storage] Failed to delete IndexedDB database "${db.name}"`);
|
||||||
resolve(); // Continue even if one fails
|
resolve();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return Promise.resolve();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,25 +83,16 @@ export async function clearAllStorage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function clearPWACache() {
|
||||||
* Clear everything: caches, service workers, and storage
|
console.log('Clearing all PWA caches and storage...');
|
||||||
* This is the main utility function for clearing all PWA data
|
|
||||||
*/
|
|
||||||
export async function clearPWACache() {
|
|
||||||
console.log('🧹 Clearing all PWA caches and storage...');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Unregister service workers
|
|
||||||
const swCount = await unregisterAllServiceWorkers();
|
const swCount = await unregisterAllServiceWorkers();
|
||||||
|
|
||||||
// 2. Clear all caches
|
|
||||||
const cacheCount = await clearAllCaches();
|
const cacheCount = await clearAllCaches();
|
||||||
|
|
||||||
// 3. Clear all storage
|
|
||||||
await clearAllStorage();
|
await clearAllStorage();
|
||||||
|
|
||||||
console.log(`✅ PWA cache cleared: ${swCount} service worker(s), ${cacheCount} cache(s), and all storage`);
|
console.log(`PWA cache cleared: ${swCount} service worker(s), ${cacheCount} cache(s), and all storage`);
|
||||||
console.log('💡 Reload the page to re-register service workers');
|
console.log('Reload the page to re-register service workers');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
serviceWorkers: swCount,
|
serviceWorkers: swCount,
|
||||||
@@ -117,15 +100,12 @@ export async function clearPWACache() {
|
|||||||
storage: true
|
storage: true
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Failed to clear PWA cache:', error);
|
console.error('Failed to clear PWA cache:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function registerServiceWorker() {
|
||||||
* Register service worker
|
|
||||||
*/
|
|
||||||
export async function registerServiceWorker() {
|
|
||||||
if (isElectronHost() || isTauriHost()) {
|
if (isElectronHost() || isTauriHost()) {
|
||||||
await unregisterAllServiceWorkers();
|
await unregisterAllServiceWorkers();
|
||||||
console.log('[SW] Skipping service worker registration in desktop host');
|
console.log('[SW] Skipping service worker registration in desktop host');
|
||||||
@@ -140,19 +120,14 @@ export async function registerServiceWorker() {
|
|||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Register or get existing service worker
|
|
||||||
const registration = await navigator.serviceWorker.register(SW_PATH, {
|
const registration = await navigator.serviceWorker.register(SW_PATH, {
|
||||||
scope: SW_SCOPE,
|
scope: SW_SCOPE,
|
||||||
updateViaCache: 'none' // Always fetch fresh service worker
|
updateViaCache: 'none'
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Service Worker registered:', registration);
|
console.log('Service Worker registered:', registration);
|
||||||
|
|
||||||
// Force immediate update check to get latest version
|
|
||||||
await registration.update();
|
await registration.update();
|
||||||
|
|
||||||
// Handle updates
|
|
||||||
registration.addEventListener('updatefound', () => {
|
registration.addEventListener('updatefound', () => {
|
||||||
const newWorker = registration.installing;
|
const newWorker = registration.installing;
|
||||||
if (newWorker) {
|
if (newWorker) {
|
||||||
@@ -160,7 +135,6 @@ export async function registerServiceWorker() {
|
|||||||
if (newWorker.state === 'installed') {
|
if (newWorker.state === 'installed') {
|
||||||
if (navigator.serviceWorker.controller) {
|
if (navigator.serviceWorker.controller) {
|
||||||
console.log('[SW] New service worker available, reloading...');
|
console.log('[SW] New service worker available, reloading...');
|
||||||
// Force reload to activate new worker
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
} else {
|
} else {
|
||||||
console.log('[SW] Service worker installed for the first time');
|
console.log('[SW] Service worker installed for the first time');
|
||||||
@@ -175,17 +149,13 @@ export async function registerServiceWorker() {
|
|||||||
console.error('Service Worker registration failed:', error);
|
console.error('Service Worker registration failed:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
console.warn('Service Workers are not supported');
|
console.warn('Service Workers are not supported');
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function resetServiceWorkers() {
|
||||||
* In development, stale service workers can break Vite module loading by
|
|
||||||
* intercepting /@fs and related requests. Clear them once and reload cleanly.
|
|
||||||
*/
|
|
||||||
export async function resetServiceWorkers() {
|
|
||||||
if (isElectronHost() || isTauriHost()) {
|
if (isElectronHost() || isTauriHost()) {
|
||||||
await unregisterAllServiceWorkers();
|
await unregisterAllServiceWorkers();
|
||||||
return false;
|
return false;
|
||||||
@@ -215,7 +185,7 @@ export async function resetServiceWorkers() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServiceWorkerStatus() {
|
async function getServiceWorkerStatus() {
|
||||||
if (isElectronHost() || isTauriHost()) {
|
if (isElectronHost() || isTauriHost()) {
|
||||||
return 'Desktop Disabled';
|
return 'Desktop Disabled';
|
||||||
}
|
}
|
||||||
@@ -243,10 +213,7 @@ export async function getServiceWorkerStatus() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function unregisterServiceWorker() {
|
||||||
* Unregister service worker
|
|
||||||
*/
|
|
||||||
export async function unregisterServiceWorker() {
|
|
||||||
if (isElectronHost() || isTauriHost()) {
|
if (isElectronHost() || isTauriHost()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -260,3 +227,13 @@ export async function unregisterServiceWorker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sw = {
|
||||||
|
clearAllCaches,
|
||||||
|
unregisterAllServiceWorkers,
|
||||||
|
clearAllStorage,
|
||||||
|
clearPWACache,
|
||||||
|
registerServiceWorker,
|
||||||
|
resetServiceWorkers,
|
||||||
|
getServiceWorkerStatus,
|
||||||
|
unregisterServiceWorker
|
||||||
|
};
|
||||||
+8
-30
@@ -7,12 +7,8 @@
|
|||||||
import React, { createContext, useContext, useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
import React, { createContext, useContext, useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||||
import { TamaguiProvider, Theme, createTamagui, YStack } from 'tamagui';
|
import { TamaguiProvider, Theme, createTamagui, YStack } from 'tamagui';
|
||||||
import {
|
import {
|
||||||
clearPWACache,
|
sw
|
||||||
clearAllCaches,
|
} from '../platform/worker.js';
|
||||||
clearAllStorage,
|
|
||||||
getServiceWorkerStatus,
|
|
||||||
unregisterAllServiceWorkers
|
|
||||||
} from '../platform/sw-register.js';
|
|
||||||
import { getProvider } from '../platform/storage.js';
|
import { getProvider } from '../platform/storage.js';
|
||||||
import * as apiClient from '../platform/api.js';
|
import * as apiClient from '../platform/api.js';
|
||||||
import * as storageModuleRef from '../platform/storage.js';
|
import * as storageModuleRef from '../platform/storage.js';
|
||||||
@@ -215,27 +211,9 @@ function App({
|
|||||||
console.warn('[App] Failed to import Router module:', error);
|
console.warn('[App] Failed to import Router module:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get API router from service worker (if available)
|
|
||||||
let api_router = null;
|
|
||||||
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
|
|
||||||
// API Router is in service worker, modules will register via message passing
|
|
||||||
// or we expose a registration function
|
|
||||||
api_router = {
|
|
||||||
register: (path, handler) => {
|
|
||||||
// Register endpoint in SW router
|
|
||||||
// Note: For now, we'll need to handle this differently since
|
|
||||||
// functions can't be serialized. Modules should register routes
|
|
||||||
// in their routes.js files which get loaded into the SW.
|
|
||||||
console.log(`[API Router] Register endpoint: ${path}`);
|
|
||||||
// TODO: Implement proper SW router registration
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
api_client: apiClient.api, // Renamed from api
|
api_client: apiClient.api, // Renamed from api
|
||||||
storage: storageModuleRef,
|
storage: storageModuleRef,
|
||||||
api_router,
|
|
||||||
ui_router,
|
ui_router,
|
||||||
menu: menuRef,
|
menu: menuRef,
|
||||||
env: envModuleRef // New service
|
env: envModuleRef // New service
|
||||||
@@ -313,7 +291,7 @@ function App({
|
|||||||
appLogger.warn('Menu service not available');
|
appLogger.warn('Menu service not available');
|
||||||
}
|
}
|
||||||
|
|
||||||
setSwStatus(await getServiceWorkerStatus());
|
setSwStatus(await sw.getServiceWorkerStatus());
|
||||||
|
|
||||||
setInitialized(true);
|
setInitialized(true);
|
||||||
initTrace.end({
|
initTrace.end({
|
||||||
@@ -533,12 +511,12 @@ export { useApp, useTheme, THEME_MODES, themeManager as ThemeManager };
|
|||||||
|
|
||||||
// Expose PWA utilities globally for console access
|
// Expose PWA utilities globally for console access
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.clearPWACache = clearPWACache;
|
window.clearPWACache = sw.clearPWACache;
|
||||||
window.__PWA_UTILS__ = {
|
window.__PWA_UTILS__ = {
|
||||||
clearPWACache,
|
clearPWACache: sw.clearPWACache,
|
||||||
clearAllCaches,
|
clearAllCaches: sw.clearAllCaches,
|
||||||
unregisterAllServiceWorkers,
|
unregisterAllServiceWorkers: sw.unregisterAllServiceWorkers,
|
||||||
clearAllStorage
|
clearAllStorage: sw.clearAllStorage
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('💡 PWA Utilities available:');
|
console.log('💡 PWA Utilities available:');
|
||||||
|
|||||||
Reference in New Issue
Block a user