@networkpro/web 1.20.0 → 1.21.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.
package/CHANGELOG.md CHANGED
@@ -22,6 +22,30 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
22
22
 
23
23
  ---
24
24
 
25
+ ## [1.21.0] - 2025-10-17
26
+
27
+ ### Added
28
+
29
+ - Introduced modular analytics initializer at `src/lib/utils/initAnalytics.js` to handle PostHog tracking, asset preloading, and cleanup logic.
30
+
31
+ ### Changed
32
+
33
+ - Bumped project version to `v1.21.0`.
34
+ - Added `pageleave` to `cspell.json` to support custom PostHog events.
35
+ - Expanded `lint` script in `package.json` to include `.cjs` files.
36
+ - Updated `src/service-worker.js` to correctly exclude `security.txt.sig` from caching.
37
+ - Refactored `+layout.svelte` to use the new `initAnalytics.js` utility for cleaner side-effect management.
38
+ - Updated fallback meta description logic in both `+layout.svelte` and `+layout.js`.
39
+ - Adjusted `"purpose"` value in `static/manifest.json` from `"any maskable"` to `"maskable"` for improved PWA icon support.
40
+ - Increased spacing before contact info in `src/lib/pages/HomeContent.svelte`.
41
+ - Enhanced `registerServiceWorker.js` to skip SW registration in Firefox during development, preventing known `/@fs/` path evaluation errors.
42
+ - Integrated automatic cleanup of existing service workers in `registerServiceWorker.js` when running in Firefox + dev mode.
43
+ - Improved logging clarity in `registerServiceWorker.js` to better distinguish SW lifecycle behavior by environment.
44
+ - Updated `unregisterServiceWorker.js` to include scoped SW logging when unregistering.
45
+ - Refactored `posthog.js` to add conditional guards for suppressing noisy analytics errors in development mode.
46
+
47
+ ---
48
+
25
49
  ## [1.20.0] - 2025-10-17
26
50
 
27
51
  ### Added
@@ -1121,7 +1145,8 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
1121
1145
 
1122
1146
  <!-- Link references -->
1123
1147
 
