@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,439 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `tot dev` — the developer's on-save local preview loop (the magic).
4
+ *
5
+ * Boots the storefront's `astro dev` (which already gives Vite HMR / live-reload
6
+ * on save) and points the browser at the developer's tenant via the DNS-free
7
+ * path-prefix route (`/<appDomain>/`). Edit a file under `content/<tenant>/`
8
+ * (home.html, pages, chrome) or the tenant theme → save → the browser reloads.
9
+ * Private, on-save, NO publish: product data renders from local fixtures; nothing
10
+ * is written to KV or shared. ("Publish" — to test/live — stays a separate,
11
+ * deliberate, compliance-gated step.)
12
+ *
13
+ * TWO MODES
14
+ * 1. MONOREPO (default): `node scripts/tot-dev.mjs <tenant>` — runs astro dev
15
+ * over the in-tree colocated `tenants/<tenant>/` layout (content/, public/,
16
+ * theme.json).
17
+ * 2. STANDALONE: `node scripts/tot-dev.mjs --workspace <checkout-path>` — the
18
+ * developer has cloned their tenant's Gitea repo (a FLAT, tenant-centric
19
+ * layout: `content/`, `public/`, `theme.json`, `.tot/config.json`). This mode
20
+ * reads the checkout's `.tot/config.json` `mappings` and grafts each workspace
21
+ * prefix into the storefront paths the app globs, then boots the same astro dev.
22
+ * Edits in the CHECKOUT hot-reload via Vite. On exit the graft (and any
23
+ * backed-up in-tree tenant content) is restored — the tree is left clean.
24
+ * Phase-0 bridge: the platform still comes from THIS storefront checkout; the
25
+ * containerized "platform baked in, tenant clone mounted" version is deferred.
26
+ *
27
+ * WHY COPY+WATCH, NOT SYMLINK: a symlink from the in-tree path to the checkout
28
+ * resolves (in Vite) to the checkout's REAL path, which is OUTSIDE the app root,
29
+ * so Vite's `server.fs.allow` denies the `?raw`/glob import ("Denied ID …"). So
30
+ * we COPY the checkout's files into the in-tree paths (inside the app root, which
31
+ * Vite trusts) and run a recursive `fs.watch` on the checkout that re-syncs each
32
+ * changed file back into the in-tree copy on save — which is what fires Vite HMR.
33
+ *
34
+ * Two things learned the hard way (see the two-liners below):
35
+ * - Tenant is selected by the URL path-prefix (`/<appDomain>/`), NOT by
36
+ * DEFAULT_TENANT_ID — the @astrojs/cloudflare dev runtime (workerd) reads env
37
+ * from .dev.vars/bindings, so a spawned process.env var never reaches it, and
38
+ * a bare `/` falls back to the first static tenant (pilot).
39
+ * - `--host` is passed so the server binds all interfaces (0.0.0.0 + ::).
40
+ * Without it astro/vite may bind IPv6 `::1` only, and browsers that resolve
41
+ * `localhost` to IPv4 `127.0.0.1` get "unable to connect".
42
+ *
43
+ * Usage:
44
+ * node scripts/tot-dev.mjs <tenant> [--port 4321]
45
+ * node scripts/tot-dev.mjs bigdvapor
46
+ * node scripts/tot-dev.mjs --workspace ~/tot/site [--port 4321] (standalone)
47
+ * (from a workspace dir with .tot/config.json) node <repo>/scripts/tot-dev.mjs
48
+ *
49
+ * Ctrl-C stops the server. Exit 1 = can't resolve tenant/domain/workspace; 2 = bad usage.
50
+ */
51
+ import { spawn, spawnSync } from "node:child_process";
52
+ import {
53
+ readFileSync,
54
+ existsSync,
55
+ lstatSync,
56
+ mkdirSync,
57
+ renameSync,
58
+ rmSync,
59
+ cpSync,
60
+ watch,
61
+ readdirSync,
62
+ statSync,
63
+ } from "node:fs";
64
+ import { dirname, resolve, join } from "node:path";
65
+ import { fileURLToPath } from "node:url";
66
+
67
+ const here = dirname(fileURLToPath(import.meta.url));
68
+ const repoRoot = resolve(here, ".."); // scripts/ -> repo root
69
+
70
+ const argv = process.argv.slice(2);
71
+ const flag = (name, def) => {
72
+ const i = argv.indexOf(`--${name}`);
73
+ return i !== -1 && argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[i + 1] : def;
74
+ };
75
+
76
+ // --- workspace (standalone) mode? --------------------------------------------
77
+ // `--workspace <path>` points at a developer's cloned tenant repo (flat layout +
78
+ // .tot/config.json). Absent → classic monorepo mode.
79
+ const workspacePath = flag("workspace", null);
80
+
81
+ // --- resolve the tenant + its appDomain --------------------------------------
82
+ // In monorepo mode the workspace config (if any) is read from CWD, as before.
83
+ // In standalone mode it comes from the checkout's .tot/config.json.
84
+ const cfgPath = workspacePath
85
+ ? join(resolve(workspacePath), ".tot", "config.json")
86
+ : join(process.cwd(), ".tot", "config.json");
87
+ let cfg = null;
88
+ if (existsSync(cfgPath)) {
89
+ try {
90
+ cfg = JSON.parse(readFileSync(cfgPath, "utf8"));
91
+ } catch {
92
+ /* ignore */
93
+ }
94
+ }
95
+
96
+ if (workspacePath && !cfg) {
97
+ console.error(
98
+ `✗ standalone mode: no readable .tot/config.json under ${resolve(workspacePath)}\n` +
99
+ ` Is this a materialized tenant checkout (content/, public/, theme.json, .tot/config.json)?`,
100
+ );
101
+ process.exit(1);
102
+ }
103
+
104
+ let tenant = argv[0] && !argv[0].startsWith("--") ? argv[0] : null;
105
+ tenant = tenant ?? cfg?.tenant ?? null;
106
+
107
+ if (!tenant) {
108
+ console.error(
109
+ "usage: node scripts/tot-dev.mjs <tenant> [--port 4321]\n" +
110
+ " node scripts/tot-dev.mjs --workspace <checkout-path> [--port 4321]\n" +
111
+ " (or run from a workspace dir containing .tot/config.json)",
112
+ );
113
+ process.exit(2);
114
+ }
115
+
116
+ /** The path-prefix segment that selects this tenant: its registered appDomain. */
117
+ function resolveDomain(id) {
118
+ // A workspace marker's `scope` carries the appDomain — but only trust it when
119
+ // it looks like a hostname (has a dot), since the path-prefix route only
120
+ // matches a domain that strictly claims the tenant (see tenantRouting.ts).
121
+ if (cfg?.scope && cfg.scope.includes(".")) return cfg.scope;
122
+ try {
123
+ const src = readFileSync(
124
+ resolve(repoRoot, "apps/storefront/src/config/tenants.ts"),
125
+ "utf8",
126
+ );
127
+ // Each tenant block declares tenant_id then appDomain; pair them up.
128
+ const re = /tenant_id:\s*"([^"]+)"[\s\S]*?appDomain:\s*"([^"]+)"/g;
129
+ for (let m; (m = re.exec(src)); ) if (m[1] === id) return m[2];
130
+ } catch {
131
+ /* ignore */
132
+ }
133
+ return null;
134
+ }
135
+
136
+ const domain = resolveDomain(tenant);
137
+ if (!domain) {
138
+ console.error(
139
+ `✗ couldn't resolve a domain for "${tenant}" — is it registered in ` +
140
+ `apps/storefront/src/config/tenants.ts (or set as a hostname in .tot/config.json scope)?`,
141
+ );
142
+ process.exit(1);
143
+ }
144
+
145
+ // --- standalone: graft the checkout into the storefront's globbed paths -------
146
+ // COPY the checkout's files into the in-tree paths (so Vite's fs.allow trusts them)
147
+ // + fs.watch the checkout to re-sync each save into the in-tree copy (fires HMR).
148
+ // Records let us undo everything on exit (leave the tree exactly as found).
149
+ /** @type {{ target: string, backup: string|null }[]} */
150
+ const grafts = [];
151
+ /** @type {import("node:fs").FSWatcher[]} */
152
+ const watchers = [];
153
+ let cleanedUp = false;
154
+
155
+ function isSymlink(p) {
156
+ try {
157
+ return lstatSync(p).isSymbolicLink();
158
+ } catch {
159
+ return false;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Move `from` → `to`, with a cross-device fallback. In the container the baked-in
165
+ * `tenants/<id>/` lives in a read-only overlay layer, and overlayfs can't rename a
166
+ * directory across the layer boundary — `renameSync` throws EXDEV. Fall back to a
167
+ * recursive copy + remove so the graft's move-aside/restore still works there. On
168
+ * macOS (same-fs) the fast rename is taken.
169
+ */
170
+ function movePath(from, to) {
171
+ try {
172
+ renameSync(from, to);
173
+ } catch (e) {
174
+ if (e?.code !== "EXDEV") throw e;
175
+ cpSync(from, to, { recursive: true });
176
+ rmSync(from, { recursive: true, force: true });
177
+ }
178
+ }
179
+
180
+ function cleanupGrafts() {
181
+ if (cleanedUp) return;
182
+ cleanedUp = true;
183
+ for (const w of watchers) {
184
+ try {
185
+ w.close();
186
+ } catch {
187
+ /* best effort */
188
+ }
189
+ }
190
+ // Undo in reverse: remove our copied-in files, then restore any backed-up content.
191
+ for (const { target, backup } of grafts.reverse()) {
192
+ try {
193
+ if (existsSync(target) || isSymlink(target)) rmSync(target, { recursive: true, force: true });
194
+ } catch {
195
+ /* best effort */
196
+ }
197
+ if (backup) {
198
+ try {
199
+ movePath(backup, target);
200
+ } catch {
201
+ /* best effort */
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ /** Re-sync one changed checkout path into its in-tree copy (copy on save, remove on delete). */
208
+ function resync(sourceRoot, targetRoot, rel) {
209
+ const from = rel ? join(sourceRoot, rel) : sourceRoot;
210
+ const to = rel ? join(targetRoot, rel) : targetRoot;
211
+ try {
212
+ if (existsSync(from)) {
213
+ mkdirSync(dirname(to), { recursive: true });
214
+ cpSync(from, to, { recursive: true });
215
+ } else if (existsSync(to)) {
216
+ rmSync(to, { recursive: true, force: true });
217
+ }
218
+ } catch (e) {
219
+ console.warn(` ⚠ re-sync failed for ${rel || "(root)"}: ${e?.message}`);
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Watch a checkout path (dir or single file) and invoke `onChange(rel)` on every
225
+ * add/change/delete, where `rel` is the source-relative path ("" for a file source).
226
+ *
227
+ * Prefers native `fs.watch` (instant, event-driven — great on macOS). Falls back to
228
+ * an mtime POLL loop when either (a) `CHOKIDAR_USEPOLLING` is set — the containerized
229
+ * `tot dev` sets it because a bind-mount often doesn't deliver inotify events across
230
+ * the VM/overlay boundary — or (b) native recursive watch throws, which it always
231
+ * does on Linux (`fs.watch(dir, {recursive:true})` is unsupported there). Dependency-
232
+ * free on purpose (matches the rest of the tenant tooling); returns a `{ close() }`.
233
+ */
234
+ function startWatch(source, isDir, onChange) {
235
+ const poll = /^(1|true|yes|on)$/i.test(process.env.CHOKIDAR_USEPOLLING || "");
236
+ if (!poll) {
237
+ try {
238
+ return watch(source, { recursive: isDir }, (_event, filename) =>
239
+ onChange(isDir ? (filename ? String(filename) : "") : ""),
240
+ );
241
+ } catch (e) {
242
+ // Linux: recursive fs.watch is ERR_FEATURE_UNAVAILABLE_ON_PLATFORM → poll.
243
+ console.warn(
244
+ ` ⚠ native watch unavailable (${e?.code || e?.message}); falling back to polling.`,
245
+ );
246
+ }
247
+ }
248
+ const interval = Number(process.env.CHOKIDAR_INTERVAL) || 300;
249
+ const seenMtimes = new Map(); // relPath -> mtimeMs
250
+ let primed = false;
251
+ const scan = () => {
252
+ const present = new Set();
253
+ const visit = (absDir, relDir) => {
254
+ let entries;
255
+ try {
256
+ entries = readdirSync(absDir, { withFileTypes: true });
257
+ } catch {
258
+ return; // dir vanished mid-scan — a later scan reconciles it
259
+ }
260
+ for (const e of entries) {
261
+ const rel = relDir ? join(relDir, e.name) : e.name;
262
+ const abs = join(absDir, e.name);
263
+ if (e.isDirectory()) {
264
+ visit(abs, rel);
265
+ continue;
266
+ }
267
+ present.add(rel);
268
+ let m;
269
+ try {
270
+ m = statSync(abs).mtimeMs;
271
+ } catch {
272
+ continue;
273
+ }
274
+ const prev = seenMtimes.get(rel);
275
+ if (prev === undefined || prev !== m) {
276
+ seenMtimes.set(rel, m);
277
+ if (primed) onChange(rel);
278
+ }
279
+ }
280
+ };
281
+ if (isDir) {
282
+ visit(source, "");
283
+ } else {
284
+ present.add("");
285
+ let m;
286
+ try {
287
+ m = statSync(source).mtimeMs;
288
+ } catch {
289
+ m = undefined;
290
+ }
291
+ const prev = seenMtimes.get("");
292
+ if (m !== undefined && prev !== m) {
293
+ seenMtimes.set("", m);
294
+ if (primed) onChange("");
295
+ }
296
+ }
297
+ for (const rel of [...seenMtimes.keys()]) {
298
+ if (!present.has(rel)) {
299
+ seenMtimes.delete(rel);
300
+ if (primed) onChange(rel);
301
+ }
302
+ }
303
+ primed = true;
304
+ };
305
+ scan(); // prime the snapshot without emitting spurious initial events
306
+ const id = setInterval(scan, interval);
307
+ if (typeof id.unref === "function") id.unref();
308
+ return { close: () => clearInterval(id) };
309
+ }
310
+
311
+ if (workspacePath) {
312
+ const wsRoot = resolve(workspacePath);
313
+ const mappings = Array.isArray(cfg.mappings) ? cfg.mappings : [];
314
+ if (mappings.length === 0) {
315
+ console.error(`✗ .tot/config.json has no "mappings" — cannot graft the checkout.`);
316
+ process.exit(1);
317
+ }
318
+
319
+ console.log(`\n tot dev — standalone (${tenant})`);
320
+ console.log(` checkout: ${wsRoot}`);
321
+
322
+ for (const map of mappings) {
323
+ // `workspace` is the checkout-relative prefix (e.g. "content/", "theme.json").
324
+ // COLOCATION: a tenant IS the repo-root dir `tenants/<id>/`, and the checkout
325
+ // (a `git subtree split --prefix=tenants/<id>` of that dir) has the SAME layout
326
+ // at its root — so the graft is an identity map: content/ -> tenants/<id>/content/,
327
+ // public/ -> tenants/<id>/public/, theme.json -> tenants/<id>/theme.json. We map
328
+ // structurally (ignoring any legacy `repo` field in the checkout's .tot/config.json).
329
+ const wsRel = String(map.workspace ?? "").replace(/\/+$/, "");
330
+ if (!wsRel) continue;
331
+ const repoRel = join("tenants", tenant, wsRel);
332
+
333
+ const source = resolve(wsRoot, wsRel); // real files in the checkout
334
+ const target = resolve(repoRoot, repoRel); // where the app globs them
335
+ const isDir = map.kind !== "file";
336
+
337
+ if (!existsSync(source)) {
338
+ console.warn(` ⚠ checkout has no ${wsRel} — skipping (${map.kind ?? "?"})`);
339
+ continue;
340
+ }
341
+
342
+ // Ensure the destination's parent exists (e.g. content/ or themes/tenants/).
343
+ mkdirSync(dirname(target), { recursive: true });
344
+
345
+ // If real in-tree content already occupies the destination, move it aside so
346
+ // we can restore it verbatim on exit (never destroy tracked tenant content).
347
+ let backup = null;
348
+ if (existsSync(target) || isSymlink(target)) {
349
+ backup = `${target}.__totdev_bak_${process.pid}`;
350
+ movePath(target, backup);
351
+ }
352
+
353
+ // COPY the checkout's files into the in-tree path (inside Vite's trusted root).
354
+ cpSync(source, target, { recursive: true });
355
+ grafts.push({ target, backup });
356
+
357
+ // WATCH the checkout for saves → re-sync into the in-tree copy → Vite HMR.
358
+ // `startWatch` is native-fs.watch on macOS and a polling loop in the container
359
+ // (Linux recursive watch is unsupported; a bind-mount may swallow inotify).
360
+ try {
361
+ const w = startWatch(source, isDir, (rel) => resync(source, target, rel));
362
+ watchers.push(w);
363
+ } catch (e) {
364
+ console.warn(` ⚠ could not watch ${wsRel} (edits won't hot-reload): ${e?.message}`);
365
+ }
366
+
367
+ console.log(` ↪ ${repoRel} ⇐ ${wsRel}${backup ? " (in-tree content backed up)" : ""}`);
368
+ }
369
+
370
+ if (grafts.length === 0) {
371
+ console.error(`✗ nothing to graft — the checkout had none of the mapped prefixes.`);
372
+ cleanupGrafts();
373
+ process.exit(1);
374
+ }
375
+ } else if (!existsSync(resolve(repoRoot, "tenants", tenant, "content"))) {
376
+ console.warn(`⚠ no tenants/${tenant}/content/ found — the tenant may not be registered yet.`);
377
+ }
378
+
379
+ const port = String(flag("port", "4321"));
380
+ const url = `http://localhost:${port}/${domain}/`;
381
+
382
+ console.log(`\n tot dev — ${tenant}`);
383
+ console.log(` → ${url}`);
384
+ if (workspacePath) {
385
+ console.log(` Edit files in your CHECKOUT (content/*.html, theme.json, public/…) + save → the browser reloads.`);
386
+ } else {
387
+ console.log(` Edit tenants/${tenant}/content/*.html (or the theme) + save → the browser reloads.`);
388
+ }
389
+ console.log(` Private local preview — nothing is published. Server binds all interfaces (LAN-visible). Ctrl-C to stop.\n`);
390
+
391
+ // --- mirror colocated tenant public/ assets into the storefront public/ dir ----
392
+ // astro dev is exec'd directly below (bypassing the `predev` npm lifecycle), so
393
+ // run the copy here: tenants/<id>/public/** -> apps/storefront/public/tenants/<id>/.
394
+ // Must run AFTER any standalone graft (so a grafted checkout's public/ is mirrored).
395
+ {
396
+ const r = spawnSync(
397
+ "node",
398
+ [resolve(repoRoot, "scripts/build/copy-tenant-assets.mjs")],
399
+ { cwd: repoRoot, stdio: "inherit" },
400
+ );
401
+ if (r.status !== 0) {
402
+ console.warn(" ⚠ copy-tenant-assets failed — static tenant assets may 404.");
403
+ }
404
+ }
405
+
406
+ // --- boot astro dev (Vite HMR); --host so IPv4 `localhost`/127.0.0.1 both work -
407
+ // In standalone mode we MUST keep astro in the FOREGROUND, attached to this
408
+ // process: Astro 7 auto-detects an agent-run terminal and forks the dev server to
409
+ // a detached daemon (`astro dev stop/status`), which would make THIS process exit
410
+ // immediately — firing our cleanup and tearing down the graft symlinks while the
411
+ // daemon keeps serving the (restored) in-tree content. Setting ASTRO_DEV_BACKGROUND
412
+ // tells Astro "you are already the managed child → run foreground" (see astro's
413
+ // cli/dev/{index,background}.js), so our SIGINT/exit lifecycle and symlink cleanup
414
+ // stay correct. Monorepo mode is left untouched (current behavior).
415
+ // TOT_DEV_TENANT tells the inline-AI edit loop (WS5 G1 — astro.config.mjs's
416
+ // inlineAiEditPlugin, scripts/dev/ai-edit.mjs) which tenant's content/theme to
417
+ // read+write: one `tot dev <tenant>` run always serves exactly one tenant, so
418
+ // there's no per-request domain lookup to do.
419
+ const spawnEnv = workspacePath
420
+ ? { ...process.env, ASTRO_DEV_BACKGROUND: "1", TOT_DEV_TENANT: tenant }
421
+ : { ...process.env, TOT_DEV_TENANT: tenant };
422
+ const child = spawn(
423
+ "pnpm",
424
+ ["--filter", "@tot/storefront-runner", "exec", "astro", "dev", "--port", port, "--host"],
425
+ { cwd: repoRoot, stdio: "inherit", env: spawnEnv },
426
+ );
427
+
428
+ // Clean up grafts on every exit path so we never leave symlinks in the tree.
429
+ function shutdown(signal) {
430
+ child.kill(signal);
431
+ }
432
+ child.on("exit", (code) => {
433
+ cleanupGrafts();
434
+ process.exit(code ?? 0);
435
+ });
436
+ process.on("SIGINT", () => shutdown("SIGINT"));
437
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
438
+ // Belt-and-suspenders: if the parent dies without the child exit firing.
439
+ process.on("exit", cleanupGrafts);
@@ -0,0 +1,52 @@
1
+ {
2
+ "posts": [
3
+ {
4
+ "title": "2016 Election",
5
+ "href": "/blogs/news/tagged/2016-election"
6
+ },
7
+ {
8
+ "title": "Aquios",
9
+ "href": "/blogs/news/tagged/aquios"
10
+ },
11
+ {
12
+ "title": "Aquios Esco Bars",
13
+ "href": "/blogs/news/tagged/aquios-esco-bars"
14
+ },
15
+ {
16
+ "title": "Article",
17
+ "href": "/blogs/news/tagged/article"
18
+ },
19
+ {
20
+ "title": "Aspire",
21
+ "href": "/blogs/news/tagged/aspire"
22
+ },
23
+ {
24
+ "title": "Aspire Atlantis",
25
+ "href": "/blogs/news/tagged/aspire-atlantis"
26
+ },
27
+ {
28
+ "title": "Aspire Premium Kit",
29
+ "href": "/blogs/news/tagged/aspire-premium-kit"
30
+ },
31
+ {
32
+ "title": "Battery",
33
+ "href": "/blogs/news/tagged/battery"
34
+ },
35
+ {
36
+ "title": "Big D Vapor",
37
+ "href": "/blogs/news/tagged/big-d-vapor"
38
+ },
39
+ {
40
+ "title": "Big Pharma",
41
+ "href": "/blogs/news/tagged/big-pharma"
42
+ },
43
+ {
44
+ "title": "Big Tobacco",
45
+ "href": "/blogs/news/tagged/big-tobacco"
46
+ },
47
+ {
48
+ "title": "biometric",
49
+ "href": "/blogs/news/tagged/biometric"
50
+ }
51
+ ]
52
+ }
@@ -0,0 +1,149 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <link rel="icon" type="image/png" href="/tenants/bigdvapor/logo-wordmark.png">
7
+ <link rel="stylesheet" href="/tenants/bigdvapor/themes/bigd-navy.css">
8
+ <link rel="stylesheet" href="/tenants/bigdvapor/pages/mkt.css">
9
+ <!--PAGE_HEAD-->
10
+ </head>
11
+ <body>
12
+ <a class="skip-link" href="#main">Skip to main content</a>
13
+
14
+ <!-- Top FDA warning bar -->
15
+ <div class="topbar-warning"><p>WARNING: This product contains nicotine. Nicotine is an addictive chemical.</p></div>
16
+
17
+ <!-- Announcement: red scrolling marquee -->
18
+ <div class="announce-marquee" aria-label="Free US shipping on orders over $100">
19
+ <div class="announce-marquee__track" aria-hidden="true">
20
+ <span>Free US shipping on orders over $100!</span><span>Free US shipping on orders over $100!</span><span>Free US shipping on orders over $100!</span><span>Free US shipping on orders over $100!</span>
21
+ <span>Free US shipping on orders over $100!</span><span>Free US shipping on orders over $100!</span><span>Free US shipping on orders over $100!</span><span>Free US shipping on orders over $100!</span>
22
+ </div>
23
+ </div>
24
+
25
+ <!-- Utility nav -->
26
+ <div class="utility-nav">
27
+ <div class="container">
28
+ <ul>
29
+ <li><a href="/blogs/news">News</a></li>
30
+ <li><a href="/pages/about-us">About</a></li>
31
+ <li><a href="/pages/contact-us">Contact</a></li>
32
+ <li><a href="/blogs/news">Blog</a></li>
33
+ <li><a href="https://bigdcbd.com/" rel="noopener">Big D CBD</a></li>
34
+ </ul>
35
+ <div class="utility-nav__right">
36
+ <span class="sel">English</span>
37
+ <span class="sel">United States (USD $)</span>
38
+ <span class="social">
39
+ <a href="https://twitter.com/bigdvapor" aria-label="X" rel="noopener"><svg viewBox="0 0 24 24"><path d="M18.9 2H22l-7.1 8.1L23 22h-6.6l-5-6.6L5.7 22H2.6l7.6-8.7L1.5 2h6.8l4.5 6 5.1-6zm-1.2 18h1.8L7.4 3.9H5.5L17.7 20z"/></svg></a>
40
+ <a href="https://pinterest.com/bigdvapor" aria-label="Pinterest" rel="noopener"><svg viewBox="0 0 24 24"><path d="M12 2a10 10 0 0 0-3.6 19.3c-.1-.8-.2-2 0-2.9l1.2-5s-.3-.6-.3-1.5c0-1.4.8-2.5 1.9-2.5.9 0 1.3.7 1.3 1.5 0 .9-.6 2.2-.9 3.5-.2 1 .5 1.9 1.6 1.9 1.9 0 3.2-2.4 3.2-5.3 0-2.2-1.5-3.8-4.1-3.8-3 0-4.9 2.2-4.9 4.7 0 .9.3 1.5.7 2 .2.2.2.3.1.5l-.2.9c-.1.3-.3.4-.6.2-1.1-.5-1.7-1.9-1.7-3.1 0-2.5 2.1-5.5 6.3-5.5 3.4 0 5.6 2.4 5.6 5 0 3.5-1.9 6.1-4.8 6.1-1 0-1.9-.5-2.2-1.1l-.6 2.3c-.2.8-.7 1.7-1.1 2.3A10 10 0 1 0 12 2z"/></svg></a>
41
+ </span>
42
+ </div>
43
+ </div>
44
+ </div>
45
+
46
+ <!-- Header -->
47
+ <header class="site-header">
48
+ <div class="container header-row">
49
+ <a class="brand" href="/" aria-label="Big D Vapor home"><img src="/tenants/bigdvapor/logo-wordmark.png" alt="Big D Vapor" width="1397" height="288"></a>
50
+ <form class="header-search" action="/search" method="get" role="search">
51
+ <label class="sr-only" for="hdr-q">Search for anything</label>
52
+ <input id="hdr-q" type="search" name="q" placeholder="Search for anything" autocomplete="off">
53
+ <button type="submit" aria-label="Search"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg></button>
54
+ </form>
55
+ <div class="header-actions">
56
+ <a href="/account" aria-label="Account"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4.4 3.6-7 8-7s8 2.6 8 7"/></svg></a>
57
+ <a class="cart" href="/cart" aria-label="Cart"><svg viewBox="0 0 24 24"><path d="M6 6h15l-1.5 9h-12z"/><circle cx="9" cy="20" r="1.4"/><circle cx="18" cy="20" r="1.4"/><path d="M6 6L5 3H2"/></svg><span class="count">0</span></a>
58
+ <button class="hamburger" id="hamburger" aria-label="Toggle navigation menu" aria-expanded="false" aria-controls="primaryNav"><span></span><span></span><span></span></button>
59
+ </div>
60
+ </div>
61
+ <nav class="primary-nav-bar" aria-label="Primary">
62
+ <div class="container">
63
+ <nav class="primary-nav" id="primaryNav">
64
+ <ul>
65
+ <li><a class="is-flag" href="/collections/texas-compliant-disposables">Texas Compliant Disposables<span class="new-badge">NEW</span></a></li>
66
+ <li><a href="/collections/disposables">Disposables<span class="caret">▾</span></a></li>
67
+ <li><a href="/collections/e-liquids">E-Liquid<span class="caret">▾</span></a></li>
68
+ <li><a href="/collections/devices">Devices<span class="caret">▾</span></a></li>
69
+ <li><a href="/collections/coils-parts">Coils &amp; Parts<span class="caret">▾</span></a></li>
70
+ <li><a href="/collections/nicotine-pouches">Nic Pouches</a></li>
71
+ <li><a href="/collections/new-products">New Products</a></li>
72
+ <li><a href="/collections/on-sale">On Sale</a></li>
73
+ <li><a href="/collections/disposables">Brands<span class="caret">▾</span></a></li>
74
+ </ul>
75
+ </nav>
76
+ </div>
77
+ </nav>
78
+ </header>
79
+
80
+ <!--PAGE_BODY-->
81
+
82
+ <!-- Compliance strip -->
83
+ <div class="compliance-strip">
84
+ <div class="container"><p>WARNING: This product contains nicotine. Nicotine is an addictive chemical.</p></div>
85
+ </div>
86
+
87
+ <!-- Footer -->
88
+ <footer class="site-footer">
89
+ <div class="container">
90
+ <div class="footer-grid">
91
+ <div class="footer-brand">
92
+ <img src="/tenants/bigdvapor/logo-wordmark.png" alt="Big D Vapor" width="1397" height="288">
93
+ <p>hello@bigdvapor.com<br>1 (866) 746-1136</p>
94
+ </div>
95
+ <div class="footer-col">
96
+ <h4>Shop</h4>
97
+ <ul>
98
+ <li><a href="/collections/disposables">Disposables</a></li>
99
+ <li><a href="/collections/e-liquids">E-Liquid</a></li>
100
+ <li><a href="/collections/devices">Devices</a></li>
101
+ <li><a href="/collections/coils-parts">Coils &amp; Parts</a></li>
102
+ <li><a href="/collections/new-products">New Products</a></li>
103
+ <li><a href="/collections/on-sale">On Sale</a></li>
104
+ </ul>
105
+ </div>
106
+ <div class="footer-col">
107
+ <h4>Support</h4>
108
+ <ul>
109
+ <li><a href="/search">Search</a></li>
110
+ <li><a href="/pages/about-us">About Us</a></li>
111
+ <li><a href="/pages/contact-us">Contact Us</a></li>
112
+ <li><a href="/blogs/news">Blog</a></li>
113
+ <li><a href="/pages/shipping-returns">Shipping Policy</a></li>
114
+ <li><a href="/pages/privacy-policy">Privacy Policy</a></li>
115
+ </ul>
116
+ </div>
117
+ <div class="footer-col">
118
+ <h4>Join the Big D Community</h4>
119
+ <p>Stay updated on new arrivals, exclusive offers.</p>
120
+ <form class="footer-news" action="/api/newsletter" method="post">
121
+ <input type="hidden" name="source" value="footer">
122
+ <label class="sr-only" for="foot-email">Email</label>
123
+ <input id="foot-email" type="email" name="email" placeholder="Email" required>
124
+ <button type="submit" aria-label="Subscribe">→</button>
125
+ </form>
126
+ <div class="pay-badges" aria-label="Accepted payments">
127
+ <span>AMEX</span><span>Discover</span><span>Google&nbsp;Pay</span><span>Mastercard</span><span>Visa</span>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ <div class="footer-warning">
132
+ <p><strong>WARNING:</strong> This product contains nicotine. Nicotine is an addictive chemical. Products intended for adults of legal smoking age (21+) only.</p>
133
+ </div>
134
+ <div class="footer-bottom">
135
+ <p>© Big D Vapor. All rights reserved.</p>
136
+ <p>Must be 21 or older to purchase. Not for sale to minors.</p>
137
+ </div>
138
+ </div>
139
+ </footer>
140
+
141
+ <script>
142
+ (function () {
143
+ var burger = document.getElementById('hamburger');
144
+ var nav = document.getElementById('primaryNav');
145
+ if (burger && nav) burger.addEventListener('click', function () { var o = nav.classList.toggle('open'); burger.setAttribute('aria-expanded', o ? 'true' : 'false'); });
146
+ })();
147
+ </script>
148
+ </body>
149
+ </html>