@decocms/blocks 7.37.0 → 7.37.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/blocks",
3
- "version": "7.37.0",
3
+ "version": "7.37.2",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"
@@ -7,6 +7,7 @@
7
7
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
8
8
  import {
9
9
  configureMeter,
10
+ normalizePath,
10
11
  type MeterAdapter,
11
12
  MetricNames,
12
13
  recordCacheMetric,
@@ -256,3 +257,37 @@ describe("recordCommerceMetric (D-11)", () => {
256
257
  ).not.toThrow();
257
258
  });
258
259
  });
260
+
261
+ /**
262
+ * `http.route` is the highest-cardinality risk on the highest-volume metric.
263
+ * These cases are the real paths measured on production when the label reached
264
+ * 20,714 distinct values across 6 tenants.
265
+ */
266
+ describe("normalizePath cardinality", () => {
267
+ it("collapses CMS content slugs", () => {
268
+ expect(normalizePath("/mochila-de-couro")).toBe("/:slug");
269
+ expect(normalizePath("/moveis/quarto-infantil")).toBe("/moveis/:slug");
270
+ expect(normalizePath("/granado/eau-de-toilette-spritz-100ml")).toBe("/granado/:slug");
271
+ expect(normalizePath("/moveis/quarto-adulto/cabeceiras-mesa-de-cabeceiras")).toBe(
272
+ "/moveis/:slug/:slug",
273
+ );
274
+ });
275
+
276
+ it("leaves bounded framework and API routes intact", () => {
277
+ expect(normalizePath("/")).toBe("/");
278
+ expect(normalizePath("/api/sessions")).toBe("/api/sessions");
279
+ expect(normalizePath("/deco/invoke/magento/loaders/features")).toBe(
280
+ "/deco/invoke/magento/loaders/features",
281
+ );
282
+ });
283
+
284
+ it("keeps dotfile segments readable", () => {
285
+ expect(normalizePath("/.well-known/passkey-endpoints")).toBe("/.well-known/:slug");
286
+ });
287
+
288
+ it("still collapses ids and product pages", () => {
289
+ expect(normalizePath("/produto/12345")).toBe("/produto/:id");
290
+ expect(normalizePath("/a/deadbeefcafe")).toBe("/a/:id");
291
+ expect(normalizePath("/some-product/p")).toBe("/:slug/p");
292
+ });
293
+ });
@@ -611,10 +611,33 @@ export function recordLoaderError(name: string) {
611
611
  */
612
612
  export function normalizePath(path: string): string {
613
613
  // Collapse dynamic segments to reduce cardinality
614
- return path
614
+ const collapsed = path
615
615
  .replace(/\/[0-9a-f]{8,}/gi, "/:id")
616
616
  .replace(/\/\d+/g, "/:id")
617
617
  .replace(/\/[^/]+\/p$/, "/:slug/p");
618
+
619
+ // Content slugs are the case none of the rules above catch: they carry no
620
+ // digits, no hex id and no `/p` suffix, so a CMS page passes through as its
621
+ // own literal path and becomes its own series.
622
+ //
623
+ // /mochila-de-couro
624
+ // /moveis/quarto-infantil
625
+ // /granado/eau-de-toilette-spritz-100ml
626
+ //
627
+ // Measured on the production ClickHouse, `http.route` reached 20,714
628
+ // distinct values across only 6 tenants — on `http.server.request.duration`,
629
+ // the highest-volume metric in the pipeline (19M rows / 3h).
630
+ //
631
+ // A hyphen is the discriminator. CMS slugs are hyphenated by construction,
632
+ // while framework and API segments are single words (`api`, `sessions`,
633
+ // `deco`, `invoke`, `loaders`, `render`). Dotfile segments such as
634
+ // `.well-known` are excluded so they keep their meaning.
635
+ return collapsed
636
+ .split("/")
637
+ .map((segment) =>
638
+ segment.includes("-") && !segment.startsWith(".") ? ":slug" : segment,
639
+ )
640
+ .join("/");
618
641
  }
619
642
 
620
643
  // ---------------------------------------------------------------------------