@networkpro/web 1.25.16 → 1.25.17

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.
@@ -45,7 +45,7 @@ jobs:
45
45
  - name: Upgrade npm
46
46
  run: |
47
47
  corepack enable
48
- npm install -g npm@11.6.2
48
+ npm install -g npm@11.7.0
49
49
 
50
50
  - name: Install Node.js dependencies
51
51
  run: npm ci
@@ -130,7 +130,7 @@ jobs:
130
130
  - name: Upgrade npm
131
131
  run: |
132
132
  corepack enable
133
- npm install -g npm@11.6.2
133
+ npm install -g npm@11.7.0
134
134
 
135
135
  - name: Install Node.js dependencies
136
136
  run: npm ci
@@ -186,7 +186,7 @@ jobs:
186
186
  - name: Upgrade npm
187
187
  run: |
188
188
  corepack enable
189
- npm install -g npm@11.6.2
189
+ npm install -g npm@11.7.0
190
190
 
191
191
  - name: Install Node.js dependencies
192
192
  run: npm ci
@@ -10,7 +10,7 @@ permissions:
10
10
 
11
11
  jobs:
12
12
  check-expiry:
13
- runs-on: ubuntu-latest
13
+ runs-on: ubuntu-24.04
14
14
  name: Validate .well-known/security.txt expiration
15
15
  env:
16
16
  ENV_MODE: ci
@@ -51,7 +51,7 @@ jobs:
51
51
  - name: Upgrade npm
52
52
  run: |
53
53
  corepack enable
54
- npm install -g npm@11.6.2
54
+ npm install -g npm@11.7.0
55
55
 
56
56
  - name: Clean previous Lighthouse reports
57
57
  run: |
@@ -41,7 +41,7 @@ jobs:
41
41
  - name: Upgrade npm
42
42
  run: |
43
43
  corepack enable
44
- npm install -g npm@11.6.2
44
+ npm install -g npm@11.7.0
45
45
 
46
46
  - name: Install Node.js dependencies
47
47
  run: npm ci
@@ -48,7 +48,7 @@ jobs:
48
48
  - name: Upgrade npm
49
49
  run: |
50
50
  corepack enable
51
- npm install -g npm@11.6.2
51
+ npm install -g npm@11.7.0
52
52
 
53
53
  - name: Install Node.js dependencies
54
54
  run: npm ci
@@ -134,7 +134,7 @@ jobs:
134
134
  - name: Upgrade npm
135
135
  run: |
136
136
  corepack enable
137
- npm install -g npm@11.6.2
137
+ npm install -g npm@11.7.0
138
138
 
139
139
  - name: Install Node.js dependencies
140
140
  run: npm ci
@@ -195,7 +195,7 @@ jobs:
195
195
  - name: Upgrade npm
196
196
  run: |
197
197
  corepack enable
198
- npm install -g npm@11.6.2
198
+ npm install -g npm@11.7.0
199
199
 
200
200
  - name: Install Node.js dependencies
201
201
  run: npm ci
@@ -53,7 +53,7 @@ jobs:
53
53
  - name: Upgrade npm
54
54
  run: |
55
55
  corepack enable
56
- npm install -g npm@11.6.2
56
+ npm install -g npm@11.7.0
57
57
 
58
58
  - name: Install Node.js dependencies
59
59
  run: npm ci
@@ -134,7 +134,7 @@ jobs:
134
134
  - name: Upgrade npm
135
135
  run: |
136
136
  corepack enable
137
- npm install -g npm@11.6.2
137
+ npm install -g npm@11.7.0
138
138
 
139
139
  - name: Install Node.js dependencies
140
140
  run: npm ci
@@ -190,7 +190,7 @@ jobs:
190
190
  - name: Upgrade npm
191
191
  run: |
192
192
  corepack enable
193
- npm install -g npm@11.6.2
193
+ npm install -g npm@11.7.0
194
194
 
195
195
  - name: Install Node.js dependencies
196
196
  run: npm ci
package/.ncurc.cjs CHANGED
@@ -31,7 +31,7 @@ This file is part of Network Pro.
31
31
  /** @type {import('npm-check-updates').RunOptions} */
