@tokenoftrust/storefront-runner 0.1.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/LICENSE +58 -0
- package/README.md +40 -0
- package/apps/storefront/.dev.vars.example +41 -0
- package/apps/storefront/.env.example +24 -0
- package/apps/storefront/astro.config.mjs +245 -0
- package/apps/storefront/env.d.ts +155 -0
- package/apps/storefront/lib/ensure-preview-reconcile-secret.sh +31 -0
- package/apps/storefront/lib/resolve-cf-token.sh +48 -0
- package/apps/storefront/lib/resolve-tot-credentials.sh +69 -0
- package/apps/storefront/migrations/0000_baseline.sql +54 -0
- package/apps/storefront/migrations/0001_products_fts.sql +9 -0
- package/apps/storefront/migrations/README.md +54 -0
- package/apps/storefront/migrations/meta/0000_snapshot.json +347 -0
- package/apps/storefront/migrations/meta/0001_snapshot.json +347 -0
- package/apps/storefront/migrations/meta/_journal.json +20 -0
- package/apps/storefront/package.json +41 -0
- package/apps/storefront/public/brand/northwind-logo-dark.svg +4 -0
- package/apps/storefront/public/brand/northwind-logo-light.svg +4 -0
- package/apps/storefront/public/brand/northwind-og.svg +13 -0
- package/apps/storefront/public/favicon.svg +5 -0
- package/apps/storefront/public/js/dashboard-team.js +147 -0
- package/apps/storefront/public/js/dashboard-vendor-search.js +115 -0
- package/apps/storefront/src/components/Badge.astro +34 -0
- package/apps/storefront/src/components/Breadcrumbs.astro +45 -0
- package/apps/storefront/src/components/CollectionCard.astro +56 -0
- package/apps/storefront/src/components/EmptyState.astro +35 -0
- package/apps/storefront/src/components/Img.astro +68 -0
- package/apps/storefront/src/components/ProductCard.astro +228 -0
- package/apps/storefront/src/components/Section.astro +39 -0
- package/apps/storefront/src/components/Seo.astro +70 -0
- package/apps/storefront/src/components/WidgetFrame.astro +34 -0
- package/apps/storefront/src/components/auth/AuthBadge.astro +44 -0
- package/apps/storefront/src/components/chrome/AnnouncementBar.astro +108 -0
- package/apps/storefront/src/components/chrome/MegaMenu.astro +26 -0
- package/apps/storefront/src/components/chrome/NavDropdown.astro +116 -0
- package/apps/storefront/src/components/chrome/SiteFooter.astro +181 -0
- package/apps/storefront/src/components/chrome/SiteHeader.astro +181 -0
- package/apps/storefront/src/components/chrome/UtilityNav.astro +79 -0
- package/apps/storefront/src/components/commerce/FoxyLoader.astro +23 -0
- package/apps/storefront/src/components/commerce/PriceDisplay.astro +91 -0
- package/apps/storefront/src/components/commerce/ProductCarousel.astro +197 -0
- package/apps/storefront/src/components/commerce/ProductGrid.astro +75 -0
- package/apps/storefront/src/components/commerce/RatingStars.astro +58 -0
- package/apps/storefront/src/components/compliance/NicotineWarning.astro +33 -0
- package/apps/storefront/src/components/home/Hero.astro +164 -0
- package/apps/storefront/src/components/islands/AgeGate.tsx +105 -0
- package/apps/storefront/src/components/islands/ImageGallery.tsx +237 -0
- package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +73 -0
- package/apps/storefront/src/components/islands/MobileNav.tsx +239 -0
- package/apps/storefront/src/components/islands/QuickView.tsx +138 -0
- package/apps/storefront/src/components/islands/RecentlyViewed.tsx +122 -0
- package/apps/storefront/src/components/islands/SavedList.tsx +99 -0
- package/apps/storefront/src/components/islands/SearchTypeahead.tsx +248 -0
- package/apps/storefront/src/components/islands/VariantSelector.tsx +378 -0
- package/apps/storefront/src/components/marketing/CardGrid.astro +72 -0
- package/apps/storefront/src/components/marketing/CodeSample.astro +20 -0
- package/apps/storefront/src/components/marketing/CtaBand.astro +24 -0
- package/apps/storefront/src/components/marketing/Faq.astro +37 -0
- package/apps/storefront/src/components/marketing/Integrations.astro +63 -0
- package/apps/storefront/src/components/marketing/MarketingBlocks.astro +53 -0
- package/apps/storefront/src/components/marketing/MarketingCtas.astro +48 -0
- package/apps/storefront/src/components/marketing/MarketingHero.astro +72 -0
- package/apps/storefront/src/components/marketing/ProofStrip.astro +37 -0
- package/apps/storefront/src/components/marketing/SplitCompare.astro +53 -0
- package/apps/storefront/src/components/marketing/Steps.astro +36 -0
- package/apps/storefront/src/components/marketing/Testimonials.astro +38 -0
- package/apps/storefront/src/components/marketing/TrustBar.astro +22 -0
- package/apps/storefront/src/components/nav/Footer.astro +148 -0
- package/apps/storefront/src/components/nav/Header.astro +190 -0
- package/apps/storefront/src/components/plp/ActiveFilters.astro +79 -0
- package/apps/storefront/src/components/plp/FacetSidebar.astro +146 -0
- package/apps/storefront/src/components/plp/Pagination.astro +99 -0
- package/apps/storefront/src/components/plp/SortSelect.astro +64 -0
- package/apps/storefront/src/config/devTenants.ts +16 -0
- package/apps/storefront/src/config/kvTenantResolver.ts +87 -0
- package/apps/storefront/src/config/resolver.ts +46 -0
- package/apps/storefront/src/config/tenants.ts +193 -0
- package/apps/storefront/src/layouts/Layout.astro +303 -0
- package/apps/storefront/src/lib/analytics/index.ts +47 -0
- package/apps/storefront/src/lib/auth/brokerAssertion.ts +136 -0
- package/apps/storefront/src/lib/auth/devAuth.ts +90 -0
- package/apps/storefront/src/lib/auth/gatePage.ts +81 -0
- package/apps/storefront/src/lib/auth/identityToken.ts +341 -0
- package/apps/storefront/src/lib/auth/loginGate.ts +107 -0
- package/apps/storefront/src/lib/auth/route.ts +146 -0
- package/apps/storefront/src/lib/auth/session.ts +203 -0
- package/apps/storefront/src/lib/auth/totAccessClient.ts +503 -0
- package/apps/storefront/src/lib/basePath.ts +41 -0
- package/apps/storefront/src/lib/cfImage.ts +55 -0
- package/apps/storefront/src/lib/chrome/model.ts +65 -0
- package/apps/storefront/src/lib/colors.ts +97 -0
- package/apps/storefront/src/lib/content-edit/client.ts +230 -0
- package/apps/storefront/src/lib/content-edit/index.ts +14 -0
- package/apps/storefront/src/lib/content-edit/route.ts +25 -0
- package/apps/storefront/src/lib/content-edit/types.ts +19 -0
- package/apps/storefront/src/lib/cspStaticHashes.ts +24 -0
- package/apps/storefront/src/lib/d1/catalog.ts +289 -0
- package/apps/storefront/src/lib/dashboard/staffAdmission.ts +43 -0
- package/apps/storefront/src/lib/dashboard/staffVendorAccess.ts +449 -0
- package/apps/storefront/src/lib/dashboard/tenantSelection.ts +136 -0
- package/apps/storefront/src/lib/dashboard/vendorQuery.ts +61 -0
- package/apps/storefront/src/lib/demoGate.ts +113 -0
- package/apps/storefront/src/lib/dev/ai-widget-client.js +127 -0
- package/apps/storefront/src/lib/dev/cliSignInCode.ts +132 -0
- package/apps/storefront/src/lib/diag/redact.ts +20 -0
- package/apps/storefront/src/lib/edgeCache.ts +128 -0
- package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +62 -0
- package/apps/storefront/src/lib/env.ts +60 -0
- package/apps/storefront/src/lib/fixtures/sampleProducts.ts +130 -0
- package/apps/storefront/src/lib/format.ts +29 -0
- package/apps/storefront/src/lib/foxyCommerce.ts +49 -0
- package/apps/storefront/src/lib/imageAttrs.ts +55 -0
- package/apps/storefront/src/lib/jsonld.ts +136 -0
- package/apps/storefront/src/lib/maintenance.ts +71 -0
- package/apps/storefront/src/lib/memoryKv.ts +32 -0
- package/apps/storefront/src/lib/messaging/messagesClient.ts +143 -0
- package/apps/storefront/src/lib/placeholder.ts +99 -0
- package/apps/storefront/src/lib/previewReload.ts +125 -0
- package/apps/storefront/src/lib/rawMarketingHtml.ts +133 -0
- package/apps/storefront/src/lib/search/index.ts +74 -0
- package/apps/storefront/src/lib/sections.ts +129 -0
- package/apps/storefront/src/lib/securityHeaders.ts +31 -0
- package/apps/storefront/src/lib/storyblok/content-model.ts +289 -0
- package/apps/storefront/src/lib/storyblok/provider.ts +524 -0
- package/apps/storefront/src/lib/tenantRouting.ts +91 -0
- package/apps/storefront/src/lib/tot/ToTClient.ts +177 -0
- package/apps/storefront/src/lib/tot/d1Client.ts +62 -0
- package/apps/storefront/src/lib/tot/query.ts +187 -0
- package/apps/storefront/src/lib/tot/totClientInterface.ts +30 -0
- package/apps/storefront/src/lib/url.ts +119 -0
- package/apps/storefront/src/lib/wishlist.ts +63 -0
- package/apps/storefront/src/middleware/index.ts +413 -0
- package/apps/storefront/src/pages/404.astro +61 -0
- package/apps/storefront/src/pages/[...slug].astro +90 -0
- package/apps/storefront/src/pages/api/auth/logout.ts +21 -0
- package/apps/storefront/src/pages/api/auth/magic-exchange.ts +107 -0
- package/apps/storefront/src/pages/api/auth/send.ts +85 -0
- package/apps/storefront/src/pages/api/auth/verify.ts +135 -0
- package/apps/storefront/src/pages/api/cache-purge.ts +44 -0
- package/apps/storefront/src/pages/api/content-edit/ai-edit.ts +64 -0
- package/apps/storefront/src/pages/api/csp-report.ts +25 -0
- package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +124 -0
- package/apps/storefront/src/pages/api/dashboard/vendor-search.ts +120 -0
- package/apps/storefront/src/pages/api/dev/cli-signin-code.ts +44 -0
- package/apps/storefront/src/pages/api/newsletter.ts +104 -0
- package/apps/storefront/src/pages/api/request-access.ts +172 -0
- package/apps/storefront/src/pages/auth/login.astro +149 -0
- package/apps/storefront/src/pages/auth/magic.astro +105 -0
- package/apps/storefront/src/pages/capabilities.astro +292 -0
- package/apps/storefront/src/pages/collections/[handle].astro +154 -0
- package/apps/storefront/src/pages/collections/index.astro +59 -0
- package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +100 -0
- package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +154 -0
- package/apps/storefront/src/pages/dashboard/index.astro +160 -0
- package/apps/storefront/src/pages/dev.astro +653 -0
- package/apps/storefront/src/pages/index.astro +290 -0
- package/apps/storefront/src/pages/llms.txt.ts +92 -0
- package/apps/storefront/src/pages/products/[handle].astro +443 -0
- package/apps/storefront/src/pages/robots.txt.ts +24 -0
- package/apps/storefront/src/pages/saved.astro +35 -0
- package/apps/storefront/src/pages/search.astro +150 -0
- package/apps/storefront/src/pages/sitemap.xml.ts +78 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +646 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +85 -0
- package/apps/storefront/src/pages/style-guide/index.astro +94 -0
- package/apps/storefront/src/pages/tenants/[id]/[...path].ts +57 -0
- package/apps/storefront/src/styles/global.css +277 -0
- package/apps/storefront/src/themes/reference.ts +61 -0
- package/apps/storefront/src/themes/schema.ts +111 -0
- package/apps/storefront/src/themes/tenants/index.ts +51 -0
- package/apps/storefront/tsconfig.json +16 -0
- package/apps/storefront/vitest.config.ts +22 -0
- package/apps/storefront/wrangler.toml +175 -0
- package/package.json +23 -0
- package/packages/public-runtime/LICENSE +58 -0
- package/packages/public-runtime/package.json +22 -0
- package/packages/public-runtime/src/binary-path.ts +68 -0
- package/packages/public-runtime/src/capabilities.ts +89 -0
- package/packages/public-runtime/src/catalog-api.ts +81 -0
- package/packages/public-runtime/src/catalog-d1.ts +192 -0
- package/packages/public-runtime/src/csp.ts +109 -0
- package/packages/public-runtime/src/customization-preview.ts +197 -0
- package/packages/public-runtime/src/customization-reconcile.ts +63 -0
- package/packages/public-runtime/src/customization-runtime.ts +157 -0
- package/packages/public-runtime/src/customization-scripts.ts +64 -0
- package/packages/public-runtime/src/customization-versioning.ts +95 -0
- package/packages/public-runtime/src/foxy.ts +184 -0
- package/packages/public-runtime/src/index.ts +30 -0
- package/packages/public-runtime/src/product.ts +159 -0
- package/packages/public-runtime/src/search.ts +45 -0
- package/packages/public-runtime/src/tenant-assets.ts +444 -0
- package/packages/public-runtime/src/tenant.ts +243 -0
- package/packages/public-runtime/tsconfig.json +8 -0
- package/packages/public-runtime/vitest.config.ts +8 -0
- package/pnpm-workspace.yaml +7 -0
- package/scripts/build/copy-tenant-assets.mjs +69 -0
- package/scripts/tot-dev.mjs +439 -0
- package/tenants/bigdvapor/content/blog.json +52 -0
- package/tenants/bigdvapor/content/chrome.html +149 -0
- package/tenants/bigdvapor/content/chrome.json +47 -0
- package/tenants/bigdvapor/content/home.html +463 -0
- package/tenants/bigdvapor/content/home.json +73 -0
- package/tenants/bigdvapor/content/pages/about.json +5 -0
- package/tenants/bigdvapor/content/pages/privacy.json +6 -0
- package/tenants/bigdvapor/content/pages/shipping-returns.json +6 -0
- package/tenants/bigdvapor/content/pages-html/blogs/news.html +86 -0
- package/tenants/bigdvapor/content/pages-html/pages/about-us.html +106 -0
- package/tenants/bigdvapor/content/pages-html/pages/contact-us.html +61 -0
- package/tenants/bigdvapor/content/pages-html/pages/privacy-policy.html +72 -0
- package/tenants/bigdvapor/content/pages-html/pages/shipping-returns.html +172 -0
- package/tenants/bigdvapor/content/themes/bigd-navy.json +109 -0
- package/tenants/bigdvapor/public/img/brands/adjust-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/again-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/al-fakher-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/arro-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/cookies-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/core-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/cyclone-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/dinner-lady-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/extre-bar-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/fifty-bar-vape-disposable.jpg +0 -0
- package/tenants/bigdvapor/public/img/brands/firerose-vape-disposable.jpg +0 -0
- package/tenants/bigdvapor/public/img/brands/flavor-beast-vape-disposable.jpg +0 -0
- package/tenants/bigdvapor/public/img/brands/foger-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/kk-energy-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/kumi-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/lost-vape-dispoable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/melo-labs-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/brands/mixo-vape-disposable.webp +0 -0
- package/tenants/bigdvapor/public/img/brands/one-tank-vape-disposable.jpg +0 -0
- package/tenants/bigdvapor/public/img/brands/oxbar-vape-disposable.webp +0 -0
- package/tenants/bigdvapor/public/img/brands/pillow-talk-vape-disposable.jpg +0 -0
- package/tenants/bigdvapor/public/img/brands/pod-king-vape-disposable.jpg +0 -0
- package/tenants/bigdvapor/public/img/brands/raz-vape-disposable.png +0 -0
- package/tenants/bigdvapor/public/img/hero-texas.jpg +0 -0
- package/tenants/bigdvapor/public/img/og.jpg +0 -0
- package/tenants/bigdvapor/public/img/pages/AdobeStock_202106312_web.jpg +0 -0
- package/tenants/bigdvapor/public/img/pages/CREW_web.jpg +0 -0
- package/tenants/bigdvapor/public/img/pages/Hero-Image.jpg +0 -0
- package/tenants/bigdvapor/public/img/tiles/adjust.png +0 -0
- package/tenants/bigdvapor/public/img/tiles/again.png +0 -0
- package/tenants/bigdvapor/public/img/tiles/al-fakher.png +0 -0
- package/tenants/bigdvapor/public/img/tiles/arro.png +0 -0
- package/tenants/bigdvapor/public/img/tiles/cookies.png +0 -0
- package/tenants/bigdvapor/public/img/tiles/core.png +0 -0
- package/tenants/bigdvapor/public/img/tiles/cyclone.png +0 -0
- package/tenants/bigdvapor/public/img/tiles/disposables.svg +23 -0
- package/tenants/bigdvapor/public/logo-wordmark.png +0 -0
- package/tenants/bigdvapor/public/pages/home.css +118 -0
- package/tenants/bigdvapor/public/pages/mkt.css +185 -0
- package/tenants/bigdvapor/public/pages/page.css +148 -0
- package/tenants/bigdvapor/public/themes/bigd-navy.css +73 -0
- package/tenants/bigdvapor/theme.json +12 -0
- package/tenants/giantvapes/content/chrome.html +152 -0
- package/tenants/giantvapes/content/chrome.json +94 -0
- package/tenants/giantvapes/content/home.html +194 -0
- package/tenants/giantvapes/content/home.json +50 -0
- package/tenants/giantvapes/content/pages/about.json +10 -0
- package/tenants/giantvapes/content/pages/privacy.json +6 -0
- package/tenants/giantvapes/content/pages/shipping-returns.json +6 -0
- package/tenants/giantvapes/content/pages-html/blogs/news.html +68 -0
- package/tenants/giantvapes/content/pages-html/pages/about-us.html +95 -0
- package/tenants/giantvapes/content/pages-html/pages/contact-us.html +68 -0
- package/tenants/giantvapes/content/pages-html/pages/privacy-policy.html +65 -0
- package/tenants/giantvapes/content/pages-html/pages/shipping-returns.html +77 -0
- package/tenants/giantvapes/content/themes/giant-navy.json +73 -0
- package/tenants/giantvapes/public/img/hero-suicide-bunny.jpg +0 -0
- package/tenants/giantvapes/public/img/hero.webp +0 -0
- package/tenants/giantvapes/public/img/og.jpg +0 -0
- package/tenants/giantvapes/public/logo-wordmark.png +0 -0
- package/tenants/giantvapes/public/pages/home.css +120 -0
- package/tenants/giantvapes/public/pages/mkt.css +185 -0
- package/tenants/giantvapes/public/pages/page.css +155 -0
- package/tenants/giantvapes/public/themes/giant-navy.css +76 -0
- package/tenants/giantvapes/theme.json +39 -0
- package/tenants/home/content/chrome.json +11 -0
- package/tenants/home/content/home.html +304 -0
- package/tenants/home/content/home.json +13 -0
- package/tenants/home/public/js/storefront.js +210 -0
- package/tenants/home/public/logo-wordmark.png +0 -0
- package/tenants/home/public/pages/storefront.css +212 -0
- package/tenants/home/theme.json +6 -0
- package/tenants/tokenoftrust/.tot/config.json +9 -0
- package/tenants/tokenoftrust/content/chrome.json +55 -0
- package/tenants/tokenoftrust/content/home.html +723 -0
- package/tenants/tokenoftrust/content/home.json +233 -0
- package/tenants/tokenoftrust/content/pages-html/careers.html +231 -0
- package/tenants/tokenoftrust/content/pages-html/company.html +275 -0
- package/tenants/tokenoftrust/content/pages-html/contact/contact-sales.html +188 -0
- package/tenants/tokenoftrust/content/pages-html/contact/startup-apply.html +206 -0
- package/tenants/tokenoftrust/content/pages-html/contact.html +178 -0
- package/tenants/tokenoftrust/content/pages-html/industries/adult-content-age-verification.html +286 -0
- package/tenants/tokenoftrust/content/pages-html/industries/cannabis.html +277 -0
- package/tenants/tokenoftrust/content/pages-html/pact-act-pricing.html +289 -0
- package/tenants/tokenoftrust/content/pages-html/pricing.html +483 -0
- package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-estimation.html +278 -0
- package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-gate.html +279 -0
- package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-verification.html +265 -0
- package/tenants/tokenoftrust/content/pages-html/product/age-assurance.html +173 -0
- package/tenants/tokenoftrust/content/pages-html/product/compliance/aml.html +214 -0
- package/tenants/tokenoftrust/content/pages-html/product/compliance/pact-act.html +226 -0
- package/tenants/tokenoftrust/content/pages-html/product/fraud-prevention.html +254 -0
- package/tenants/tokenoftrust/content/pages-html/product/social-profile-verification.html +212 -0
- package/tenants/tokenoftrust/content/pages-html/product/tax/excise-tax.html +213 -0
- package/tenants/tokenoftrust/content/pages-html/product/verification/aml.html +259 -0
- package/tenants/tokenoftrust/content/pages-html/product/verification/biometric-selfie.html +305 -0
- package/tenants/tokenoftrust/content/pages-html/product/verification/coverage.html +254 -0
- package/tenants/tokenoftrust/content/pages-html/product/verification/document-verification.html +306 -0
- package/tenants/tokenoftrust/content/pages-html/product/verification/electronic-identity-verification.html +304 -0
- package/tenants/tokenoftrust/content/pages-html/product/verification/government-id-verification.html +308 -0
- package/tenants/tokenoftrust/content/pages-html/product/verification.html +183 -0
- package/tenants/tokenoftrust/content/pages-html/product.html +228 -0
- package/tenants/tokenoftrust/content/pages-html/resources/integrations/bigcommerce-integration.html +220 -0
- package/tenants/tokenoftrust/content/pages-html/resources/integrations/shopify-integration.html +221 -0
- package/tenants/tokenoftrust/content/pages-html/resources/integrations/wordpress.html +220 -0
- package/tenants/tokenoftrust/content/pages-html/resources/integrations.html +172 -0
- package/tenants/tokenoftrust/content/pages-html/resources/refer-a-friend-program.html +317 -0
- package/tenants/tokenoftrust/content/pages-html/resources.html +177 -0
- package/tenants/tokenoftrust/content/pages-html/reviews.html +273 -0
- package/tenants/tokenoftrust/content/pages-html/solutions.html +292 -0
- package/tenants/tokenoftrust/content/pages-html/vlp-alcohol.html +289 -0
- package/tenants/tokenoftrust/content/pages-html/vlp-cigars-and-tobacco.html +286 -0
- package/tenants/tokenoftrust/content/pages-html/vlp-firearm-accessories.html +267 -0
- package/tenants/tokenoftrust/content/pages-html/vlp-peptides.html +273 -0
- package/tenants/tokenoftrust/content/themes/tot-navy.json +88 -0
- package/tenants/tokenoftrust/public/favicon.png +0 -0
- package/tenants/tokenoftrust/public/logo-icon.png +0 -0
- package/tenants/tokenoftrust/public/logo-wordmark.png +0 -0
- package/tenants/tokenoftrust/public/pages/company.css +108 -0
- package/tenants/tokenoftrust/public/pages/home.css +457 -0
- package/tenants/tokenoftrust/public/pages/mkt.css +482 -0
- package/tenants/tokenoftrust/public/pages/pricing.css +214 -0
- package/tenants/tokenoftrust/public/pages/solutions.css +66 -0
- package/tenants/tokenoftrust/public/themes/tot-navy-1.0.0.css +136 -0
- package/tenants/tokenoftrust/public/themes/tot-navy.css +358 -0
- package/tenants/tokenoftrust/theme.json +31 -0
- package/tsconfig.base.json +20 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map human color-option values to swatch fills for product cards.
|
|
3
|
+
*
|
|
4
|
+
* Merchants name colors in their own vernacular ("Oatmeal", "Spruce"), not hex.
|
|
5
|
+
* We resolve a known palette first, fall back to a CSS named color when the
|
|
6
|
+
* value happens to be one, and otherwise render an "unknown" swatch (neutral
|
|
7
|
+
* with a slash) rather than guessing wrong. Tenant-agnostic: this is product
|
|
8
|
+
* data, not theme.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Curated names common to apparel/home catalogs (lowercased keys). */
|
|
12
|
+
const PALETTE: Record<string, string> = {
|
|
13
|
+
black: "#1a1a1a",
|
|
14
|
+
charcoal: "#36393b",
|
|
15
|
+
graphite: "#3a3a3a",
|
|
16
|
+
slate: "#556770",
|
|
17
|
+
grey: "#8a8d91",
|
|
18
|
+
gray: "#8a8d91",
|
|
19
|
+
silver: "#c7c9cc",
|
|
20
|
+
white: "#f6f5f1",
|
|
21
|
+
ivory: "#f3efe4",
|
|
22
|
+
cream: "#efe9d8",
|
|
23
|
+
ecru: "#e8e1cd",
|
|
24
|
+
oatmeal: "#ddd3bf",
|
|
25
|
+
natural: "#e3d9c2",
|
|
26
|
+
sand: "#d8c6a3",
|
|
27
|
+
stone: "#cbbfa9",
|
|
28
|
+
tan: "#c5a980",
|
|
29
|
+
camel: "#b48a5e",
|
|
30
|
+
rust: "#a4512f",
|
|
31
|
+
terracotta: "#bf6a4a",
|
|
32
|
+
brick: "#8f4334",
|
|
33
|
+
olive: "#6f6f3a",
|
|
34
|
+
forest: "#2f4a36",
|
|
35
|
+
spruce: "#23413a",
|
|
36
|
+
sage: "#9aa583",
|
|
37
|
+
teal: "#2a6f72",
|
|
38
|
+
navy: "#1f2a44",
|
|
39
|
+
indigo: "#2c3a63",
|
|
40
|
+
denim: "#41597d",
|
|
41
|
+
blue: "#2f5e8f",
|
|
42
|
+
burgundy: "#5e2230",
|
|
43
|
+
wine: "#5e2230",
|
|
44
|
+
plum: "#5a3a55",
|
|
45
|
+
blush: "#e7c7c0",
|
|
46
|
+
pink: "#e3a6ad",
|
|
47
|
+
mustard: "#c79a3a",
|
|
48
|
+
amber: "#b5612f",
|
|
49
|
+
brown: "#5f4733",
|
|
50
|
+
chocolate: "#46342a",
|
|
51
|
+
khaki: "#9a8b66",
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** CSS named colors we accept as a fallback when not in PALETTE. */
|
|
55
|
+
const CSS_NAMED = new Set([
|
|
56
|
+
"red", "orange", "yellow", "green", "blue", "purple", "pink", "brown",
|
|
57
|
+
"black", "white", "gray", "grey", "beige", "ivory", "navy", "teal",
|
|
58
|
+
"maroon", "olive", "coral", "salmon", "khaki", "tan", "gold",
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
export interface Swatch {
|
|
62
|
+
/** Original option value, e.g. "Oatmeal". */
|
|
63
|
+
label: string;
|
|
64
|
+
/** CSS color for the dot, or null when unknown. */
|
|
65
|
+
fill: string | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function resolveSwatch(value: string): Swatch {
|
|
69
|
+
const key = value.trim().toLowerCase();
|
|
70
|
+
if (key in PALETTE) return { label: value, fill: PALETTE[key]! };
|
|
71
|
+
// Two-word names: try the last token ("Heather Grey" -> "grey").
|
|
72
|
+
const last = key.split(/\s+/).pop()!;
|
|
73
|
+
if (last in PALETTE) return { label: value, fill: PALETTE[last]! };
|
|
74
|
+
if (CSS_NAMED.has(key)) return { label: value, fill: key };
|
|
75
|
+
if (CSS_NAMED.has(last)) return { label: value, fill: last };
|
|
76
|
+
return { label: value, fill: null };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The product option that holds colors, if any (Color / Colour / Shade). */
|
|
80
|
+
export function colorOptionValues(
|
|
81
|
+
options: { name: string; values: string[] }[],
|
|
82
|
+
): string[] {
|
|
83
|
+
const opt = options.find((o) => /colou?r|shade|finish/i.test(o.name));
|
|
84
|
+
return opt ? opt.values : [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** True when a fill is light enough to need a ring so it reads on a light bg. */
|
|
88
|
+
export function isLightFill(fill: string): boolean {
|
|
89
|
+
const m = /^#([0-9a-f]{6})$/i.exec(fill);
|
|
90
|
+
if (!m) return false;
|
|
91
|
+
const n = parseInt(m[1]!, 16);
|
|
92
|
+
const r = (n >> 16) & 255,
|
|
93
|
+
g = (n >> 8) & 255,
|
|
94
|
+
b = n & 255;
|
|
95
|
+
// Perceived luminance.
|
|
96
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b > 200;
|
|
97
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JsonRpcContentEditClient — the storefront's server-to-server caller for
|
|
3
|
+
* tot-mcp's `content_edit` tool (the inline-AI edit loop, WS5 G1). Mirrors
|
|
4
|
+
* {@link JsonRpcChangeClient} exactly (same transport, same session-validation,
|
|
5
|
+
* same tool-result unwrap, same typed errors) — reusing the forge seam's
|
|
6
|
+
* exported transport + error types so there is ONE wire contract, not two.
|
|
7
|
+
*
|
|
8
|
+
* AUTH SHAPE (G4 design note, `pending beta/WS2 confirmation`): the storefront
|
|
9
|
+
* backend calls `content_edit` as the TENANT OPERATOR (`credential_validate`
|
|
10
|
+
* with storefront's own TOT_API_KEY/TOT_SECRET_KEY — the SAME credential
|
|
11
|
+
* change/accept already uses), not as the individual signed-in developer.
|
|
12
|
+
* Developer-level authorization is the caller's job (`/dev`'s own
|
|
13
|
+
* `readViewerSession()` + capability check, BEFORE this client is ever
|
|
14
|
+
* constructed) — this client only proves "a legitimate storefront backend is
|
|
15
|
+
* asking", the same trust boundary `/api/changes/accept` already relies on.
|
|
16
|
+
*/
|
|
17
|
+
import {
|
|
18
|
+
FetchTransport,
|
|
19
|
+
ForgeAuthError,
|
|
20
|
+
ForgeConfigError,
|
|
21
|
+
ForgeTransportError,
|
|
22
|
+
SESSION_HEADER,
|
|
23
|
+
type McpTransport,
|
|
24
|
+
type JsonRpcRequest,
|
|
25
|
+
type TotCredentials,
|
|
26
|
+
type TransportResponse,
|
|
27
|
+
} from "@/lib/forge";
|
|
28
|
+
import { mapForgeError } from "@/lib/forge/errors.js";
|
|
29
|
+
import { readEnv } from "@/lib/env";
|
|
30
|
+
import type { ContentEditFile, ContentEditResult } from "./types.js";
|
|
31
|
+
|
|
32
|
+
export const CONTENT_EDIT_TOOL = {
|
|
33
|
+
validate: "credential_validate",
|
|
34
|
+
edit: "content_edit",
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
export { SESSION_HEADER } from "@/lib/forge";
|
|
38
|
+
|
|
39
|
+
// --- MCP tool-result envelope (mirrors the change client) -------------------
|
|
40
|
+
|
|
41
|
+
interface McpToolResult {
|
|
42
|
+
content?: Array<{ type?: string; text?: string }>;
|
|
43
|
+
structuredContent?: unknown;
|
|
44
|
+
isError?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseTextContent(content: McpToolResult["content"]): unknown {
|
|
48
|
+
const text = content?.find((c) => c.type === "text" || c.text != null)?.text;
|
|
49
|
+
if (text == null) return undefined;
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(text);
|
|
52
|
+
} catch {
|
|
53
|
+
return text;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function unwrapToolResult<T>(result: unknown): T {
|
|
58
|
+
const env = (result ?? {}) as McpToolResult;
|
|
59
|
+
const payload =
|
|
60
|
+
env.structuredContent !== undefined
|
|
61
|
+
? env.structuredContent
|
|
62
|
+
: parseTextContent(env.content);
|
|
63
|
+
|
|
64
|
+
if (env.isError) {
|
|
65
|
+
const p = (payload ?? {}) as Record<string, unknown>;
|
|
66
|
+
throw mapForgeError({
|
|
67
|
+
code: typeof p.code === "number" ? p.code : undefined,
|
|
68
|
+
message: typeof p.message === "string" ? p.message : "content_edit tool error",
|
|
69
|
+
data: (p.data as Record<string, unknown>) ?? p,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return payload as T;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// --- Config -------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
export interface JsonRpcContentEditClientConfig {
|
|
78
|
+
/** MCP base URL (the `POST /mcp` endpoint). */
|
|
79
|
+
baseUrl: string;
|
|
80
|
+
/** Storefront's ToT operator credentials for `credential_validate`. */
|
|
81
|
+
credentials: TotCredentials;
|
|
82
|
+
/** Transport override (defaults to fetch). Injected by tests. */
|
|
83
|
+
transport?: McpTransport;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// --- The client -----------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
export class JsonRpcContentEditClient {
|
|
89
|
+
private readonly baseUrl: string;
|
|
90
|
+
private readonly credentials: TotCredentials;
|
|
91
|
+
private readonly transport: McpTransport;
|
|
92
|
+
private nextId = 1;
|
|
93
|
+
/** Cached session validation — validate once, reuse (lazily). */
|
|
94
|
+
private sessionPromise?: Promise<string | undefined>;
|
|
95
|
+
|
|
96
|
+
constructor(config: JsonRpcContentEditClientConfig) {
|
|
97
|
+
if (!config.baseUrl) {
|
|
98
|
+
throw new ForgeConfigError("content-edit: MCP_BASE_URL is not configured");
|
|
99
|
+
}
|
|
100
|
+
if (!config.credentials?.apiKey) {
|
|
101
|
+
throw new ForgeConfigError(
|
|
102
|
+
"content-edit: storefront ToT credentials are not configured",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
this.baseUrl = config.baseUrl;
|
|
106
|
+
this.credentials = config.credentials;
|
|
107
|
+
this.transport = config.transport ?? new FetchTransport(config.baseUrl);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async editContent(
|
|
111
|
+
prompt: string,
|
|
112
|
+
files: readonly ContentEditFile[],
|
|
113
|
+
): Promise<ContentEditResult> {
|
|
114
|
+
const sessionId = await this.ensureSession();
|
|
115
|
+
const result = await this.rpc(
|
|
116
|
+
"tools/call",
|
|
117
|
+
{ name: CONTENT_EDIT_TOOL.edit, arguments: { prompt, files } },
|
|
118
|
+
sessionId,
|
|
119
|
+
);
|
|
120
|
+
return unwrapToolResult<ContentEditResult>(result);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// --- internals (mirror JsonRpcChangeClient) --------------------------------
|
|
124
|
+
|
|
125
|
+
private ensureSession(): Promise<string | undefined> {
|
|
126
|
+
this.sessionPromise ??= this.validateSession();
|
|
127
|
+
return this.sessionPromise;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private async validateSession(): Promise<string | undefined> {
|
|
131
|
+
const args = this.credentialArgs();
|
|
132
|
+
let res: TransportResponse;
|
|
133
|
+
try {
|
|
134
|
+
res = await this.rpcRaw(
|
|
135
|
+
"tools/call",
|
|
136
|
+
{ name: CONTENT_EDIT_TOOL.validate, arguments: args },
|
|
137
|
+
undefined,
|
|
138
|
+
);
|
|
139
|
+
} catch (err) {
|
|
140
|
+
this.sessionPromise = undefined; // let a later call retry
|
|
141
|
+
throw err;
|
|
142
|
+
}
|
|
143
|
+
if (res.body.error) {
|
|
144
|
+
this.sessionPromise = undefined;
|
|
145
|
+
throw new ForgeAuthError(
|
|
146
|
+
res.body.error.message ?? "content-edit: credential validation failed",
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
const validated = unwrapToolResult<{ session?: string; sessionId?: string }>(
|
|
151
|
+
res.body.result,
|
|
152
|
+
);
|
|
153
|
+
return (
|
|
154
|
+
res.sessionId ?? validated?.session ?? validated?.sessionId ?? undefined
|
|
155
|
+
);
|
|
156
|
+
} catch (err) {
|
|
157
|
+
this.sessionPromise = undefined;
|
|
158
|
+
throw err instanceof ForgeAuthError
|
|
159
|
+
? err
|
|
160
|
+
: new ForgeAuthError("content-edit: credential validation was rejected", {
|
|
161
|
+
cause: err,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Build the credential payload; omits absent secrets. Never logged. */
|
|
167
|
+
private credentialArgs(): Record<string, unknown> {
|
|
168
|
+
const c = this.credentials;
|
|
169
|
+
const out: Record<string, unknown> = { apiKey: c.apiKey };
|
|
170
|
+
if (c.secretKey) out.secretKey = c.secretKey;
|
|
171
|
+
if (c.accessToken) out.accessToken = c.accessToken;
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private async rpc(
|
|
176
|
+
method: string,
|
|
177
|
+
params: unknown,
|
|
178
|
+
sessionId: string | undefined,
|
|
179
|
+
): Promise<unknown> {
|
|
180
|
+
const res = await this.rpcRaw(method, params, sessionId);
|
|
181
|
+
if (res.body.error) throw mapForgeError(res.body.error);
|
|
182
|
+
return res.body.result;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private async rpcRaw(
|
|
186
|
+
method: string,
|
|
187
|
+
params: unknown,
|
|
188
|
+
sessionId: string | undefined,
|
|
189
|
+
): Promise<TransportResponse> {
|
|
190
|
+
const headers: Record<string, string> = {};
|
|
191
|
+
if (sessionId) headers[SESSION_HEADER] = sessionId;
|
|
192
|
+
const body: JsonRpcRequest = {
|
|
193
|
+
jsonrpc: "2.0",
|
|
194
|
+
id: this.nextId++,
|
|
195
|
+
method,
|
|
196
|
+
params,
|
|
197
|
+
};
|
|
198
|
+
try {
|
|
199
|
+
return await this.transport.post({ body, headers });
|
|
200
|
+
} catch (err) {
|
|
201
|
+
if (err instanceof ForgeTransportError) throw err;
|
|
202
|
+
throw new ForgeTransportError(
|
|
203
|
+
`content-edit: transport failure calling ${method}`,
|
|
204
|
+
{ cause: err },
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// --- Factory ----------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Build a {@link JsonRpcContentEditClient} from the runtime env — the SAME env
|
|
214
|
+
* the change client reads (`MCP_BASE_URL` + storefront's own ToT credentials).
|
|
215
|
+
* Throws {@link ForgeConfigError} when the base URL or api key is missing.
|
|
216
|
+
* Secrets are read via {@link readEnv} and never logged.
|
|
217
|
+
*/
|
|
218
|
+
export async function createContentEditClient(
|
|
219
|
+
overrides: Partial<JsonRpcContentEditClientConfig> = {},
|
|
220
|
+
): Promise<JsonRpcContentEditClient> {
|
|
221
|
+
const baseUrl = overrides.baseUrl ?? (await readEnv("MCP_BASE_URL")) ?? "";
|
|
222
|
+
const credentials =
|
|
223
|
+
overrides.credentials ??
|
|
224
|
+
({
|
|
225
|
+
apiKey: (await readEnv("TOT_API_KEY")) ?? "",
|
|
226
|
+
secretKey: await readEnv("TOT_SECRET_KEY"),
|
|
227
|
+
accessToken: await readEnv("TOT_ACCESS_TOKEN"),
|
|
228
|
+
} satisfies TotCredentials);
|
|
229
|
+
return new JsonRpcContentEditClient({ ...overrides, baseUrl, credentials });
|
|
230
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* content_edit integration — public barrel. Import the typed client and its
|
|
3
|
+
* route helper from here (`@/lib/content-edit`) so call sites never reach into
|
|
4
|
+
* individual files.
|
|
5
|
+
*/
|
|
6
|
+
export type { ContentEditFile, ContentEditFileDiff, ContentEditResult } from "./types.js";
|
|
7
|
+
export {
|
|
8
|
+
JsonRpcContentEditClient,
|
|
9
|
+
createContentEditClient,
|
|
10
|
+
CONTENT_EDIT_TOOL,
|
|
11
|
+
SESSION_HEADER,
|
|
12
|
+
} from "./client.js";
|
|
13
|
+
export type { JsonRpcContentEditClientConfig } from "./client.js";
|
|
14
|
+
export { getContentEditClient } from "./route.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route helper for `/api/content-edit/ai-edit` — mirrors `@/lib/change/route.ts`'s
|
|
3
|
+
* `getChangeClient`: build the env-configured client, or a 503 Response when
|
|
4
|
+
* the MCP integration isn't configured (missing `MCP_BASE_URL`/credentials).
|
|
5
|
+
*/
|
|
6
|
+
import { ForgeError } from "@/lib/forge";
|
|
7
|
+
import { createContentEditClient } from "./client.js";
|
|
8
|
+
import { json } from "@/lib/grants/route.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Build a content-edit client over the real MCP from env, or return a 503
|
|
12
|
+
* Response when the integration is not configured. Never leaks secret values.
|
|
13
|
+
*/
|
|
14
|
+
export async function getContentEditClient(): Promise<
|
|
15
|
+
Awaited<ReturnType<typeof createContentEditClient>> | Response
|
|
16
|
+
> {
|
|
17
|
+
try {
|
|
18
|
+
return await createContentEditClient();
|
|
19
|
+
} catch (err) {
|
|
20
|
+
if (err instanceof ForgeError && err.kind === "config") {
|
|
21
|
+
return json({ error: "content_edit integration not configured" }, 503);
|
|
22
|
+
}
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Wire shape for tot-mcp's `content_edit` tool — mirrors tot-mcp's own
|
|
2
|
+
* ContentFile/ContentFileDiff/ContentEditResult (src/services/content-editor.ts). */
|
|
3
|
+
|
|
4
|
+
export interface ContentEditFile {
|
|
5
|
+
/** e.g. "content/home.html" or "theme.json" — content_edit's own allowlist. */
|
|
6
|
+
path: string;
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ContentEditFileDiff {
|
|
11
|
+
path: string;
|
|
12
|
+
/** Unified diff (`--- a/<path>` / `+++ b/<path>`) against the given content. */
|
|
13
|
+
diff: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ContentEditResult {
|
|
17
|
+
diffs: ContentEditFileDiff[];
|
|
18
|
+
summary: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSP hashes for the **static** inline `<script>`/`<style>` that Astro emits in
|
|
3
|
+
* the production build — the `client:load|idle|only` hydration directive
|
|
4
|
+
* loaders, the `<astro-island>` definition, the `astro-island{display:contents}`
|
|
5
|
+
* style, and bundled Layout scripts. These are identical across tenants and
|
|
6
|
+
* requests (no dynamic data), so hashes (not nonces) are the correct, strict
|
|
7
|
+
* tool for them.
|
|
8
|
+
*
|
|
9
|
+
* They change only when Astro or our bundled scripts change (e.g. an Astro
|
|
10
|
+
* upgrade). A drift check re-extracts them from a fresh build and fails if this
|
|
11
|
+
* list is stale — see `scripts/check-csp-hashes.mjs`. Regenerate with:
|
|
12
|
+
* node scripts/check-csp-hashes.mjs --print
|
|
13
|
+
*/
|
|
14
|
+
export const STATIC_SCRIPT_HASHES: readonly string[] = [
|
|
15
|
+
"'sha256-BF0290pkb3jxQsE7z00xR8Imp8X34FLC88L0lkMnrGw='",
|
|
16
|
+
"'sha256-SaCkFfPruIdTXT8/97JArQmGxiJAL2o4bBDvSgJ5y3Q='",
|
|
17
|
+
"'sha256-QzWFZi+FLIx23tnm9SBU4aEgx4x8DsuASP07mfqol/c='",
|
|
18
|
+
"'sha256-YicfxUFBkKrQapZ/tzZKlaKTdNHgwVfv7y2Wa0NC6/k='",
|
|
19
|
+
"'sha256-eIXWvAmxkr251LJZkjniEK5LcPF3NkapbJepohwYRIc='",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export const STATIC_STYLE_HASHES: readonly string[] = [
|
|
23
|
+
"'sha256-vv9IoKo7BSLbWcUHr3tNmfNVmm5L/9Cfn2H6LMk7/ow='",
|
|
24
|
+
];
|