@se-studio/ab-testing 18.0.31 → 18.0.33

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
@@ -1,5 +1,19 @@
1
1
  # @se-studio/ab-testing
2
2
 
3
+ ## 18.0.33
4
+
5
+ ### Patch Changes
6
+
7
+ - @se-studio/core-ui@1.35.2
8
+
9
+ ## 18.0.32
10
+
11
+ ### Patch Changes
12
+
13
+ - Map page-test homepage canonical paths (`/`) to CMS slug `index` so control `indexed` is used instead of the variant's `noindex`.
14
+ - Updated dependencies
15
+ - @se-studio/core-ui@1.35.1
16
+
3
17
  ## 18.0.31
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -159,9 +159,9 @@ export const config = {
159
159
 
160
160
  #### Page-test route (static rebuild pattern)
161
161
 
162
- When using `createStaticAbTestMiddleware` with `variantPathPrefix: '/page-test'`, add a `/page-test/[...slugs]` route that rewrites serve variant content on the control URL. Use `findCanonicalPath(testsByPath, variantSlug)` to resolve the user-facing path, then call the paired handlers from `@se-studio/core-ui/server`:
162
+ When using `createStaticAbTestMiddleware` with `variantPathPrefix: '/page-test'`, add a `/page-test/[...slugs]` route that rewrites serve variant content on the control URL. Use `findCanonicalPath(testsByPath, variantSlug)` to resolve the user-facing path, then `controlSlugFromCanonicalPath(canonicalPath)` for the control CMS slug (`/` → `index`). Do **not** use `canonicalPath.replace(/^\/|\/$/g, '') || variantSlug` — that maps the homepage to the variant (`indexed: false`) and flip-flops robots. Then call the paired handlers from `@se-studio/core-ui/server`:
163
163
 
164
- - `generatePageTestMetadata` — control `indexed` and canonical path in `<head>`
164
+ - `generatePageTestMetadata` — control `indexed` and canonical path in `<head>` (re-resolves `/` to `index` even if the caller still passes the variant slug)
165
165
  - `generatePageTest` — variant body with control identity for breadcrumbs, `href`, and JSON-LD
166
166
 
167
167
  See the `se-marketing-sites-create-page` skill for the full route template. Direct visits to a variant's own CMS URL (normal page route) should keep using `generatePage`.
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export type { AbTestMiddlewareConfig, AbTestResult, CachedAbTest, StaticAbTestMi
11
11
  export { applyUrlParams, buildVariantId, clearTestCache, computeCachedTest, createAbTestMiddleware, createAssignment, createStaticAbTestMiddleware, DEFAULT_COOKIE_MAX_AGE, DEFAULT_COOKIE_NAME, getActiveTestIds, getAssignment, getCachedTests, getTestCacheState, isValidAssignment, normalizePath, parseCookie, processAbTestRequest, pruneStaleAssignments, readCookieFromDocument, selectVariant, serializeCookie, setAssignment, } from './middleware/index.js';
12
12
  export { buildExperimentImpression } from './reporting/buildExperimentImpression.js';
13
13
  export type { AbTest, AbTestAssignment, AbTestCookie, AbTestVariant, AbTestVariantConfig, IBlobStore, } from './types.js';
14
- export { findCanonicalPath } from './utils.js';
14
+ export { CMS_HOMEPAGE_SLUG, controlSlugFromCanonicalPath, findCanonicalPath } from './utils.js';
15
15
  export type { RawPageTest, WebhookHandlerConfig, WebhookResult, } from './webhook/index.js';
16
16
  export { createWebhookHandler, normalizeVariantConfig, processAbTestWebhook, transformPageTest, } from './webhook/index.js';
17
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAE5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACV,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,6BAA6B,EAC7B,UAAU,GACX,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,4BAA4B,EAC5B,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AAErF,YAAY,EACV,MAAM,EACN,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EACV,WAAW,EACX,oBAAoB,EACpB,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAE5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACV,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,6BAA6B,EAC7B,UAAU,GACX,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,4BAA4B,EAC5B,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AAErF,YAAY,EACV,MAAM,EACN,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAChG,YAAY,EACV,WAAW,EACX,oBAAoB,EACpB,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ export { useAbTestAssignments } from './hooks/index.js';
11
11
  export { applyUrlParams, buildVariantId, clearTestCache, computeCachedTest, createAbTestMiddleware, createAssignment, createStaticAbTestMiddleware, DEFAULT_COOKIE_MAX_AGE, DEFAULT_COOKIE_NAME, getActiveTestIds, getAssignment, getCachedTests, getTestCacheState, isValidAssignment, normalizePath, parseCookie, processAbTestRequest, pruneStaleAssignments, readCookieFromDocument, selectVariant, serializeCookie, setAssignment, } from './middleware/index.js';
12
12
  export { buildExperimentImpression } from './reporting/buildExperimentImpression.js';
13
13
  // Utilities
14
- export { findCanonicalPath } from './utils.js';
14
+ export { CMS_HOMEPAGE_SLUG, controlSlugFromCanonicalPath, findCanonicalPath } from './utils.js';
15
15
  // Re-export webhook utilities
16
16
  export { createWebhookHandler, normalizeVariantConfig, processAbTestWebhook, transformPageTest, } from './webhook/index.js';
17
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,kBAAkB;AAClB,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAQxD,iCAAiC;AACjC,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,4BAA4B,EAC5B,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AAUrF,YAAY;AACZ,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAM/C,8BAA8B;AAC9B,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,kBAAkB;AAClB,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAQxD,iCAAiC;AACjC,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,4BAA4B,EAC5B,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AAUrF,YAAY;AACZ,OAAO,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMhG,8BAA8B;AAC9B,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,20 @@
1
1
  import type { CachedAbTest } from './middleware/types';
2
+ /** CMS slug for the marketing homepage on SE Studio sites (public URL `/`). */
3
+ export declare const CMS_HOMEPAGE_SLUG = "index";
4
+ /**
5
+ * Map a public canonical path to the Contentful page slug used to fetch the
6
+ * PageTest **control**.
7
+ *
8
+ * Empty / root paths (`/`, `""`) map to {@link CMS_HOMEPAGE_SLUG} (`index`).
9
+ * Do **not** fall back to the variant slug: variants are `indexed: false`, so
10
+ * `canonicalPath.replace(/^\/|\/$/g, '') || variantSlug` noindexes `/`.
11
+ *
12
+ * Sites whose homepage CMS slug is not `index` (e.g. Pedestal `home`) should
13
+ * pass that slug as `homepageSlug`.
14
+ *
15
+ * Keep in sync with `@se-studio/core-ui` `controlSlugFromCanonicalPath`.
16
+ */
17
+ export declare function controlSlugFromCanonicalPath(canonicalPath: string, homepageSlug?: string): string;
2
18
  /**
3
19
  * Given a testsByPath map and a variant slug, returns the canonical
4
20
  * (user-facing) path that owns the variant.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,EAC3C,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CASpB"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,aAAa,EAAE,MAAM,EACrB,YAAY,GAAE,MAA0B,GACvC,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,EAC3C,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CASpB"}
package/dist/utils.js CHANGED
@@ -1,3 +1,21 @@
1
+ /** CMS slug for the marketing homepage on SE Studio sites (public URL `/`). */
2
+ export const CMS_HOMEPAGE_SLUG = 'index';
3
+ /**
4
+ * Map a public canonical path to the Contentful page slug used to fetch the
5
+ * PageTest **control**.
6
+ *
7
+ * Empty / root paths (`/`, `""`) map to {@link CMS_HOMEPAGE_SLUG} (`index`).
8
+ * Do **not** fall back to the variant slug: variants are `indexed: false`, so
9
+ * `canonicalPath.replace(/^\/|\/$/g, '') || variantSlug` noindexes `/`.
10
+ *
11
+ * Sites whose homepage CMS slug is not `index` (e.g. Pedestal `home`) should
12
+ * pass that slug as `homepageSlug`.
13
+ *
14
+ * Keep in sync with `@se-studio/core-ui` `controlSlugFromCanonicalPath`.
15
+ */
16
+ export function controlSlugFromCanonicalPath(canonicalPath, homepageSlug = CMS_HOMEPAGE_SLUG) {
17
+ return canonicalPath.replace(/^\/+|\/+$/g, '') || homepageSlug;
18
+ }
1
19
  /**
2
20
  * Given a testsByPath map and a variant slug, returns the canonical
3
21
  * (user-facing) path that owns the variant.
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,WAA2C,EAC3C,WAAmB;IAEnB,KAAK,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;gBACtD,OAAO,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,CAAC;YACrE,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAEzC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,4BAA4B,CAC1C,aAAqB,EACrB,YAAY,GAAW,iBAAiB;IAExC,OAAO,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC;AACjE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,WAA2C,EAC3C,WAAmB;IAEnB,KAAK,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;gBACtD,OAAO,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,CAAC;YACrE,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
package/docs/llms.md CHANGED
@@ -96,11 +96,12 @@ import {
96
96
 
97
97
  ```ts
98
98
  import {
99
- selectVariant, // weighted random variant selection
100
- getAssignment, // read assignment from cookies
101
- setAssignment, // write assignment to response cookies
102
- isValidAssignment, // validate an assignment object
103
- normalizePath, // normalise URL paths for comparison
104
- findCanonicalPath, // resolve variant path back to canonical
99
+ selectVariant, // weighted random variant selection
100
+ getAssignment, // read assignment from cookies
101
+ setAssignment, // write assignment to response cookies
102
+ isValidAssignment, // validate an assignment object
103
+ normalizePath, // normalise URL paths for comparison
104
+ findCanonicalPath, // resolve variant path back to canonical
105
+ controlSlugFromCanonicalPath, // `/` → CMS slug `index` (never the variant)
105
106
  } from '@se-studio/ab-testing';
106
107
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/ab-testing",
3
- "version": "18.0.31",
3
+ "version": "18.0.33",
4
4
  "description": "Server-side A/B testing framework for Next.js applications with Contentful CMS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -67,13 +67,13 @@
67
67
  "url": "https://github.com/Something-Else-Studio/se-core-product/issues"
68
68
  },
69
69
  "peerDependencies": {
70
- "@se-studio/core-ui": "1.35.0",
70
+ "@se-studio/core-ui": "1.35.2",
71
71
  "next": ">=15.5.0 <17",
72
72
  "react": "^19.0.0"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@biomejs/biome": "^2.5.12",
76
- "@se-studio/core-ui": "1.35.0",
76
+ "@se-studio/core-ui": "1.35.2",
77
77
  "@types/node": "^24.13.3",
78
78
  "@types/react": "^19.2.18",
79
79
  "next": "^16.3.4",