32
32
  module.exports = {
33
33
  // Ignore specific dependencies (prevent upgrades)
34
- reject: ['vitest', '@vitest/coverage-v8', 'prettier', 'jsdom'],
34
+ reject: ['vitest', '@vitest/coverage-v8', 'prettier'],
35
35
 
36
36
  // Always upgrade devDependencies as well
37
37
  dep: 'prod,dev',
package/CHANGELOG.md CHANGED
@@ -22,6 +22,69 @@ This project attempts to follow [Keep a Changelog](https://keepachangelog.com/en
22
22
 
23
23
  ---
24
24
 
25
+ ## [1.25.17] - 2025-12-11
26
+
27
+ ### Added
28
+
29
+ - Added SSR boundary protection test (`tests/unit/server/internal/ssrBoundary.test.js`):
30
+ - Detects Node-only imports (`jsdom`, `fs`, `path`, etc.) in client-visible modules.
31
+ - Ensures imports are properly gated behind `import.meta.env.SSR`.
32
+ - Prevents accidental SSR/client boundary violations in future code changes.
33
+ - Added support for detecting SSR-safe code paths by allowing SSR-gated dynamic imports in shared modules.
34
+
35
+ ### Changed
36
+
37
+ - Refactored `src/service-worker.js` for improved consistency, clarity, and lint compatibility:
38
+ - Removed unused function parameters (`_err`) and adjusted callback signatures to align with ESLint expectations.
39
+ - Replaced anonymous no-op parameters with explicitly ignored placeholders using the `_` naming convention.
40
+ - Improved async iteration patterns in asset caching logic for better readability and maintainability.
41
+ - Updated JSDoc annotations for accuracy and improved editor support.
42
+ - Ensured all cache operations conform to structured error-handling patterns consistent with the rest of the codebase.
43
+
44
+ - Updated `src/lib/utils/purify.js`:
45
+ - Replaced `typeof window !== 'undefined'` guard with compile-time `import.meta.env.SSR`.
46
+ - Ensures Vite tree-shakes `jsdom` imports from client bundles.
47
+ - Fixed build failures caused by jsdom/cssstyle when bundled on the client.
48
+ - Preserves existing DOMPurify caching and SSR behavior.
49
+
50
+ - Enhanced ESLint `no-unused-vars` rule in `eslint.config.mjs`:
51
+ - Added support for ignoring unused catch parameters via `caughtErrors` and `caughtErrorsIgnorePattern`.
52
+ - Prevented false positives on intentionally unused error variables (e.g., `_err`).
53
+ - Expanded ignore patterns to match project coding conventions.
54
+
55
+ - Replaced `src/lib/img/qr/vcard.png` and `src/lib/img/qr/vcard.webp` with revised versions.
56
+ - Updated GitHub workflows to utilize **npm** `11.7.0`.
57
+ - Updated generator metadata in `src/app.html` to reflect **SvelteKit 2.49.2**.
58
+ - Updated `src/lib/README.md` to reflect the newly updated app constant.
59
+ - Updated contact information in `static/bin/contact.vcf`.
60
+ - Updated `CONTACT.PHONE` app constant to reflect our new phone number, (602) 428-5300.
61
+ - Removed `jsdom` from `.ncurc.cjs` `reject` list.
62
+ - Bumped project version to `v1.25.17`.
63
+ - Updated dependencies:
64
+ - `dompurify` `^3.3.0` → `^3.3.1`
65
+ - `posthog-js` `^1.295.0` → `^1.305.0`
66
+ - `svelte` `5.43.12` → `5.45.9`
67
+ - `@playwright/test` `^1.56.1` → `^1.57.0`
68
+ - `@sveltejs/adapter-vercel` `^6.1.1` → `^6.2.0`
69
+ - `@sveltejs/kit` `2.48.5` → `2.49.2`
70
+ - `browserslist` `^4.28.0` → `^4.28.1`
71
+ - `eslint-plugin-jsdoc` `^61.2.1` → `^61.5.0`
72
+ - `eslint-plugin-svelte` `^3.13.0` → `^3.13.1`
73
+ - `markdownlint` `^0.39.0` → `^0.40.0`
74
+ - `markdownlint-cli2` `0.19.0` → `0.20.0`
75
+ - `playwright` `^1.56.1` → `^1.57.0`
76
+ - `stylelint` `^16.25.0` → `^16.26.1`
77
+ - `svelte-eslint-parser` `^1.4.0` → `^1.4.1`
78
+ - `vite` `^7.2.2` → `^7.2.7`
79
+ - `jsdom` `26.1.0` → `27.3.0`
80
+
81
+ ### Fixed
82
+
83
+ - Resolved client-side build failures caused by dynamic jsdom imports leaking into the Vite dependency graph.
84
+ - Resolved false positive ESLint errors for unused catch bindings in JS modules.
85
+
86
+ ---
87
+
25
88
  ## [1.25.16] - 2025-11-18
26
89
 
27
90
  ### Changed
@@ -1961,7 +2024,8 @@ This enables analytics filtering and CSP hardening for the audit environment.
1961
2024
 
1962
2025
  <!-- Link references -->
1963
2026
 
1964
- [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.25.16...HEAD
2027
+ [Unreleased]: https://github.com/netwk-pro/netwk-pro.github.io/compare/v1.25.17...HEAD
2028
+ [1.25.17]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.17
1965
2029
  [1.25.16]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.16
1966
2030
  [1.25.15]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.15
1967
2031
  [1.25.14]: https://github.com/netwk-pro/netwk-pro.github.io/releases/tag/v1.25.14
package/eslint.config.mjs CHANGED
@@ -65,14 +65,27 @@ 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
68
+
69
+ // Updated unused variable handling:
70
+ // - Ignore args starting with "_"
71
+ // - Ignore vars starting with "_"
72
+ // - Allow unused catch variables named "_err" or any "_*"
73
+ 'no-unused-vars': [
74
+ 'error',
75
+ {
76
+ argsIgnorePattern: '^_',
77
+ varsIgnorePattern: '^_',
78
+ caughtErrors: 'all',
79
+ caughtErrorsIgnorePattern: '^_',
80
+ },
81
+ ],
82
+
69
83
  'jsdoc/check-alignment': 'warn', // Ensure JSDoc block tags are aligned
70
84
  'jsdoc/check-param-names': 'warn', // Checks parameter names in JSDoc
71
- // Updated rule to allow the @updated tag
72
85
  'jsdoc/check-tag-names': [
73
86
  'warn',
74
87
  {
75
- definedTags: ['updated'],
88
+ definedTags: ['updated'], // Allow custom @updated tag
76
89
  },
77
90
  ],
78
91
  'jsdoc/check-types': 'warn', // Checks if types in JSDoc are defined correctly
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@networkpro/web",
3
3
  "private": false,
4
- "version": "1.25.16",
4
+ "version": "1.25.17",
5
5
  "description": "Locking Down Networks, Unlocking Confidence™ | Security, Networking, Privacy — Network Pro Strategies",
6
6
  "keywords": [
7
7
  "advisory",
@@ -85,49 +85,50 @@
85
85
  "pre-push": "if [ \"$CI\" = \"true\" ]; then exit 0; else npm run checkout; fi"
86
86
  },
87
87
  "dependencies": {
88
- "dompurify": "^3.3.0",
89
- "posthog-js": "^1.295.0",
88
+ "dompurify": "^3.3.1",
89
+ "posthog-js": "^1.305.0",
90
90
  "semver": "^7.7.3",
91
- "svelte": "5.43.12"
91
+ "svelte": "5.45.9"
92
92
  },
93
93
  "devDependencies": {
94
94
  "@eslint/compat": "^2.0.0",
95
95
  "@eslint/js": "^9.39.1",
96
96
  "@lhci/cli": "^0.15.1",
97
- "@playwright/test": "^1.56.1",
97
+ "@playwright/test": "^1.57.0",
98
98
  "@sveltejs/adapter-netlify": "^5.2.4",
99
- "@sveltejs/adapter-vercel": "^6.1.1",
100
- "@sveltejs/kit": "2.48.5",
99
+ "@sveltejs/adapter-vercel": "^6.2.0",
100
+ "@sveltejs/kit": "2.49.2",
101
101
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
102
102
  "@testing-library/jest-dom": "^6.9.1",
103
103
  "@testing-library/svelte": "^5.2.9",
104
104
  "@vitest/coverage-v8": "3.2.4",
105
105
  "autoprefixer": "^10.4.22",
106
- "browserslist": "^4.28.0",
106
+ "browserslist": "^4.28.1",
107
107
  "eslint": "^9.39.1",
108
108
  "eslint-config-prettier": "^10.1.8",
109
- "eslint-plugin-jsdoc": "^61.2.1",
110
- "eslint-plugin-svelte": "^3.13.0",
109
+ "eslint-plugin-jsdoc": "^61.5.0",
110
+ "eslint-plugin-svelte": "^3.13.1",
111
111
  "globals": "^16.5.0",
112
- "jsdom": "26.1.0",
112
+ "globby": "^16.0.0",
113
+ "jsdom": "27.3.0",
113
114
  "lightningcss": "^1.30.2",
114
- "markdownlint": "^0.39.0",
115
- "markdownlint-cli2": "0.19.0",
115
+ "markdownlint": "^0.40.0",
116
+ "markdownlint-cli2": "0.20.0",
116
117
  "npm-run-all": "^4.1.5",
117
- "playwright": "^1.56.1",
118
+ "playwright": "^1.57.0",
118
119
  "postcss": "^8.5.6",
119
120
  "prettier": "3.6.2",
120
121
  "prettier-plugin-svelte": "^3.4.0",
121
122
  "simple-git-hooks": "^2.13.1",
122
- "stylelint": "^16.25.0",
123
+ "stylelint": "^16.26.1",
123
124
  "stylelint-config-html": "^1.1.0",
124
125
  "stylelint-config-recommended": "^17.0.0",
125
126
  "stylelint-order": "^7.0.0",
126
127
  "svelte-check": "^4.3.4",
127
- "svelte-eslint-parser": "^1.4.0",
128
+ "svelte-eslint-parser": "^1.4.1",
128
129
  "svelte-preprocess": "^6.0.3",
129
130
  "typescript": "^5.9.3",
130
- "vite": "^7.2.2",
131
+ "vite": "^7.2.7",
131
132
  "vite-plugin-devtools-json": "^1.0.0",
132
133
  "vite-plugin-lightningcss": "^0.0.5",
133
134
  "vite-tsconfig-paths": "^5.1.4",
package/src/app.html CHANGED
@@ -53,7 +53,7 @@
53
53
  content="bx4ham0zkpvzztzu213bhpt76m9siq" />
54
54
  <!-- cspell:enable -->
55
55
 
56
- <meta name="generator" content="SvelteKit 2.48.5" />
56
+ <meta name="generator" content="SvelteKit 2.49.2" />
57
57
 
58
58
  <script src="/disableSw.js"></script>
59
59
 
package/src/lib/README.md CHANGED
@@ -97,7 +97,7 @@ console.log(CONSTANTS.COMPANY_INFO.APP_NAME); // "Network Pro"
97
97
  | `SECURE_LINK` | Secure contact address (link) | `contact@s.neteng.pro` |
98
98
  | `PRIVACY` | Privacy-related contact | `privacy (at) netwk.pro` |
99
99
  | `PRIVACY_LINK` | Privacy-related contact (link) | `privacy@netwk.pro` |
100
- | `PHONE` | Company phone number | `(623) 252-4350` |
100
+ | `PHONE` | Company phone number | `(602) 428-5300` |
101
101
 
102
102
  ### 🗂️ PAGE
103
103
 
Binary file
Binary file
package/src/lib/index.js CHANGED
@@ -62,7 +62,7 @@ export const CONSTANTS = {
62
62
  SECURE_LINK: 'contact@s.neteng.pro',
63
63
  PRIVACY: 'privacy (at) netwk.pro',
64
64
  PRIVACY_LINK: 'privacy@netwk.pro',
65
- PHONE: '(623) 252-4350',
65
+ PHONE: '(602) 428-5300',
66
66
  },
67
67
  PAGE: {
68
68
  BLANK: '_blank',
@@ -10,9 +10,9 @@ This file is part of Network Pro.
10
10
  * @file purify.js
11
11
  * @description Universal DOMPurify instance for SSR + client with safe build support.
12
12
  * Secures untrusted HTML before injecting it into the DOM.
13
- * @module src/lib/utils/
13
+ * @module src/lib/utils
14
14
  * @author Scott Lopez
15
- * @updated 2025-06-01
15
+ * @updated 2025-12-11
16
16
  */
17
17
 
18
18
  import createDOMPurify from 'dompurify';
@@ -37,11 +37,11 @@ let jsdomWindow = null;
37
37
  export async function getDOMPurify() {
38
38
  if (DOMPurifyInstance) return DOMPurifyInstance;
39
39
 
40
- if (typeof window !== 'undefined') {
40
+ if (!import.meta.env.SSR) {
41
41
  // ✅ Client-side: use native window
42
42
  DOMPurifyInstance = createDOMPurify(window);
43
43
  } else {
44
- // ✅ SSR: dynamically import jsdom to avoid bundling
44
+ // ✅ SSR: dynamically import jsdom gated so Vite will tree-shake it from the client bundle
45
45
  const { JSDOM } = await import('jsdom');
46
46
  jsdomWindow = jsdomWindow || new JSDOM('').window;
47
47
  DOMPurifyInstance = createDOMPurify(jsdomWindow);
@@ -6,18 +6,20 @@ 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
- /** @type {ServiceWorkerGlobalScope} */
9
+ /// <reference lib="webworker" />
10
+ /// <reference types="vite/client" />
11
+
12
+ /**
13
+ * @type {ServiceWorkerGlobalScope}
14
+ */
10
15
  const sw = /** @type {ServiceWorkerGlobalScope} */ (
11
16
  /** @type {unknown} */ (self)
12
17
  );
13
18
 
14
- /// <reference types="vite/client" />
15
-
16
19
  const isDev = location.hostname === 'localhost';
17
- const disallowedHosts = [
18
- 'us.i.posthog.com', // Add PostHog to disallowed hosts
19
- 'posthog.com', // Add PostHog to disallowed hosts
20
- ];
20
+
21
+ /** @type {string[]} */
22
+ const disallowedHosts = ['us.i.posthog.com', 'posthog.com'];
21
23
 
22
24
  import { build, files, version } from '$service-worker';
23
25
 
@@ -27,6 +29,7 @@ const CACHE = `cache-${version}`;
27
29
  /** @type {string[]} */
28
30
  const excludedAssets = [];
29
31
 
32
+ /** @type {Set<string>} */
30
33
  const IGNORE_PATHS = new Set([
31
34
  '/.well-known/security.txt.sig',
32
35
  '/img/banner-1280x640.png',
@@ -76,6 +79,7 @@ const ASSETS = [
76
79
  ),
77
80
  ];
78
81
 
82
+ /** @type {string[]} */
79
83
  const uniqueExcludedAssets = [...new Set(excludedAssets)].sort();
80
84
 
81
85
  /** @type {string[]} */
@@ -108,12 +112,12 @@ if (isDev) {
108
112
  }
109
113
 
110
114
  /**
111
- * Safely cache a list of assets, logging or throwing if required assets fail.
115
+ * Safely cache a list of assets.
112
116
  *
113
117
  * @param {Cache} cache
114
118
  * @param {string[]} assets
115
- * @param {string[]} required
116
- * @returns {Promise<string[]>} Cached asset paths
119
+ * @param {string[]} [required=[]]
120
+ * @returns {Promise<string[]>}
117
121
  */
118
122
  async function cacheAssetsSafely(cache, assets, required = []) {
119
123
  /** @type {string[]} */
@@ -150,6 +154,9 @@ async function cacheAssetsSafely(cache, assets, required = []) {
150
154
  }
151
155
 
152
156
  // 🔹 Install event
157
+ /**
158
+ * @param {ExtendableEvent} event
159
+ */
153
160
  sw.addEventListener('install', (event) => {
154
161
  if (isDev) console.log('[SW] Install event');
155
162
 
@@ -160,9 +167,7 @@ sw.addEventListener('install', (event) => {
160
167
 
161
168
  try {
162
169
  cachedPaths = await cacheAssetsSafely(cache, ASSETS, REQUIRED_ASSETS);
163
- if (isDev) {
164
- console.log('[SW] Cached assets:', cachedPaths);
165
- }
170
+ if (isDev) console.log('[SW] Cached assets:', cachedPaths);
166
171
  } catch (err) {
167
172
  if (isDev) throw err;
168
173
  console.warn('[SW] Error while precaching (non-fatal in prod):', err);
@@ -175,8 +180,12 @@ sw.addEventListener('install', (event) => {
175
180
  });
176
181
 
177
182
  // 🔹 Activate event
183
+ /**
184
+ * @param {ExtendableEvent} event
185
+ */
178
186
  sw.addEventListener('activate', (event) => {
179
187
  if (isDev) console.log('[SW] Activate event');
188
+
180
189
  event.waitUntil(
181
190
  (async () => {
182
191
  const tasks = [];
@@ -210,9 +219,7 @@ sw.addEventListener('activate', (event) => {
210
219
  });
211
220
 
212
221
  /**
213
- * Determine if a request should be skipped by the service worker.
214
- * Specifically filters out dev/build files, module imports, and source files.
215
- * Only active in development mode.
222
+ * Determine if a request should be ignored during development.
216
223
  *
217
224
  * @param {URL} url
218
225
  * @returns {boolean}
@@ -230,13 +237,13 @@ function shouldSkipDevModule(url) {
230
237
  }
231
238
 
232
239
  // 🔹 Fetch event
240
+ /**
241
+ * @param {FetchEvent} event
242
+ */
233
243
  sw.addEventListener('fetch', (event) => {
234
244
  const requestUrl = new URL(event.request.url);
235
245
 
236
- // ✅ Skip cross-origin requests
237
246
  if (requestUrl.origin !== location.origin) return;
238
-
239
- // ✅ Skip internal dev/module files (only in dev)
240
247
  if (shouldSkipDevModule(requestUrl)) return;
241
248
 
242
249
  if (isDev) console.log('[SW] Fetch intercepted:', event.request.url);
@@ -253,12 +260,8 @@ sw.addEventListener('fetch', (event) => {
253
260
  if (event.request.mode === 'navigate') {
254
261
  const preloadResponse = await event.preloadResponse;
255
262
  if (preloadResponse) {
256
- if (isDev) {
257
- console.log(
258
- '[SW] Using preload response for:',
259
- event.request.url,
260
- );
261
- }
263
+ if (isDev)
264
+ console.log('[SW] Using preload response:', event.request.url);
262
265
  return preloadResponse;
263
266
  }
264
267
  }
@@ -267,18 +270,17 @@ sw.addEventListener('fetch', (event) => {
267
270
  console.log('[SW] Fetching from network:', event.request.url);
268
271
 
269
272
  return await fetch(event.request);
270
- } catch (err) {
271
- if (isDev) {
273
+ } catch (_err) {
274
+ if (isDev)
272
275
  console.warn(
273
- '[SW] Fetch failed; offline fallback used:',
276
+ '[SW] Fetch failed; offline fallback:',
274
277
  event.request.url,
275
- err,
276
278
  );
277
- }
278
279
 
279
280
  if (event.request.mode === 'navigate') {
280
281
  const offline = await caches.match('/offline.html');
281
282
  if (offline) return offline;
283
+
282
284
  return new Response('<h1>Offline</h1>', {
283
285
  headers: { 'Content-Type': 'text/html' },
284
286
  });
@@ -289,5 +291,3 @@ sw.addEventListener('fetch', (event) => {
289
291
  })(),
290
292
  );
291
293
  });
292
-
293
- // @cspell:ignore precaching
@@ -2,11 +2,11 @@ BEGIN:VCARD
2
2
  VERSION:3.0
3
3
  FN:Scott Lopez
4
4
  N:Lopez;Scott
5
- TEL;TYPE=WORK,PREF=1:(623) 252-4350
5
+ TEL;TYPE=WORK,PREF=1:(602) 428-5300
6
6
  EMAIL;TYPE=WORK:support@netwk.pro
7
7
  EMAIL;TYPE=Secure:business@s.neteng.pro
8
8
  ADR;TYPE=WORK:;;Peoria\, AZ 85382\nUS
9
9
  ORG:Network Pro Strategies
10
- TITLE:Network Engineer
10
+ TITLE:Network Engineer and Consultant
11
11
  URL:https://netwk.pro
12
12
  END:VCARD
@@ -0,0 +1,107 @@
1
+ /* ==========================================================================
2
+ tests/unit/server/ssrBoundary.test.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 ssrBoundary.test.js
11
+ * @description Checks for improper usage of Node
12
+ * @module tests/unit/server/internal
13
+ * @author Scott Lopez
14
+ * @updated 2025-12-11
15
+ */
16
+
17
+ // @vitest-environment node
18
+
19
+ import fs from 'fs/promises';
20
+ import { globby } from 'globby';
21
+
22
+ // Node-only modules that cannot appear in client-visible code
23
+ const NODE_ONLY_IMPORTS = [
24
+ 'fs',
25
+ 'path',
26
+ 'url',
27
+ 'crypto',
28
+ 'os',
29
+ 'child_process',
30
+ 'module',
31
+ 'jsdom',
32
+ ];
33
+
34
+ // Files in these locations are ALWAYS allowed to use Node-only modules
35
+ const SERVER_ONLY_ALLOWLIST = [
36
+ 'src/lib/server/',
37
+ '/server/',
38
+ '+server.js',
39
+ '+server.ts',
40
+ '.test.',
41
+ '.spec.',
42
+ 'vitest.config',
43
+ 'playwright.config',
44
+ ];
45
+
46
+ function isServerOnlyFile(filePath) {
47
+ return SERVER_ONLY_ALLOWLIST.some((key) => filePath.includes(key));
48
+ }
49
+
50
+ // Regex helpers
51
+ function createStaticImportRegex(moduleName) {
52
+ return new RegExp(`import\\s+[^;]*['"]${moduleName}['"]`);
53
+ }
54
+
55
+ function createDynamicImportRegex(moduleName) {
56
+ return new RegExp(`import\\(['"]${moduleName}['"]\\)`);
57
+ }
58
+
59
+ function hasSSRGuard(text) {
60
+ // Basic detection of SSR guard presence
61
+ // Stronger variants are possible, but this avoids false positives
62
+ return /import\.meta\.env\.SSR/.test(text);
63
+ }
64
+
65
+ test('no Node-only modules leak into client-visible modules', async () => {
66
+ const files = await globby([
67
+ 'src/**/*.{js,ts,svelte}',
68
+ '!src/lib/server/**', // ignore server-only utilities
69
+ '!**/*.test.*',
70
+ '!**/*.spec.*',
71
+ ]);
72
+
73
+ const violations = [];
74
+
75
+ for (const file of files) {
76
+ if (isServerOnlyFile(file)) continue;
77
+
78
+ const text = await fs.readFile(file, 'utf8');
79
+
80
+ for (const mod of NODE_ONLY_IMPORTS) {
81
+ const staticMatch = createStaticImportRegex(mod).test(text);
82
+ const dynamicMatch = createDynamicImportRegex(mod).test(text);
83
+
84
+ if (!staticMatch && !dynamicMatch) continue;
85
+
86
+ // If SSR guarded, allow it
87
+ if (hasSSRGuard(text)) continue;
88
+
89
+ violations.push({
90
+ file,
91
+ module: mod,
92
+ });
93
+ }
94
+ }
95
+
96
+ if (violations.length > 0) {
97
+ const formatted = violations
98
+ .map((v) => `❌ ${v.module} imported in ${v.file}`)
99
+ .join('\n');
100
+
101
+ throw new Error(
102
+ 'SSR boundary violations detected:\n' +
103
+ formatted +
104
+ '\n\nTo fix: move to src/lib/server/, or wrap the import in import.meta.env.SSR.',
105
+ );
106
+ }
107
+ });
package/static/CNAME DELETED
@@ -1 +0,0 @@
1
- netwk.pro