@ohos-ports/layer0-prefetch 4.20.0-beta.0

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.
Files changed (59) hide show
  1. package/README.md +7 -0
  2. package/constants.d.ts +23 -0
  3. package/constants.js +25 -0
  4. package/index.js +24 -0
  5. package/package.json +50 -0
  6. package/sw/CustomCacheKeyPlugin.d.ts +10 -0
  7. package/sw/CustomCacheKeyPlugin.js +54 -0
  8. package/sw/CustomExpirationPlugin.d.ts +122 -0
  9. package/sw/CustomExpirationPlugin.js +280 -0
  10. package/sw/DeepFetchPlugin.d.ts +108 -0
  11. package/sw/DeepFetchPlugin.js +144 -0
  12. package/sw/DevtoolsPlugin.d.ts +64 -0
  13. package/sw/DevtoolsPlugin.js +131 -0
  14. package/sw/PrefetchPlugin.d.ts +32 -0
  15. package/sw/PrefetchPlugin.js +167 -0
  16. package/sw/Prefetcher.d.ts +209 -0
  17. package/sw/Prefetcher.js +367 -0
  18. package/sw/getServiceWorkerMaxAge.d.ts +22 -0
  19. package/sw/getServiceWorkerMaxAge.js +51 -0
  20. package/sw/index.d.ts +2 -0
  21. package/sw/index.js +6 -0
  22. package/sw/log.d.ts +1 -0
  23. package/sw/log.js +9 -0
  24. package/sw/messageBrowser.d.ts +7 -0
  25. package/sw/messageBrowser.js +18 -0
  26. package/sw/prefetch.d.ts +9 -0
  27. package/sw/prefetch.js +17 -0
  28. package/window/InstallOptions.d.ts +77 -0
  29. package/window/InstallOptions.js +2 -0
  30. package/window/PrefetchOptions.d.ts +19 -0
  31. package/window/PrefetchOptions.js +2 -0
  32. package/window/entry.d.ts +1 -0
  33. package/window/entry.js +8 -0
  34. package/window/getHostName.d.ts +1 -0
  35. package/window/getHostName.js +6 -0
  36. package/window/getUserAgent.d.ts +1 -0
  37. package/window/getUserAgent.js +6 -0
  38. package/window/index.d.ts +3 -0
  39. package/window/index.js +8 -0
  40. package/window/install.d.ts +13 -0
  41. package/window/install.js +72 -0
  42. package/window/isSafari.d.ts +6 -0
  43. package/window/isSafari.js +31 -0
  44. package/window/loadManifest.d.ts +3 -0
  45. package/window/loadManifest.js +20 -0
  46. package/window/prefetch.d.ts +71 -0
  47. package/window/prefetch.js +157 -0
  48. package/window/prefetchWhenVisible.d.ts +5 -0
  49. package/window/prefetchWhenVisible.js +20 -0
  50. package/window/registerServiceWorker.d.ts +2 -0
  51. package/window/registerServiceWorker.js +66 -0
  52. package/window/runWhenVisible.d.ts +6 -0
  53. package/window/runWhenVisible.js +28 -0
  54. package/window/waitForServiceWorker.d.ts +4 -0
  55. package/window/waitForServiceWorker.js +27 -0
  56. package/window/watchElements.d.ts +7 -0
  57. package/window/watchElements.js +63 -0
  58. package/window/watchLinks.d.ts +9 -0
  59. package/window/watchLinks.js +65 -0
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* istanbul ignore file */
4
+ const isSafari_1 = require("./isSafari");
5
+ function registerServiceWorker(serviceWorkerPath) {
6
+ if (isSafari_1.isSafariPrivateWindow()) {
7
+ // Private windows in safari have a known bug with sending cookies
8
+ // in POST requests. This often breaks cart and checkout, so we choose
9
+ // not to use service workers at all when in safari private windows.
10
+ // See the bug report here: https://bugs.webkit.org/show_bug.cgi?id=186617
11
+ console.log('skipping service worker in Safari private window');
12
+ unregisterServiceWorker();
13
+ return;
14
+ }
15
+ if ('serviceWorker' in navigator) {
16
+ if (document.readyState === 'complete') {
17
+ registerValidSW(serviceWorkerPath);
18
+ }
19
+ else {
20
+ window.addEventListener('load', () => {
21
+ registerValidSW(serviceWorkerPath);
22
+ });
23
+ }
24
+ }
25
+ }
26
+ exports.registerServiceWorker = registerServiceWorker;
27
+ function registerValidSW(swUrl) {
28
+ navigator.serviceWorker
29
+ .register(swUrl)
30
+ .then(registration => {
31
+ registration.onupdatefound = () => {
32
+ const installingWorker = registration.installing;
33
+ if (!installingWorker)
34
+ return;
35
+ installingWorker.onstatechange = () => {
36
+ console.log('[layer0 service worker] state:', installingWorker.state);
37
+ if (installingWorker.state === 'installed') {
38
+ if (navigator.serviceWorker.controller) {
39
+ // At this point, the old content will have been purged and
40
+ // the fresh content will have been added to the cache.
41
+ // It's the perfect time to display a "New content is
42
+ // available; please refresh." message in your web app.
43
+ document.dispatchEvent(new CustomEvent('sw-update-available'));
44
+ }
45
+ else {
46
+ // At this point, everything has been precached.
47
+ // It's the perfect time to display a
48
+ // "Content is cached for offline use." message.
49
+ console.log('Content is cached for offline use.');
50
+ }
51
+ }
52
+ };
53
+ };
54
+ })
55
+ .catch(error => {
56
+ console.error('Error during service worker registration:', error);
57
+ });
58
+ }
59
+ function unregisterServiceWorker() {
60
+ if ('serviceWorker' in navigator) {
61
+ navigator.serviceWorker.ready.then(registration => {
62
+ registration.unregister();
63
+ });
64
+ }
65
+ }
66
+ exports.unregisterServiceWorker = unregisterServiceWorker;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Runs a callback function when an element it is visible in the viewport
3
+ * @param {HTMLElement} el The element
4
+ * @param {Function} callback The function to call once the element is visible
5
+ */
6
+ export default function runWhenVisible(el: HTMLElement, callback: (param: HTMLElement) => void): void;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Runs a callback function when an element it is visible in the viewport
5
+ * @param {HTMLElement} el The element
6
+ * @param {Function} callback The function to call once the element is visible
7
+ */
8
+ function runWhenVisible(el, callback) {
9
+ /* istanbul ignore next */
10
+ if (typeof IntersectionObserver === 'undefined')
11
+ return;
12
+ const observer = new IntersectionObserver(entries => {
13
+ // if intersectionRatio is 0, the element is out of view and we do not need to do anything.
14
+ if (entries[0].intersectionRatio > 0) {
15
+ observer.disconnect();
16
+ callback(el);
17
+ }
18
+ }, {
19
+ // setting this to > 0 to avoid a race condition where an element comes into the
20
+ // viewport at the same time as display/visibility becomes block/visible, and
21
+ // the IntersectionObserver is then only triggered with a ratio of 0
22
+ threshold: 0.01,
23
+ });
24
+ // Note: apparently we don't need to clean these up when the observed node is removed.
25
+ // See https://stackoverflow.com/questions/51106261/should-mutationobservers-be-removed-disconnected-when-the-attached-dom-node-is-r/51106262#51106262
26
+ observer.observe(el);
27
+ }
28
+ exports.default = runWhenVisible;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Resolves when the service worker has been installed.
3
+ */
4
+ export default function waitForServiceWorker(): Promise<ServiceWorker>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Resolves when the service worker has been installed.
5
+ */
6
+ async function waitForServiceWorker() {
7
+ if (!navigator.serviceWorker || !navigator.serviceWorker.ready) {
8
+ throw new Error('service worker not supported');
9
+ }
10
+ await navigator.serviceWorker.ready;
11
+ if (navigator.serviceWorker.controller) {
12
+ return navigator.serviceWorker.controller;
13
+ }
14
+ else {
15
+ return new Promise((resolve, reject) => {
16
+ navigator.serviceWorker.addEventListener('controllerchange', () => {
17
+ if (navigator.serviceWorker.controller) {
18
+ resolve(navigator.serviceWorker.controller);
19
+ }
20
+ else {
21
+ reject(new Error('service worker not supported'));
22
+ }
23
+ });
24
+ });
25
+ }
26
+ }
27
+ exports.default = waitForServiceWorker;
@@ -0,0 +1,7 @@
1
+ import { PrefetchWatcherConfig } from './InstallOptions';
2
+ /**
3
+ * Sets up observers to watch for elements matching the list of selectors, then
4
+ * perform the given callback when an element becomes visible
5
+ * @param {PrefetchWatcherConfig[]} configArr Contains the list of selector/callback pairs
6
+ */
7
+ export default function watchElements(configArr: PrefetchWatcherConfig[] | undefined): void;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const runWhenVisible_1 = __importDefault(require("./runWhenVisible"));
7
+ let observer;
8
+ const watchConfigs = new Set();
9
+ /**
10
+ * Sets up observers to watch for elements matching the list of selectors, then
11
+ * perform the given callback when an element becomes visible
12
+ * @param {PrefetchWatcherConfig[]} configArr Contains the list of selector/callback pairs
13
+ */
14
+ function watchElements(configArr) {
15
+ /* istanbul ignore next */
16
+ if (typeof MutationObserver === 'undefined')
17
+ return;
18
+ if (!configArr || !configArr.length)
19
+ return;
20
+ configArr.forEach(watch => watchConfigs.add(watch));
21
+ if (!observer) {
22
+ observer = new MutationObserver(mutationsList => {
23
+ for (let mutation of mutationsList) {
24
+ ;
25
+ [...watchConfigs].forEach(watch => {
26
+ filterBySelector(mutation.addedNodes, watch.selector).forEach(match => runWhenVisible_1.default(match, watch.callback));
27
+ });
28
+ }
29
+ });
30
+ }
31
+ observer.observe(document.body, {
32
+ subtree: true,
33
+ childList: true,
34
+ });
35
+ configArr.forEach(watch => {
36
+ document.querySelectorAll(watch.selector).forEach(match => {
37
+ const el = match;
38
+ runWhenVisible_1.default(el, watch.callback);
39
+ });
40
+ });
41
+ }
42
+ exports.default = watchElements;
43
+ /**
44
+ * Returns all nodes in the node list that match one of the given selectors
45
+ * @param {NodeList} nodes A node list to filter
46
+ * @param {String} selector Selector used to match elements
47
+ */
48
+ function filterBySelector(nodes, selector) {
49
+ const results = new Set();
50
+ Array.from(nodes).forEach(n => {
51
+ if (n.nodeType === Node.ELEMENT_NODE) {
52
+ const el = n;
53
+ if (el.matches(selector)) {
54
+ results.add(el);
55
+ }
56
+ else {
57
+ const matches = el.querySelectorAll(selector);
58
+ matches.forEach(match => results.add(match));
59
+ }
60
+ }
61
+ });
62
+ return results;
63
+ }
@@ -0,0 +1,9 @@
1
+ import CacheManifest from '@layer0/core/router/CacheManifest';
2
+ import { ObserveOptionsConfig } from './InstallOptions';
3
+ /**
4
+ * Watches the DOM for all current and future links whose href matches one of the
5
+ * specified URL patterns
6
+ * @param {CacheManifest} cacheManifest Regular expressions that will be tested against link href attributes
7
+ * @param {ObserveOptionsConfig} observeOpts Configuration for how the DOM is observed for node changes
8
+ */
9
+ export default function watchLinks(cacheManifest: CacheManifest, observerOpts?: ObserveOptionsConfig): void;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const prefetchWhenVisible_1 = __importDefault(require("./prefetchWhenVisible"));
7
+ const CacheManifest_1 = __importDefault(require("@layer0/core/router/CacheManifest"));
8
+ const observerDefaults = {
9
+ disabled: false,
10
+ attributes: false,
11
+ };
12
+ let observer;
13
+ const searchedEntries = new Set();
14
+ /**
15
+ * Watches the DOM for all current and future links whose href matches one of the
16
+ * specified URL patterns
17
+ * @param {CacheManifest} cacheManifest Regular expressions that will be tested against link href attributes
18
+ * @param {ObserveOptionsConfig} observeOpts Configuration for how the DOM is observed for node changes
19
+ */
20
+ function watchLinks(cacheManifest, observerOpts) {
21
+ /* istanbul ignore next */
22
+ if (typeof MutationObserver === 'undefined')
23
+ return;
24
+ cacheManifest.entries.forEach(entry => searchedEntries.add(entry));
25
+ observerOpts = { ...observerDefaults, ...observerOpts };
26
+ if (!observer) {
27
+ observer = new MutationObserver(mutationsList => {
28
+ for (let mutation of mutationsList) {
29
+ filterByHref(mutation.addedNodes, CacheManifest_1.default.fromEntries([...searchedEntries.values()])).forEach(prefetchWhenVisible_1.default);
30
+ }
31
+ });
32
+ if (!observerOpts.disabled) {
33
+ observer.observe(document.body, {
34
+ attributes: observerOpts.attributes,
35
+ childList: true,
36
+ subtree: true,
37
+ });
38
+ }
39
+ }
40
+ filterByHref(document.querySelectorAll('a'), cacheManifest).forEach(prefetchWhenVisible_1.default);
41
+ }
42
+ exports.default = watchLinks;
43
+ /**
44
+ * Returns all nodes in the node list whose href matches at least one of the specified patterns.
45
+ * @param {NodeList} nodes A node list to filter
46
+ * @param {CacheManifest} cacheManifest Contains the list of route patterns to check
47
+ */
48
+ function filterByHref(nodes, cacheManifest) {
49
+ const isMatchingLink = (el) => {
50
+ const href = el.getAttribute('href');
51
+ if (!href || el.tagName.toLowerCase() !== 'a') {
52
+ return false;
53
+ }
54
+ return cacheManifest.shouldPrefetch(new URL(href, window.location.href));
55
+ };
56
+ const results = new Set();
57
+ Array.from(nodes).forEach(n => {
58
+ if (n.nodeType === Node.ELEMENT_NODE) {
59
+ const el = n;
60
+ const links = [el, ...Array.from(el.querySelectorAll('a'))];
61
+ links.filter(isMatchingLink).forEach(link => results.add(link));
62
+ }
63
+ });
64
+ return results;
65
+ }