@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.
Files changed (337) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +40 -0
  3. package/apps/storefront/.dev.vars.example +41 -0
  4. package/apps/storefront/.env.example +24 -0
  5. package/apps/storefront/astro.config.mjs +245 -0
  6. package/apps/storefront/env.d.ts +155 -0
  7. package/apps/storefront/lib/ensure-preview-reconcile-secret.sh +31 -0
  8. package/apps/storefront/lib/resolve-cf-token.sh +48 -0
  9. package/apps/storefront/lib/resolve-tot-credentials.sh +69 -0
  10. package/apps/storefront/migrations/0000_baseline.sql +54 -0
  11. package/apps/storefront/migrations/0001_products_fts.sql +9 -0
  12. package/apps/storefront/migrations/README.md +54 -0
  13. package/apps/storefront/migrations/meta/0000_snapshot.json +347 -0
  14. package/apps/storefront/migrations/meta/0001_snapshot.json +347 -0
  15. package/apps/storefront/migrations/meta/_journal.json +20 -0
  16. package/apps/storefront/package.json +41 -0
  17. package/apps/storefront/public/brand/northwind-logo-dark.svg +4 -0
  18. package/apps/storefront/public/brand/northwind-logo-light.svg +4 -0
  19. package/apps/storefront/public/brand/northwind-og.svg +13 -0
  20. package/apps/storefront/public/favicon.svg +5 -0
  21. package/apps/storefront/public/js/dashboard-team.js +147 -0
  22. package/apps/storefront/public/js/dashboard-vendor-search.js +115 -0
  23. package/apps/storefront/src/components/Badge.astro +34 -0
  24. package/apps/storefront/src/components/Breadcrumbs.astro +45 -0
  25. package/apps/storefront/src/components/CollectionCard.astro +56 -0
  26. package/apps/storefront/src/components/EmptyState.astro +35 -0
  27. package/apps/storefront/src/components/Img.astro +68 -0
  28. package/apps/storefront/src/components/ProductCard.astro +228 -0
  29. package/apps/storefront/src/components/Section.astro +39 -0
  30. package/apps/storefront/src/components/Seo.astro +70 -0
  31. package/apps/storefront/src/components/WidgetFrame.astro +34 -0
  32. package/apps/storefront/src/components/auth/AuthBadge.astro +44 -0
  33. package/apps/storefront/src/components/chrome/AnnouncementBar.astro +108 -0
  34. package/apps/storefront/src/components/chrome/MegaMenu.astro +26 -0
  35. package/apps/storefront/src/components/chrome/NavDropdown.astro +116 -0
  36. package/apps/storefront/src/components/chrome/SiteFooter.astro +181 -0
  37. package/apps/storefront/src/components/chrome/SiteHeader.astro +181 -0
  38. package/apps/storefront/src/components/chrome/UtilityNav.astro +79 -0
  39. package/apps/storefront/src/components/commerce/FoxyLoader.astro +23 -0
  40. package/apps/storefront/src/components/commerce/PriceDisplay.astro +91 -0
  41. package/apps/storefront/src/components/commerce/ProductCarousel.astro +197 -0
  42. package/apps/storefront/src/components/commerce/ProductGrid.astro +75 -0
  43. package/apps/storefront/src/components/commerce/RatingStars.astro +58 -0
  44. package/apps/storefront/src/components/compliance/NicotineWarning.astro +33 -0
  45. package/apps/storefront/src/components/home/Hero.astro +164 -0
  46. package/apps/storefront/src/components/islands/AgeGate.tsx +105 -0
  47. package/apps/storefront/src/components/islands/ImageGallery.tsx +237 -0
  48. package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +73 -0
  49. package/apps/storefront/src/components/islands/MobileNav.tsx +239 -0
  50. package/apps/storefront/src/components/islands/QuickView.tsx +138 -0
  51. package/apps/storefront/src/components/islands/RecentlyViewed.tsx +122 -0
  52. package/apps/storefront/src/components/islands/SavedList.tsx +99 -0
  53. package/apps/storefront/src/components/islands/SearchTypeahead.tsx +248 -0
  54. package/apps/storefront/src/components/islands/VariantSelector.tsx +378 -0
  55. package/apps/storefront/src/components/marketing/CardGrid.astro +72 -0
  56. package/apps/storefront/src/components/marketing/CodeSample.astro +20 -0
  57. package/apps/storefront/src/components/marketing/CtaBand.astro +24 -0
  58. package/apps/storefront/src/components/marketing/Faq.astro +37 -0
  59. package/apps/storefront/src/components/marketing/Integrations.astro +63 -0
  60. package/apps/storefront/src/components/marketing/MarketingBlocks.astro +53 -0
  61. package/apps/storefront/src/components/marketing/MarketingCtas.astro +48 -0
  62. package/apps/storefront/src/components/marketing/MarketingHero.astro +72 -0
  63. package/apps/storefront/src/components/marketing/ProofStrip.astro +37 -0
  64. package/apps/storefront/src/components/marketing/SplitCompare.astro +53 -0
  65. package/apps/storefront/src/components/marketing/Steps.astro +36 -0
  66. package/apps/storefront/src/components/marketing/Testimonials.astro +38 -0
  67. package/apps/storefront/src/components/marketing/TrustBar.astro +22 -0
  68. package/apps/storefront/src/components/nav/Footer.astro +148 -0
  69. package/apps/storefront/src/components/nav/Header.astro +190 -0
  70. package/apps/storefront/src/components/plp/ActiveFilters.astro +79 -0
  71. package/apps/storefront/src/components/plp/FacetSidebar.astro +146 -0
  72. package/apps/storefront/src/components/plp/Pagination.astro +99 -0
  73. package/apps/storefront/src/components/plp/SortSelect.astro +64 -0
  74. package/apps/storefront/src/config/devTenants.ts +16 -0
  75. package/apps/storefront/src/config/kvTenantResolver.ts +87 -0
  76. package/apps/storefront/src/config/resolver.ts +46 -0
  77. package/apps/storefront/src/config/tenants.ts +193 -0
  78. package/apps/storefront/src/layouts/Layout.astro +303 -0
  79. package/apps/storefront/src/lib/analytics/index.ts +47 -0
  80. package/apps/storefront/src/lib/auth/brokerAssertion.ts +136 -0
  81. package/apps/storefront/src/lib/auth/devAuth.ts +90 -0
  82. package/apps/storefront/src/lib/auth/gatePage.ts +81 -0
  83. package/apps/storefront/src/lib/auth/identityToken.ts +341 -0
  84. package/apps/storefront/src/lib/auth/loginGate.ts +107 -0
  85. package/apps/storefront/src/lib/auth/route.ts +146 -0
  86. package/apps/storefront/src/lib/auth/session.ts +203 -0
  87. package/apps/storefront/src/lib/auth/totAccessClient.ts +503 -0
  88. package/apps/storefront/src/lib/basePath.ts +41 -0
  89. package/apps/storefront/src/lib/cfImage.ts +55 -0
  90. package/apps/storefront/src/lib/chrome/model.ts +65 -0
  91. package/apps/storefront/src/lib/colors.ts +97 -0
  92. package/apps/storefront/src/lib/content-edit/client.ts +230 -0
  93. package/apps/storefront/src/lib/content-edit/index.ts +14 -0
  94. package/apps/storefront/src/lib/content-edit/route.ts +25 -0
  95. package/apps/storefront/src/lib/content-edit/types.ts +19 -0
  96. package/apps/storefront/src/lib/cspStaticHashes.ts +24 -0
  97. package/apps/storefront/src/lib/d1/catalog.ts +289 -0
  98. package/apps/storefront/src/lib/dashboard/staffAdmission.ts +43 -0
  99. package/apps/storefront/src/lib/dashboard/staffVendorAccess.ts +449 -0
  100. package/apps/storefront/src/lib/dashboard/tenantSelection.ts +136 -0
  101. package/apps/storefront/src/lib/dashboard/vendorQuery.ts +61 -0
  102. package/apps/storefront/src/lib/demoGate.ts +113 -0
  103. package/apps/storefront/src/lib/dev/ai-widget-client.js +127 -0
  104. package/apps/storefront/src/lib/dev/cliSignInCode.ts +132 -0
  105. package/apps/storefront/src/lib/diag/redact.ts +20 -0
  106. package/apps/storefront/src/lib/edgeCache.ts +128 -0
  107. package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +62 -0
  108. package/apps/storefront/src/lib/env.ts +60 -0
  109. package/apps/storefront/src/lib/fixtures/sampleProducts.ts +130 -0
  110. package/apps/storefront/src/lib/format.ts +29 -0
  111. package/apps/storefront/src/lib/foxyCommerce.ts +49 -0
  112. package/apps/storefront/src/lib/imageAttrs.ts +55 -0
  113. package/apps/storefront/src/lib/jsonld.ts +136 -0
  114. package/apps/storefront/src/lib/maintenance.ts +71 -0
  115. package/apps/storefront/src/lib/memoryKv.ts +32 -0
  116. package/apps/storefront/src/lib/messaging/messagesClient.ts +143 -0
  117. package/apps/storefront/src/lib/placeholder.ts +99 -0
  118. package/apps/storefront/src/lib/previewReload.ts +125 -0
  119. package/apps/storefront/src/lib/rawMarketingHtml.ts +133 -0
  120. package/apps/storefront/src/lib/search/index.ts +74 -0
  121. package/apps/storefront/src/lib/sections.ts +129 -0
  122. package/apps/storefront/src/lib/securityHeaders.ts +31 -0
  123. package/apps/storefront/src/lib/storyblok/content-model.ts +289 -0
  124. package/apps/storefront/src/lib/storyblok/provider.ts +524 -0
  125. package/apps/storefront/src/lib/tenantRouting.ts +91 -0
  126. package/apps/storefront/src/lib/tot/ToTClient.ts +177 -0
  127. package/apps/storefront/src/lib/tot/d1Client.ts +62 -0
  128. package/apps/storefront/src/lib/tot/query.ts +187 -0
  129. package/apps/storefront/src/lib/tot/totClientInterface.ts +30 -0
  130. package/apps/storefront/src/lib/url.ts +119 -0
  131. package/apps/storefront/src/lib/wishlist.ts +63 -0
  132. package/apps/storefront/src/middleware/index.ts +413 -0
  133. package/apps/storefront/src/pages/404.astro +61 -0
  134. package/apps/storefront/src/pages/[...slug].astro +90 -0
  135. package/apps/storefront/src/pages/api/auth/logout.ts +21 -0
  136. package/apps/storefront/src/pages/api/auth/magic-exchange.ts +107 -0
  137. package/apps/storefront/src/pages/api/auth/send.ts +85 -0
  138. package/apps/storefront/src/pages/api/auth/verify.ts +135 -0
  139. package/apps/storefront/src/pages/api/cache-purge.ts +44 -0
  140. package/apps/storefront/src/pages/api/content-edit/ai-edit.ts +64 -0
  141. package/apps/storefront/src/pages/api/csp-report.ts +25 -0
  142. package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +124 -0
  143. package/apps/storefront/src/pages/api/dashboard/vendor-search.ts +120 -0
  144. package/apps/storefront/src/pages/api/dev/cli-signin-code.ts +44 -0
  145. package/apps/storefront/src/pages/api/newsletter.ts +104 -0
  146. package/apps/storefront/src/pages/api/request-access.ts +172 -0
  147. package/apps/storefront/src/pages/auth/login.astro +149 -0
  148. package/apps/storefront/src/pages/auth/magic.astro +105 -0
  149. package/apps/storefront/src/pages/capabilities.astro +292 -0
  150. package/apps/storefront/src/pages/collections/[handle].astro +154 -0
  151. package/apps/storefront/src/pages/collections/index.astro +59 -0
  152. package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +100 -0
  153. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +154 -0
  154. package/apps/storefront/src/pages/dashboard/index.astro +160 -0
  155. package/apps/storefront/src/pages/dev.astro +653 -0
  156. package/apps/storefront/src/pages/index.astro +290 -0
  157. package/apps/storefront/src/pages/llms.txt.ts +92 -0
  158. package/apps/storefront/src/pages/products/[handle].astro +443 -0
  159. package/apps/storefront/src/pages/robots.txt.ts +24 -0
  160. package/apps/storefront/src/pages/saved.astro +35 -0
  161. package/apps/storefront/src/pages/search.astro +150 -0
  162. package/apps/storefront/src/pages/sitemap.xml.ts +78 -0
  163. package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +646 -0
  164. package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +85 -0
  165. package/apps/storefront/src/pages/style-guide/index.astro +94 -0
  166. package/apps/storefront/src/pages/tenants/[id]/[...path].ts +57 -0
  167. package/apps/storefront/src/styles/global.css +277 -0
  168. package/apps/storefront/src/themes/reference.ts +61 -0
  169. package/apps/storefront/src/themes/schema.ts +111 -0
  170. package/apps/storefront/src/themes/tenants/index.ts +51 -0
  171. package/apps/storefront/tsconfig.json +16 -0
  172. package/apps/storefront/vitest.config.ts +22 -0
  173. package/apps/storefront/wrangler.toml +175 -0
  174. package/package.json +23 -0
  175. package/packages/public-runtime/LICENSE +58 -0
  176. package/packages/public-runtime/package.json +22 -0
  177. package/packages/public-runtime/src/binary-path.ts +68 -0
  178. package/packages/public-runtime/src/capabilities.ts +89 -0
  179. package/packages/public-runtime/src/catalog-api.ts +81 -0
  180. package/packages/public-runtime/src/catalog-d1.ts +192 -0
  181. package/packages/public-runtime/src/csp.ts +109 -0
  182. package/packages/public-runtime/src/customization-preview.ts +197 -0
  183. package/packages/public-runtime/src/customization-reconcile.ts +63 -0
  184. package/packages/public-runtime/src/customization-runtime.ts +157 -0
  185. package/packages/public-runtime/src/customization-scripts.ts +64 -0
  186. package/packages/public-runtime/src/customization-versioning.ts +95 -0
  187. package/packages/public-runtime/src/foxy.ts +184 -0
  188. package/packages/public-runtime/src/index.ts +30 -0
  189. package/packages/public-runtime/src/product.ts +159 -0
  190. package/packages/public-runtime/src/search.ts +45 -0
  191. package/packages/public-runtime/src/tenant-assets.ts +444 -0
  192. package/packages/public-runtime/src/tenant.ts +243 -0
  193. package/packages/public-runtime/tsconfig.json +8 -0
  194. package/packages/public-runtime/vitest.config.ts +8 -0
  195. package/pnpm-workspace.yaml +7 -0
  196. package/scripts/build/copy-tenant-assets.mjs +69 -0
  197. package/scripts/tot-dev.mjs +439 -0
  198. package/tenants/bigdvapor/content/blog.json +52 -0
  199. package/tenants/bigdvapor/content/chrome.html +149 -0
  200. package/tenants/bigdvapor/content/chrome.json +47 -0
  201. package/tenants/bigdvapor/content/home.html +463 -0
  202. package/tenants/bigdvapor/content/home.json +73 -0
  203. package/tenants/bigdvapor/content/pages/about.json +5 -0
  204. package/tenants/bigdvapor/content/pages/privacy.json +6 -0
  205. package/tenants/bigdvapor/content/pages/shipping-returns.json +6 -0
  206. package/tenants/bigdvapor/content/pages-html/blogs/news.html +86 -0
  207. package/tenants/bigdvapor/content/pages-html/pages/about-us.html +106 -0
  208. package/tenants/bigdvapor/content/pages-html/pages/contact-us.html +61 -0
  209. package/tenants/bigdvapor/content/pages-html/pages/privacy-policy.html +72 -0
  210. package/tenants/bigdvapor/content/pages-html/pages/shipping-returns.html +172 -0
  211. package/tenants/bigdvapor/content/themes/bigd-navy.json +109 -0
  212. package/tenants/bigdvapor/public/img/brands/adjust-vape-disposable.png +0 -0
  213. package/tenants/bigdvapor/public/img/brands/again-vape-disposable.png +0 -0
  214. package/tenants/bigdvapor/public/img/brands/al-fakher-vape-disposable.png +0 -0
  215. package/tenants/bigdvapor/public/img/brands/arro-vape-disposable.png +0 -0
  216. package/tenants/bigdvapor/public/img/brands/cookies-vape-disposable.png +0 -0
  217. package/tenants/bigdvapor/public/img/brands/core-vape-disposable.png +0 -0
  218. package/tenants/bigdvapor/public/img/brands/cyclone-vape-disposable.png +0 -0
  219. package/tenants/bigdvapor/public/img/brands/dinner-lady-vape-disposable.png +0 -0
  220. package/tenants/bigdvapor/public/img/brands/extre-bar-vape-disposable.png +0 -0
  221. package/tenants/bigdvapor/public/img/brands/fifty-bar-vape-disposable.jpg +0 -0
  222. package/tenants/bigdvapor/public/img/brands/firerose-vape-disposable.jpg +0 -0
  223. package/tenants/bigdvapor/public/img/brands/flavor-beast-vape-disposable.jpg +0 -0
  224. package/tenants/bigdvapor/public/img/brands/foger-vape-disposable.png +0 -0
  225. package/tenants/bigdvapor/public/img/brands/kk-energy-vape-disposable.png +0 -0
  226. package/tenants/bigdvapor/public/img/brands/kumi-vape-disposable.png +0 -0
  227. package/tenants/bigdvapor/public/img/brands/lost-vape-dispoable.png +0 -0
  228. package/tenants/bigdvapor/public/img/brands/melo-labs-vape-disposable.png +0 -0
  229. package/tenants/bigdvapor/public/img/brands/mixo-vape-disposable.webp +0 -0
  230. package/tenants/bigdvapor/public/img/brands/one-tank-vape-disposable.jpg +0 -0
  231. package/tenants/bigdvapor/public/img/brands/oxbar-vape-disposable.webp +0 -0
  232. package/tenants/bigdvapor/public/img/brands/pillow-talk-vape-disposable.jpg +0 -0
  233. package/tenants/bigdvapor/public/img/brands/pod-king-vape-disposable.jpg +0 -0
  234. package/tenants/bigdvapor/public/img/brands/raz-vape-disposable.png +0 -0
  235. package/tenants/bigdvapor/public/img/hero-texas.jpg +0 -0
  236. package/tenants/bigdvapor/public/img/og.jpg +0 -0
  237. package/tenants/bigdvapor/public/img/pages/AdobeStock_202106312_web.jpg +0 -0
  238. package/tenants/bigdvapor/public/img/pages/CREW_web.jpg +0 -0
  239. package/tenants/bigdvapor/public/img/pages/Hero-Image.jpg +0 -0
  240. package/tenants/bigdvapor/public/img/tiles/adjust.png +0 -0
  241. package/tenants/bigdvapor/public/img/tiles/again.png +0 -0
  242. package/tenants/bigdvapor/public/img/tiles/al-fakher.png +0 -0
  243. package/tenants/bigdvapor/public/img/tiles/arro.png +0 -0
  244. package/tenants/bigdvapor/public/img/tiles/cookies.png +0 -0
  245. package/tenants/bigdvapor/public/img/tiles/core.png +0 -0
  246. package/tenants/bigdvapor/public/img/tiles/cyclone.png +0 -0
  247. package/tenants/bigdvapor/public/img/tiles/disposables.svg +23 -0
  248. package/tenants/bigdvapor/public/logo-wordmark.png +0 -0
  249. package/tenants/bigdvapor/public/pages/home.css +118 -0
  250. package/tenants/bigdvapor/public/pages/mkt.css +185 -0
  251. package/tenants/bigdvapor/public/pages/page.css +148 -0
  252. package/tenants/bigdvapor/public/themes/bigd-navy.css +73 -0
  253. package/tenants/bigdvapor/theme.json +12 -0
  254. package/tenants/giantvapes/content/chrome.html +152 -0
  255. package/tenants/giantvapes/content/chrome.json +94 -0
  256. package/tenants/giantvapes/content/home.html +194 -0
  257. package/tenants/giantvapes/content/home.json +50 -0
  258. package/tenants/giantvapes/content/pages/about.json +10 -0
  259. package/tenants/giantvapes/content/pages/privacy.json +6 -0
  260. package/tenants/giantvapes/content/pages/shipping-returns.json +6 -0
  261. package/tenants/giantvapes/content/pages-html/blogs/news.html +68 -0
  262. package/tenants/giantvapes/content/pages-html/pages/about-us.html +95 -0
  263. package/tenants/giantvapes/content/pages-html/pages/contact-us.html +68 -0
  264. package/tenants/giantvapes/content/pages-html/pages/privacy-policy.html +65 -0
  265. package/tenants/giantvapes/content/pages-html/pages/shipping-returns.html +77 -0
  266. package/tenants/giantvapes/content/themes/giant-navy.json +73 -0
  267. package/tenants/giantvapes/public/img/hero-suicide-bunny.jpg +0 -0
  268. package/tenants/giantvapes/public/img/hero.webp +0 -0
  269. package/tenants/giantvapes/public/img/og.jpg +0 -0
  270. package/tenants/giantvapes/public/logo-wordmark.png +0 -0
  271. package/tenants/giantvapes/public/pages/home.css +120 -0
  272. package/tenants/giantvapes/public/pages/mkt.css +185 -0
  273. package/tenants/giantvapes/public/pages/page.css +155 -0
  274. package/tenants/giantvapes/public/themes/giant-navy.css +76 -0
  275. package/tenants/giantvapes/theme.json +39 -0
  276. package/tenants/home/content/chrome.json +11 -0
  277. package/tenants/home/content/home.html +304 -0
  278. package/tenants/home/content/home.json +13 -0
  279. package/tenants/home/public/js/storefront.js +210 -0
  280. package/tenants/home/public/logo-wordmark.png +0 -0
  281. package/tenants/home/public/pages/storefront.css +212 -0
  282. package/tenants/home/theme.json +6 -0
  283. package/tenants/tokenoftrust/.tot/config.json +9 -0
  284. package/tenants/tokenoftrust/content/chrome.json +55 -0
  285. package/tenants/tokenoftrust/content/home.html +723 -0
  286. package/tenants/tokenoftrust/content/home.json +233 -0
  287. package/tenants/tokenoftrust/content/pages-html/careers.html +231 -0
  288. package/tenants/tokenoftrust/content/pages-html/company.html +275 -0
  289. package/tenants/tokenoftrust/content/pages-html/contact/contact-sales.html +188 -0
  290. package/tenants/tokenoftrust/content/pages-html/contact/startup-apply.html +206 -0
  291. package/tenants/tokenoftrust/content/pages-html/contact.html +178 -0
  292. package/tenants/tokenoftrust/content/pages-html/industries/adult-content-age-verification.html +286 -0
  293. package/tenants/tokenoftrust/content/pages-html/industries/cannabis.html +277 -0
  294. package/tenants/tokenoftrust/content/pages-html/pact-act-pricing.html +289 -0
  295. package/tenants/tokenoftrust/content/pages-html/pricing.html +483 -0
  296. package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-estimation.html +278 -0
  297. package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-gate.html +279 -0
  298. package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-verification.html +265 -0
  299. package/tenants/tokenoftrust/content/pages-html/product/age-assurance.html +173 -0
  300. package/tenants/tokenoftrust/content/pages-html/product/compliance/aml.html +214 -0
  301. package/tenants/tokenoftrust/content/pages-html/product/compliance/pact-act.html +226 -0
  302. package/tenants/tokenoftrust/content/pages-html/product/fraud-prevention.html +254 -0
  303. package/tenants/tokenoftrust/content/pages-html/product/social-profile-verification.html +212 -0
  304. package/tenants/tokenoftrust/content/pages-html/product/tax/excise-tax.html +213 -0
  305. package/tenants/tokenoftrust/content/pages-html/product/verification/aml.html +259 -0
  306. package/tenants/tokenoftrust/content/pages-html/product/verification/biometric-selfie.html +305 -0
  307. package/tenants/tokenoftrust/content/pages-html/product/verification/coverage.html +254 -0
  308. package/tenants/tokenoftrust/content/pages-html/product/verification/document-verification.html +306 -0
  309. package/tenants/tokenoftrust/content/pages-html/product/verification/electronic-identity-verification.html +304 -0
  310. package/tenants/tokenoftrust/content/pages-html/product/verification/government-id-verification.html +308 -0
  311. package/tenants/tokenoftrust/content/pages-html/product/verification.html +183 -0
  312. package/tenants/tokenoftrust/content/pages-html/product.html +228 -0
  313. package/tenants/tokenoftrust/content/pages-html/resources/integrations/bigcommerce-integration.html +220 -0
  314. package/tenants/tokenoftrust/content/pages-html/resources/integrations/shopify-integration.html +221 -0
  315. package/tenants/tokenoftrust/content/pages-html/resources/integrations/wordpress.html +220 -0
  316. package/tenants/tokenoftrust/content/pages-html/resources/integrations.html +172 -0
  317. package/tenants/tokenoftrust/content/pages-html/resources/refer-a-friend-program.html +317 -0
  318. package/tenants/tokenoftrust/content/pages-html/resources.html +177 -0
  319. package/tenants/tokenoftrust/content/pages-html/reviews.html +273 -0
  320. package/tenants/tokenoftrust/content/pages-html/solutions.html +292 -0
  321. package/tenants/tokenoftrust/content/pages-html/vlp-alcohol.html +289 -0
  322. package/tenants/tokenoftrust/content/pages-html/vlp-cigars-and-tobacco.html +286 -0
  323. package/tenants/tokenoftrust/content/pages-html/vlp-firearm-accessories.html +267 -0
  324. package/tenants/tokenoftrust/content/pages-html/vlp-peptides.html +273 -0
  325. package/tenants/tokenoftrust/content/themes/tot-navy.json +88 -0
  326. package/tenants/tokenoftrust/public/favicon.png +0 -0
  327. package/tenants/tokenoftrust/public/logo-icon.png +0 -0
  328. package/tenants/tokenoftrust/public/logo-wordmark.png +0 -0
  329. package/tenants/tokenoftrust/public/pages/company.css +108 -0
  330. package/tenants/tokenoftrust/public/pages/home.css +457 -0
  331. package/tenants/tokenoftrust/public/pages/mkt.css +482 -0
  332. package/tenants/tokenoftrust/public/pages/pricing.css +214 -0
  333. package/tenants/tokenoftrust/public/pages/solutions.css +66 -0
  334. package/tenants/tokenoftrust/public/themes/tot-navy-1.0.0.css +136 -0
  335. package/tenants/tokenoftrust/public/themes/tot-navy.css +358 -0
  336. package/tenants/tokenoftrust/theme.json +31 -0
  337. package/tsconfig.base.json +20 -0
