@syntrologie/adapt-product 2.32.0 → 2.34.0
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/dist/cdn.js +2 -2
- package/dist/{chunk-GL5TWSUQ.js → chunk-FAKCB3BS.js} +1 -2
- package/dist/chunk-FAKCB3BS.js.map +7 -0
- package/dist/{chunk-QN24QEGC.js → chunk-NH3CFDTZ.js} +8 -4
- package/dist/{chunk-QN24QEGC.js.map → chunk-NH3CFDTZ.js.map} +3 -3
- package/dist/runtime.d.ts +0 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -2
- package/dist/schema.d.ts +0 -6
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +1 -1
- package/dist/widgets/ProductCardLit.d.ts.map +1 -1
- package/dist/widgets/ProductRecoCarouselLit.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-GL5TWSUQ.js.map +0 -7
package/dist/cdn.js
CHANGED
|
@@ -242,7 +242,6 @@ var recoItemSchema = z2.object({
|
|
|
242
242
|
pdp_href: z2.string().regex(SAFE_HREF, "pdp_href must be a safe path/URL")
|
|
243
243
|
});
|
|
244
244
|
var recoSchema = z2.object({
|
|
245
|
-
heading: z2.string().nullish(),
|
|
246
245
|
items: z2.array(recoItemSchema).max(12).default([])
|
|
247
246
|
});
|
|
248
247
|
var tileWidgets = [
|
|
@@ -321,4 +320,4 @@ export {
|
|
|
321
320
|
tileWidgets,
|
|
322
321
|
CAPABILITIES_DOCUMENTATION
|
|
323
322
|
};
|
|
324
|
-
//# sourceMappingURL=chunk-
|
|
323
|
+
//# sourceMappingURL=chunk-FAKCB3BS.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/schema.ts", "../src/schema-primitives.ts", "../src/platformAdapter.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod';\nimport { productSchema } from './schema-primitives';\n\n// Top-level schemas use Zod's default `.strip()` mode so the runtime-injected\n// fields ``chromeless`` and ``instanceId`` that SyntroTileCard adds to every\n// widget mount don't fail validation. The inner ``productSchema`` remains\n// strict \u2014 that's the actual product contract, and unknown fields there\n// would signal author error rather than runtime envelope leakage.\n// Keys the LLM may include in `visibleFacts` to curate which baked facts\n// render on a card. `name` / `image` / `ctas` are identity + PDP CTA and\n// always show \u2014 they're not toggleable. Omitting `visibleFacts` renders\n// every populated block (back-compat for configs that never opted in).\nexport const VISIBLE_FACT_KEYS = [\n 'tagline',\n 'price',\n 'rating',\n 'availability',\n 'badge',\n 'specs',\n 'framing',\n] as const;\n\nexport type VisibleFactKey = (typeof VISIBLE_FACT_KEYS)[number];\n\nexport const cardSchema = z.object({\n product: productSchema,\n density: z.enum(['compact', 'standard']).default('standard'),\n /**\n * LLM-curated subset of facts to render, in author order. When omitted,\n * the card renders every populated block. When set, only listed keys\n * render (plus the always-shown identity + CTAs). List order = render\n * order \u2014 `[\"rating\", \"price\"]` and `[\"price\", \"rating\"]` produce\n * different layouts.\n */\n visibleFacts: z.array(z.enum(VISIBLE_FACT_KEYS)).max(VISIBLE_FACT_KEYS.length).optional(),\n // NOTE: variant presence is NOT a config/LLM field. Whether a product has\n // selectable SKUs is a CATALOG fact, resolved at render from the platform\n // adapter's fetchVariants (host API for real tenants, seed data for the\n // demo). The card derives its Add-to-cart behavior from that fetched payload\n // \u2014 see ProductCardLit `#hasSelectableVariants`. A stored `has_variants`\n // flag drifts from the catalog and can't be known by the LLM, so it was\n // removed (BUG-1783100102 follow-up).\n});\n\n/**\n * One comparison dimension, rendered as a matrix row. `valueA`..`valueD` are the\n * cells for `products[0]`..`products[3]` (a row need only fill as many as there\n * are products; missing cells render as \"\u2014\"). Flat scalar columns \u2014 NOT a nested\n * array \u2014 so the whole row is authorable as one `struct_list` item by the\n * assistant. This is the LLM-authorable shape of a comparison: a flat list of\n * rows the assistant fills to answer the visitor's actual question, aligned by\n * construction (each row carries every product's value), unlike per-product\n * attribute lists which drift out of sync.\n */\nexport const comparisonRowSchema = z.object({\n label: z.string(),\n // Schema floor (mainpeptides filler-cell incident): a row's first two cells\n // are always visitor-facing (a comparison mounts \u22652 products) \u2014 an empty\n // cell is a \"we don't know\" in a tile that exists to answer exactly that\n // question. Whitespace-only cells are caught at render (ProductComparisonLit\n // drops the row); the server-side filler gate rejects placeholder prose.\n valueA: z.string().min(1),\n valueB: z.string().min(1),\n valueC: z.string().optional(),\n valueD: z.string().optional(),\n});\n\nexport const comparisonSchema = z.object({\n products: z.array(productSchema).min(2).max(4),\n // The comparison ALWAYS renders as a side-by-side matrix (products = columns,\n // rows = dimensions) \u2014 that's the whole point of a comparison. When the\n // assistant authors `rows`, those are used verbatim; when omitted, the widget\n // synthesizes rows from each product's `attributes`. There is deliberately NO\n // layout toggle: the LLM can't choose a stacked/accordion presentation.\n rows: z.array(comparisonRowSchema).optional(),\n heading: z.string().optional(),\n});\n\nexport const heroSchema = z.object({\n product: productSchema,\n layout: z.enum(['image-left', 'image-right', 'image-top']).default('image-left'),\n longCopy: z.string().max(800).optional(),\n});\n\nexport const gridSchema = z.object({\n products: z.array(productSchema).min(2).max(12),\n desktopColumns: z.union([z.literal(2), z.literal(3)]).default(3),\n heading: z.string().optional(),\n});\n\n// [Adversarial SEC] scheme-validate pdp_href \u2014 block javascript:/data:/vbscript:\n// by requiring the URL to start with a known-safe scheme or relative path.\nconst SAFE_HREF = /^(https?:\\/\\/|\\/|\\.\\/|\\.\\.\\/|#|\\?|mailto:|tel:)/i;\n\n// nullish (not optional): the runtime-backend serializes Pydantic None as\n// JSON null \u2014 optional() alone rejects null, which silently blanked every\n// mounted carousel with an unset image/price/hook (BUG-1783408976).\nexport const recoItemSchema = z.object({\n image_url: z.string().nullish(),\n price: z.string().nullish(),\n hook: z.string().max(40).nullish(),\n pdp_href: z.string().regex(SAFE_HREF, 'pdp_href must be a safe path/URL'),\n});\n\n// The carousel's TITLE is not a widget prop \u2014 it rides the mount's\n// content['title'] (lifted into tile chrome like every other element). A\n// widget-level `heading` used to render a duplicate in-widget h2 (user\n// report 2026-07-24). Stale cached payloads may still carry a heading key;\n// z.object() strips unknown keys on parse, so they mount fine.\nexport const recoSchema = z.object({\n items: z.array(recoItemSchema).max(12).default([]),\n});\n\nexport type CardProps = z.infer<typeof cardSchema>;\nexport type ComparisonProps = z.infer<typeof comparisonSchema>;\nexport type HeroProps = z.infer<typeof heroSchema>;\nexport type GridProps = z.infer<typeof gridSchema>;\nexport type RecoProps = z.infer<typeof recoSchema>;\nexport type RecoItemProps = z.infer<typeof recoItemSchema>;\n\nexport const tileWidgets = [\n { widget: 'adaptive-product:card', defName: 'productCardProps', propsSchema: cardSchema },\n {\n widget: 'adaptive-product:comparison',\n defName: 'productComparisonProps',\n propsSchema: comparisonSchema,\n },\n { widget: 'adaptive-product:hero', defName: 'productHeroProps', propsSchema: heroSchema },\n { widget: 'adaptive-product:grid', defName: 'productGridProps', propsSchema: gridSchema },\n { widget: 'adaptive-product:reco', defName: 'productRecoProps', propsSchema: recoSchema },\n] as const;\n\n// ============================================================================\n// Capabilities Documentation (injected into JSON Schema for LLM prompts)\n// ============================================================================\n\nexport const CAPABILITIES_DOCUMENTATION = {\n packageId: 'adaptive-product',\n plannerSummary:\n 'Product merchandising widgets for cards, comparisons, heroes, grids, and recommendation carousels. Reach for this when the strategy needs product facts, PDP support, recommendations, or commerce-oriented social proof.',\n description:\n 'Product adaptive for presenting catalog-backed product facts and recommendations. Widgets support product cards, side-by-side comparisons, hero blocks, product grids, recommendation carousels, and a host-owned PDP element.',\n whenToUse: [\n {\n goal: 'Show one curated product with controlled visible facts',\n action:\n 'Add a tile with widget: \"adaptive-product:card\" and provide product, density, and optional visibleFacts props.',\n },\n {\n goal: 'Compare two to four products side by side',\n action:\n 'Add a tile with widget: \"adaptive-product:comparison\"; products become columns and optional rows define the comparison dimensions.',\n },\n {\n goal: 'Feature one product in a larger editorial layout',\n action:\n 'Add a tile with widget: \"adaptive-product:hero\" and choose image-left, image-right, or image-top layout.',\n },\n {\n goal: 'Show a small collection of products',\n action:\n 'Add a tile with widget: \"adaptive-product:grid\" for 2-12 products and choose two or three desktop columns.',\n },\n {\n goal: 'Show recommended next products or actions',\n action:\n 'Add a tile with widget: \"adaptive-product:reco\" and provide up to 12 recommendation items with safe pdp_href values.',\n },\n ],\n conventions: [\n {\n name: 'Catalog facts stay inside product',\n description:\n 'Use the product object for identity, image, price, rating, availability, badge, specs, framing, and CTAs. Keep visibleFacts top-level on card props; it is not nested under product.',\n },\n {\n name: 'Comparison has one presentation',\n description:\n 'adaptive-product:comparison always renders a side-by-side matrix. Do not add layout toggles such as stacked, accordion, expandBehavior, or defaultExpandedIndex.',\n },\n {\n name: 'Recommendation links must be safe',\n description:\n 'reco item pdp_href values must use http(s), relative paths, hashes, query strings, mailto, or tel. javascript:, data:, and other executable schemes are rejected.',\n },\n {\n name: 'Live binding is a product adapter concern',\n description:\n 'Price, image, variant, Shopify, WooCommerce, JSON-LD, and OpenGraph binding are resolved through the adaptive-product platform adapter, not through runtime-specific branches.',\n },\n ],\n events: [],\n};\n\nexport type {\n AddToCartInput,\n AddToCartResult,\n AttributeDef,\n AttributeValue,\n ProductPlatformAdapter,\n SwatchSpec,\n Variant,\n VariantPayload,\n} from './platformAdapter';\nexport { getProductPlatformAdapter } from './platformAdapter';\nexport type { ImageBind, PriceBind, Product } from './schema-primitives';\nexport { productSchema } from './schema-primitives';\n\n// \u2500\u2500 Syntro PDP (config-first personalized PDP; live slots via /api/pdp/module) \u2500\n\nexport interface SyntroPdpProps {\n /** Stable product identifier passed to the backend planner. */\n productId: string;\n /** Display name used by the planner when authoring headers / copy. */\n productName: string;\n /** Optional short product blurb passed verbatim into the planner. */\n productBlurb?: string;\n}\n", "// src/schema-primitives.ts\nimport { z } from 'zod';\n\nconst SAFE_HREF_PATTERN =\n /^(?:[/.#?]|[hH][tT][tT][pP][sS]?:\\/\\/|[mM][aA][iI][lL][tT][oO]:|[tT][eE][lL]:)/;\n\nexport const HrefZ = z\n .string()\n .min(1)\n .regex(SAFE_HREF_PATTERN, {\n message:\n 'href must start with /, ./, ../, #, ?, http(s)://, mailto:, or tel: \u2014 javascript:, data:, and vbscript: are not allowed',\n })\n .refine(\n (s) => {\n try {\n const parsed = new URL(s, 'https://syntro.local/');\n return ['http:', 'https:', 'mailto:', 'tel:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n },\n { message: 'href resolves to an unsupported protocol' }\n );\n\nexport const PriceBindZ = z.discriminatedUnion('type', [\n z.object({ type: z.literal('dom-selector'), selector: z.string().min(1) }).strict(),\n z\n .object({ type: z.literal('shopify-ajax'), handle: z.string().min(1), base: HrefZ.optional() })\n .strict(),\n z\n .object({\n type: z.literal('woocommerce-store-api'),\n slug: z.string().min(1),\n base: HrefZ.optional(),\n })\n .strict(),\n z.object({ type: z.literal('jsonld'), url: HrefZ.optional() }).strict(),\n]);\n\nexport const ImageBindZ = z.discriminatedUnion('type', [\n z.object({ type: z.literal('dom-selector'), selector: z.string().min(1) }).strict(),\n z\n .object({ type: z.literal('shopify-ajax'), handle: z.string().min(1), base: HrefZ.optional() })\n .strict(),\n z.object({ type: z.literal('opengraph'), url: HrefZ }).strict(),\n z.object({ type: z.literal('jsonld'), url: HrefZ.optional() }).strict(),\n]);\n\n// ---------------------------------------------------------------------------\n// productSchema v2 \u2014 Google Merchant Center / schema.org/Product alignment\n//\n// Layered model:\n// 1. Strict typed core (id, name, image, price, ctas) \u2014 rendering depends on\n// these; unchanged from v1.\n// 2. Common typed optional (brand, availability, salePrice, rating) \u2014 widely\n// reused across product types; renderers know what to do with them.\n// 3. `specs[]` \u2014 open spec table modelled on Google's `product_detail[]` /\n// schema.org's `additionalProperty`. Arbitrary `{section, name, value}`\n// triples for category-specific facts. Cards group by section.\n// 4. `labels{}` \u2014 Google `custom_label_0..4` style: free-form targeting\n// data the renderer ignores and the targeting layer reads.\n//\n// `attributes[]` from v1 is preserved as an optional, deprecated field so\n// existing configs keep working. Renderers should treat it as a synthetic\n// \"About\" spec section. New configs should use `specs[]`.\n// ---------------------------------------------------------------------------\n\nconst specRowSchema = z\n .object({\n section: z.string().min(1).describe('Section header \u2014 \"Supplement Facts\", \"Shipping\", etc.'),\n name: z.string().min(1).describe('Attribute name \u2014 \"Vitamin D3\", \"Lead time\"'),\n value: z.string().describe('Attribute value as a string \u2014 \"5000\", \"2\"'),\n unit: z\n .string()\n .optional()\n .describe('Unit suffix shown small next to value \u2014 \"IU\", \"mg\", \"days\"'),\n emphasis: z.boolean().default(false),\n priority: z\n .number()\n .optional()\n .describe('Higher = more important. Compact cards show top N by priority.'),\n })\n .strict();\n\nexport const productSchema = z\n .object({\n // \u2500\u2500 Tier 1: strict typed core \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n id: z.string().min(1).describe('Stable identifier for analytics and dedup'),\n name: z.string().min(1),\n tagline: z.string().optional(),\n image: z\n .object({\n src: HrefZ,\n alt: z.string(),\n bind: ImageBindZ.optional(),\n })\n .strict(),\n price: z\n .object({\n amount: z.string(),\n cadence: z.string().optional(),\n bind: PriceBindZ.optional(),\n })\n .strict()\n .optional(),\n badge: z\n .object({\n label: z.string(),\n tone: z.enum(['neutral', 'primary', 'success', 'warning']).default('neutral'),\n })\n .strict()\n .optional(),\n framing: z.string().max(280).optional(),\n ctas: z\n .array(\n z\n .object({\n label: z.string().min(1),\n href: HrefZ.optional(),\n target: z.enum(['_self', '_blank']).default('_self'),\n variant: z.enum(['primary', 'secondary', 'ghost']).default('primary'),\n actionId: z.string().optional(),\n })\n .strict()\n )\n .min(1)\n .max(2),\n\n // \u2500\u2500 Tier 2: common typed optional (mirrors GMC / schema.org Offer) \u2500\n /** Cross-platform product identifiers. SKU/GTIN/MPN per GMC; platform handles for bind auto-resolution. */\n identifiers: z\n .object({\n sku: z.string().optional(),\n gtin: z.string().optional(),\n mpn: z.string().optional(),\n shopifyHandle: z.string().optional(),\n wooSlug: z.string().optional(),\n })\n .strict()\n .optional(),\n brand: z.string().optional(),\n /** GMC availability enum \u2014 drives default badge if no explicit badge set. */\n availability: z.enum(['in_stock', 'preorder', 'backorder', 'out_of_stock']).optional(),\n /** Strikethrough source price. `price` becomes the \"was\" value when this is set. */\n salePrice: z\n .object({\n amount: z.string(),\n cadence: z.string().optional(),\n validUntil: z.string().datetime().optional(),\n bind: PriceBindZ.optional(),\n })\n .strict()\n .optional(),\n /** AggregateRating \u2014 value, count, optional max (defaults to 5). */\n rating: z\n .object({\n value: z.number().min(0),\n count: z.number().int().min(0),\n max: z.number().default(5),\n })\n .strict()\n .optional(),\n\n // \u2500\u2500 Tier 3: open spec table (Google product_detail / schema.org additionalProperty) \u2500\u2500\n /** Category-specific spec rows grouped by section. Renderers show as grouped tables. */\n specs: z.array(specRowSchema).max(32).optional(),\n\n // \u2500\u2500 Tier 4: passthrough targeting labels (Google custom_label_*) \u2500\u2500\u2500\n /** Flat record of targeting/segmentation labels. Renderer ignores; targeting layer reads. */\n labels: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),\n\n // \u2500\u2500 Deprecated: v1 flat attributes (renderers shim into a synthetic \"About\" spec section) \u2500\u2500\n /** @deprecated Use `specs[]` with `section: \"About\"`. Retained for backward compatibility. */\n attributes: z\n .array(\n z\n .object({\n label: z.string(),\n value: z.string(),\n emphasis: z.boolean().default(false),\n })\n .strict()\n )\n .max(8)\n .optional(),\n\n /**\n * Optional variant block for products with attribute-based SKUs.\n * When present, indicates the product has multiple SKUs distinguished\n * by attributes (size, color, etc.). This block on the product itself\n * is the seed-data shape the demo uses to serve its Shopify\n * GET /products/{handle}.js endpoint.\n *\n * The card does NOT read this directly to decide whether to show a\n * variant picker: variant presence is resolved at render from the\n * platform adapter's fetchVariants (host API for real tenants, this\n * seed data for the demo), so a single catalog source drives it.\n * For real Shopify/Woo tenants this field is unused on the mount\n * payload; the adapter fetches from the host API instead.\n */\n variants: z\n .object({\n attributes: z.array(\n z.object({\n key: z.string(),\n label: z.string(),\n kind: z.enum(['pill', 'swatch']),\n values: z.array(\n z.object({\n id: z.string(),\n label: z.string(),\n swatch: z\n .object({\n kind: z.enum(['color', 'image']),\n value: z.string(),\n })\n .nullable(),\n })\n ),\n })\n ),\n variants: z.array(\n z.object({\n id: z.string(),\n selection: z.record(z.string(), z.string()),\n price: z.number(),\n compare_at_price: z.number().nullable(),\n in_stock: z.boolean(),\n // Same URL-safety policy as image.src \u2014 this block is config/LLM-\n // authored, so javascript:/data:/vbscript: must be rejected here too.\n featured_image: HrefZ.optional(),\n })\n ),\n })\n .optional(),\n })\n .strict();\n\nexport type Product = z.infer<typeof productSchema>;\nexport type PriceBind = z.infer<typeof PriceBindZ>;\nexport type ImageBind = z.infer<typeof ImageBindZ>;\n", "/**\n * Platform-agnostic commerce interface the product-card widget reads to fetch\n * variants, add to cart, and open the cart. The widget never branches on\n * platform \u2014 it just reads whatever adapter the RUNTIME published for the\n * detected platform.\n *\n * Implementations live in the platform packages and are wired in by the runtime\n * (see runtime-sdk `_platforms-registered.ts` \u2192 `setProductCommerceGlobal`):\n * - platform-shopify: /products/{handle}.js + /cart/add.js + navigate to /cart.\n * - platform-woocommerce (future): Store API + ?wc-ajax=add_to_cart.\n *\n * This is NOT host-injected. The host page supplies nothing.\n */\nexport interface ProductPlatformAdapter {\n /** Fetch normalized variant data for a product. */\n fetchVariants(productId: string): Promise<VariantPayload>;\n\n /** Perform the platform-specific add-to-cart POST. Returns success or\n * a structured error the widget can render. */\n addToCart(input: AddToCartInput): Promise<AddToCartResult>;\n\n /** Open the host's cart UI. Implementation is entirely platform-specific.\n * The widget calls this AFTER closing the chat canvas. */\n openCart(): Promise<void>;\n}\n\nexport interface AddToCartInput {\n product_id: string;\n /** null for single-SKU products (no variant to pick). */\n variant_id: string | null;\n quantity: number;\n}\n\nexport interface AddToCartResult {\n ok: boolean;\n /** Set when ok=false. */\n error?: { code: 'oos' | 'network' | 'validation' | 'unknown'; message: string };\n}\n\nexport interface VariantPayload {\n product_id: string;\n attributes: AttributeDef[];\n variants: Variant[];\n}\n\nexport interface AttributeDef {\n /** Stable id: 'size', 'color', 'cadence'. */\n key: string;\n /** Display label: 'Size', 'Color', 'Delivery'. */\n label: string;\n /** Render mode. Extensible: future kinds may include 'dropdown'. */\n kind: 'pill' | 'swatch';\n values: AttributeValue[];\n}\n\nexport interface AttributeValue {\n /** Stable id: 'large', 'red', 'subscribe'. */\n id: string;\n /** Display label: 'Large', 'Red', 'Subscribe \u2014 save 15%'. */\n label: string;\n /** Present when the attribute's kind is 'swatch'; null for pill attributes. */\n swatch: SwatchSpec | null;\n}\n\nexport interface SwatchSpec {\n kind: 'color' | 'image';\n /** Hex color (#000000) for kind 'color'; URL for kind 'image'. */\n value: string;\n}\n\nexport interface Variant {\n /** Platform-native SKU/variant id used as the cart-POST id. */\n id: string;\n /** Map of attribute key \u2192 value id, e.g. { size: 'large', color: 'red' }. */\n selection: Record<string, string>;\n price: number;\n compare_at_price: number | null;\n in_stock: boolean;\n /** Optional per-variant hero image URL. When present the variant panel swaps\n * its image to this on selection; otherwise it keeps the product-level image.\n * Populated by platforms that carry variant-level media (Shopify\n * `variant.featured_image`); absent for products whose image never varies by\n * SKU (e.g. pack-size only). */\n featured_image?: string;\n}\n\n// \u2500\u2500 Window-level lookup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// The widget ships as a bundled IIFE with its own module closure, so a\n// module-level variable can't be shared with the runtime that sets the adapter.\n// The runtime publishes the detected platform's commerce adapter on this window\n// key (runtime-sdk `setProductCommerceGlobal`); the widget only reads it.\n// Returns null when no platform was detected \u2014 the widget then renders its\n// add-to-cart CTA disabled.\n\nconst ADAPTER_KEY = '__SYNTRO_PRODUCT_ADAPTER__';\n\n/** Retrieve the runtime-published commerce adapter. Null if none was set. */\nexport function getProductPlatformAdapter(): ProductPlatformAdapter | null {\n if (typeof window === 'undefined') return null;\n return (\n (window as unknown as Record<string, ProductPlatformAdapter | undefined>)[ADAPTER_KEY] ?? null\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["z", "z"]
|
|
7
|
+
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
gridSchema,
|
|
11
11
|
heroSchema,
|
|
12
12
|
recoSchema
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FAKCB3BS.js";
|
|
14
14
|
|
|
15
15
|
// ../../../node_modules/@lit/context/lib/create-context.js
|
|
16
16
|
function n(n2) {
|
|
@@ -5702,7 +5702,12 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5702
5702
|
// element in legacy un-oriented -webkit-box layout — the
|
|
5703
5703
|
// unwrapped-clipped-line bug this replaces.
|
|
5704
5704
|
display: "-webkit-box",
|
|
5705
|
-
|
|
5705
|
+
// The line COUNT is the host canvas's call — a height-bounded
|
|
5706
|
+
// band (velvet's 228-288px deck) can't afford 3 lines without
|
|
5707
|
+
// pushing the CTA rows to the clipped bottom edge (user
|
|
5708
|
+
// report 2026-07-24). Token bridge across sc-mount's shadow
|
|
5709
|
+
// root, same as --sc-comparison-max-fields.
|
|
5710
|
+
WebkitLineClamp: "var(--sc-card-tagline-lines, 3)",
|
|
5706
5711
|
WebkitBoxOrient: "vertical",
|
|
5707
5712
|
overflow: "hidden",
|
|
5708
5713
|
// Terminal fallback (item b): a 60-char unbroken tagline token
|
|
@@ -6518,7 +6523,6 @@ var ProductRecoCarouselLit = class extends LitElement11 {
|
|
|
6518
6523
|
if (items.length === 0) return html11``;
|
|
6519
6524
|
return html11`
|
|
6520
6525
|
<section class="sc-reco" style="box-sizing:border-box;display:flex;flex-direction:column;height:100%;padding:2px var(--sc-reco-inset,12px) var(--sc-reco-inset,12px);">
|
|
6521
|
-
${this._parsed?.heading ? html11`<h2 class="sc-reco__heading" data-reco-heading style="margin:0 0 8px;flex:0 0 auto;font-size:0.95rem;">${this._parsed.heading}</h2>` : nothing7}
|
|
6522
6526
|
<div class="sc-reco__carousel" role="list" style="display:flex;align-items:stretch;gap:8px;flex:1 1 auto;min-height:0;overflow-x:auto;scroll-snap-type:x mandatory;">
|
|
6523
6527
|
${items.map(
|
|
6524
6528
|
(it) => html11`
|
|
@@ -11085,4 +11089,4 @@ export {
|
|
|
11085
11089
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
11086
11090
|
*)
|
|
11087
11091
|
*/
|
|
11088
|
-
//# sourceMappingURL=chunk-
|
|
11092
|
+
//# sourceMappingURL=chunk-NH3CFDTZ.js.map
|