@openmrs/esm-app-shell 5.3.3-pre.1231 → 5.3.3-pre.1247
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +98 -98
- package/dist/9c276181fc6599f8.js.map +1 -0
- package/dist/d81faa62d5818f52.js.map +1 -0
- package/dist/index.html +1 -1
- package/dist/{openmrs.954886865de0b85a.js → openmrs.6213811dbd70a295.js} +2 -2
- package/dist/openmrs.6213811dbd70a295.js.map +1 -0
- package/dist/openmrs.c9c4fe7ea57e9920.css.map +1 -1
- package/dist/service-worker.js +1 -1
- package/dist/service-worker.js.map +1 -1
- package/lib/{3975decbab0164f3.js → 9b51c0739002f900.js} +1 -1
- package/lib/{f29978db163aaa3d.js → c074b9133e91fad3.js} +5 -5
- package/lib/esm-devtools-app/68.js.map +1 -1
- package/lib/esm-devtools-app/889.js +1 -1
- package/lib/esm-devtools-app/988.js.map +1 -1
- package/lib/esm-devtools-app/main.js +1 -1
- package/lib/esm-devtools-app/main.js.map +1 -1
- package/lib/esm-devtools-app/openmrs-esm-devtools-app.js +1 -1
- package/lib/esm-devtools-app/openmrs-esm-devtools-app.js.buildmanifest.json +5 -5
- package/lib/esm-devtools-app/routes.json +1 -1
- package/lib/esm-implementer-tools-app/426.js.map +1 -1
- package/lib/esm-implementer-tools-app/560.js +1 -1
- package/lib/esm-implementer-tools-app/560.js.map +1 -1
- package/lib/esm-implementer-tools-app/587.js.map +1 -1
- package/lib/esm-implementer-tools-app/727.js +1 -1
- package/lib/esm-implementer-tools-app/727.js.map +1 -1
- package/lib/esm-implementer-tools-app/main.js +1 -1
- package/lib/esm-implementer-tools-app/main.js.map +1 -1
- package/lib/esm-implementer-tools-app/openmrs-esm-implementer-tools-app.js +1 -1
- package/lib/esm-implementer-tools-app/openmrs-esm-implementer-tools-app.js.buildmanifest.json +13 -13
- package/lib/esm-implementer-tools-app/routes.json +1 -1
- package/lib/esm-login-app/370.js +1 -1
- package/lib/esm-login-app/370.js.map +1 -1
- package/lib/esm-login-app/main.js +1 -1
- package/lib/esm-login-app/main.js.map +1 -1
- package/lib/esm-login-app/openmrs-esm-login-app.js +1 -1
- package/lib/esm-login-app/openmrs-esm-login-app.js.buildmanifest.json +8 -8
- package/lib/esm-login-app/routes.json +1 -1
- package/lib/esm-offline-tools-app/102.js +1 -1
- package/lib/esm-offline-tools-app/102.js.map +1 -1
- package/lib/esm-offline-tools-app/main.js +1 -1
- package/lib/esm-offline-tools-app/main.js.map +1 -1
- package/lib/esm-offline-tools-app/openmrs-esm-offline-tools-app.js +1 -1
- package/lib/esm-offline-tools-app/openmrs-esm-offline-tools-app.js.buildmanifest.json +8 -8
- package/lib/esm-offline-tools-app/routes.json +1 -1
- package/lib/esm-primary-navigation-app/735.js +1 -1
- package/lib/esm-primary-navigation-app/735.js.map +1 -1
- package/lib/esm-primary-navigation-app/main.js +1 -1
- package/lib/esm-primary-navigation-app/main.js.map +1 -1
- package/lib/esm-primary-navigation-app/openmrs-esm-primary-navigation-app.js +1 -1
- package/lib/esm-primary-navigation-app/openmrs-esm-primary-navigation-app.js.buildmanifest.json +8 -8
- package/lib/esm-primary-navigation-app/routes.json +1 -1
- package/lib/index.html +1 -1
- package/lib/openmrs.js +135 -135
- package/lib/service-worker.js +9 -9
- package/package.json +3 -3
- package/src/apps.ts +32 -72
- package/src/declarations.d.ts +3 -6
- package/src/helpers.ts +2 -4
- package/src/index.ts +13 -15
- package/src/locale.ts +24 -34
- package/src/run.ts +53 -87
- package/src/service-worker/caching.ts +14 -22
- package/src/service-worker/constants.ts +8 -13
- package/src/service-worker/http-header-utils.ts +5 -15
- package/src/service-worker/import-map-utils.ts +14 -25
- package/src/service-worker/index.ts +8 -8
- package/src/service-worker/message.ts +9 -15
- package/src/service-worker/routing.ts +23 -50
- package/src/service-worker/storage.ts +5 -5
- package/src/service-worker/types.ts +1 -1
- package/src/ui/breadcrumbs.tsx +14 -29
- package/src/ui/index.ts +6 -6
- package/tools/helpers.js +3 -7
- package/webpack.config.js +95 -117
- package/dist/966c4dfec919951f.js.map +0 -1
- package/dist/fca8d09359d3b887.js.map +0 -1
- package/dist/openmrs.954886865de0b85a.js.map +0 -1
- /package/dist/{fca8d09359d3b887.js → 9c276181fc6599f8.js} +0 -0
- /package/dist/{966c4dfec919951f.js → d81faa62d5818f52.js} +0 -0
- /package/dist/{openmrs.954886865de0b85a.js.LICENSE.txt → openmrs.6213811dbd70a295.js.LICENSE.txt} +0 -0
package/src/run.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { start, triggerAppChange } from
|
|
1
|
+
import { start, triggerAppChange } from 'single-spa';
|
|
2
2
|
import {
|
|
3
3
|
setupApiModule,
|
|
4
4
|
renderLoadingSpinner,
|
|
@@ -31,19 +31,15 @@ import {
|
|
|
31
31
|
OpenmrsRoutes,
|
|
32
32
|
getCurrentImportMap,
|
|
33
33
|
importDynamic,
|
|
34
|
-
} from
|
|
35
|
-
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
tryRegisterExtension,
|
|
39
|
-
} from "./apps";
|
|
40
|
-
import { setupI18n } from "./locale";
|
|
41
|
-
import { appName, getCoreExtensions } from "./ui";
|
|
34
|
+
} from '@openmrs/esm-framework/src/internal';
|
|
35
|
+
import { finishRegisteringAllApps, registerApp, tryRegisterExtension } from './apps';
|
|
36
|
+
import { setupI18n } from './locale';
|
|
37
|
+
import { appName, getCoreExtensions } from './ui';
|
|
42
38
|
|
|
43
39
|
// @internal
|
|
44
40
|
// used to track when the window.installedModules global is finalised
|
|
45
41
|
// so we can pre-load all modules
|
|
46
|
-
const REGISTRATION_PROMISES = Symbol(
|
|
42
|
+
const REGISTRATION_PROMISES = Symbol('openmrs_registration_promises');
|
|
47
43
|
|
|
48
44
|
/**
|
|
49
45
|
* Sets up the frontend modules (apps). Uses the defined export
|
|
@@ -52,9 +48,7 @@ const REGISTRATION_PROMISES = Symbol("openmrs_registration_promises");
|
|
|
52
48
|
* as the registry of all apps in the application.
|
|
53
49
|
*/
|
|
54
50
|
async function setupApps() {
|
|
55
|
-
const scriptTags = document.querySelectorAll<HTMLScriptElement>(
|
|
56
|
-
"script[type='openmrs-routes']"
|
|
57
|
-
);
|
|
51
|
+
const scriptTags = document.querySelectorAll<HTMLScriptElement>("script[type='openmrs-routes']");
|
|
58
52
|
|
|
59
53
|
const promises: Array<Promise<OpenmrsRoutes>> = [];
|
|
60
54
|
for (let i = 0; i < scriptTags.length; i++) {
|
|
@@ -68,33 +62,26 @@ async function setupApps() {
|
|
|
68
62
|
routes = (await openmrsFetch<OpenmrsRoutes>(scriptTag.src)).data;
|
|
69
63
|
}
|
|
70
64
|
} catch (e) {
|
|
71
|
-
console.error(
|
|
72
|
-
`Caught error while loading routes from ${
|
|
73
|
-
scriptTag.src ?? "JSON script tag content"
|
|
74
|
-
}`,
|
|
75
|
-
e
|
|
76
|
-
);
|
|
65
|
+
console.error(`Caught error while loading routes from ${scriptTag.src ?? 'JSON script tag content'}`, e);
|
|
77
66
|
|
|
78
67
|
return {};
|
|
79
68
|
}
|
|
80
69
|
|
|
81
70
|
return Promise.resolve(routes ?? {});
|
|
82
|
-
})(scriptTags.item(i))
|
|
71
|
+
})(scriptTags.item(i)),
|
|
83
72
|
);
|
|
84
73
|
}
|
|
85
74
|
|
|
86
75
|
const routes = (await Promise.all(promises)).reduce(
|
|
87
76
|
(accumulatedRoutes, routes) => ({ ...accumulatedRoutes, ...routes }),
|
|
88
|
-
{}
|
|
77
|
+
{},
|
|
89
78
|
);
|
|
90
79
|
|
|
91
80
|
const modules: typeof window.installedModules = [];
|
|
92
|
-
const registrationPromises = Object.entries(routes).map(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
);
|
|
81
|
+
const registrationPromises = Object.entries(routes).map(async ([module, routes]) => {
|
|
82
|
+
modules.push([module, routes]);
|
|
83
|
+
registerApp(module, routes);
|
|
84
|
+
});
|
|
98
85
|
|
|
99
86
|
window[REGISTRATION_PROMISES] = Promise.all(registrationPromises);
|
|
100
87
|
window.installedModules = modules;
|
|
@@ -120,9 +107,9 @@ function connectivityChanged() {
|
|
|
120
107
|
dispatchConnectivityChanged(online);
|
|
121
108
|
showToast({
|
|
122
109
|
critical: true,
|
|
123
|
-
description: `Connection: ${online ?
|
|
124
|
-
title:
|
|
125
|
-
kind: online ?
|
|
110
|
+
description: `Connection: ${online ? 'online' : 'offline'}`,
|
|
111
|
+
title: 'App',
|
|
112
|
+
kind: online ? 'success' : 'warning',
|
|
126
113
|
});
|
|
127
114
|
}
|
|
128
115
|
|
|
@@ -130,18 +117,15 @@ function connectivityChanged() {
|
|
|
130
117
|
* Runs the shell by importing the translations and starting single SPA.
|
|
131
118
|
*/
|
|
132
119
|
function runShell() {
|
|
133
|
-
window.addEventListener(
|
|
134
|
-
window.addEventListener(
|
|
120
|
+
window.addEventListener('offline', connectivityChanged);
|
|
121
|
+
window.addEventListener('online', connectivityChanged);
|
|
135
122
|
return setupI18n()
|
|
136
123
|
.catch((err) => console.error(`Failed to initialize translations`, err))
|
|
137
124
|
.then(() => start());
|
|
138
125
|
}
|
|
139
126
|
|
|
140
127
|
async function preloadScripts() {
|
|
141
|
-
const [, importMap] = await Promise.all([
|
|
142
|
-
window[REGISTRATION_PROMISES],
|
|
143
|
-
getCurrentImportMap(),
|
|
144
|
-
]);
|
|
128
|
+
const [, importMap] = await Promise.all([window[REGISTRATION_PROMISES], getCurrentImportMap()]);
|
|
145
129
|
|
|
146
130
|
window.installedModules.map(async ([module]) => {
|
|
147
131
|
// we simply swallow the error here since this is only a preload
|
|
@@ -155,28 +139,25 @@ function handleInitFailure(e: Error) {
|
|
|
155
139
|
}
|
|
156
140
|
|
|
157
141
|
function renderFatalErrorPage(e?: Error) {
|
|
158
|
-
const template = document.querySelector<HTMLTemplateElement>(
|
|
142
|
+
const template = document.querySelector<HTMLTemplateElement>('#app-error');
|
|
159
143
|
|
|
160
144
|
if (template) {
|
|
161
145
|
const fragment = template.content.cloneNode(true) as DocumentFragment;
|
|
162
146
|
const messageContainer = fragment.querySelector('[data-var="message"]');
|
|
163
147
|
|
|
164
148
|
if (messageContainer) {
|
|
165
|
-
messageContainer.textContent =
|
|
166
|
-
e?.message || "No additional information available.";
|
|
149
|
+
messageContainer.textContent = e?.message || 'No additional information available.';
|
|
167
150
|
}
|
|
168
151
|
|
|
169
152
|
if (
|
|
170
|
-
localStorage.getItem(
|
|
171
|
-
Object.keys(localStorage).some((k) =>
|
|
172
|
-
k.startsWith("import-map-override:")
|
|
173
|
-
)
|
|
153
|
+
localStorage.getItem('openmrs:devtools') &&
|
|
154
|
+
Object.keys(localStorage).some((k) => k.startsWith('import-map-override:'))
|
|
174
155
|
) {
|
|
175
|
-
const appErrorActionButtons = fragment?.querySelector(
|
|
156
|
+
const appErrorActionButtons = fragment?.querySelector('#buttons');
|
|
176
157
|
if (appErrorActionButtons) {
|
|
177
|
-
const clearDevOverridesButton = document.createElement(
|
|
178
|
-
clearDevOverridesButton.className =
|
|
179
|
-
clearDevOverridesButton.innerHTML =
|
|
158
|
+
const clearDevOverridesButton = document.createElement('button');
|
|
159
|
+
clearDevOverridesButton.className = 'cds--btn';
|
|
160
|
+
clearDevOverridesButton.innerHTML = 'Clear dev overrides';
|
|
180
161
|
clearDevOverridesButton.onclick = clearDevOverrides;
|
|
181
162
|
appErrorActionButtons.appendChild(clearDevOverridesButton);
|
|
182
163
|
}
|
|
@@ -189,10 +170,8 @@ function renderFatalErrorPage(e?: Error) {
|
|
|
189
170
|
function clearDevOverrides() {
|
|
190
171
|
for (const key of Object.keys(localStorage)) {
|
|
191
172
|
if (
|
|
192
|
-
key.startsWith(
|
|
193
|
-
![
|
|
194
|
-
key
|
|
195
|
-
)
|
|
173
|
+
key.startsWith('import-map-override:') &&
|
|
174
|
+
!['import-map-override:react', 'import-map-override:react-dom'].includes(key)
|
|
196
175
|
) {
|
|
197
176
|
localStorage.removeItem(key);
|
|
198
177
|
}
|
|
@@ -217,34 +196,30 @@ function createConfigLoader(configUrls: Array<string>) {
|
|
|
217
196
|
value: {},
|
|
218
197
|
};
|
|
219
198
|
});
|
|
220
|
-
})
|
|
199
|
+
}),
|
|
221
200
|
);
|
|
222
201
|
return () => loadingConfigs.then(loadConfigs);
|
|
223
202
|
}
|
|
224
203
|
|
|
225
204
|
function showNotifications() {
|
|
226
|
-
renderInlineNotifications(
|
|
227
|
-
document.querySelector(".omrs-inline-notifications-container")
|
|
228
|
-
);
|
|
205
|
+
renderInlineNotifications(document.querySelector('.omrs-inline-notifications-container'));
|
|
229
206
|
return;
|
|
230
207
|
}
|
|
231
208
|
|
|
232
209
|
function showActionableNotifications() {
|
|
233
|
-
renderActionableNotifications(
|
|
234
|
-
document.querySelector(".omrs-actionable-notifications-container")
|
|
235
|
-
);
|
|
210
|
+
renderActionableNotifications(document.querySelector('.omrs-actionable-notifications-container'));
|
|
236
211
|
}
|
|
237
212
|
|
|
238
213
|
function showToasts() {
|
|
239
|
-
renderToasts(document.querySelector(
|
|
214
|
+
renderToasts(document.querySelector('.omrs-toasts-container'));
|
|
240
215
|
}
|
|
241
216
|
|
|
242
217
|
function showSnackbars() {
|
|
243
|
-
renderSnackbars(document.querySelector(
|
|
218
|
+
renderSnackbars(document.querySelector('.omrs-snackbars-container'));
|
|
244
219
|
}
|
|
245
220
|
|
|
246
221
|
function showModals() {
|
|
247
|
-
renderModals(document.querySelector(
|
|
222
|
+
renderModals(document.querySelector('.omrs-modals-container'));
|
|
248
223
|
}
|
|
249
224
|
|
|
250
225
|
function showLoadingSpinner() {
|
|
@@ -263,16 +238,14 @@ function registerCoreExtensions() {
|
|
|
263
238
|
|
|
264
239
|
async function setupOffline() {
|
|
265
240
|
try {
|
|
266
|
-
await registerOmrsServiceWorker(
|
|
267
|
-
`${window.getOpenmrsSpaBase()}service-worker.js`
|
|
268
|
-
);
|
|
241
|
+
await registerOmrsServiceWorker(`${window.getOpenmrsSpaBase()}service-worker.js`);
|
|
269
242
|
await activateOfflineCapability();
|
|
270
243
|
setupOfflineStaticDependencyPrecaching();
|
|
271
244
|
} catch (error) {
|
|
272
|
-
console.error(
|
|
245
|
+
console.error('Error while setting up offline mode.', error);
|
|
273
246
|
showNotification({
|
|
274
|
-
kind:
|
|
275
|
-
title:
|
|
247
|
+
kind: 'error',
|
|
248
|
+
title: 'Offline Setup Error',
|
|
276
249
|
description: error.message,
|
|
277
250
|
});
|
|
278
251
|
}
|
|
@@ -283,9 +256,7 @@ function setupOfflineStaticDependencyPrecaching() {
|
|
|
283
256
|
let lastPrecache: Date | null = null;
|
|
284
257
|
|
|
285
258
|
subscribeOnlineAndLoginChange((online, hasLoggedInUser) => {
|
|
286
|
-
const hasExceededPrecacheDelay =
|
|
287
|
-
!lastPrecache ||
|
|
288
|
-
new Date().getTime() - lastPrecache.getTime() > precacheDelay;
|
|
259
|
+
const hasExceededPrecacheDelay = !lastPrecache || new Date().getTime() - lastPrecache.getTime() > precacheDelay;
|
|
289
260
|
|
|
290
261
|
if (hasLoggedInUser && online && hasExceededPrecacheDelay) {
|
|
291
262
|
lastPrecache = new Date();
|
|
@@ -294,9 +265,7 @@ function setupOfflineStaticDependencyPrecaching() {
|
|
|
294
265
|
});
|
|
295
266
|
}
|
|
296
267
|
|
|
297
|
-
function subscribeOnlineAndLoginChange(
|
|
298
|
-
cb: (online: boolean, hasLoggedInUser: boolean) => void
|
|
299
|
-
) {
|
|
268
|
+
function subscribeOnlineAndLoginChange(cb: (online: boolean, hasLoggedInUser: boolean) => void) {
|
|
300
269
|
let isOnline = false;
|
|
301
270
|
let hasLoggedInUser = false;
|
|
302
271
|
|
|
@@ -316,40 +285,37 @@ async function precacheGlobalStaticDependencies() {
|
|
|
316
285
|
|
|
317
286
|
// By default, cache the session endpoint.
|
|
318
287
|
// This ensures that a lot of user/session related functions also work offline.
|
|
319
|
-
const sessionPathUrl = new URL(
|
|
320
|
-
`${window.openmrsBase}/ws/rest/v1/session`,
|
|
321
|
-
window.location.origin
|
|
322
|
-
).href;
|
|
288
|
+
const sessionPathUrl = new URL(`${window.openmrsBase}/ws/rest/v1/session`, window.location.origin).href;
|
|
323
289
|
|
|
324
290
|
await messageOmrsServiceWorker({
|
|
325
|
-
type:
|
|
291
|
+
type: 'registerDynamicRoute',
|
|
326
292
|
url: sessionPathUrl,
|
|
327
|
-
strategy:
|
|
293
|
+
strategy: 'network-first',
|
|
328
294
|
});
|
|
329
295
|
|
|
330
|
-
await openmrsFetch(
|
|
296
|
+
await openmrsFetch('/ws/rest/v1/session').catch((e) =>
|
|
331
297
|
console.warn(
|
|
332
|
-
|
|
333
|
-
e
|
|
334
|
-
)
|
|
298
|
+
'Failed to precache the user session data from the app shell. MFs depending on this data may run into problems while offline.',
|
|
299
|
+
e,
|
|
300
|
+
),
|
|
335
301
|
);
|
|
336
302
|
}
|
|
337
303
|
|
|
338
304
|
async function precacheImportMap() {
|
|
339
305
|
const importMap = await window.importMapOverrides.getCurrentPageMap();
|
|
340
306
|
await messageOmrsServiceWorker({
|
|
341
|
-
type:
|
|
307
|
+
type: 'onImportMapChanged',
|
|
342
308
|
importMap,
|
|
343
309
|
});
|
|
344
310
|
}
|
|
345
311
|
|
|
346
312
|
function setupOfflineCssClasses() {
|
|
347
313
|
subscribeConnectivity(({ online }) => {
|
|
348
|
-
const body = document.querySelector(
|
|
314
|
+
const body = document.querySelector('body')!;
|
|
349
315
|
if (online) {
|
|
350
|
-
body.classList.remove(
|
|
316
|
+
body.classList.remove('omrs-offline');
|
|
351
317
|
} else {
|
|
352
|
-
body.classList.add(
|
|
318
|
+
body.classList.add('omrs-offline');
|
|
353
319
|
}
|
|
354
320
|
});
|
|
355
321
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
import type { ImportMap } from
|
|
3
|
-
import { retry } from
|
|
4
|
-
import { absoluteWbManifestUrls, omrsCacheName } from
|
|
5
|
-
import { fetchUrlsToCacheFromImportMap } from
|
|
6
|
-
import { ServiceWorkerDb } from
|
|
2
|
+
import type { ImportMap } from '@openmrs/esm-globals';
|
|
3
|
+
import { retry } from '@openmrs/esm-utils';
|
|
4
|
+
import { absoluteWbManifestUrls, omrsCacheName } from './constants';
|
|
5
|
+
import { fetchUrlsToCacheFromImportMap } from './import-map-utils';
|
|
6
|
+
import { ServiceWorkerDb } from './storage';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Attempts to resolve cacheable files from the specified import map (files are retrieved via convention)
|
|
@@ -43,17 +43,13 @@ export async function addToOmrsCache(urls: Array<string>) {
|
|
|
43
43
|
urls.map(async (url) => {
|
|
44
44
|
try {
|
|
45
45
|
await retry(() => cache.add(url), {
|
|
46
|
-
onError: (e, attempt) =>
|
|
47
|
-
console.debug(
|
|
48
|
-
`[SW] Failure attempt ${attempt} at caching "${url}". Error: `,
|
|
49
|
-
e
|
|
50
|
-
),
|
|
46
|
+
onError: (e, attempt) => console.debug(`[SW] Failure attempt ${attempt} at caching "${url}". Error: `, e),
|
|
51
47
|
});
|
|
52
48
|
return { url, success: true };
|
|
53
49
|
} catch (e) {
|
|
54
50
|
return { url, success: false };
|
|
55
51
|
}
|
|
56
|
-
})
|
|
52
|
+
}),
|
|
57
53
|
);
|
|
58
54
|
|
|
59
55
|
const cached = results.filter((r) => r.success);
|
|
@@ -62,14 +58,14 @@ export async function addToOmrsCache(urls: Array<string>) {
|
|
|
62
58
|
if (cached.length > 0) {
|
|
63
59
|
console.debug(
|
|
64
60
|
`[SW] Successfully added ${cached.length} URLs to the OMRS cache. URLs: `,
|
|
65
|
-
cached.map((r) => r.url)
|
|
61
|
+
cached.map((r) => r.url),
|
|
66
62
|
);
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
if (failedToCache.length > 0) {
|
|
70
66
|
console.error(
|
|
71
67
|
`[SW] Failed to cache ${failedToCache.length} URLs. URLs: `,
|
|
72
|
-
failedToCache.map((r) => r.url)
|
|
68
|
+
failedToCache.map((r) => r.url),
|
|
73
69
|
);
|
|
74
70
|
}
|
|
75
71
|
}
|
|
@@ -77,27 +73,23 @@ export async function addToOmrsCache(urls: Array<string>) {
|
|
|
77
73
|
async function invalidateObsoleteCacheEntries(newImportMapUrls: Array<string>) {
|
|
78
74
|
const cache = await caches.open(omrsCacheName);
|
|
79
75
|
const cachedUrls = (await cache.keys()).map((x) => x.url);
|
|
80
|
-
const dynamicRoutes =
|
|
81
|
-
await new ServiceWorkerDb().dynamicRouteRegistrations.toArray();
|
|
76
|
+
const dynamicRoutes = await new ServiceWorkerDb().dynamicRouteRegistrations.toArray();
|
|
82
77
|
|
|
83
78
|
const urlsToInvalidate = cachedUrls.filter(
|
|
84
79
|
(cachedUrl) =>
|
|
85
80
|
!absoluteWbManifestUrls.includes(cachedUrl) &&
|
|
86
81
|
!newImportMapUrls.includes(cachedUrl) &&
|
|
87
|
-
!dynamicRoutes.some((route) => new RegExp(route.pattern).test(cachedUrl))
|
|
82
|
+
!dynamicRoutes.some((route) => new RegExp(route.pattern).test(cachedUrl)),
|
|
88
83
|
);
|
|
89
84
|
|
|
90
|
-
console.info(
|
|
91
|
-
"[SW] Removing the following expired URLs from the cache: ",
|
|
92
|
-
urlsToInvalidate
|
|
93
|
-
);
|
|
85
|
+
console.info('[SW] Removing the following expired URLs from the cache: ', urlsToInvalidate);
|
|
94
86
|
|
|
95
87
|
// eslint-disable-next-line no-console
|
|
96
88
|
console.debug(
|
|
97
|
-
|
|
89
|
+
'[SW] The following URLs were known and not invalidated: ',
|
|
98
90
|
absoluteWbManifestUrls,
|
|
99
91
|
newImportMapUrls,
|
|
100
|
-
dynamicRoutes
|
|
92
|
+
dynamicRoutes,
|
|
101
93
|
);
|
|
102
94
|
|
|
103
95
|
await Promise.all(urlsToInvalidate.map((url) => cache.delete(url)));
|
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
import uniq from
|
|
1
|
+
import uniq from 'lodash-es/uniq';
|
|
2
2
|
|
|
3
3
|
// note that these constants are also defined in @openmrs/esm-offline
|
|
4
|
-
export const omrsOfflineResponseBodyHttpHeaderName =
|
|
5
|
-
|
|
6
|
-
export const
|
|
7
|
-
"x-omrs-offline-response-status";
|
|
8
|
-
export const omrsOfflineCachingStrategyHttpHeaderName =
|
|
9
|
-
"x-omrs-offline-caching-strategy";
|
|
4
|
+
export const omrsOfflineResponseBodyHttpHeaderName = 'x-omrs-offline-response-body';
|
|
5
|
+
export const omrsOfflineResponseStatusHttpHeaderName = 'x-omrs-offline-response-status';
|
|
6
|
+
export const omrsOfflineCachingStrategyHttpHeaderName = 'x-omrs-offline-caching-strategy';
|
|
10
7
|
|
|
11
|
-
export const omrsCachePrefix =
|
|
8
|
+
export const omrsCachePrefix = 'omrs';
|
|
12
9
|
export const omrsCacheName = `${omrsCachePrefix}-spa-cache-v1`;
|
|
13
10
|
|
|
14
11
|
export const wbManifest = self.__WB_MANIFEST;
|
|
15
|
-
export const indexUrl = prefixWithServiceWorkerLocationIfRelative(
|
|
16
|
-
export const absoluteWbManifestUrls = uniq(
|
|
17
|
-
wbManifest.map(({ url }) => prefixWithServiceWorkerLocationIfRelative(url))
|
|
18
|
-
);
|
|
12
|
+
export const indexUrl = prefixWithServiceWorkerLocationIfRelative('index.html');
|
|
13
|
+
export const absoluteWbManifestUrls = uniq(wbManifest.map(({ url }) => prefixWithServiceWorkerLocationIfRelative(url)));
|
|
19
14
|
|
|
20
|
-
export const buildManifestSuffix =
|
|
15
|
+
export const buildManifestSuffix = '.buildmanifest.json';
|
|
21
16
|
|
|
22
17
|
function prefixWithServiceWorkerLocationIfRelative(path: string) {
|
|
23
18
|
return new URL(path, self.location.href).href;
|
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
OmrsOfflineHttpHeaders,
|
|
4
|
-
} from "@openmrs/esm-offline";
|
|
5
|
-
import {
|
|
6
|
-
omrsOfflineResponseBodyHttpHeaderName,
|
|
7
|
-
omrsOfflineResponseStatusHttpHeaderName,
|
|
8
|
-
} from "./constants";
|
|
1
|
+
import type { OmrsOfflineHttpHeaderNames, OmrsOfflineHttpHeaders } from '@openmrs/esm-offline';
|
|
2
|
+
import { omrsOfflineResponseBodyHttpHeaderName, omrsOfflineResponseStatusHttpHeaderName } from './constants';
|
|
9
3
|
|
|
10
4
|
export function parseOmrsOfflineResponseBodyHeader(headers: Headers) {
|
|
11
5
|
// The ?? undefined here is important as getOmrsHeader returns null by default when the header
|
|
12
6
|
// is missing. undefined is different than null in this case since we want the body to be missing
|
|
13
7
|
// if the header is not there (null is not missing).
|
|
14
|
-
return (
|
|
15
|
-
getOmrsHeader(headers, omrsOfflineResponseBodyHttpHeaderName) ?? undefined
|
|
16
|
-
);
|
|
8
|
+
return getOmrsHeader(headers, omrsOfflineResponseBodyHttpHeaderName) ?? undefined;
|
|
17
9
|
}
|
|
18
10
|
|
|
19
11
|
export function parseOmrsOfflineResponseStatusHeader(headers: Headers) {
|
|
20
|
-
const status = +(
|
|
21
|
-
getOmrsHeader(headers, omrsOfflineResponseStatusHttpHeaderName) ?? ""
|
|
22
|
-
);
|
|
12
|
+
const status = +(getOmrsHeader(headers, omrsOfflineResponseStatusHttpHeaderName) ?? '');
|
|
23
13
|
|
|
24
14
|
// The Response API requires the status to be in the 200-599 range and throws otherwise.
|
|
25
15
|
return isNaN(status) || status < 200 || status > 599 ? 503 : status;
|
|
@@ -27,7 +17,7 @@ export function parseOmrsOfflineResponseStatusHeader(headers: Headers) {
|
|
|
27
17
|
|
|
28
18
|
export function getOmrsHeader<T extends OmrsOfflineHttpHeaderNames>(
|
|
29
19
|
headers: Headers,
|
|
30
|
-
name: T
|
|
20
|
+
name: T,
|
|
31
21
|
): OmrsOfflineHttpHeaders[T] | null {
|
|
32
22
|
return headers.get(name) as OmrsOfflineHttpHeaders[T];
|
|
33
23
|
}
|
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
import type { ImportMap } from
|
|
2
|
-
import { buildManifestSuffix } from
|
|
3
|
-
import { BuildManifest } from
|
|
4
|
-
import flatten from
|
|
1
|
+
import type { ImportMap } from '@openmrs/esm-globals';
|
|
2
|
+
import { buildManifestSuffix } from './constants';
|
|
3
|
+
import { BuildManifest } from './types';
|
|
4
|
+
import flatten from 'lodash-es/flatten';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Given an import map object, resolves the URLs of all cacheable files defined in the import map.
|
|
8
8
|
* Resolving relies on a build manifest file existing in the same location as the file referenced
|
|
9
9
|
* in the import map.
|
|
10
10
|
*/
|
|
11
|
-
export async function fetchUrlsToCacheFromImportMap({
|
|
12
|
-
imports = {},
|
|
13
|
-
}: ImportMap) {
|
|
11
|
+
export async function fetchUrlsToCacheFromImportMap({ imports = {} }: ImportMap) {
|
|
14
12
|
const importMapUrlAddresses = Object.values(imports);
|
|
15
13
|
const urlsToCache = await Promise.all(
|
|
16
14
|
importMapUrlAddresses.map(async (importMapAddress) => {
|
|
17
15
|
const buildManifestUrl = getBuildManifestUrl(importMapAddress);
|
|
18
16
|
const buildManifest = await tryFetchBuildManifest(buildManifestUrl);
|
|
19
|
-
return buildManifest
|
|
20
|
-
|
|
21
|
-
: [];
|
|
22
|
-
})
|
|
17
|
+
return buildManifest ? getUrlsFromBuildManifests(importMapAddress, buildManifest) : [];
|
|
18
|
+
}),
|
|
23
19
|
);
|
|
24
20
|
|
|
25
21
|
return flatten(urlsToCache);
|
|
@@ -29,26 +25,19 @@ function getBuildManifestUrl(importMapAddress: string) {
|
|
|
29
25
|
return importMapAddress + buildManifestSuffix;
|
|
30
26
|
}
|
|
31
27
|
|
|
32
|
-
function tryFetchBuildManifest(
|
|
33
|
-
buildManifestUrl: string
|
|
34
|
-
): Promise<BuildManifest | null> {
|
|
28
|
+
function tryFetchBuildManifest(buildManifestUrl: string): Promise<BuildManifest | null> {
|
|
35
29
|
return fetch(buildManifestUrl)
|
|
36
30
|
.then((res) => res.json())
|
|
37
31
|
.catch(() => null);
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
function getUrlsFromBuildManifests(
|
|
41
|
-
importMapAddress: string,
|
|
42
|
-
buildManifest: BuildManifest
|
|
43
|
-
) {
|
|
34
|
+
function getUrlsFromBuildManifests(importMapAddress: string, buildManifest: BuildManifest) {
|
|
44
35
|
// The try here guards against malformed JSON responses.
|
|
45
36
|
// While we do expect the build manifest to have the correct format, we cannot *rely* on it.
|
|
46
37
|
// Using a try/catch here seems better to me than doing defensive checks on every field/type in the response.
|
|
47
38
|
try {
|
|
48
39
|
const results: Array<string> = [];
|
|
49
|
-
const baseUrlForFiles = getUrlOfFileParentDir(
|
|
50
|
-
new URL(importMapAddress, self.location.href)
|
|
51
|
-
);
|
|
40
|
+
const baseUrlForFiles = getUrlOfFileParentDir(new URL(importMapAddress, self.location.href));
|
|
52
41
|
|
|
53
42
|
for (const chunk of buildManifest.chunks ?? []) {
|
|
54
43
|
for (const file of chunk.files ?? []) {
|
|
@@ -61,7 +50,7 @@ function getUrlsFromBuildManifests(
|
|
|
61
50
|
console.error(
|
|
62
51
|
"[SW] Failed to determine the dependencies of the module with the URL %s. Not precaching any of the module's assets. Error: ",
|
|
63
52
|
importMapAddress,
|
|
64
|
-
e
|
|
53
|
+
e,
|
|
65
54
|
);
|
|
66
55
|
|
|
67
56
|
return [];
|
|
@@ -70,7 +59,7 @@ function getUrlsFromBuildManifests(
|
|
|
70
59
|
|
|
71
60
|
function getUrlOfFileParentDir(url: URL) {
|
|
72
61
|
const fullPath = url.origin + url.pathname; // Removes params + hash.
|
|
73
|
-
const parts = fullPath.split(
|
|
74
|
-
parts[parts.length - 1] =
|
|
75
|
-
return parts.join(
|
|
62
|
+
const parts = fullPath.split('/');
|
|
63
|
+
parts[parts.length - 1] = '';
|
|
64
|
+
return parts.join('/');
|
|
76
65
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { setCacheNameDetails } from
|
|
2
|
-
import { handleMessage } from
|
|
3
|
-
import { precacheAppShell } from
|
|
4
|
-
import { registerAllOmrsRoutes } from
|
|
5
|
-
import { omrsCachePrefix } from
|
|
1
|
+
import { setCacheNameDetails } from 'workbox-core';
|
|
2
|
+
import { handleMessage } from './message';
|
|
3
|
+
import { precacheAppShell } from './caching';
|
|
4
|
+
import { registerAllOmrsRoutes } from './routing';
|
|
5
|
+
import { omrsCachePrefix } from './constants';
|
|
6
6
|
|
|
7
7
|
self.__WB_DISABLE_DEV_LOGS = true;
|
|
8
8
|
|
|
@@ -11,9 +11,9 @@ setCacheNameDetails({ prefix: omrsCachePrefix });
|
|
|
11
11
|
|
|
12
12
|
registerAllOmrsRoutes();
|
|
13
13
|
|
|
14
|
-
self.addEventListener(
|
|
14
|
+
self.addEventListener('message', handleMessage);
|
|
15
15
|
|
|
16
|
-
self.addEventListener(
|
|
16
|
+
self.addEventListener('install', (e) => {
|
|
17
17
|
self.skipWaiting();
|
|
18
18
|
|
|
19
19
|
// The app shell files are special in the sense that they can immediately be cached during SW installation.
|
|
@@ -22,6 +22,6 @@ self.addEventListener("install", (e) => {
|
|
|
22
22
|
e.waitUntil(precacheAppShell());
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
self.addEventListener(
|
|
25
|
+
self.addEventListener('activate', (e) => {
|
|
26
26
|
e.waitUntil(self.clients.claim());
|
|
27
27
|
});
|
|
@@ -2,10 +2,10 @@ import type {
|
|
|
2
2
|
MessageServiceWorkerResult,
|
|
3
3
|
OnImportMapChangedMessage,
|
|
4
4
|
RegisterDynamicRouteMessage,
|
|
5
|
-
} from
|
|
6
|
-
import escapeRegExp from
|
|
7
|
-
import { cacheImportMapReferences } from
|
|
8
|
-
import { DynamicRouteRegistration, ServiceWorkerDb } from
|
|
5
|
+
} from '@openmrs/esm-offline';
|
|
6
|
+
import escapeRegExp from 'lodash-es/escapeRegExp';
|
|
7
|
+
import { cacheImportMapReferences } from './caching';
|
|
8
|
+
import { DynamicRouteRegistration, ServiceWorkerDb } from './storage';
|
|
9
9
|
|
|
10
10
|
const messageHandlers = {
|
|
11
11
|
onImportMapChanged,
|
|
@@ -21,11 +21,7 @@ async function clearDynamicRoutes() {
|
|
|
21
21
|
await new ServiceWorkerDb().dynamicRouteRegistrations.clear();
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
async function registerDynamicRoute({
|
|
25
|
-
pattern,
|
|
26
|
-
url,
|
|
27
|
-
strategy,
|
|
28
|
-
}: RegisterDynamicRouteMessage) {
|
|
24
|
+
async function registerDynamicRoute({ pattern, url, strategy }: RegisterDynamicRouteMessage) {
|
|
29
25
|
let finalPattern = pattern;
|
|
30
26
|
if (!finalPattern && url) {
|
|
31
27
|
finalPattern = `^${escapeRegExp(url)}$`;
|
|
@@ -50,12 +46,10 @@ async function registerDynamicRoute({
|
|
|
50
46
|
* @param event The event data containing the message dispatched to the Service Worker.
|
|
51
47
|
*/
|
|
52
48
|
export async function handleMessage(event: ExtendableMessageEvent) {
|
|
53
|
-
const handler = messageHandlers[event.data?.type?.toString() ??
|
|
49
|
+
const handler = messageHandlers[event.data?.type?.toString() ?? ''];
|
|
54
50
|
|
|
55
51
|
if (!handler) {
|
|
56
|
-
fail(
|
|
57
|
-
`Received an unknown message of type "${event.data?.type} which cannot be handled.`
|
|
58
|
-
);
|
|
52
|
+
fail(`Received an unknown message of type "${event.data?.type} which cannot be handled.`);
|
|
59
53
|
return;
|
|
60
54
|
}
|
|
61
55
|
|
|
@@ -66,11 +60,11 @@ export async function handleMessage(event: ExtendableMessageEvent) {
|
|
|
66
60
|
result,
|
|
67
61
|
});
|
|
68
62
|
} catch (e) {
|
|
69
|
-
fail(e?.message ?? e?.toString() ??
|
|
63
|
+
fail(e?.message ?? e?.toString() ?? 'Unknown error.');
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
function fail(error: string) {
|
|
73
|
-
console.warn(
|
|
67
|
+
console.warn('[SW] Handling a message resulted in an error.', error);
|
|
74
68
|
resolve({
|
|
75
69
|
success: false,
|
|
76
70
|
error,
|