@@ -0,0 +1,290 @@
1
+ ---
2
+ /**
3
+ * Homepage — composed from Storyblok blocks (local fallback in Phase 1).
4
+ * Editorial composition comes from the ContentProvider; product/collection data
5
+ * is resolved from the ToTClient. All async data resolution happens HERE in the
6
+ * frontmatter (Astro templates can't host multi-statement async arrows), then
7
+ * the template renders simple typed view-models.
8
+ */
9
+ import Layout from "@/layouts/Layout.astro";
10
+ import Section from "@/components/Section.astro";
11
+ import Hero from "@/components/home/Hero.astro";
12
+ import ProductCard from "@/components/ProductCard.astro";
13
+ import CollectionCard from "@/components/CollectionCard.astro";
14
+ import Img from "@/components/Img.astro";
15
+ import MarketingBlocks from "@/components/marketing/MarketingBlocks.astro";
16
+ import { withBase } from "@/lib/basePath";
17
+ import { rawHtmlResponse } from "@/lib/rawMarketingHtml";
18
+ import type { CatalogCollection, CatalogProduct } from "@tot/public-runtime";
19
+ import {
20
+ isMarketingBlock,
21
+ type HeroBlock,
22
+ type EditorialBlock,
23
+ type NewsletterBlock,
24
+ type PromoTilesBlock,
25
+ type MarketingBlock,
26
+ } from "@/lib/storyblok/content-model";
27
+
28
+ const { tenant, tot, content, basePath, features } = Astro.locals;
29
+ const marketing = !features.catalog;
30
+
31
+ // Raw-HTML home (vendor-injected): serve the tenant's own self-contained
32
+ // document VERBATIM, bypassing the block Layout entirely. Its inline
33
+ // <style>/<script> get this request's CSP nonce so the strict policy still
34
+ // allows them. This route stays fully inside Astro — middleware already applied
35
+ // tenant resolution + canonical host, and on the way out applies security
36
+ // headers, the CSP, and (in prod) the edge page cache. SEO title/meta/canonical/
37
+ // OpenGraph/JSON-LD come from the document's own <head>. The homepage `/` is in
38
+ // the marketing sitemap (sitemap.xml.ts).
39
+ //
40
+ // Served regardless of siteType: a tenant that ships home.html gets its raw
41
+ // marketing home whether or not commerce is on. This is the HYBRID tenant —
42
+ // pixel-perfect marketing chrome at `/` surrounding a live commerce core at
43
+ // /collections + /products/* (see playbook/site-migration/commerce-handoff.md §1
44
+ // and product-boundaries.md). Commerce tenants with no home.html fall through to
45
+ // the block-composed home below, unchanged. Mirrors the raw-subpage path in
46
+ // [...slug].astro (getPageHtml is already siteType-agnostic).
47
+ {
48
+ const rawHtml = await content.getHomeHtml();
49
+ if (rawHtml) {
50
+ // Shared chrome: if the tenant ships a chrome.html wrapper AND this home is a
51
+ // body-only fragment, rawHtmlResponse splices it in; a full document serves
52
+ // verbatim (backward-compatible).
53
+ const chromeWrapper = await content.getChromeHtml();
54
+ return rawHtmlResponse(rawHtml, { nonce: Astro.locals.cspNonce, basePath, chromeWrapper });
55
+ }
56
+ }
57
+
58
+ const home = await content.getHome();
59
+
60
+ // Marketing tenants (no catalog) compose the homepage from marketing blocks and
61
+ // skip ALL product/collection resolution below.
62
+ const marketingBlocks: MarketingBlock[] = marketing
63
+ ? home.blocks.filter(isMarketingBlock)
64
+ : [];
65
+
66
+ const collections = marketing ? [] : await tot.listCollections();
67
+
68
+ // --- Resolve each block into a typed, render-ready view-model -----------------
69
+ type Resolved =
70
+ | { kind: "hero"; block: HeroBlock; product: CatalogProduct | null }
71
+ | { kind: "promo_tiles"; title?: string; tiles: PromoTilesBlock["tiles"] }
72
+ | { kind: "collections"; title?: string; cols: CatalogCollection[] }
73
+ | { kind: "products"; title?: string; products: CatalogProduct[] }
74
+ | { kind: "editorial"; block: EditorialBlock }
75
+ | { kind: "newsletter"; block: NewsletterBlock };
76
+
77
+ async function resolveProducts(
78
+ source: "featured" | "newest",
79
+ handles: string[] | undefined,
80
+ limit: number,
81
+ ): Promise<CatalogProduct[]> {
82
+ if (handles?.length) {
83
+ const all = await Promise.all(handles.map((h) => tot.getProductByHandle(h)));
84
+ return all
85
+ .filter((p): p is CatalogProduct => !!p && p.status === "active")
86
+ .slice(0, limit);
87
+ }
88
+ if (source === "newest") {
89
+ const { products } = await tot.listProducts({ sort: "newest", pageSize: limit });
90
+ return products;
91
+ }
92
+ return tot.getFeatured(limit);
93
+ }
94
+
95
+ const resolved: Resolved[] = [];
96
+ for (const block of marketing ? [] : home.blocks) {
97
+ switch (block.component) {
98
+ case "hero": {
99
+ let product: CatalogProduct | null = null;
100
+ if (block.featureCollection) {
101
+ const col = collections.find((c) => c.handle === block.featureCollection);
102
+ const firstHandle = col?.product_handles[0];
103
+ if (firstHandle) product = await tot.getProductByHandle(firstHandle);
104
+ }
105
+ resolved.push({ kind: "hero", block, product });
106
+ break;
107
+ }
108
+ case "promo_tiles": {
109
+ if (block.tiles?.length) {
110
+ resolved.push({ kind: "promo_tiles", title: block.title, tiles: block.tiles });
111
+ }
112
+ break;
113
+ }
114
+ case "featured_collections": {
115
+ const handles = block.handles?.length
116
+ ? block.handles
117
+ : collections.map((c) => c.handle);
118
+ const cols = handles
119
+ .map((h) => collections.find((c) => c.handle === h))
120
+ .filter((c): c is CatalogCollection => !!c);
121
+ resolved.push({ kind: "collections", title: block.title, cols });
122
+ break;
123
+ }
124
+ case "featured_products": {
125
+ const products = await resolveProducts(
126
+ block.source,
127
+ block.handles,
128
+ block.limit ?? 4,
129
+ );
130
+ resolved.push({ kind: "products", title: block.title, products });
131
+ break;
132
+ }
133
+ case "editorial":
134
+ resolved.push({ kind: "editorial", block });
135
+ break;
136
+ case "newsletter":
137
+ resolved.push({ kind: "newsletter", block });
138
+ break;
139
+ }
140
+ }
141
+ ---
142
+
143
+ <Layout
144
+ title={home.seoTitle ?? tenant.displayName}
145
+ description={home.seoDescription}
146
+ path="/"
147
+ ogType="website"
148
+ fullBleed={marketing}
149
+ >
150
+ {marketing && <MarketingBlocks blocks={marketingBlocks} basePath={basePath} />}
151
+ {
152
+ !marketing && resolved.map((r) => {
153
+ if (r.kind === "hero") {
154
+ return <Hero block={r.block} featureProduct={r.product} />;
155
+ }
156
+ if (r.kind === "promo_tiles") {
157
+ return (
158
+ <Section title={r.title} eyebrow="Featured" tone="bg">
159
+ <div
160
+ class:list={[
161
+ "grid gap-5",
162
+ r.tiles.length >= 3 ? "sm:grid-cols-3" : "sm:grid-cols-2",
163
+ ]}
164
+ >
165
+ {r.tiles.map((t) => (
166
+ <a
167
+ href={withBase(basePath, t.href)}
168
+ class="group relative block aspect-[16/9] overflow-hidden rounded-[var(--radius-lg)] shadow-[var(--shadow-sm)]"
169
+ >
170
+ {t.image && (
171
+ <img
172
+ src={t.image}
173
+ alt={t.label}
174
+ loading="lazy"
175
+ class="absolute inset-0 h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
176
+ />
177
+ )}
178
+ <span class="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 to-transparent p-4 font-display text-lg font-semibold text-white">
179
+ {t.label}
180
+ </span>
181
+ </a>
182
+ ))}
183
+ </div>
184
+ </Section>
185
+ );
186
+ }
187
+ if (r.kind === "collections") {
188
+ return (
189
+ <Section title={r.title} eyebrow="Collections" tone="bg">
190
+ <div class="grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
191
+ {r.cols.map((c) => (
192
+ <CollectionCard collection={c} productCount={c.product_handles.length} />
193
+ ))}
194
+ </div>
195
+ </Section>
196
+ );
197
+ }
198
+ if (r.kind === "products") {
199
+ return (
200
+ <Section title={r.title} eyebrow="Shop" tone="surface">
201
+ <div class="grid grid-cols-2 gap-5 lg:grid-cols-4">
202
+ {r.products.map((p, i) => (
203
+ <ProductCard product={p} position={i} list={r.title} />
204
+ ))}
205
+ </div>
206
+ </Section>
207
+ );
208
+ }
209
+ if (r.kind === "editorial") {
210
+ const b = r.block;
211
+ const right = b.align !== "left";
212
+ return (
213
+ <Section tone="bg">
214
+ <div
215
+ class:list={[
216
+ "grid items-center gap-10 md:grid-cols-2",
217
+ right ? "" : "md:[&>*:first-child]:order-2",
218
+ ]}
219
+ >
220
+ <div data-reveal>
221
+ {b.eyebrow && <p class="eyebrow eyebrow--tick mb-4">{b.eyebrow}</p>}
222
+ <h2 class="display-md">
223
+ {b.title}
224
+ </h2>
225
+ <div class="rte mt-5 text-[var(--color-muted)]" set:html={b.body_html} />
226
+ {b.ctaLabel && b.ctaHref && (
227
+ <a
228
+ href={withBase(basePath, b.ctaHref)}
229
+ class="link-accent mt-7 inline-block pb-0.5 font-display text-sm font-medium"
230
+ >
231
+ {b.ctaLabel} →
232
+ </a>
233
+ )}
234
+ </div>
235
+ <div data-reveal>
236
+ <div class="overflow-hidden rounded-[var(--radius-lg)] shadow-[var(--shadow-md)]">
237
+ <Img
238
+ seed={b.imageSeed ?? b.title}
239
+ label={b.title}
240
+ alt=""
241
+ width={1000}
242
+ height={750}
243
+ sizes="(min-width:768px) 48vw, 100vw"
244
+ class="h-full w-full object-cover"
245
+ />
246
+ </div>
247
+ </div>
248
+ </div>
249
+ </Section>
250
+ );
251
+ }
252
+ if (r.kind === "newsletter") {
253
+ const b = r.block;
254
+ return (
255
+ <Section tone="surface" id="newsletter">
256
+ <div class="mx-auto max-w-xl text-center" data-reveal>
257
+ <h2 class="display-md">
258
+ {b.title}
259
+ </h2>
260
+ {b.body && <p class="mt-3 text-[var(--color-muted)]">{b.body}</p>}
261
+ <form
262
+ action={withBase(basePath, "/api/newsletter")}
263
+ method="post"
264
+ class="mx-auto mt-7 flex max-w-md flex-col gap-3 sm:flex-row"
265
+ >
266
+ <input type="hidden" name="source" value="home" />
267
+ <label class="sr-only" for="home-news-email">Email address</label>
268
+ <input
269
+ id="home-news-email"
270
+ type="email"
271
+ name="email"
272
+ required
273
+ placeholder={b.placeholder ?? "you@example.com"}
274
+ class="flex-1 rounded-full border border-[var(--color-border)] bg-[var(--color-bg)] px-5 py-3 text-[var(--color-text)] placeholder:text-[var(--color-muted)]"
275
+ />
276
+ <button
277
+ type="submit"
278
+ class="rounded-full bg-[var(--color-primary)] px-6 py-3 font-display text-sm font-medium text-[var(--color-primary-contrast)] transition-transform hover:-translate-y-0.5"
279
+ >
280
+ {b.ctaLabel ?? "Subscribe"}
281
+ </button>
282
+ </form>
283
+ </div>
284
+ </Section>
285
+ );
286
+ }
287
+ return null;
288
+ })
289
+ }
290
+ </Layout>
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Per-tenant llms.txt — the emerging /llms.txt convention: a concise,
3
+ * machine-readable guide that helps LLM answer engines (ChatGPT, Perplexity,
4
+ * Google AI Overviews, etc.) understand what this store is and where its key
5
+ * content lives. Mirrors robots.txt / sitemap.xml: built per request from the
6
+ * resolved tenant's catalog + content, canonical base from the Host.
7
+ *
8
+ * Every line traces to REAL migrated data or tenant config — no fabricated copy
9
+ * (playbook/codebase-health.md T7). Summary/descriptions are the merchant's own
10
+ * SEO text; compliance facts come from tenant.compliance.
11
+ */
12
+ import type { APIContext } from "astro";
13
+ import { createContentProvider } from "@/lib/storyblok/provider";
14
+
15
+ /** Collapse HTML/whitespace to a single trimmed line for a link description. */
16
+ function oneLine(s: string | undefined, max = 140): string | undefined {
17
+ if (!s) return undefined;
18
+ const t = s.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
19
+ if (!t) return undefined;
20
+ return t.length > max ? `${t.slice(0, max - 1)}…` : t;
21
+ }
22
+
23
+ export async function GET(context: APIContext): Promise<Response> {
24
+ const { tot, tenant, canonicalBase } = context.locals;
25
+ const base = canonicalBase.replace(/\/$/, "");
26
+ const provider = createContentProvider(tenant);
27
+
28
+ const [collections, pages, featured, home] = await Promise.all([
29
+ tot.listCollections(),
30
+ provider.listPages(),
31
+ tot.getFeatured(12),
32
+ provider.getHome().catch(() => null),
33
+ ]);
34
+
35
+ const lines: string[] = [`# ${tenant.displayName}`, ""];
36
+
37
+ const summary = oneLine(home?.seoDescription, 280);
38
+ if (summary) lines.push(`> ${summary}`, "");
39
+
40
+ // Compliance facts — sourced from tenant config, never invented.
41
+ const c = tenant.compliance;
42
+ if (c && (c.minAge || c.nicotineWarning || c.shippingRestriction)) {
43
+ const facts: string[] = [];
44
+ if (c.minAge) facts.push(`age-restricted — customers must be ${c.minAge}+`);
45
+ if (c.nicotineWarning) facts.push("products contain nicotine (FDA warning applies)");
46
+ if (facts.length) lines.push(`**Compliance:** ${facts.join("; ")}.`);
47
+ const ship = oneLine(c.shippingRestriction, 240);
48
+ if (ship) lines.push(`**Shipping:** ${ship}`);
49
+ lines.push("");
50
+ }
51
+
52
+ if (collections.length) {
53
+ lines.push("## Collections");
54
+ for (const col of collections) {
55
+ const desc = oneLine(col.description_text ?? col.seo.description);
56
+ lines.push(`- [${col.title}](${base}/collections/${col.handle})${desc ? `: ${desc}` : ""}`);
57
+ }
58
+ lines.push("");
59
+ }
60
+
61
+ if (featured.length) {
62
+ lines.push("## Featured products");
63
+ for (const p of featured) {
64
+ const desc = oneLine(p.seo.description ?? p.description_text);
65
+ lines.push(`- [${p.title}](${base}/products/${p.handle})${desc ? `: ${desc}` : ""}`);
66
+ }
67
+ lines.push("");
68
+ }
69
+
70
+ if (pages.length) {
71
+ lines.push("## Pages");
72
+ for (const pg of pages) {
73
+ lines.push(`- [${pg.title}](${base}/${pg.slug})`);
74
+ }
75
+ lines.push("");
76
+ }
77
+
78
+ lines.push("## Optional");
79
+ lines.push(`- [Full product catalog (XML sitemap)](${base}/sitemap.xml)`);
80
+ lines.push(`- [Search](${base}/search)`);
81
+ lines.push(
82
+ "- Every page ships Schema.org JSON-LD (Product, Offer, AggregateRating, Breadcrumb, Organization) for structured extraction.",
83
+ );
84
+ lines.push("");
85
+
86
+ return new Response(lines.join("\n"), {
87
+ headers: {
88
+ "content-type": "text/plain; charset=utf-8",
89
+ "cache-control": "public, max-age=300, s-maxage=3600",
90
+ },
91
+ });
92
+ }