@svelte-vitals/vite 0.10.0 → 0.11.1

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.
@@ -108,6 +108,26 @@ function parseHtmlHead(html) {
108
108
  return { tags, htmlLang, headings, images };
109
109
  }
110
110
 
111
+ // src/loopback.ts
112
+ function isLoopbackOrigin(origin) {
113
+ try {
114
+ const host = new URL(origin).hostname;
115
+ return host === "localhost" || host === "127.0.0.1" || host === "[::1]";
116
+ } catch {
117
+ return false;
118
+ }
119
+ }
120
+ function isLoopbackHost(host) {
121
+ if (host === void 0) return false;
122
+ try {
123
+ return isLoopbackOrigin(`http://${host}`);
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+
111
129
  export {
112
- parseHtmlHead
130
+ parseHtmlHead,
131
+ isLoopbackOrigin,
132
+ isLoopbackHost
113
133
  };
@@ -1,6 +1,7 @@
1
1
  import {
2
+ isLoopbackOrigin,
2
3
  parseHtmlHead
3
- } from "../chunk-LIC7DE52.js";
4
+ } from "../chunk-4LXPHVAW.js";
4
5
 
5
6
  // src/hooks/handle.ts
6
7
  import { DEV } from "esm-env";
@@ -35,14 +36,6 @@ function findingSignature(results, config) {
35
36
  }
36
37
 
37
38
  // src/hooks/handle.ts
38
- function isLoopbackOrigin(origin) {
39
- try {
40
- const host = new URL(origin).hostname;
41
- return host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host === "::1";
42
- } catch {
43
- return false;
44
- }
45
- }
46
39
  async function postIngest(origin, route, results) {
47
40
  if (!isLoopbackOrigin(origin)) {
48
41
  if (globalThis.process?.env?.SVELTE_VITALS_DEBUG) {
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import {
2
+ isLoopbackHost,
3
+ isLoopbackOrigin,
2
4
  parseHtmlHead
3
- } from "./chunk-LIC7DE52.js";
5
+ } from "./chunk-4LXPHVAW.js";
4
6
 
5
7
  // src/plugin.ts
6
8
  import { existsSync } from "fs";
@@ -98,34 +100,25 @@ async function collectRenderedProject(cwd, htmlLang) {
98
100
  }
99
101
 
100
102
  // src/providers/source/components.ts
101
- import { readFile as readFile3 } from "fs/promises";
103
+ import { readFile as readFile3, access as access2 } from "fs/promises";
102
104
  import { join as join3 } from "path";
103
105
  import { glob as glob2 } from "tinyglobby";
104
- import { parseComponentFacts } from "@svelte-vitals/core";
105
- async function collectComponentFacts(root) {
106
- const files = await glob2("src/**/*.svelte", { cwd: root, dot: false });
107
- return Promise.all(
108
- files.sort().map(async (rel) => {
109
- try {
110
- const source = await readFile3(join3(root, rel), "utf8");
111
- return { file: rel, ...parseComponentFacts(source, rel) };
112
- } catch {
113
- return {
114
- file: rel,
115
- eachBlocks: [],
116
- effects: [],
117
- htmlTags: [],
118
- javascriptUrls: [],
119
- loc: 0,
120
- propCount: 0,
121
- imports: [],
122
- namespaceImports: [],
123
- constableStates: [],
124
- suppressions: []
125
- };
126
- }
127
- })
128
- );
106
+ import { collectComponentFacts as collect } from "@svelte-vitals/core";
107
+ var nodeRuntime = {
108
+ readFile: (path) => readFile3(path, "utf8"),
109
+ async exists(path) {
110
+ try {
111
+ await access2(path);
112
+ return true;
113
+ } catch {
114
+ return false;
115
+ }
116
+ },
117
+ glob: (pattern, cwd) => glob2(pattern, { cwd, dot: false }),
118
+ join: (...parts) => join3(...parts)
119
+ };
120
+ function collectComponentFacts(root) {
121
+ return collect(nodeRuntime, root);
129
122
  }
130
123
 
131
124
  // src/version.ts
@@ -219,11 +212,16 @@ function renderDashboard(results, config, meta) {
219
212
 
220
213
  // src/ui/middleware.ts
221
214
  var SEVERITIES = /* @__PURE__ */ new Set(["critical", "warning", "info"]);
215
+ var CATEGORIES = /* @__PURE__ */ new Set(["seo", "performance", "correctness", "security", "architecture"]);
216
+ function isOptionalString(v) {
217
+ return v === void 0 || typeof v === "string";
218
+ }
222
219
  function isResultLike(x) {
223
220
  if (typeof x !== "object" || x === null) return false;
224
221
  const r = x;
225
222
  const d = r.detection;
226
- return typeof r.id === "string" && typeof r.message === "string" && typeof r.severity === "string" && SEVERITIES.has(r.severity) && typeof d === "object" && d !== null && typeof d.presence === "string" && typeof d.value === "string";
223
+ const f = r.fix;
224
+ return typeof r.id === "string" && typeof r.message === "string" && typeof r.severity === "string" && SEVERITIES.has(r.severity) && typeof d === "object" && d !== null && typeof d.presence === "string" && typeof d.value === "string" && (r.category === void 0 || typeof r.category === "string" && CATEGORIES.has(r.category)) && isOptionalString(r.location) && isOptionalString(r.recommendation) && isOptionalString(r.docsUrl) && (f === void 0 || typeof f === "object" && f !== null && typeof f.description === "string" && isOptionalString(f.snippet) && isOptionalString(f.lang)) && (r.line === void 0 || typeof r.line === "number") && isOptionalString(r.route);
227
225
  }
228
226
  function installUiMiddleware(server, config, version) {
229
227
  const store = createStore();
@@ -243,6 +241,14 @@ function installUiMiddleware(server, config, version) {
243
241
  });
244
242
  server.middlewares.use("/__svelte-vitals", (req, res) => {
245
243
  const url = req.url ?? "/";
244
+ const origin = req.headers.origin;
245
+ const host = req.headers.host;
246
+ if (typeof origin === "string" && !isLoopbackOrigin(origin) || !isLoopbackHost(host)) {
247
+ req.resume();
248
+ res.statusCode = 403;
249
+ res.end("svelte-vitals dev UI is only available from localhost");
250
+ return;
251
+ }
246
252
  if (req.method === "POST" && url.startsWith("/ingest")) {
247
253
  const chunks = [];
248
254
  req.on("data", (c) => chunks.push(c));
@@ -270,8 +276,14 @@ function installUiMiddleware(server, config, version) {
270
276
  req.on("close", () => clients.delete(res));
271
277
  return;
272
278
  }
273
- res.setHeader("Content-Type", "text/html");
274
- res.end(renderDashboard(store.snapshot(), config, { version }));
279
+ try {
280
+ const html = renderDashboard(store.snapshot(), config, { version });
281
+ res.setHeader("Content-Type", "text/html");
282
+ res.end(html);
283
+ } catch {
284
+ res.statusCode = 500;
285
+ res.end("svelte-vitals dashboard failed to render");
286
+ }
275
287
  });
276
288
  }
277
289
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svelte-vitals/vite",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Vite/SvelteKit plugin for svelte-vitals — analyzes prerendered HTML during vite build.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "homepage": "https://github.com/oekazuma/svelte-vitals#readme",
24
24
  "engines": {
25
- "node": ">=18.20.8"
25
+ "node": ">=22.13.0"
26
26
  },
27
27
  "sideEffects": false,
28
28
  "exports": {
@@ -42,10 +42,10 @@
42
42
  "esm-env": "^1.2.2",
43
43
  "node-html-parser": "^8.0.4",
44
44
  "tinyglobby": "^0.2.17",
45
- "@svelte-vitals/core": "0.19.0"
45
+ "@svelte-vitals/core": "0.21.0"
46
46
  },
47
47
  "peerDependencies": {
48
- "@sveltejs/kit": "^2.69.0",
48
+ "@sveltejs/kit": "^2.69.1",
49
49
  "vite": "^8.1.3"
50
50
  },
51
51
  "peerDependenciesMeta": {
@@ -54,7 +54,7 @@
54
54
  }
55
55
  },
56
56
  "devDependencies": {
57
- "@sveltejs/kit": "^2.69.0",
57
+ "@sveltejs/kit": "^2.69.1",
58
58
  "@types/node": "^24.13.2",
59
59
  "svelte": "^5.56.4",
60
60
  "vite": "^8.1.3"