1124
- [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.20.0...HEAD
1148
+ [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.21.0...HEAD
1149
+ [1.21.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.21.0
1125
1150
  [1.20.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.20.0
1126
1151
  [1.19.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.19.0
1127
1152
  [1.18.5]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.18.5
package/cspell.json CHANGED
@@ -61,6 +61,7 @@
61
61
  "obtainium",
62
62
  "openpgp",
63
63
  "opgp",
64
+ "pageleave",
64
65
  "pallyy",
65
66
  "posthog",
66
67
  "precaching",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@networkpro/web",
3
3
  "private": false,
4
- "version": "1.20.0",
4
+ "version": "1.21.0",
5
5
  "description": "Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro Strategies",
6
6
  "keywords": [
7
7
  "advisory",
@@ -63,11 +63,11 @@
63
63
  "coverage:client": "node scripts/openReport.js client",
64
64
  "coverage:server": "node scripts/openReport.js server",
65
65
  "coverage:open": "npm run coverage:client && npm run coverage:server",
66
- "lint": "eslint . --ext .mjs,.js,.svelte",
67
- "lint:fix": "eslint . --ext .mjs,.js,.svelte --fix",
68
- "lint:jsdoc": "eslint . --ext .js,.mjs,.svelte --max-warnings=0",
66
+ "lint": "eslint . --ext .js,.cjs,.mjs,.svelte",
67
+ "lint:fix": "eslint . --ext .js,.cjs,.mjs,.svelte --fix",
68
+ "lint:jsdoc": "eslint . --ext .js,.cjs,.mjs,.svelte --max-warnings=0",
69
69
  "lint:css": "stylelint \"**/*.{css,svelte}\" --ignore-path .stylelintignore",
70
- "lint:md": "npx markdownlint-cli2 \"**/*.{md,markdown}\" \"#node_modules/**\" \"#build/**\" \"#playwright-report/**\" \"#test-results/**\"",
70
+ "lint:md": "npx markdownlint-cli2 \"**/*.{md,markdown}\" \"#node_modules/**\" \"#playwright-report/**\" \"#test-results/**\"",
71
71
  "lint:all": "npm run lint && npm run lint:md && npm run lint:css && npm run format",
72
72
  "format": "prettier --check .",
73
73
  "format:fix": "prettier --write .",
@@ -69,6 +69,8 @@ This file is part of Network Pro.
69
69
  </em>
70
70
  </p>
71
71
 
72
+ <div class="spacer"></div>
73
+
72
74
  <p class={classCenter}>
73
75
  <strong>{COMPANY_INFO.NAME}</strong><br />
74
76
  📞 <strong>Phone:</strong>
@@ -6,7 +6,7 @@ SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
6
6
  This file is part of Network Pro.
7
7
  ========================================================================== */
8
8
 
9
- // cspell:ignore nosw beforeinstallprompt
9
+ import { unregisterServiceWorker } from '$lib/unregisterServiceWorker';
10
10
 
11
11
  /**
12
12
  * Registers the service worker and handles update lifecycle, install prompt,
@@ -34,11 +34,11 @@ export function registerServiceWorker() {
34
34
 
35
35
  if ('serviceWorker' in navigator) {
36
36
  const isFirefox = navigator.userAgent.includes('Firefox');
37
- const isDevelopment =
38
- location.hostname === 'localhost' || location.hostname === '127.0.0.1';
37
+ const isDevMode = import.meta.env.MODE === 'development';
39
38
 
40
- if (isFirefox && isDevelopment) {
41
- console.log('🛑 SW registration skipped in Firefox development mode');
39
+ if (isFirefox && isDevMode) {
40
+ console.info('[SW] Dev mode in Firefox unregistering existing service workers.');
41
+ unregisterServiceWorker();
42
42
  return;
43
43
  }
44
44
 
@@ -107,3 +107,5 @@ export function registerServiceWorker() {
107
107
  });
108
108
  }
109
109
  }
110
+
111
+ // cspell:ignore nosw beforeinstallprompt
@@ -42,40 +42,50 @@ let ph = null;
42
42
  */
43
43
  export async function initPostHog() {
44
44
  if (initialized || typeof window === 'undefined') return;
45
+ const isDev = import.meta.env.MODE === 'development';
46
+ if (isDev) {
47
+ console.info('[PostHog] Skipping init in development mode.');
48
+ return;
49
+ }
50
+
45
51
  initialized = true;
46
52
 
47
53
  const { enabled } = get(trackingPreferences);
48
54
  trackingEnabled.set(enabled);
49
- showReminder.set(get(remindUserToReconsent)); // use derived store instead
55
+ showReminder.set(get(remindUserToReconsent)); // use derived store instead
50
56
 
51
57
  if (!enabled) {
52
58
  console.log('[PostHog] Tracking is disabled — skipping init.');
53
59
  return;
54
60
  }
55
61
 
56
- const posthogModule = await import('posthog-js');
57
- ph = posthogModule.default;
58
-
59
- // cspell:disable-next-line
60
- ph.init('phc_Qshfo6AXzh4pS7aPigfqyeo4qj1qlyh7gDuHDeVMSR0', {
61
- api_host: '/relay-MSR0/',
62
- ui_host: 'https://us.posthog.com',
63
- autocapture: true,
64
- capture_pageview: false,
65
- person_profiles: 'identified_only',
66
- loaded: (phInstance) => {
67
- if (!enabled) {
68
- console.log(
69
- '[PostHog] ⛔ User opted out — calling opt_out_capturing()',
70
- );
71
- phInstance.opt_out_capturing();
72
- } else {
73
- console.log('[PostHog] Tracking enabled');
74
- }
75
- },
76
- });
77
-
78
- ph.capture('$pageview');
62
+ try {
63
+ const posthogModule = await import('posthog-js');
64
+ ph = posthogModule.default;
65
+
66
+ // cspell:disable-next-line
67
+ ph.init('phc_Qshfo6AXzh4pS7aPigfqyeo4qj1qlyh7gDuHDeVMSR0', {
68
+ api_host: '/relay-MSR0/',
69
+ ui_host: 'https://us.posthog.com',
70
+ autocapture: true,
71
+ capture_pageview: false,
72
+ person_profiles: 'identified_only',
73
+ loaded: (phInstance) => {
74
+ if (!enabled) {
75
+ console.log(
76
+ '[PostHog] ⛔ User opted out — calling opt_out_capturing()',
77
+ );
78
+ phInstance.opt_out_capturing();
79
+ } else {
80
+ console.log('[PostHog] ✅ Tracking enabled');
81
+ }
82
+ },
83
+ });
84
+
85
+ ph.capture('$pageview');
86
+ } catch (err) {
87
+ console.warn('[PostHog] Failed to initialize:', err);
88
+ }
79
89
  }
80
90
 
81
91
  /**
@@ -84,8 +94,13 @@ export async function initPostHog() {
84
94
  * @param {Record<string, any>} [properties={}] - Optional event properties
85
95
  */
86
96
  export function capture(event, properties = {}) {
87
- if (ph !== null && get(trackingEnabled)) {
97
+ const isDev = import.meta.env.MODE === 'development';
98
+ if (isDev || ph === null || !get(trackingEnabled)) return;
99
+
100
+ try {
88
101
  ph.capture(event, properties);
102
+ } catch (err) {
103
+ console.warn(`[PostHog] capture(${event}) failed:`, err);
89
104
  }
90
105
  }
91
106
 
@@ -95,8 +110,13 @@ export function capture(event, properties = {}) {
95
110
  * @param {Record<string, any>} [properties={}] - Optional user traits
96
111
  */
97
112
  export function identify(id, properties = {}) {
98
- if (ph !== null && get(trackingEnabled)) {
113
+ const isDev = import.meta.env.MODE === 'development';
114
+ if (isDev || ph === null || !get(trackingEnabled)) return;
115
+
116
+ try {
99
117
  ph.identify(id, properties);
118
+ } catch (err) {
119
+ console.warn(`[PostHog] identify(${id}) failed:`, err);
100
120
  }
101
121
  }
102
122
 
@@ -8,12 +8,20 @@ This file is part of Network Pro.
8
8
 
9
9
  /**
10
10
  * Allows for manual toggling of the service worker
11
+ * DEV USE ONLY
12
+ * @internal
11
13
  */
12
14
  export function unregisterServiceWorker() {
13
15
  if ('serviceWorker' in navigator) {
14
16
  navigator.serviceWorker.getRegistrations().then((registrations) => {
15
- registrations.forEach((reg) => reg.unregister());
16
- console.log('🧹 All service workers unregistered.');
17
+ if (registrations.length === 0) {
18
+ console.log('🧼 No service workers to unregister.');
19
+ } else {
20
+ registrations.forEach((reg) => {
21
+ console.log(`🧹 Unregistering SW: ${reg.scope}`);
22
+ reg.unregister();
23
+ });
24
+ }
17
25
  });
18
26
  }
19
27
  }
@@ -0,0 +1,75 @@
1
+ /* ==========================================================================
2
+ src/lib/utils/initAnalytics.js
3
+
4
+ Copyright © 2025 Network Pro Strategies (Network Pro™)
5
+ SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
6
+ This file is part of Network Pro.
7
+ ========================================================================== */
8
+
9
+ /**
10
+ * @file initAnalytics.js
11
+ * @description Helper utility for initializing analytics.
12
+ *
13
+ * @module src/lib/utils
14
+ * @author Scott Lopez
15
+ * @updated 2025-10-17
16
+ */
17
+
18
+ import { browser } from '$app/environment';
19
+ import { afterNavigate } from '$app/navigation';
20
+ import { appleTouchIcon, faviconSvg, logoPng, logoWbp } from '$lib';
21
+ import { registerServiceWorker } from '$lib/registerServiceWorker.js';
22
+ import { capture, initPostHog } from '$lib/stores/posthog';
23
+
24
+ /**
25
+ * Initializes analytics and telemetry (e.g., PostHog tracking, asset preload).
26
+ * Should be called once per app mount (e.g., from +layout.svelte).
27
+ *
28
+ * @returns {() => void} Cleanup function to unregister global event listeners
29
+ */
30
+ export function initAnalytics() {
31
+ if (!browser) return () => {};
32
+
33
+ console.log('[APP] initAnalytics() running');
34
+
35
+ registerServiceWorker();
36
+ initPostHog();
37
+
38
+ afterNavigate(() => {
39
+ capture('$pageview');
40
+ });
41
+
42
+ // Track $pageleave
43
+ let hasFiredLeave = false;
44
+ const sendPageLeave = () => {
45
+ if (hasFiredLeave) return;
46
+ hasFiredLeave = true;
47
+ capture('$pageleave');
48
+ };
49
+
50
+ window.addEventListener('pagehide', sendPageLeave);
51
+ window.addEventListener('beforeunload', sendPageLeave);
52
+
53
+ // Debug toggle logic
54
+ const isDev = import.meta.env.MODE === 'development';
55
+ const urlParams = new URLSearchParams(window.location.search);
56
+ const debug = urlParams.get('debug') === 'true';
57
+
58
+ if (isDev || debug) {
59
+ console.log('ENV MODE =', import.meta.env.MODE);
60
+ console.log('isDev =', isDev);
61
+ console.log('debug param =', debug);
62
+ }
63
+
64
+ // Preload logo assets
65
+ [logoPng, logoWbp, faviconSvg, appleTouchIcon].forEach((src) => {
66
+ const img = new Image();
67
+ img.src = src;
68
+ });
69
+
70
+ // Clean up listeners when component is destroyed
71
+ return () => {
72
+ window.removeEventListener('pagehide', sendPageLeave);
73
+ window.removeEventListener('beforeunload', sendPageLeave);
74
+ };
75
+ }
@@ -21,7 +21,7 @@ import { meta as routeMeta } from '$lib/meta.js'; // Import meta from $lib/meta.
21
21
  const fallbackMeta = {
22
22
  title: 'Security, Networking, Privacy — Network Pro™',
23
23
  description:
24
- 'Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro',
24
+ 'Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro Strategies',
25
25
  };
26
26
 
27
27
  export const prerender = 'auto';
@@ -10,13 +10,11 @@ This file is part of Network Pro.
10
10
  export let data;
11
11
 
12
12
  import { onMount } from 'svelte';
13
- import { afterNavigate } from '$app/navigation';
14
- import { initPostHog, showReminder, capture } from '$lib/stores/posthog';
15
- import { registerServiceWorker } from '$lib/registerServiceWorker.js';
16
- import { browser } from '$app/environment';
17
- import { logoPng, logoWbp, faviconSvg, appleTouchIcon } from '$lib';
13
+ import { initAnalytics } from '$lib/utils/initAnalytics';
14
+ import { showReminder } from '$lib/stores/posthog';
18
15
  import { ContainerSection, PWAInstallButton } from '$lib/components';
19
16
  import { Footer, HeaderDefault, HeaderHome } from '$lib/components/layout';
17
+ import { appleTouchIcon, faviconSvg, logoPng, logoWbp } from '$lib';
20
18
 
21
19
  import '$lib/styles/global.min.css';
22
20
  import '$lib/styles/fa-global.css';
@@ -24,35 +22,8 @@ This file is part of Network Pro.
24
22
  $: shouldShowReminder = $showReminder;
25
23
 
26
24
  onMount(() => {
27
- console.log('[APP] onMount triggered in +layout.svelte');
28
-
29
- registerServiceWorker();
30
- initPostHog();
31
-
32
- // Register navigation tracking only on client
33
- afterNavigate(() => {
34
- capture('$pageview');
35
- });
36
-
37
- if (browser) {
38
- const isDev = import.meta.env.MODE === 'development';
39
-
40
- // Check for ?debug=true in URL (no persistence)
41
- const urlParams = new URLSearchParams(window.location.search);
42
- const debug = urlParams.get('debug') === 'true';
43
-
44
- if (isDev || debug) {
45
- console.log('ENV MODE =', import.meta.env.MODE);
46
- console.log('isDev =', isDev);
47
- console.log('debug param =', debug);
48
- }
49
-
50
- // Preload logo assets
51
- [logoPng, logoWbp, appleTouchIcon].forEach((src) => {
52
- const img = new Image();
53
- img.src = src;
54
- });
55
- }
25
+ const cleanup = initAnalytics();
26
+ return cleanup;
56
27
  });
57
28
 
58
29
  // fallback values if data.meta not set
@@ -60,7 +31,7 @@ This file is part of Network Pro.
60
31
  data?.meta?.title || 'Security, Networking, Privacy — Network Pro™';
61
32
  const metaDescription =
62
33
  data?.meta?.description ||
63
- 'Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro';
34
+ 'Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro Strategies';
64
35
  </script>
65
36
 
66
37
  <svelte:head>
@@ -28,7 +28,7 @@ const CACHE = `cache-${version}`;
28
28
  const excludedAssets = [];
29
29
 
30
30
  const IGNORE_PATHS = new Set([
31
- '/.well-known/security.txt.asc',
31
+ '/.well-known/security.txt.sig',
32
32
  '/img/banner-1280x640.png',
33
33
  '/img/logo-transparent.png',
34
34
  '/img/logo.png',
@@ -27,7 +27,7 @@
27
27
  "src": "/icon-512x512-maskable.png",
28
28
  "type": "image/png",
29
29
  "sizes": "512x512",
30
- "purpose": "any maskable"
30
+ "purpose": "maskable"
31
31
  },
32
32
  {
33
33
  "src": "/icon-splash.png",