@networkpro/web 1.12.9 → 1.13.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 (98) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/README.md +8 -8
  3. package/eslint.config.mjs +48 -48
  4. package/netlify/edge-functions/csp-report.js +31 -31
  5. package/package.json +1 -1
  6. package/playwright.config.js +14 -14
  7. package/postcss.config.mjs +1 -1
  8. package/scripts/auditScripts.js +16 -16
  9. package/scripts/bundleCss.js +5 -5
  10. package/scripts/checkEnv.js +6 -6
  11. package/scripts/checkNode.js +10 -10
  12. package/scripts/checkVersions.js +6 -6
  13. package/scripts/flattenHeaders.js +13 -13
  14. package/scripts/generateTest.js +5 -5
  15. package/scripts/openReport.js +3 -3
  16. package/scripts/validateHeaders.js +13 -13
  17. package/src/hooks.client.ts +1 -1
  18. package/src/hooks.server.js +31 -31
  19. package/src/lib/components/Badges.svelte +9 -9
  20. package/src/lib/components/CodeBlock.svelte +1 -1
  21. package/src/lib/components/ContainerSection.svelte +1 -1
  22. package/src/lib/components/FullWidthSection.svelte +3 -3
  23. package/src/lib/components/LegalNav.svelte +6 -6
  24. package/src/lib/components/Logo.svelte +9 -9
  25. package/src/lib/components/MetaTags.svelte +3 -3
  26. package/src/lib/components/PWAInstallButton.svelte +4 -4
  27. package/src/lib/components/RedirectPage.svelte +4 -4
  28. package/src/lib/components/SocialMedia.svelte +16 -16
  29. package/src/lib/components/foss/FossItemContent.svelte +18 -18
  30. package/src/lib/components/layout/Footer.svelte +17 -17
  31. package/src/lib/components/layout/HeaderDefault.svelte +16 -16
  32. package/src/lib/components/layout/HeaderHome.svelte +14 -14
  33. package/src/lib/images.js +34 -34
  34. package/src/lib/index.js +15 -15
  35. package/src/lib/meta.js +29 -29
  36. package/src/lib/pages/AboutContent.svelte +24 -24
  37. package/src/lib/pages/FossContent.svelte +12 -12
  38. package/src/lib/pages/HomeContent.svelte +6 -6
  39. package/src/lib/pages/LicenseContent.svelte +38 -38
  40. package/src/lib/pages/PGPContent.svelte +23 -23
  41. package/src/lib/pages/PrivacyContent.svelte +39 -39
  42. package/src/lib/pages/PrivacyDashboard.svelte +12 -12
  43. package/src/lib/pages/TermsConditionsContent.svelte +28 -28
  44. package/src/lib/pages/TermsUseContent.svelte +26 -26
  45. package/src/lib/registerServiceWorker.js +25 -25
  46. package/src/lib/stores/posthog.js +13 -13
  47. package/src/lib/stores/trackingPreferences.js +19 -19
  48. package/src/lib/unregisterServiceWorker.js +1 -1
  49. package/src/lib/utils/purify.js +4 -4
  50. package/src/lib/utils/utm.js +2 -2
  51. package/src/routes/+error.svelte +4 -4
  52. package/src/routes/+layout.js +6 -6
  53. package/src/routes/+layout.svelte +29 -29
  54. package/src/routes/+page.server.js +2 -2
  55. package/src/routes/+page.svelte +9 -9
  56. package/src/routes/about/+page.server.js +2 -2
  57. package/src/routes/about/+page.svelte +7 -7
  58. package/src/routes/api/mock-csp/+server.js +3 -3
  59. package/src/routes/consultation/+page.svelte +5 -5
  60. package/src/routes/contact/+page.svelte +5 -5
  61. package/src/routes/foss-spotlight/+page.server.js +2 -2
  62. package/src/routes/foss-spotlight/+page.svelte +7 -7
  63. package/src/routes/license/+page.server.js +2 -2
  64. package/src/routes/license/+page.svelte +7 -7
  65. package/src/routes/pgp/+page.server.js +2 -2
  66. package/src/routes/pgp/+page.svelte +7 -7
  67. package/src/routes/pgp/[key]/+server.js +9 -9
  68. package/src/routes/privacy/+page.server.js +2 -2
  69. package/src/routes/privacy/+page.svelte +7 -7
  70. package/src/routes/privacy-dashboard/+page.server.js +2 -2
  71. package/src/routes/privacy-dashboard/+page.svelte +8 -8
  72. package/src/routes/privacy-rights/+page.svelte +5 -5
  73. package/src/routes/status/+page.server.js +2 -2
  74. package/src/routes/terms-conditions/+page.server.js +2 -2
  75. package/src/routes/terms-conditions/+page.svelte +7 -7
  76. package/src/routes/terms-of-use/+page.server.js +2 -2
  77. package/src/routes/terms-of-use/+page.svelte +7 -7
  78. package/src/service-worker.js +86 -86
  79. package/static/disableSw.js +2 -2
  80. package/static/offline.html +7 -7
  81. package/stylelint.config.js +56 -56
  82. package/svelte.config.js +6 -6
  83. package/tests/e2e/app.spec.js +25 -25
  84. package/tests/e2e/mobile.spec.js +18 -18
  85. package/tests/e2e/shared/helpers.js +4 -4
  86. package/tests/internal/auditCoverage.test.js +24 -24
  87. package/tests/unit/checkEnv.test.js +10 -10
  88. package/tests/unit/checkVersions.test.js +4 -4
  89. package/tests/unit/csp-report.test.js +24 -24
  90. package/tests/unit/demo.test.js +3 -3
  91. package/tests/unit/lib/utils/purify.test.js +12 -12
  92. package/tests/unit/routes/page.svelte.test.js +10 -10
  93. package/tests/unit/unregisterServiceWorker.test.js +5 -5
  94. package/tests/unit/utm.test.js +13 -13
  95. package/vite.config.js +5 -5
  96. package/vitest-setup-client.js +4 -4
  97. package/vitest.config.client.js +15 -15
  98. package/vitest.config.server.js +13 -13
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.13.0] - 2025-06-11
26
+
27
+ ### Added
28
+
29
+ - Introduced `/pgp` route to publish OpenPGP contact information, download links, and QR codes
30
+ - Added `.well-known/humans.txt` to document project authorship
31
+ - Added `.well-known/security.txt` to define the official security contact and vulnerability disclosure policy
32
+ - Linked OpenPGP keys to external directories for validation (e.g. keys.openpgp.org)
33
+ - Added new GitHub Actions workflow: `check-security-txt-expiry.yml` to monitor `security.txt` expiration
34
+
35
+ ### Changed
36
+
37
+ - Enforced `"singleQuote": true` in `.prettierrc` and formatted the codebase using Prettier
38
+ - Updated `src/service-worker.js` to exclude `security.txt.asc` from caching
39
+ - CSP policy updated to allow `clipboard-write` for improved UX on PGP fingerprint buttons
40
+ - Clarified that addresses under the `s.neteng.pro` domain are powered by Proton Mail and support native E2EE
41
+ - Revised `SECURITY.md` and `security.txt` with accurate Proton Mail usage notes and PGP policy references
42
+
43
+ ### Removed
44
+
45
+ - Legacy reference to a "coming soon" PGP section in `SECURITY.md` (now live and linked)
46
+
47
+ ---
48
+
25
49
  ## [1.12.9] - 2025-06-11
