The origin of my question comes from loading in a manifest object since the request url requires an authorization header.
I can fetch the a valid IIIF manifest but have not found a way to pass it into Universal Viewer.
The only valid option for IIIF what I have found is passing the URL via iiifManifestId
as option
import { init } from 'universalviewer'
init('uv-viewer', {
iiifManifestId: myManifestUrl
})
From the examples of the repo manifest
is used but that should not make a difference with iiifManifestId
according to UniversalViewer.ts#L57
What I want to be able to do is something like:
import { init } from 'universalviewer'
const myManifestData = await getManifest(myManifestUrl)
init('uv-viewer', {
iiifManifestData: myManifestData
})
OR like what Mirador Viewer does:
import { init } from 'universalviewer'
init('uv-viewer', {
iiifManifestId: myManifestUrl,
requests: {
preprocessors: [
(options) => {
return {
...options,
headers: { authorization: 'Bearer ' + getToken() },
}
},
],
},
})
I have seen GitHub issue #43 witch could resolve this issue.
However due to the lack of my understanding of Universal Viewer I wont be continuing that route. Unless the maintainers agree on my findings (in said issue).
Conal-Tuohy commented on Sep 18
Having read your Stack Overflow post, I now see that your use case is different to the one originally raised in this issue: it's actually about authentication is it not?
A Service Worker might be a good way to intercept and authenticate the HTTPS requests made by UV
A Service Worker resolves the issue to add an authorization header to the request for Universal Vieuwer. Below you can see my implementation of the Service Worker, registration, and initialization.
I explained what is going on in the comments in the code.
UniversalViewer.worker.js
self.addEventListener('install', () => {
// Skip over the "waiting" lifecycle state, to ensure that our
// new service worker is activated immediately, even if there's
// another tab open controlled by our older service worker code.
self.skipWaiting()
})
self.addEventListener('activate', () => {
// Optional: Get a list of all the current open windows/tabs under
// our service worker's control, and force them to reload.
// This can "unbreak" any open windows/tabs as soon as the new
// service worker activates, rather than users having to manually reload.
self.clients.matchAll({ type: 'window' }).then((windowClients) => {
windowClients.forEach((windowClient) => {
windowClient.navigate(windowClient.url)
})
})
})
self.addEventListener('message', (event) => {
if (event.data?.source === 'universal-viewer') {
token = `${event.data.token}`
}
})
// NOTE: My regexp is more complex but it is a start to identify the iiif manifest
const manifestRegexp =
/\/iiif\/[0-9]\/manifest\.json$/
/**
* Catches fetch events and checks if request is made by UniversalViewer
* @param {FetchEvent} event
*/
const fetchEvent = async (event) => {
// Stop modification for requests that are not fit the expected iiif manifest url
if (manifestRegexp.test(event.request.url) !== true) {
return
}
const modifiedRequest = new Request(event.request, {
headers: {
authorization: token,
},
})
event.respondWith(fetch(modifiedRequest))
}
self.addEventListener('fetch', fetchEvent)
UniversalViewer.register.ts
const name = 'UniversalViewer Worker'
export const registerUniversalViewerWorker = (token = 'No Provider') => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/UniversalViewer.worker.js', {
scope: '/',
updateViaCache: 'none',
})
.then((registration) => {
console.log(`${name} registered service worker`)
registration.update()
console.log(`${name} updated service worker`)
registration.active?.postMessage({
source: 'universal-viewer',
token: `Bearer ${token}`,
})
})
}
}
main.ts // NOTE: this is a simplified example on my implementation
import { registerUniversalViewerWorker } from './UniversalViewer.register'
initAuthProfider().then((provider) => {
// other code you do with your provider
registerUniversalViewerWorker(provider.token)
})