179 lines
5.3 KiB
JavaScript
179 lines
5.3 KiB
JavaScript
import { NodeStore } from '/js/{{ .VERSION }}/node_store.mjs'
|
|
|
|
const CACHE_NAME = 'notes2-{{ .VERSION }}'
|
|
const CACHED_ASSETS = [
|
|
'/',
|
|
'/offline',
|
|
|
|
'/css/{{ .VERSION }}/main.css',
|
|
'/css/{{ .VERSION }}/markdown.css',
|
|
'/css/{{ .VERSION }}/notes2.css',
|
|
'/css/{{ .VERSION }}/page_history.css',
|
|
'/css/{{ .VERSION }}/theme.css',
|
|
|
|
'/images/{{ .VERSION }}/collapsed.svg',
|
|
'/images/{{ .VERSION }}/expanded.svg',
|
|
'/images/{{ .VERSION }}/icon_back.svg',
|
|
'/images/{{ .VERSION }}/icon_history.svg',
|
|
'/images/{{ .VERSION }}/icon_home.svg',
|
|
'/images/{{ .VERSION }}/icon_markdown_hollow.svg',
|
|
'/images/{{ .VERSION }}/icon_markdown.svg',
|
|
'/images/{{ .VERSION }}/icon_menu.svg',
|
|
'/images/{{ .VERSION }}/icon_new_document.svg',
|
|
'/images/{{ .VERSION }}/icon_refresh.svg',
|
|
'/images/{{ .VERSION }}/icon_save_disabled.svg',
|
|
'/images/{{ .VERSION }}/icon_save.svg',
|
|
'/images/{{ .VERSION }}/icon_search.svg',
|
|
'/images/{{ .VERSION }}/icon_settings.svg',
|
|
'/images/{{ .VERSION }}/icon_storage.svg',
|
|
'/images/{{ .VERSION }}/icon_table.svg',
|
|
'/images/{{ .VERSION }}/icon_transfer.svg',
|
|
'/images/{{ .VERSION }}/leaf.svg',
|
|
'/images/{{ .VERSION }}/logo_small.svg',
|
|
'/images/{{ .VERSION }}/logo.svg',
|
|
|
|
'/js/{{ .VERSION }}/api.mjs',
|
|
'/js/{{ .VERSION }}/app.mjs',
|
|
'/js/{{ .VERSION }}/checklist.mjs',
|
|
'/js/{{ .VERSION }}/file.mjs',
|
|
'/js/{{ .VERSION }}/lib/css_colorize.mjs',
|
|
'/js/{{ .VERSION }}/lib/custom_html_element.mjs',
|
|
'/js/{{ .VERSION }}/lib/node_modules/marked/lib/marked.esm.js',
|
|
'/js/{{ .VERSION }}/lib/node_modules/marked-token-position/lib/index.esm.js',
|
|
'/js/{{ .VERSION }}/marked_position.mjs',
|
|
'/js/{{ .VERSION }}/mbus.mjs',
|
|
'/js/{{ .VERSION }}/node_store.mjs',
|
|
'/js/{{ .VERSION }}/notes2.mjs',
|
|
'/js/{{ .VERSION }}/page_history.mjs',
|
|
'/js/{{ .VERSION }}/page_node.mjs',
|
|
'/js/{{ .VERSION }}/page_preferences.mjs',
|
|
'/js/{{ .VERSION }}/page_storage.mjs',
|
|
'/js/{{ .VERSION }}/sidebar.mjs',
|
|
'/js/{{ .VERSION }}/sync.mjs',
|
|
]
|
|
|
|
async function precache() {
|
|
const cache = await caches.open(CACHE_NAME)
|
|
return cache.addAll(CACHED_ASSETS)
|
|
}
|
|
|
|
async function fetchAsset(event) {
|
|
try {
|
|
const cache = await caches.open(CACHE_NAME)
|
|
const match = await cache.match(event.request)
|
|
|
|
if (match !== undefined) {
|
|
// -----------------------------------------------
|
|
// This page is precached - return it immediately.
|
|
// -----------------------------------------------
|
|
console.debug('From cache', event.request.url)
|
|
return match
|
|
} else {
|
|
// ---------------------------------------------------------------
|
|
// Not in cache - send it for an online request/browser cache hit.
|
|
// ---------------------------------------------------------------
|
|
console.debug('From network', event.request.url)
|
|
const resp = await fetch(event.request)
|
|
|
|
// This will trigger on an HTTP error such as 502.
|
|
if (!resp.ok) {
|
|
console.error('HTTP error', resp.status)
|
|
|
|
// When JSON is expected, return that instead of the offline HTML page.
|
|
return await offline(event, `${resp.status} ${resp.statusText}`)
|
|
}
|
|
return resp
|
|
}
|
|
} catch (e) {
|
|
// An error here is something like a DNS problem, not a regular HTTP problem.
|
|
console.error('Network error', e, event.request.url)
|
|
return await offline(event, e)
|
|
}
|
|
}
|
|
|
|
async function offline(event, errText) {
|
|
if (event.request.headers.get('X-JSON')) {
|
|
return new Response('{ "OK": false, "Error": "Network is offline"}', { headers: { 'Content-Type': 'application/json' } })
|
|
}
|
|
|
|
const cache = await caches.open(CACHE_NAME)
|
|
const offline = await cache.match('/offline')
|
|
let body = await offline.text()
|
|
body = body.replace('||ERROR||', errText)
|
|
return new Response(body, { headers: { 'Content-Type': 'text/html' } })
|
|
}
|
|
|
|
async function cleanupCache() {
|
|
const keys = await caches.keys()
|
|
const keysToDelete = keys.map(key => {
|
|
if (key !== CACHE_NAME)
|
|
return caches.delete(key)
|
|
})
|
|
return Promise.all(keysToDelete)
|
|
}
|
|
|
|
self.addEventListener('install', event => {
|
|
console.debug('SERVICE WORKER: install')
|
|
self.skipWaiting()
|
|
event.waitUntil(precache())
|
|
})
|
|
|
|
self.addEventListener('activate', event => {
|
|
console.debug('SERVICE WORKER: activate')
|
|
self.clients.claim()
|
|
event.waitUntil(cleanupCache())
|
|
})
|
|
|
|
self.addEventListener('fetch', event => {
|
|
const url = new URL(event.request.url)
|
|
|
|
// The fetch event is also seeing requests to other domains.
|
|
// Just let the browser handle those for itself.
|
|
const ourDomain = (url.host == self.location.host)
|
|
if (!ourDomain)
|
|
return event
|
|
|
|
if (url.pathname == '/stream-local') {
|
|
event.respondWith(indexeddbFile(event))
|
|
return
|
|
}
|
|
|
|
if (`{{ .DevMode }}` == 'true')
|
|
return event
|
|
else
|
|
event.respondWith(fetchAsset(event))
|
|
})
|
|
|
|
|
|
let nodestore = null
|
|
async function getNodestore() {
|
|
if (nodestore)
|
|
return nodestore
|
|
|
|
// When setting nodestore directly, then waiting on initializeDB,
|
|
// a second call for getNodestore can return the nodestore before
|
|
// initialized.
|
|
const initializingNodeStore = new NodeStore()
|
|
await initializingNodeStore.initializeDB()
|
|
nodestore = initializingNodeStore
|
|
return nodestore
|
|
}
|
|
|
|
async function indexeddbFile(event) {
|
|
const url = new URL(event.request.url)
|
|
const uuid = url.searchParams.get('uuid')
|
|
|
|
try {
|
|
const nodeStore = await getNodestore()
|
|
const md = await nodeStore.filesMetadata.get(uuid)
|
|
const stream = await nodeStore.fileSegments.getStream(uuid)
|
|
|
|
return new Response(stream, {
|
|
headers: {
|
|
'Content-Type': md.type,
|
|
}
|
|
})
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
}
|