26
50
 
27
51
  ### Added
@@ -286,7 +310,8 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
286
310
 
287
311
  <!-- Link references -->
288
312
 
289
- [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.12.9...HEAD
313
+ [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.13.0...HEAD
314
+ [1.13.0]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.13.0
290
315
  [1.12.9]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.12.9
291
316
  [1.12.8]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.12.8
292
317
  [1.12.7]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.12.7
package/README.md CHANGED
@@ -221,12 +221,12 @@ This script runs `scripts/checkNode.js`, which compares your current Node.js and
221
221
  **_Node Version Check (snippet from `scripts/checkNode.js`)_**
222
222
 
223
223
  ```javascript
224
- const semver = require("semver");
225
- const { engines } = require("../package.json");
224
+ const semver = require('semver');
225
+ const { engines } = require('../package.json');
226
226
 
227
227
  const requiredNode = engines.node;
228
228
  const requiredNpm = engines.npm;
229
- const isPostInstall = process.env.npm_lifecycle_event === "postinstall";
229
+ const isPostInstall = process.env.npm_lifecycle_event === 'postinstall';
230
230
 
231
231
  let hasError = false;
232
232
 
@@ -236,8 +236,8 @@ if (!semver.satisfies(process.version, requiredNode)) {
236
236
  if (!isPostInstall) hasError = true;
237
237
  }
238
238
 
239
- const npmVersion = require("child_process")
240
- .execSync("npm -v")
239
+ const npmVersion = require('child_process')
240
+ .execSync('npm -v')
241
241
  .toString()
242
242
  .trim();
243
243
 
@@ -248,7 +248,7 @@ if (!semver.satisfies(npmVersion, requiredNpm)) {
248
248
  }
249
249
 
250
250
  if (!hasError) {
251
- console.log("✅ Node and npm versions are valid.");
251
+ console.log('✅ Node and npm versions are valid.');
252
252
  } else {
253
253
  process.exit(1);
254
254
  }
@@ -343,7 +343,7 @@ It unregisters **all active service worker registrations** and logs the result.
343
343
  Located at `static/disableSw.js`, this file sets a global flag if the URL contains the `?nosw` query parameter:
344
344
 
345
345
  ```js
346
- if (location.search.includes("nosw")) {
346
+ if (location.search.includes('nosw')) {
347
347
  window.__DISABLE_SW__ = true;
348
348
  }
349
349
  ```
@@ -365,7 +365,7 @@ https://netwk.pro/?nosw
365
365
  To register the service worker conditionally, call the function from client code:
366
366
 
367
367
  ```js
368
- import { registerServiceWorker } from "$lib/registerServiceWorker.js";
368
+ import { registerServiceWorker } from '$lib/registerServiceWorker.js';
369
369
 
370
370
  registerServiceWorker();
371
371
  ```
package/eslint.config.mjs CHANGED
@@ -6,57 +6,57 @@ 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
- import js from "@eslint/js"; // Provides ESLint core rules and recommended config
10
- import eslintConfigPrettier from "eslint-config-prettier"; // Prettier config to disable conflicting ESLint rules
11
- import jsdocPlugin from "eslint-plugin-jsdoc"; // JSDoc plugin
12
- import sveltePlugin from "eslint-plugin-svelte"; // Svelte plugin
13
- import globals from "globals";
14
- import svelteParser from "svelte-eslint-parser"; // Svelte parser
9
+ import js from '@eslint/js'; // Provides ESLint core rules and recommended config
10
+ import eslintConfigPrettier from 'eslint-config-prettier'; // Prettier config to disable conflicting ESLint rules
11
+ import jsdocPlugin from 'eslint-plugin-jsdoc'; // JSDoc plugin
12
+ import sveltePlugin from 'eslint-plugin-svelte'; // Svelte plugin
13
+ import globals from 'globals';
14
+ import svelteParser from 'svelte-eslint-parser'; // Svelte parser
15
15
 
16
16
  const GLOBALS = {
17
17
  ...globals.browser,
18
18
  ...globals.node,
19
- self: "readonly",
20
- location: "readonly",
21
- indexedDB: "readonly",
19
+ self: 'readonly',
20
+ location: 'readonly',
21
+ indexedDB: 'readonly',
22
22
  ...globals.vitest, // Add Vitest globals for test functions like afterEach, describe, etc.
23
23
  };
24
24
 
25
25
  // Define general ESLint rules (non-Svelte-specific)
26
26
  const ESLINT_RULES = {
27
- indent: "off", // Turn off the 'indent' rule, managed by Prettier
28
- quotes: "off", // Turn off the 'quotes' rule, managed by Prettier
29
- semi: "off", // Turn off the 'semi' rule, managed by Prettier
27
+ indent: 'off', // Turn off the 'indent' rule, managed by Prettier
28
+ quotes: 'off', // Turn off the 'quotes' rule, managed by Prettier
29
+ semi: 'off', // Turn off the 'semi' rule, managed by Prettier
30
30
  };
31
31
 
32
32
  export default [
33
33
  // Global ignores
34
34
  {
35
35
  ignores: [
36
- ".*", // Hidden files
37
- "*.xml", // XML files
38
- "**/.cache/**", // Cache directories
39
- "**/.vscode/**", // VSCode-specific files
40
- "**/coverage/**", // Coverage reports
41
- "**/build/**", // Distribution files
42
- "package.json", // NPM package manifest
43
- "package-lock.json", // NPM lockfile
44
- "**/playwright-report/**", // Playwright report files
45
- "node_modules/", // Node.js dependencies
46
- "**/test-results/**", // Test results
47
- ".vite/", // Vite-specific cache directory
48
- "*.lock", // Lock files
49
- ".env*", // Environment files
36
+ '.*', // Hidden files
37
+ '*.xml', // XML files
38
+ '**/.cache/**', // Cache directories
39
+ '**/.vscode/**', // VSCode-specific files
40
+ '**/coverage/**', // Coverage reports
41
+ '**/build/**', // Distribution files
42
+ 'package.json', // NPM package manifest
43
+ 'package-lock.json', // NPM lockfile
44
+ '**/playwright-report/**', // Playwright report files
45
+ 'node_modules/', // Node.js dependencies
46
+ '**/test-results/**', // Test results
47
+ '.vite/', // Vite-specific cache directory
48
+ '*.lock', // Lock files
49
+ '.env*', // Environment files
50
50
  ],
51
51
  },
52
52
 
53
53
  // General JavaScript/Node.js configuration
54
54
  {
55
- files: ["**/*.mjs", "**/*.js"],
55
+ files: ['**/*.mjs', '**/*.js'],
56
56
  languageOptions: {
57
57
  globals: GLOBALS,
58
- ecmaVersion: "latest",
59
- sourceType: "module",
58
+ ecmaVersion: 'latest',
59
+ sourceType: 'module',
60
60
  },
61
61
  plugins: {
62
62
  jsdoc: jsdocPlugin, // Include JSDoc plugin
@@ -65,21 +65,21 @@ export default [
65
65
  ...js.configs.recommended.rules, // ESLint's core recommended rules (scoped)
66
66
  ...eslintConfigPrettier.rules, // Prettier config to disable conflicting ESLint rules (scoped)
67
67
  ...ESLINT_RULES, // Additional custom rules
68
- "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], // Ignore unused variables starting with an underscore
69
- "jsdoc/check-alignment": "warn", // Ensure JSDoc block tags are aligned
70
- "jsdoc/check-param-names": "warn", // Checks parameter names in JSDoc
68
+ 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // Ignore unused variables starting with an underscore
69
+ 'jsdoc/check-alignment': 'warn', // Ensure JSDoc block tags are aligned
70
+ 'jsdoc/check-param-names': 'warn', // Checks parameter names in JSDoc
71
71
  // Updated rule to allow the @updated tag
72
- "jsdoc/check-tag-names": [
73
- "warn",
72
+ 'jsdoc/check-tag-names': [
73
+ 'warn',
74
74
  {
75
- definedTags: ["updated"],
75
+ definedTags: ['updated'],
76
76
  },
77
77
  ],
78
- "jsdoc/check-types": "warn", // Checks if types in JSDoc are defined correctly
79
- "jsdoc/require-param": "warn", // Requires @param in JSDoc
80
- "jsdoc/require-returns": "warn", // Requires @returns in JSDoc
81
- "jsdoc/require-jsdoc": [
82
- "warn",
78
+ 'jsdoc/check-types': 'warn', // Checks if types in JSDoc are defined correctly
79
+ 'jsdoc/require-param': 'warn', // Requires @param in JSDoc
80
+ 'jsdoc/require-returns': 'warn', // Requires @returns in JSDoc
81
+ 'jsdoc/require-jsdoc': [
82
+ 'warn',
83
83
  {
84
84
  publicOnly: true,
85
85
  require: {
@@ -94,33 +94,33 @@ export default [
94
94
 
95
95
  // Svelte-specific configuration
96
96
  {
97
- files: ["**/*.svelte"],
97
+ files: ['**/*.svelte'],
98
98
  plugins: { svelte: sveltePlugin }, // Use imported Svelte plugin
99
99
  languageOptions: {
100
100
  parser: svelteParser, // Use imported Svelte parser
101
101
  globals: GLOBALS, // Your global variables
102
- ecmaVersion: "latest", // Use "latest" for Svelte to leverage modern features
103
- sourceType: "module",
102
+ ecmaVersion: 'latest', // Use "latest" for Svelte to leverage modern features
103
+ sourceType: 'module',
104
104
  },
105
105
  rules: {
106
106
  ...sveltePlugin.configs.recommended.rules, // Svelte recommended rules
107
107
  ...sveltePlugin.configs.prettier.rules, // Prettier compatibility for Svelte
108
- "svelte/no-at-html-tags": "warn", // Warn on use of @html (security risk)
109
- "svelte/require-optimized-style-attribute": "warn", // Recommend optimized style attributes
108
+ 'svelte/no-at-html-tags': 'warn', // Warn on use of @html (security risk)
109
+ 'svelte/require-optimized-style-attribute': 'warn', // Recommend optimized style attributes
110
110
  },
111
111
  },
112
112
 
113
113
  // Vitest-specific configuration
114
114
  {
115
- files: ["**/*.test.js", "**/*.spec.js", "**/vitest-setup-client.js"], // Test-related files
115
+ files: ['**/*.test.js', '**/*.spec.js', '**/vitest-setup-client.js'], // Test-related files
116
116
  languageOptions: {
117
117
  globals: {
118
118
  ...GLOBALS,
119
- afterEach: "readonly", // Explicitly declare afterEach as a global
119
+ afterEach: 'readonly', // Explicitly declare afterEach as a global
120
120
  },
121
121
  },
122
122
  rules: {
123
- "no-undef": "off", // Turn off no-undef for test globals
123
+ 'no-undef': 'off', // Turn off no-undef for test globals
124
124
  },
125
125
  },
126
126
  ];
@@ -27,29 +27,29 @@ This file is part of Network Pro.
27
27
  * @returns {Promise<Response>} HTTP Response with status 204 or 405
28
28
  */
29
29
  export default async (request, _context) => {
30
- if (request.method !== "POST") {
31
- return new Response("Method Not Allowed", { status: 405 });
30
+ if (request.method !== 'POST') {
31
+ return new Response('Method Not Allowed', { status: 405 });
32
32
  }
33
33
 
34
34
  try {
35
35
  const body = await request.json();
36
- const report = body["csp-report"];
36
+ const report = body['csp-report'];
37
37
 
38
38
  // Ignore if report is missing or malformed
39
- if (!report || typeof report !== "object") {
39
+ if (!report || typeof report !== 'object') {
40
40
  return new Response(null, { status: 204 });
41
41
  }
42
42
 
43
- const violated = report["violated-directive"] ?? "";
44
- const blockedUri = report["blocked-uri"] ?? "";
43
+ const violated = report['violated-directive'] ?? '';
44
+ const blockedUri = report['blocked-uri'] ?? '';
45
45
 
46
46
  // Filter: Skip img-src violations and empty URIs
47
47
  const ignored = [
48
- violated.startsWith("img-src"),
49
- blockedUri === "",
50
- blockedUri === "about",
51
- blockedUri.startsWith("chrome-extension://"),
52
- blockedUri.startsWith("moz-extension://"),
48
+ violated.startsWith('img-src'),
49
+ blockedUri === '',
50
+ blockedUri === 'about',
51
+ blockedUri.startsWith('chrome-extension://'),
52
+ blockedUri.startsWith('moz-extension://'),
53
53
  ].some(Boolean);
54
54
 
55
55
  if (ignored) {
@@ -60,15 +60,15 @@ export default async (request, _context) => {
60
60
  await sendToNtfy(violated, blockedUri, report);
61
61
 
62
62
  // Log useful violations
63
- console.log("[CSP-Edge] Violation:", {
63
+ console.log('[CSP-Edge] Violation:', {
64
64
  directive: violated,
65
65
  uri: blockedUri,
66
- referrer: report["referrer"],
67
- source: report["source-file"],
68
- line: report["line-number"],
66
+ referrer: report['referrer'],
67
+ source: report['source-file'],
68
+ line: report['line-number'],
69
69
  });
70
70
  } catch (err) {
71
- console.warn("[CSP-Edge] Failed to parse CSP report:", err.message);
71
+ console.warn('[CSP-Edge] Failed to parse CSP report:', err.message);
72
72
  }
73
73
 
74
74
  return new Response(null, { status: 204 });
@@ -87,13 +87,13 @@ const VIOLATION_TTL_MS = 60_000;
87
87
  */
88
88
  async function sendToNtfy(violated, blockedUri, report) {
89
89
  const highRiskDirectives = [
90
- "script-src",
91
- "form-action",
92
- "frame-ancestors",
93
- "base-uri",
90
+ 'script-src',
91
+ 'form-action',
92
+ 'frame-ancestors',
93
+ 'base-uri',
94
94
  ];
95
95
 
96
- const directiveKey = violated.split(" ")[0]; // strip fallback values or sources
96
+ const directiveKey = violated.split(' ')[0]; // strip fallback values or sources
97
97
  const isHighRisk = highRiskDirectives.includes(directiveKey);
98
98
  console.log(`[CSP-Edge] Checking directive: ${directiveKey}`);
99
99
  if (!isHighRisk) return;
@@ -120,23 +120,23 @@ async function sendToNtfy(violated, blockedUri, report) {
120
120
  }
121
121
  }
122
122
 
123
- const topicUrl = "https://ntfy.neteng.pro/csp-alerts";
123
+ const topicUrl = 'https://ntfy.neteng.pro/csp-alerts';
124
124
 
125
125
  const message = [
126
126
  `🚨 CSP Violation Detected`,
127
127
  `Directive: ${violated}`,
128
128
  `Blocked URI: ${blockedUri}`,
129
- `Referrer: ${report.referrer || "N/A"}`,
130
- `Source: ${report["source-file"] || "N/A"}`,
131
- `Line: ${report["line-number"] || "N/A"}`,
132
- ].join("\n");
129
+ `Referrer: ${report.referrer || 'N/A'}`,
130
+ `Source: ${report['source-file'] || 'N/A'}`,
131
+ `Line: ${report['line-number'] || 'N/A'}`,
132
+ ].join('\n');
133
133
 
134
134
  await fetch(topicUrl, {
135
- method: "POST",
135
+ method: 'POST',
136
136
  headers: {
137
- "Content-Type": "text/plain",
138
- "X-Title": "High-Risk CSP Violation",
139
- "X-Priority": "5",
137
+ 'Content-Type': 'text/plain',
138
+ 'X-Title': 'High-Risk CSP Violation',
139
+ 'X-Priority': '5',
140
140
  },
141
141
  body: message,
142
142
  });
@@ -147,5 +147,5 @@ async function sendToNtfy(violated, blockedUri, report) {
147
147
  * This sets the endpoint route to /api/csp-report
148
148
  */
149
149
  export const config = {
150
- path: "/api/csp-report",
150
+ path: '/api/csp-report',
151
151
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@networkpro/web",
3
3
  "private": false,
4
- "version": "1.12.9",
4
+ "version": "1.13.0",
5
5
  "description": "Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro Strategies",
6
6
  "keywords": [
7
7
  "advisory",
@@ -7,14 +7,14 @@ This file is part of Network Pro.
7
7
  ========================================================================== */
8
8
 
9
9
  // @ts-check
10
- import { defineConfig, devices } from "@playwright/test";
10
+ import { defineConfig, devices } from '@playwright/test';
11
11
 
12
12
  /**
13
13
  * @see https://playwright.dev/docs/test-configuration
14
14
  */
15
15
  export default defineConfig({
16
- testDir: "./tests/e2e",
17
- testMatch: "*.spec.js",
16
+ testDir: './tests/e2e',
17
+ testMatch: '*.spec.js',
18
18
 
19
19
  /* Run tests in files in parallel */
20
20
  fullyParallel: true,
@@ -29,12 +29,12 @@ export default defineConfig({
29
29
  workers: process.env.CI ? 1 : undefined,
30
30
 
31
31
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
32
- reporter: "html",
32
+ reporter: 'html',
33
33
 
34
34
  /* Shared settings for all projects */
35
35
  use: {
36
- baseURL: "http://localhost:4173?nosw", // Update to use preview server URL
37
- trace: "on-first-retry",
36
+ baseURL: 'http://localhost:4173?nosw', // Update to use preview server URL
37
+ trace: 'on-first-retry',
38
38
  timeout: 60000, // Default action timeout of 60 seconds for each step
39
39
  navigationTimeout: 60000, // Timeout for navigation operations
40
40
  },
@@ -43,16 +43,16 @@ export default defineConfig({
43
43
  projects: [
44
44
  // Desktop Browsers
45
45
  {
46
- name: "chromium",
46
+ name: 'chromium',
47
47
  use: {
48
- browserName: "chromium", // Use Chromium browser
48
+ browserName: 'chromium', // Use Chromium browser
49
49
  headless: true, // Enable true headless mode
50
50
  },
51
51
  },
52
52
  {
53
- name: "firefox",
53
+ name: 'firefox',
54
54
  use: {
55
- ...devices["Desktop Firefox"], // Use default Firefox settings
55
+ ...devices['Desktop Firefox'], // Use default Firefox settings
56
56
  },
57
57
  },
58
58
  // FIXME: Webkit and Safari consistently failing, disabled for now
@@ -65,9 +65,9 @@ export default defineConfig({
65
65
 
66
66
  // Mobile Browsers
67
67
  {
68
- name: "Mobile Chrome",
68
+ name: 'Mobile Chrome',
69
69
  use: {
70
- ...devices["Galaxy S9+"], // Use the Galaxy S9+ device profile
70
+ ...devices['Galaxy S9+'], // Use the Galaxy S9+ device profile
71
71
  headless: true, // Enable true headless mode
72
72
  },
73
73
  },
@@ -82,8 +82,8 @@ export default defineConfig({
82
82
 
83
83
  /* Run your local preview server before starting the tests */
84
84
  webServer: {
85
- command: "npm run preview", // Use preview server
86
- url: "http://localhost:4173?nosw", // Match the preview server URL
85
+ command: 'npm run preview', // Use preview server
86
+ url: 'http://localhost:4173?nosw', // Match the preview server URL
87
87
  reuseExistingServer: !process.env.CI,
88
88
  timeout: 60 * 1000, // wait up to 60 seconds for preview to be ready
89
89
  },
@@ -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
- import autoprefixer from "autoprefixer";
9
+ import autoprefixer from 'autoprefixer';
10
10
 
11
11
  export default {
12
12
  plugins: [
@@ -15,16 +15,16 @@ This file is part of Network Pro.
15
15
  * @updated 2025-05-21
16
16
  */
17
17
 
18
- import fs from "fs";
19
- import path from "path";
18
+ import fs from 'fs';
19
+ import path from 'path';
20
20
 
21
- const scriptsDir = path.resolve("./scripts");
22
- const testsDir = path.resolve("./tests");
21
+ const scriptsDir = path.resolve('./scripts');
22
+ const testsDir = path.resolve('./tests');
23
23
 
24
24
  // Scripts intentionally excluded from test coverage
25
25
  const allowList = new Set([
26
- "checkNode.js",
27
- "auditScripts.js", // itself
26
+ 'checkNode.js',
27
+ 'auditScripts.js', // itself
28
28
  ]);
29
29
 
30
30
  // Recursively gather all test files
@@ -38,10 +38,10 @@ function getAllTestFiles(dir) {
38
38
  files.push(...getAllTestFiles(fullPath));
39
39
  } else if (
40
40
  entry.isFile() &&
41
- (entry.name.endsWith(".test.js") ||
42
- entry.name.endsWith(".spec.js") ||
43
- entry.name.endsWith(".test.mjs") ||
44
- entry.name.endsWith(".spec.mjs"))
41
+ (entry.name.endsWith('.test.js') ||
42
+ entry.name.endsWith('.spec.js') ||
43
+ entry.name.endsWith('.test.mjs') ||
44
+ entry.name.endsWith('.spec.mjs'))
45
45
  ) {
46
46
  files.push(fullPath);
47
47
  }
@@ -56,17 +56,17 @@ const testedModules = new Set(
56
56
  testFiles.map((filePath) =>
57
57
  path
58
58
  .basename(filePath)
59
- .replace(/\.test\.js$|\.spec\.js$|\.test\.mjs$|\.spec\.mjs$/, ""),
59
+ .replace(/\.test\.js$|\.spec\.js$|\.test\.mjs$|\.spec\.mjs$/, ''),
60
60
  ),
61
61
  );
62
62
 
63
63
  // Gather all scripts (.js and .mjs)
64
64
  const scriptFiles = fs
65
65
  .readdirSync(scriptsDir)
66
- .filter((file) => file.endsWith(".js") || file.endsWith(".mjs"));
66
+ .filter((file) => file.endsWith('.js') || file.endsWith('.mjs'));
67
67
 
68
68
  const untested = scriptFiles.filter((file) => {
69
- const base = file.replace(/\.(js|mjs)$/, "");
69
+ const base = file.replace(/\.(js|mjs)$/, '');
70
70
  return !allowList.has(file) && !testedModules.has(base);
71
71
  });
72
72
 
@@ -75,7 +75,7 @@ const pathRelative = (file) =>
75
75
 
76
76
  // Output results
77
77
  if (untested.length) {
78
- console.warn("\n⚠ Untested script files detected:\n");
78
+ console.warn('\n⚠ Untested script files detected:\n');
79
79
 
80
80
  untested.forEach((file) => {
81
81
  const filePath = pathRelative(file);
@@ -87,9 +87,9 @@ if (untested.length) {
87
87
  console.warn(
88
88
  `\nAdd a corresponding test file in /tests (e.g., ${untested[0].replace(
89
89
  /\.(js|mjs)$/,
90
- ".test.js",
90
+ '.test.js',
91
91
  )})`,
92
92
  );
93
93
  } else {
94
- console.log("✅ All script files have corresponding tests.");
94
+ console.log('✅ All script files have corresponding tests.');
95
95
  }
@@ -15,15 +15,15 @@ This file is part of Network Pro.
15
15
  * @updated 2025-05-16
16
16
  */
17
17
 
18
- import fs from "fs";
19
- import { bundle } from "lightningcss";
20
- import path from "path";
18
+ import fs from 'fs';
19
+ import { bundle } from 'lightningcss';
20
+ import path from 'path';
21
21
 
22
22
  // Define the path to your input CSS file
23
- const inputFilePath = path.resolve("src/lib/styles/css/global.css");
23
+ const inputFilePath = path.resolve('src/lib/styles/css/global.css');
24
24
 
25
25
  // Define the path for the output CSS file
26
- const outputFilePath = path.resolve("src/lib/styles/css/global.min.css");
26
+ const outputFilePath = path.resolve('src/lib/styles/css/global.min.css');
27
27
 
28
28
  // Bundle and minify the CSS
29
29
  const { code, map } = bundle({
@@ -15,10 +15,10 @@ This file is part of Network Pro.
15
15
  * @updated 2025-05-21
16
16
  */
17
17
 
18
- import { basename } from "path";
19
- import { fileURLToPath } from "url";
18
+ import { basename } from 'path';
19
+ import { fileURLToPath } from 'url';
20
20
 
21
- const validEnvs = new Set(["dev", "test", "ci", "prod", "preview"]);
21
+ const validEnvs = new Set(['dev', 'test', 'ci', 'prod', 'preview']);
22
22
 
23
23
  /**
24
24
  * Checks and returns validation for ENV_MODE
@@ -36,7 +36,7 @@ export function checkEnv() {
36
36
  let wasDefaulted = false;
37
37
 
38
38
  if (!mode) {
39
- mode = "dev";
39
+ mode = 'dev';
40
40
  process.env.ENV_MODE = mode;
41
41
  wasDefaulted = true;
42
42
  console.warn("⚠️ ENV_MODE not set. Defaulting to 'dev'.");
@@ -45,11 +45,11 @@ export function checkEnv() {
45
45
  valid = validEnvs.has(mode);
46
46
 
47
47
  if (valid) {
48
- const tag = wasDefaulted ? "[info]" : "[ok]";
48
+ const tag = wasDefaulted ? '[info]' : '[ok]';
49
49
  console.log(`${tag} ENV_MODE is set to: "${mode}"`);
50
50
  } else {
51
51
  console.error(
52
- `❌ Invalid ENV_MODE "${mode}". Must be one of: ${[...validEnvs].join(", ")}`,
52
+ `❌ Invalid ENV_MODE "${mode}". Must be one of: ${[...validEnvs].join(', ')}`,
53
53
  );
54
54
  }
55
55