@tokenoftrust/cli 3.12.0 → 3.12.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": "@tokenoftrust/cli",
3
- "version": "3.12.0",
3
+ "version": "3.12.2",
4
4
  "description": "Token of Trust developer CLI — clone a tenant store, run it locally with save→reload, and submit it for preview. Installs the `tot` command.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Token of Trust",
package/src/sample.mjs CHANGED
@@ -13,9 +13,10 @@
13
13
  * is resolved by the RUNNER's SANITIZED tenant registry
14
14
  * (apps/storefront/src/config/tenants.ts — rewritten at build time by
15
15
  * scripts/build/build-runner.mjs), keyed by domain. The runner registers ONE
16
- * generic sample tenant, `sample-store.example`, that carries a `compliance`
17
- * block (minAge 21, nicotineWarning), so the sample lights up the age-gate +
18
- * nicotine warning off a NON-merchant identity with zero server. The bundled
16
+ * generic sample tenant, `sample-store.example`, that carries the same
17
+ * compliance section inputs as a primary vape-nicotine-us store (minAge 21,
18
+ * nicotine warning, shipping restriction, excise, age gate), so the sample
19
+ * lights those bands up off a NON-merchant identity with zero server. The bundled
19
20
  * template below (`template/sample-store/`) is neutral, fictional "Sample Vapor
20
21
  * Co." content — no real merchant's brand, copy, or assets ship here.
21
22
  *
package/src/validate.mjs CHANGED
@@ -592,6 +592,19 @@ function validatePromoTiles(block, file, at, out, tenantId) {
592
592
  }
593
593
  }
594
594
 
595
+ function validateHeroMediaFields(owner, file, at, out, tenantId) {
596
+ if ((owner.width === undefined) !== (owner.height === undefined)) out.push(mk(ERROR, "block-prop", file, `${at}.width and ${at}.height must be supplied together`));
597
+ for (const prop of ["width", "height"]) {
598
+ if (owner[prop] !== undefined && (typeof owner[prop] !== "number" || !Number.isInteger(owner[prop]) || owner[prop] <= 0)) {
599
+ out.push(mk(ERROR, "block-prop", file, `${at}.${prop} must be a positive integer`));
600
+ }
601
+ }
602
+ if (owner.imageMobile !== undefined) {
603
+ if (typeof owner.imageMobile !== "string" || !owner.imageMobile.trim()) out.push(mk(ERROR, "block-prop", file, `${at}.imageMobile must be a non-empty string`));
604
+ else validateVisualAsset(owner.imageMobile, file, `${at}.imageMobile`, out, tenantId);
605
+ }
606
+ }
607
+
595
608
  function validateHeroSlides(slides, file, at, out, tenantId) {
596
609
  if (!Array.isArray(slides) || slides.length === 0) { out.push(mk(ERROR, "block-prop", file, `${at}.slides must be a non-empty array`)); return; }
597
610
  slides.forEach((slide, index) => {
@@ -599,6 +612,7 @@ function validateHeroSlides(slides, file, at, out, tenantId) {
599
612
  if (slide == null || typeof slide !== "object" || Array.isArray(slide)) { out.push(mk(ERROR, "block-prop", file, `${slideAt} must be an object`)); return; }
600
613
  for (const prop of ["image", "imageAlt"]) if (typeof slide[prop] !== "string" || !slide[prop].trim()) out.push(mk(ERROR, "block-required", file, `${slideAt}.${prop} must be a non-empty string`));
601
614
  validateVisualAsset(slide.image, file, `${slideAt}.image`, out, tenantId);
615
+ validateHeroMediaFields(slide, file, slideAt, out, tenantId);
602
616
  for (const prop of ["headline", "ctaLabel", "ctaHref"]) if (slide[prop] !== undefined && (typeof slide[prop] !== "string" || !slide[prop].trim())) out.push(mk(ERROR, "block-prop", file, `${slideAt}.${prop} must be a non-empty string`));
603
617
  if ((slide.ctaLabel === undefined) !== (slide.ctaHref === undefined)) out.push(mk(ERROR, "block-required", file, `${slideAt}.ctaLabel and ${slideAt}.ctaHref must be supplied together`));
604
618
  if (typeof slide.ctaHref === "string" && !isSafeStorefrontHref(slide.ctaHref)) out.push(mk(ERROR, "navigation-href", file, `${slideAt}.ctaHref must be a same-storefront root-relative path`));
@@ -701,6 +715,7 @@ function validateHomeDoc(doc, file, tenantId) {
701
715
  if (component === "hero" && block.image !== undefined) {
702
716
  validateVisualAsset(block.image, file, `${at}.image`, out, tenantId);
703
717
  }
718
+ if (component === "hero") validateHeroMediaFields(block, file, at, out, tenantId);
704
719
  if (component === "hero" && block.slides !== undefined) validateHeroSlides(block.slides, file, at, out, tenantId);
705
720
  if (component === "hero" && block.notice !== undefined && (typeof block.notice !== "string" || !block.notice.trim())) {
706
721
  out.push(mk(ERROR, "block-prop", file, `${at}.notice must be a non-empty plain-text string`));