Compare commits

..

No commits in common. "c21d21015f7ab98ba8d4d6199360827afe62a60d" and "5669489dc9284af55d8fd7bdd1726b442d12fac1" have entirely different histories.

7 changed files with 4 additions and 122 deletions

View file

@ -1,13 +0,0 @@
.island__is_online {
position: sticky;
top: 0;
width: 100%;
text-align: center;
padding: var(--_gap-half);
/* invert accent color */
background: hsl(from #82c91e calc(h + 180) s l / 1);
font-family: var(--_font-family-accent);
color: white;
font-weight: bold;
z-index: 9999;
}

View file

@ -1,52 +0,0 @@
import { type Signal, useSignal } from '@preact/signals'
import { useEffect } from 'preact/hooks'
import { JSX } from 'preact'
import { requestApi } from ':src/utils.ts'
type NetworkConnection = {
addEventListener: (
type: 'change',
listener: (event: Event) => void | Promise<void>,
) => void
}
export default function IsOnline(
{ online, offline }: { online?: string; offline: string },
) {
const status = useSignal(offline)
const connection = 'connection' in navigator
? navigator.connection as NetworkConnection
: null
useEffect(() => {
// Update connection status on network changes
connection?.addEventListener('change', () => {
updateNetworkStatus(status, online, offline)
})
// Update connection status on 1st load
updateNetworkStatus(status, online, offline)
// Update connection status on interval (10s)
setInterval(() => updateNetworkStatus(status, online, offline), 10_000)
})
return <>{status}</>
}
async function updateNetworkStatus(
status: Signal<JSX.Element>,
online: string | undefined,
offline: string,
) {
const isOnline = await requestApi<void, boolean>(
'/serviceworker/is-online',
'POST',
).catch(() => false)
if (isOnline) {
status.value = online === undefined
? <span style={{ display: 'none' }}></span>
: <span>{online}</span>
} else {
status.value = <span class={'island__is_online'}>{offline}</span>
}
}

View file

@ -3,7 +3,6 @@ import { type PageProps } from '$fresh/server.ts'
import { Footer } from ':components/Footer.tsx' import { Footer } from ':components/Footer.tsx'
import { Header } from ':components/Header.tsx' import { Header } from ':components/Header.tsx'
import { ProgressiveWebApp } from ':components/ProgressiveWebApp.tsx' import { ProgressiveWebApp } from ':components/ProgressiveWebApp.tsx'
import IsOnline from ':islands/IsOnline.tsx'
export default function App({ Component }: PageProps) { export default function App({ Component }: PageProps) {
return ( return (
@ -43,9 +42,6 @@ export default function App({ Component }: PageProps) {
</Head> </Head>
<body> <body>
<Header /> <Header />
<IsOnline
offline={'Vous êtes hors ligne / Serveur inaccessible'}
/>
<main f-client-nav> <main f-client-nav>
<Partial name='main'> <Partial name='main'>
<Component /> <Component />

View file

@ -1,9 +0,0 @@
import { SessionHandlers } from ':src/session/mod.ts'
import { respondApi } from ':src/utils.ts'
export const handler: SessionHandlers = {
POST() {
// Check if server is online
return respondApi<'success', true>('success', true)
},
}

View file

@ -1,16 +1,11 @@
import { expandGlob } from '$std/fs/mod.ts' import { expandGlob } from '$std/fs/mod.ts'
import { SessionHandlers } from ':src/session/mod.ts' import { SessionHandlers } from ':src/session/mod.ts'
import { respondApi } from ':src/utils.ts' import { respondApi } from ':src/utils.ts'
import { BUILD_ID } from '$fresh/src/server/build_id.ts'
import { encodeBase64 } from '@std/encoding'
export type PrecacheResponse = { version: string; preCachedUrls: string[] } export type PrecacheResponse = { version: string; preCachedUrls: string[] }
async function getVersion() { // Updated only at server start
const versionBytes = new TextEncoder().encode(BUILD_ID) const version = crypto.randomUUID()
const versionHash = await crypto.subtle.digest('SHA-256', versionBytes)
return encodeBase64(versionHash)
}
export const handler: SessionHandlers = { export const handler: SessionHandlers = {
async GET() { async GET() {
@ -18,7 +13,6 @@ export const handler: SessionHandlers = {
const preCachedUrls: string[] = ['/', '/imports/markdown_css'] const preCachedUrls: string[] = ['/', '/imports/markdown_css']
const paths = ['/static/**', '/_fresh/static/**'] const paths = ['/static/**', '/_fresh/static/**']
const routes = '/routes/*/index.tsx' const routes = '/routes/*/index.tsx'
const version = await getVersion()
//Pre-cache routes //Pre-cache routes
for await (const route of expandGlob(routes, { root: '.' })) { for await (const route of expandGlob(routes, { root: '.' })) {

View file

@ -69,7 +69,6 @@ if (IS_SW) {
}) })
self.addEventListener('push', (event) => { self.addEventListener('push', (event) => {
console.log('push')
const { title, options } = (event.data?.json() ?? {}) as { const { title, options } = (event.data?.json() ?? {}) as {
title?: string title?: string
options?: Partial<NotificationOptions> options?: Partial<NotificationOptions>
@ -87,15 +86,11 @@ async function fetchHandler(event: FetchEvent) {
const method = event.request.method const method = event.request.method
const preCachedUrls = await getPreCachedUrls() const preCachedUrls = await getPreCachedUrls()
const cache = await getCache() const cache = await getCache()
// Cache will be updated on each request if version change
updateCache()
// Cache first for "pre-cached-urls" // Cache first for "pre-cached-urls"
if (preCachedUrls.includes(url.pathname) && method === 'GET') { if (preCachedUrls.includes(url.pathname) && method === 'GET') {
const cached = await cache.match(event.request) ?? const cached = await cache.match(event.request) ??
await fetch(event.request).then((response) => await fetch(event.request).catch(() => null) ??
response.ok ? response : null
).catch(() => null) ??
await cache.match(event.request, { ignoreSearch: true }) await cache.match(event.request, { ignoreSearch: true })
if (cached === undefined) { if (cached === undefined) {
@ -110,12 +105,7 @@ async function fetchHandler(event: FetchEvent) {
const response = fetch(event.request) const response = fetch(event.request)
.then((response) => { .then((response) => {
if (!response.ok) { // Update cache
throw new Error(
`failed to get request: [${response.status}] ${response.statusText}`,
)
}
// Update cache if ok
cache.put(event.request, response.clone()) cache.put(event.request, response.clone())
return response return response
}) })
@ -138,29 +128,6 @@ async function fetchHandler(event: FetchEvent) {
return fetch(event.request) return fetch(event.request)
} }
async function updateCache() {
const serverVersion = await getServerCacheVersion()
const clientVersion = await swStorage.getItem<string>('$sw.cache.version')
if (clientVersion === null) return
if (serverVersion === undefined) return
if (clientVersion === serverVersion) return
// Open new pre-cache
await openCache()
// Delete old pre-cache
caches.delete(clientVersion)
}
async function getServerCacheVersion() {
const response = await fetch('/api/serviceworker/precache').then(
(response) => response.json() as Promise<ApiPayload<PrecacheResponse>>,
)
if (response.kind === 'success') {
return response.data.version
}
}
async function openCache() { async function openCache() {
const response = await fetch('/api/serviceworker/precache').then( const response = await fetch('/api/serviceworker/precache').then(
(response) => response.json() as Promise<ApiPayload<PrecacheResponse>>, (response) => response.json() as Promise<ApiPayload<PrecacheResponse>>,

View file

@ -13,4 +13,3 @@
@import url('../../islands/MoreBox.css'); @import url('../../islands/MoreBox.css');
@import url('../../islands/AiChatBox.css'); @import url('../../islands/AiChatBox.css');
@import url('../../islands/LoginForm.css'); @import url('../../islands/LoginForm.css');
@import url('../../islands/IsOnline.css');