@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
package/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ Token of Trust Source-Available License — Local Development Only
2
+ Version 1.0
3
+
4
+ Copyright (c) 2026 Token of Trust, Inc. All rights reserved.
5
+
6
+ 1. DEFINITIONS
7
+ "Software" means this source code and any accompanying files in this
8
+ repository or distribution, including the storefront renderer runtime, the
9
+ `@tot/public-runtime` package, the storefront-runner distributable, and any
10
+ derivative works.
11
+ "Local Development" means running, building, and modifying the Software on a
12
+ machine you control, for the sole purpose of evaluating it or developing and
13
+ previewing your own tenant content against it. Serving the Software to any
14
+ third party, or over any public or shared network, is NOT Local Development.
15
+ "Token of Trust" means Token of Trust, Inc.
16
+
17
+ 2. GRANT (LOCAL DEVELOPMENT ONLY)
18
+ Subject to the terms below, Token of Trust grants you a personal,
19
+ non-exclusive, non-transferable, revocable license to use, copy, build, and
20
+ modify the Software SOLELY for Local Development.
21
+
22
+ 3. PERMISSION REQUIRED FOR EVERYTHING ELSE
23
+ Any use of the Software beyond Local Development requires the PRIOR WRITTEN
24
+ PERMISSION of Token of Trust. Without such permission you may NOT, in whole or
25
+ in part:
26
+ (a) deploy, host, serve, or otherwise run the Software in production or for
27
+ any third party, or on any public, staging, or shared/network-accessible
28
+ environment;
29
+ (b) use the Software for any commercial purpose or to provide a service to
30
+ others;
31
+ (c) distribute, publish, sublicense, sell, rent, lease, or otherwise make the
32
+ Software (or a derivative of it) available to any third party; or
33
+ (d) remove or obscure this license or the copyright notices.
34
+ To request permission, contact Token of Trust at legal@tokenoftrust.com.
35
+
36
+ 4. NO TRADEMARK LICENSE
37
+ This license grants no rights to the Token of Trust name, logos, or
38
+ trademarks.
39
+
40
+ 5. RESERVATION OF RIGHTS
41
+ All rights not expressly granted are reserved by Token of Trust. This is a
42
+ source-available license, not an open-source license; the Software is not
43
+ licensed under any OSI-approved license.
44
+
45
+ 6. TERMINATION
46
+ This license terminates automatically if you breach it. On termination you
47
+ must stop using the Software and destroy all copies in your possession.
48
+
49
+ 7. DISCLAIMER OF WARRANTY
50
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
53
+
54
+ 8. LIMITATION OF LIABILITY
55
+ IN NO EVENT SHALL TOKEN OF TRUST BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
56
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM,
57
+ OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
58
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Storefront Runner
2
+
3
+ A world-shareable, multi-tenant **renderer runtime** for the Token of Trust
4
+ storefront. It serves N tenants (or differently-named variants of one tenant) at
5
+ path-prefix URLs — the same thing `astro dev` does for the full platform — with
6
+ the control-plane services (content authoring, compliance, and the publish/deploy
7
+ control plane) kept private and **physically carved out**.
8
+
9
+ ## Run
10
+
11
+ ```sh
12
+ pnpm install
13
+ pnpm dev # astro dev on http://localhost:4321
14
+ ```
15
+
16
+ Tenants resolve by `Host` header first, then by a `/<domain>/…` path prefix
17
+ (DNS-free, for localhost). Try:
18
+
19
+ - http://localhost:4321/tokenoftrust.com/
20
+ - http://localhost:4321/tokenoftrust-preview.com/ (renamed variant of the same tenant)
21
+ - http://localhost:4321/bigdvapor.net/
22
+
23
+ ## Add a tenant
24
+
25
+ Adding a tenant — or a renamed variant of an existing one — is a one-object edit
26
+ in `apps/storefront/src/config/tenants.ts` (see `TOKENOFTRUST_PREVIEW_TENANT`),
27
+ plus a `tenants/<id>/` directory for its content/theme/public assets.
28
+
29
+ ## IP boundary
30
+
31
+ This distributable depends only on `@tot/public-runtime` (the renderer-safe
32
+ model). The private control-plane package is absent, so a control-plane import
33
+ cannot resolve here.
34
+
35
+ ## License
36
+
37
+ Source-available, **local-development only** (see `LICENSE`). You may run, build,
38
+ and modify this for Local Development. Any other use — deploying, hosting, or
39
+ serving it to third parties, or any production/commercial use — requires the
40
+ prior written permission of Token of Trust, Inc.
@@ -0,0 +1,41 @@
1
+ # Copy to `.dev.vars` for local dev (gitignored). With NO values set, the app
2
+ # falls back to FixtureToTClient reading packages/migration/out/catalog/*.json,
3
+ # so the site renders fully offline. Set the TOT_* block to hit live tot20.
4
+
5
+ # --- ToT catalog API (leave blank to use fixtures) ---------------------------
6
+ # TOT_CATALOG_BASE_URL=https://api.tokenoftrust.com/api/catalog
7
+ # Either a bearer token...
8
+ # TOT_ACCESS_TOKEN=
9
+ # ...or an API key/secret pair:
10
+ # TOT_API_KEY=
11
+ # TOT_SECRET_KEY=
12
+
13
+ # --- Storyblok (leave blank to use local fallback content) -------------------
14
+ # Per-tenant delivery token; with none, LocalContentProvider reads
15
+ # src/content/pilot/*.json. The pilot tenant's token also lives in
16
+ # src/config/tenants.ts (placeholder there).
17
+ # STORYBLOK_DELIVERY_TOKEN=
18
+
19
+ # --- Analytics ---------------------------------------------------------------
20
+ # PUBLIC_CF_ANALYTICS_TOKEN=
21
+
22
+ # --- Staff broker assertion (#8453 staff-invite-proof-via-broker) ------------
23
+ # The storefront-signed RS256 staff proof presented to tot20 in the
24
+ # X-ToT-Broker-Assertion header (proves the signed-in ToT-staff actor server-side;
25
+ # replaces the spoofable plaintext staff-email field). Server-side ONLY — the
26
+ # private key must NEVER reach the client bundle. With this UNSET, the staff
27
+ # invite / vendor-search / enter-vendor routes fail closed (503).
28
+ # STOREFRONT_BROKER_PRIVATE_KEY_B64 = base64 of the PKCS8 PEM RS256 private key.
29
+ # tot20 verifies with the matching PUBLIC key registered under STOREFRONT_BROKER_KID.
30
+ # STOREFRONT_BROKER_PRIVATE_KEY_B64=
31
+ # STOREFRONT_BROKER_KID=storefront-qa-1
32
+ # STOREFRONT_BROKER_ISSUER=storefront
33
+
34
+ # --- Local dev auth (localhost only; never reaches prod) ----------------------
35
+ # tot20 sends invite/sign-in emails, so on localhost no email goes out. Set
36
+ # DEV_AUTH=1 to instead PRINT the one-time sign-in code to the SERVER CONSOLE
37
+ # (POST /api/auth/send) so you can complete sign-in locally without email. The
38
+ # whole path is behind `import.meta.env.DEV` and is tree-shaken from prod builds.
39
+ # (Accepting the printed code to mint a local session is being wired next — see
40
+ # handoff 2026-07-09-storefront-local-dev-auth-mode.md.)
41
+ # DEV_AUTH=1
@@ -0,0 +1,24 @@
1
+ # Storefront environment variables (copy to .env for local dev).
2
+ # All are OPTIONAL — with none set, the storefront runs fully offline:
3
+ # catalog from the local fixture store, content from src/content/<tenant>/*.json.
4
+
5
+ # --- Catalog backend (ToT) ---------------------------------------------------
6
+ # When BASE_URL + (ACCESS_TOKEN | API_KEY+SECRET_KEY) are set, the storefront
7
+ # reads the live ToT catalog API instead of the local fixtures.
8
+ TOT_CATALOG_BASE_URL=
9
+ TOT_API_KEY=
10
+ TOT_SECRET_KEY=
11
+ TOT_ACCESS_TOKEN=
12
+
13
+ # --- Storyblok (editorial CMS) -----------------------------------------------
14
+ # Set a real delivery token to switch the pilot tenant from LocalContentProvider
15
+ # to the live StoryblokContentProvider. Model your space's components to match
16
+ # src/lib/storyblok/content-model.ts (home, chrome, pages/*).
17
+ STORYBLOK_PILOT_TOKEN=
18
+ # Space region: eu (default) | us | ap | ca
19
+ STORYBLOK_REGION=eu
20
+ # Content version: published (default) | draft (use draft for previewing)
21
+ STORYBLOK_VERSION=published
22
+
23
+ # --- Analytics ---------------------------------------------------------------
24
+ PUBLIC_CF_ANALYTICS_TOKEN=
@@ -0,0 +1,245 @@
1
+ // @ts-check
2
+ import { defineConfig } from "astro/config";
3
+ import cloudflare from "@astrojs/cloudflare";
4
+ import preact from "@astrojs/preact";
5
+ import tailwindcss from "@tailwindcss/vite";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ // Repo-root tenants/ dir (colocated tenant layout) + the generated static dest
9
+ // the predev copy step mirrors public/ into. astro.config.mjs lives at
10
+ // apps/storefront/, so tenants/ is two levels up. Forward-slash normalized to
11
+ // match Vite's ctx.file (Vite always reports posix-style paths).
12
+ const TENANTS_DIR = fileURLToPath(new URL("../../tenants", import.meta.url)).replace(/\\/g, "/");
13
+ const PUBLIC_TENANTS_DEST = fileURLToPath(new URL("./public/tenants", import.meta.url));
14
+
15
+ // Dev-only default posture: save a colocated tenant file → the browser reloads.
16
+ // The `tenants/<id>/` tree sits ABOVE the Astro root and reaches the app only
17
+ // through a lazy `?raw` glob (HTML, bypassed by the dev disk-read) or the predev
18
+ // public/ copy — never Vite's own module graph — so Vite doesn't watch it and a
19
+ // save would otherwise do nothing. We watch it explicitly and reload on change:
20
+ // - content/**.html — read fresh from disk per request
21
+ // (LocalContentProvider.readRawDevFile), so just reload. (The Vite HMR client
22
+ // is injected into these otherwise-pipeline-bypassing pages in dev; see
23
+ // rawHtmlResponse in src/lib/rawMarketingHtml.ts.)
24
+ // - public/** — re-mirror the one changed asset into public/tenants/<id>/
25
+ // (skipping R2-versioned tenants, like copy-tenant-assets.mjs), then reload.
26
+ // content/*.json, themes/*.json and theme.json are ordinary glob imports, so Vite
27
+ // already invalidates + reloads them — left to default handling. Returning []
28
+ // suppresses the pointless glob HMR that would otherwise fire for the raw files.
29
+ function tenantHotReload() {
30
+ // Typed `any`: `vite` isn't a direct dependency of this package (it's pulled in
31
+ // transitively via astro), so `import('vite').Plugin` can't be resolved here and
32
+ // importing from "vite" would even fail at runtime. `any` keeps the hook params
33
+ // untyped without that reference.
34
+ /** @type {any} */
35
+ const plugin = {
36
+ name: "tot:tenant-hot-reload",
37
+ apply: "serve",
38
+ /** @param {any} server */
39
+ configureServer(server) {
40
+ server.watcher.add(TENANTS_DIR);
41
+ },
42
+ /** @param {any} ctx */
43
+ async handleHotUpdate(ctx) {
44
+ const file = ctx.file.replace(/\\/g, "/");
45
+ if (!file.startsWith(TENANTS_DIR + "/")) return undefined;
46
+ const rel = file.slice(TENANTS_DIR.length + 1); // "<id>/<...>"
47
+ const slash = rel.indexOf("/");
48
+ if (slash < 0) return undefined;
49
+ const id = rel.slice(0, slash);
50
+ const rest = rel.slice(slash + 1);
51
+
52
+ // Content HTML: the change invalidates the SSR module graph, so the
53
+ // Cloudflare Vite plugin reloads the worker and — once it is ready — emits
54
+ // its own correctly-timed full-reload (which the injected Vite HMR client
55
+ // acts on). We must NOT send our own reload: firing on the raw file-change
56
+ // event races ahead of the worker reload, so the browser re-navigates while
57
+ // miniflare is mid-teardown → "page not loaded" + an error overlay. Just let
58
+ // default handling run.
59
+ if (rest.startsWith("content/") && rest.endsWith(".html")) {
60
+ return undefined;
61
+ }
62
+
63
+ // Public assets (CSS, images) aren't in the module graph — they're mirrored
64
+ // into public/tenants/<id>/ at predev, and a programmatic write there does
65
+ // NOT trip the platform's own reload. So: re-mirror the one changed file
66
+ // (await it so the served copy is current), THEN send the reload ourselves.
67
+ // Unlike content HTML this reloads no worker, so there's no teardown race to
68
+ // fire ahead of. Skip R2-versioned tenants, like copy-tenant-assets.mjs.
69
+ if (rest.startsWith("public/")) {
70
+ // fs via dynamic import so a config-load issue could never break startup.
71
+ const [{ cp, mkdir }, { existsSync }, { dirname, join }] = await Promise.all([
72
+ import("node:fs/promises"),
73
+ import("node:fs"),
74
+ import("node:path"),
75
+ ]);
76
+ const versioned = existsSync(join(TENANTS_DIR, id, ".tot", "assets-versioned"));
77
+ if (!versioned) {
78
+ const target = join(PUBLIC_TENANTS_DEST, id, rest.slice("public/".length));
79
+ try {
80
+ await mkdir(dirname(target), { recursive: true });
81
+ await cp(ctx.file, target);
82
+ } catch {
83
+ /* best-effort; still reload below */
84
+ }
85
+ }
86
+ ctx.server.ws.send({ type: "full-reload" });
87
+ return [];
88
+ }
89
+
90
+ return undefined;
91
+ },
92
+ };
93
+ return plugin;
94
+ }
95
+
96
+ // Repo root, two levels up (astro.config.mjs lives at apps/storefront/).
97
+ const REPO_ROOT = fileURLToPath(new URL("../../", import.meta.url));
98
+ const WIDGET_CLIENT_PATH = fileURLToPath(
99
+ new URL("./src/lib/dev/ai-widget-client.js", import.meta.url),
100
+ );
101
+
102
+ /** @param {any} req */
103
+ async function readJsonBody(req) {
104
+ const chunks = [];
105
+ for await (const chunk of req) chunks.push(chunk);
106
+ const raw = Buffer.concat(chunks).toString("utf8");
107
+ return raw ? JSON.parse(raw) : {};
108
+ }
109
+
110
+ /** @param {any} res @param {number} status @param {any} body */
111
+ function sendJson(res, status, body) {
112
+ res.statusCode = status;
113
+ res.setHeader("content-type", "application/json");
114
+ res.end(JSON.stringify(body));
115
+ }
116
+
117
+ /** @param {unknown} e */
118
+ function errorMessage(e) {
119
+ return e instanceof Error ? e.message : String(e);
120
+ }
121
+
122
+ // The inline-AI edit loop (WS5 G1): the floating "✦ ask" box + its dev-server
123
+ // endpoints. Dev-only (`apply: "serve"`) — never runs in `astro build`, so it
124
+ // can never reach the production Cloudflare Worker. The widget itself is
125
+ // unconditional in dev (matching the Vite HMR client injection in
126
+ // rawMarketingHtml.ts) — it's the /__tot/ai-* ENDPOINTS below that gate on
127
+ // TOT_DEV_TENANT (set by scripts/tot-dev.mjs), since that's a Node-process env
128
+ // var these Vite-layer handlers see reliably (unlike SSR code, which under the
129
+ // Cloudflare adapter runs inside workerd and does NOT see it — see tot-dev.mjs's
130
+ // own note on this exact env-var-doesn't-reach-workerd gap). A bare `astro dev`
131
+ // (no active tenant) still shows the widget, but "Ask" reports `no_tenant`
132
+ // rather than erroring silently.
133
+ function inlineAiEditPlugin() {
134
+ /** @type {any} */
135
+ const plugin = {
136
+ name: "tot:inline-ai-edit",
137
+ apply: "serve",
138
+ /** @param {any} server */
139
+ configureServer(server) {
140
+ server.middlewares.use(async (
141
+ /** @type {any} */ req,
142
+ /** @type {any} */ res,
143
+ /** @type {any} */ next,
144
+ ) => {
145
+ if (req.url === "/__tot/ai-widget-client.js") {
146
+ const { readFileSync } = await import("node:fs");
147
+ res.setHeader("content-type", "text/javascript");
148
+ res.end(readFileSync(WIDGET_CLIENT_PATH, "utf8"));
149
+ return;
150
+ }
151
+ if (req.method === "POST" && req.url === "/__tot/ai-edit") {
152
+ const tenantId = process.env.TOT_DEV_TENANT;
153
+ if (!tenantId) {
154
+ sendJson(res, 200, { ok: false, status: "no_tenant", message: "This `astro dev` wasn't started via `tot dev` — no active tenant." });
155
+ return;
156
+ }
157
+ const { handleAiEdit } = await import("../../scripts/dev/ai-edit.mjs");
158
+ try {
159
+ const { prompt } = await readJsonBody(req);
160
+ const result = await handleAiEdit({
161
+ repoRoot: REPO_ROOT, tenantId, prompt, mcpBaseUrl: undefined,
162
+ });
163
+ sendJson(res, 200, result);
164
+ } catch (e) {
165
+ sendJson(res, 200, { ok: false, status: "error", message: errorMessage(e) });
166
+ }
167
+ return;
168
+ }
169
+ if (req.method === "POST" && req.url === "/__tot/ai-undo") {
170
+ const tenantId = process.env.TOT_DEV_TENANT;
171
+ if (!tenantId) {
172
+ sendJson(res, 200, { ok: false, status: "no_tenant", message: "This `astro dev` wasn't started via `tot dev` — no active tenant." });
173
+ return;
174
+ }
175
+ const { handleAiUndo } = await import("../../scripts/dev/ai-edit.mjs");
176
+ try {
177
+ sendJson(res, 200, handleAiUndo({ repoRoot: REPO_ROOT, tenantId }));
178
+ } catch (e) {
179
+ sendJson(res, 200, { ok: false, status: "error", message: errorMessage(e) });
180
+ }
181
+ return;
182
+ }
183
+ next();
184
+ });
185
+ },
186
+ // Covers pages that DO go through Astro/Vite's own render pipeline (e.g.
187
+ // Layout.astro commerce pages). Raw marketing pages (content/home.html)
188
+ // bypass that pipeline entirely — they inject the same script tag
189
+ // themselves in rawMarketingHtml.ts, right next to the Vite HMR client
190
+ // that function already injects for the same reason.
191
+ /** @param {string} html */
192
+ transformIndexHtml(html) {
193
+ const tag = '<script type="module" src="/__tot/ai-widget-client.js"></script>';
194
+ return html.includes("</body>") ? html.replace("</body>", `${tag}</body>`) : `${html}${tag}`;
195
+ },
196
+ };
197
+ return plugin;
198
+ }
199
+
200
+ // SSR on Cloudflare Workers. `output: 'server'` because every response is
201
+ // tenant-resolved at the edge from the Host header (see src/middleware).
202
+ // Preact powers the handful of interactive islands (variant selector, gallery,
203
+ // facets, search typeahead, mobile drawer) — near-zero JS everywhere else.
204
+ export default defineConfig({
205
+ output: "server",
206
+ // Externalize all CSS (no auto-inlined <style>) so a strict CSP needs no
207
+ // inline-style allowance for elements — every stylesheet is a 'self' <link>.
208
+ // Small first-paint tradeoff, offset by cross-page caching (see LIMITATIONS).
209
+ build: { inlineStylesheets: "never" },
210
+ adapter: cloudflare({
211
+ // Local image/asset placeholders are served from /public; real product
212
+ // images get rehosted to R2 in Phase 1 ETL (see DECISIONS.md).
213
+ imageService: "compile",
214
+ }),
215
+ integrations: [preact({ compat: true })],
216
+ vite: {
217
+ plugins: [tailwindcss(), tenantHotReload(), inlineAiEditPlugin()],
218
+ // Dev-only: let the dev server accept real tenant Host headers so host-based
219
+ // tenant routing can be tested locally (e.g. curl -H 'Host: giantvapes.com').
220
+ // Prod runs on Cloudflare Workers, which has no such allowlist.
221
+ server: {
222
+ allowedHosts: [
223
+ "giantvapes.com",
224
+ "www.giantvapes.com",
225
+ "pilot.tokenoftrust.com",
226
+ ],
227
+ // Containerized `tot dev` (scripts/dev): a bind-mount often doesn't deliver
228
+ // inotify events, so Vite's file watcher must POLL for save→HMR to fire.
229
+ // Gated on CHOKIDAR_USEPOLLING (set by the dev image/compose) so native/local
230
+ // dev keeps instant, zero-overhead event-based watching. Explicit rather than
231
+ // relying on Vite auto-reading the env, so it's version-proof.
232
+ ...(process.env.CHOKIDAR_USEPOLLING
233
+ ? {
234
+ watch: {
235
+ usePolling: true,
236
+ interval: Number(process.env.CHOKIDAR_INTERVAL) || 300,
237
+ },
238
+ }
239
+ : {}),
240
+ },
241
+ },
242
+ // Canonical/sitemap host comes from the resolved tenant, not here.
243
+ // `site` is a fallback only used when no tenant context is available.
244
+ site: "https://pilot.tokenoftrust.com",
245
+ });
@@ -0,0 +1,155 @@
1
+ /// <reference path="./.astro/types.d.ts" />
2
+ /// <reference types="astro/client" />
3
+
4
+ import type {
5
+ TenantConfig,
6
+ CustomizationEnv,
7
+ TenantFeatures,
8
+ ResolvedFoxyCommerce,
9
+ CapabilityConfig,
10
+ } from "@tot/public-runtime";
11
+ import type { ToTClient } from "@/lib/tot/ToTClient";
12
+ import type { ContentProvider } from "@/lib/storyblok/provider";
13
+
14
+ /**
15
+ * Minimal binding shapes. We intentionally do NOT depend on
16
+ * @cloudflare/workers-types (not installed); these cover what Phase 1 touches.
17
+ * Widen them when real KV/R2 calls are added.
18
+ */
19
+ interface KVNamespaceLike {
20
+ get(key: string, opts?: { cacheTtl?: number }): Promise<string | null>;
21
+ put(key: string, value: string, opts?: Record<string, unknown>): Promise<void>;
22
+ list(opts?: { prefix?: string; cursor?: string; limit?: number }): Promise<{
23
+ keys: { name: string }[];
24
+ list_complete: boolean;
25
+ cursor?: string;
26
+ }>;
27
+ delete(key: string): Promise<void>;
28
+ }
29
+ interface R2BucketLike {
30
+ get(key: string): Promise<unknown>;
31
+ put(key: string, value: unknown): Promise<unknown>;
32
+ }
33
+
34
+ interface CloudflareEnv {
35
+ /** Astro session store (adapter default). */
36
+ SESSION?: KVNamespaceLike;
37
+ /** Tenant config + catalog cache KV. */
38
+ TENANT_CACHE?: KVNamespaceLike;
39
+ /** Rehosted product images. */
40
+ PRODUCT_IMAGES?: R2BucketLike;
41
+ /**
42
+ * Versioned tenant static assets (`public/**`), keyed
43
+ * `tenants/<id>/<versionId>/<rel>`. Served by src/pages/tenants/[id]/[...path].
44
+ */
45
+ TENANT_ASSETS?: R2BucketLike;
46
+ // Secrets / vars surfaced at runtime.
47
+ TOT_CATALOG_BASE_URL?: string;
48
+ TOT_API_KEY?: string;
49
+ TOT_SECRET_KEY?: string;
50
+ TOT_ACCESS_TOKEN?: string;
51
+ PUBLIC_CF_ANALYTICS_TOKEN?: string;
52
+ /** HMAC secret for signing/verifying customization preview tokens (D4). */
53
+ CUSTOMIZATION_PREVIEW_SECRET?: string;
54
+ /**
55
+ * FoxyCart (Track A). `FOXY_STORE_SUBDOMAIN` overrides the tenant's default
56
+ * demo store subdomain (swap the demo store with zero code change).
57
+ * `FOXY_CART_SECRET` is the store's cart-validation secret for signed mode —
58
+ * absent in the unsigned demo (validation OFF), present on preview/live.
59
+ */
60
+ FOXY_STORE_SUBDOMAIN?: string;
61
+ /** Branded custom checkout domain override (e.g. checkout.preview.tokenoftrust.com). */
62
+ FOXY_STORE_DOMAIN?: string;
63
+ FOXY_CART_SECRET?: string;
64
+ }
65
+
66
+ declare global {
67
+ // Alias used elsewhere.
68
+ type KVNamespace = KVNamespaceLike;
69
+ type R2Bucket = R2BucketLike;
70
+
71
+ namespace App {
72
+ interface Locals {
73
+ /** Tenant resolved from the request Host by src/middleware. */
74
+ tenant: TenantConfig;
75
+ /**
76
+ * Effective capability flags for the resolved tenant (commerce defaults
77
+ * unless siteType:"marketing"/explicit features). Chrome, layout islands,
78
+ * sitemap, and commerce routes gate on these — no tenant-identity checks.
79
+ */
80
+ features: TenantFeatures;
81
+ /** Catalog client bound to the resolved tenant's data scope. */
82
+ tot: ToTClient;
83
+ /**
84
+ * Content provider for this request — overlays any published "Own Your
85
+ * Look" content for the resolved customizationEnv over Storyblok/local.
86
+ */
87
+ content: ContentProvider;
88
+ /** Inline CSS-variable theme block already serialized for <head>. */
89
+ themeStyle: string;
90
+ /** Absolute canonical base for this request. */
91
+ canonicalBase: string;
92
+ /**
93
+ * Path prefix the request was routed under: "" for host-routed requests,
94
+ * or "/<domain>" when a `/<domain>/*` path segment selected the tenant
95
+ * (DNS-free local/preview routing). The Layout keeps root-absolute links
96
+ * inside this prefix on the client.
97
+ */
98
+ basePath: string;
99
+ /**
100
+ * Which customization environment to serve (D4). "live" on production
101
+ * hosts; "test" only behind a valid, tenant-bound preview token on a
102
+ * preview host. Downstream theme/content selection reads this.
103
+ */
104
+ customizationEnv: CustomizationEnv;
105
+ /**
106
+ * Per-request CSP nonce (D2). Placed on the platform's own inline
107
+ * <style>/<script is:inline> tags so a strict CSP can allow them without
108
+ * `unsafe-inline`.
109
+ */
110
+ cspNonce: string;
111
+ /**
112
+ * Resolved FoxyCart cart/checkout facts for this request (loader src, cart
113
+ * URL, mode). Present only for commerce tenants with a FoxyCart store;
114
+ * undefined for marketing tenants or when no store is configured.
115
+ */
116
+ commerce?: ResolvedFoxyCommerce;
117
+ /**
118
+ * Effective, per-environment capability switches (cart/checkout, age
119
+ * verification, excise tax) for this request. Resolved from the tenant's
120
+ * build-time default overridden by the published capabilities artifact for
121
+ * the current customizationEnv — so the value reflects exactly what a PR
122
+ * promoted to THIS environment.
123
+ */
124
+ capabilities: CapabilityConfig;
125
+ /**
126
+ * Signed-in viewer for a login-gated preview host (set by the demo login
127
+ * gate once a valid, resource-bound `tot_session` cookie is present). Carries
128
+ * the email + the role(s)/capability tot20 resolved on this tenant, so chrome
129
+ * can show "signed in as … — owner/developer/staff". Absent on open or
130
+ * password-gated hosts.
131
+ */
132
+ viewer?: {
133
+ email: string;
134
+ roles: string[];
135
+ capability: string;
136
+ };
137
+ /** Cloudflare runtime (env bindings) — provided by the adapter on Workers. */
138
+ runtime?: { env: CloudflareEnv };
139
+ }
140
+ }
141
+ }
142
+
143
+ interface ImportMetaEnv {
144
+ readonly TOT_CATALOG_BASE_URL?: string;
145
+ readonly TOT_API_KEY?: string;
146
+ readonly TOT_SECRET_KEY?: string;
147
+ readonly TOT_ACCESS_TOKEN?: string;
148
+ readonly PUBLIC_CF_ANALYTICS_TOKEN?: string;
149
+ readonly CUSTOMIZATION_PREVIEW_SECRET?: string;
150
+ }
151
+ interface ImportMeta {
152
+ readonly env: ImportMetaEnv;
153
+ }
154
+
155
+ export {};
@@ -0,0 +1,31 @@
1
+ # ensure-preview-reconcile-secret.sh — resolve-or-MINT PREVIEW_RECONCILE_SECRET.
2
+ #
3
+ # ONE secret shared across ALL environments (preview/test/production) — they all
4
+ # point at the same Gitea instance (git.tokenoftrust.com), so there is exactly one
5
+ # webhook-signing secret to keep in sync, not one per tier. SOURCED (not executed)
6
+ # by deploy.sh; idempotent.
7
+ #
8
+ # env wins; else SSM SecureString at /tot/app/storefront/preview-reconcile-secret;
9
+ # else MINT a fresh random value and store it to that SAME SSM param — the first
10
+ # deploy that ever needs it creates it, every deploy after (any environment)
11
+ # resolves the identical value. Silent no-op if aws/openssl are unavailable (the
12
+ # caller then just skips whatever needs this secret, same fail-open shape as the
13
+ # other resolvers in this dir).
14
+ if [ -z "${PREVIEW_RECONCILE_SECRET:-}" ] && command -v aws >/dev/null 2>&1; then
15
+ _prs_ssm_name="/tot/app/storefront/preview-reconcile-secret"
16
+ _prs_region="${AWS_REGION:-us-east-1}"
17
+ _prs_val="$(aws ssm get-parameter --name "$_prs_ssm_name" --with-decryption --region "$_prs_region" --query Parameter.Value --output text 2>/dev/null || true)"
18
+ if [ -n "$_prs_val" ] && [ "$_prs_val" != "None" ]; then
19
+ export PREVIEW_RECONCILE_SECRET="$_prs_val"
20
+ echo "Loaded PREVIEW_RECONCILE_SECRET from SSM ($_prs_ssm_name)"
21
+ elif command -v openssl >/dev/null 2>&1; then
22
+ _prs_val="$(openssl rand -hex 32)"
23
+ if aws ssm put-parameter --name "$_prs_ssm_name" --type SecureString --value "$_prs_val" --region "$_prs_region" --query Version --output text >/dev/null 2>&1; then
24
+ export PREVIEW_RECONCILE_SECRET="$_prs_val"
25
+ echo "Minted a new PREVIEW_RECONCILE_SECRET and stored it to SSM ($_prs_ssm_name) — shared across all environments."
26
+ else
27
+ echo "Failed to mint/store PREVIEW_RECONCILE_SECRET to SSM ($_prs_ssm_name) — leaving it unset." >&2
28
+ fi
29
+ fi
30
+ unset _prs_val _prs_ssm_name _prs_region
31
+ fi
@@ -0,0 +1,48 @@
1
+ # resolve-cf-token.sh — resolve CLOUDFLARE_API_TOKEN into the environment for
2
+ # Cloudflare CLI/API work. SOURCED (not executed) by provision.sh + deploy.sh so it
3
+ # exports into the caller. Single source of truth for the token + its fallback chain.
4
+ #
5
+ # Precedence: an already-set CLOUDFLARE_API_TOKEN in the env ALWAYS wins (CI injects
6
+ # it that way). Otherwise try each SSM SecureString param named in
7
+ # CLOUDFLARE_API_TOKEN_SSM (space-separated, PRIORITY ORDER), exporting the first
8
+ # that resolves:
9
+ # 1. /tot/cloudflare/provision-token broad control-plane — R2 + DNS + SSL/Certs
10
+ # + Workers Routes/Scripts + Zone:Read.
11
+ # 2. /tot/cloudflare/storefront-r2-token FALLBACK — narrower R2 + DNS. Keeps the R2
12
+ # and DNS steps working before the broad
13
+ # token is provisioned. NOTE: under-scoped
14
+ # for SSL-for-SaaS (Step 6) / Workers Routes,
15
+ # so those steps may still skip or warn.
16
+ #
17
+ # Set CLOUDFLARE_API_TOKEN_SSM="" to disable the SSM lookup entirely (e.g. to force
18
+ # wrangler's OAuth). Silent no-op if the token is already set, the aws CLI is absent,
19
+ # or nothing resolves — callers then just skip the CF-dependent steps.
20
+ #
21
+ # Secrets Manager works too: swap the fetch for
22
+ # aws secretsmanager get-secret-value --secret-id "$_cf_name" --query SecretString --output text
23
+ # Each candidate is VERIFIED with Cloudflare before it's accepted, so a
24
+ # present-but-invalid param (expired/revoked/broken — not just a missing one) falls
25
+ # through to the next in the chain instead of poisoning the run. `/user/tokens/verify`
26
+ # works for any token to check itself. If curl is unavailable, verification is
27
+ # skipped and the first resolvable token is taken as-is.
28
+ _cf_verify() {
29
+ command -v curl >/dev/null 2>&1 || return 0 # can't verify → accept
30
+ curl -fsS -H "Authorization: Bearer $1" \
31
+ https://api.cloudflare.com/client/v4/user/tokens/verify 2>/dev/null \
32
+ | grep -q '"status":"active"'
33
+ }
34
+ CLOUDFLARE_API_TOKEN_SSM="${CLOUDFLARE_API_TOKEN_SSM-/tot/cloudflare/provision-token /tot/cloudflare/storefront-r2-token}"
35
+ if [ -z "${CLOUDFLARE_API_TOKEN:-}" ] && [ -n "$CLOUDFLARE_API_TOKEN_SSM" ] && command -v aws >/dev/null 2>&1; then
36
+ for _cf_name in $CLOUDFLARE_API_TOKEN_SSM; do
37
+ _cf_tok="$(aws ssm get-parameter --name "$_cf_name" --with-decryption --query Parameter.Value --output text 2>/dev/null || true)"
38
+ [ -n "$_cf_tok" ] && [ "$_cf_tok" != "None" ] || continue
39
+ if ! _cf_verify "$_cf_tok"; then
40
+ echo "Skipping $_cf_name — token failed Cloudflare verify (expired/revoked/invalid)"
41
+ continue
42
+ fi
43
+ export CLOUDFLARE_API_TOKEN="$_cf_tok"
44
+ echo "Loaded CLOUDFLARE_API_TOKEN from SSM ($_cf_name)"
45
+ break
46
+ done
47
+ unset _cf_tok _cf_name
48
+ fi