@tokenoftrust/storefront-runner 1.3.2

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 (310) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +42 -0
  3. package/apps/storefront/astro.config.mjs +66 -0
  4. package/apps/storefront/dev-plugins/dev-loop-state.mjs +147 -0
  5. package/apps/storefront/dev-plugins/tenant-hot-reload.mjs +238 -0
  6. package/apps/storefront/env.d.ts +162 -0
  7. package/apps/storefront/migrations/0000_baseline.sql +54 -0
  8. package/apps/storefront/migrations/0001_products_fts.sql +9 -0
  9. package/apps/storefront/migrations/README.md +54 -0
  10. package/apps/storefront/migrations/meta/0000_snapshot.json +347 -0
  11. package/apps/storefront/migrations/meta/0001_snapshot.json +347 -0
  12. package/apps/storefront/migrations/meta/_journal.json +20 -0
  13. package/apps/storefront/package.json +42 -0
  14. package/apps/storefront/public/brand/northwind-logo-dark.svg +4 -0
  15. package/apps/storefront/public/brand/northwind-logo-light.svg +4 -0
  16. package/apps/storefront/public/brand/northwind-og.svg +13 -0
  17. package/apps/storefront/public/favicon.svg +5 -0
  18. package/apps/storefront/public/js/dashboard-team.js +147 -0
  19. package/apps/storefront/public/js/dashboard-vendor-search.js +115 -0
  20. package/apps/storefront/public/shared/commerce-chrome.css +369 -0
  21. package/apps/storefront/src/components/Badge.astro +34 -0
  22. package/apps/storefront/src/components/Breadcrumbs.astro +45 -0
  23. package/apps/storefront/src/components/CollectionCard.astro +56 -0
  24. package/apps/storefront/src/components/EmptyState.astro +55 -0
  25. package/apps/storefront/src/components/Img.astro +68 -0
  26. package/apps/storefront/src/components/ProductCard.astro +228 -0
  27. package/apps/storefront/src/components/Section.astro +39 -0
  28. package/apps/storefront/src/components/Seo.astro +70 -0
  29. package/apps/storefront/src/components/WidgetFrame.astro +34 -0
  30. package/apps/storefront/src/components/admin/AdminAIWorkflowsTab.astro +531 -0
  31. package/apps/storefront/src/components/admin/AdminCustomersTab.astro +597 -0
  32. package/apps/storefront/src/components/admin/AdminFoxyCartSettingsPanel.astro +227 -0
  33. package/apps/storefront/src/components/admin/AdminFulfillmentTab.astro +465 -0
  34. package/apps/storefront/src/components/admin/AdminProductsTab.astro +901 -0
  35. package/apps/storefront/src/components/admin/AdminReportingTab.astro +435 -0
  36. package/apps/storefront/src/components/admin/AdminSettingsTab.astro +782 -0
  37. package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +1223 -0
  38. package/apps/storefront/src/components/auth/AuthBadge.astro +44 -0
  39. package/apps/storefront/src/components/chrome/AnnouncementBar.astro +108 -0
  40. package/apps/storefront/src/components/chrome/MegaMenu.astro +26 -0
  41. package/apps/storefront/src/components/chrome/NavDropdown.astro +201 -0
  42. package/apps/storefront/src/components/chrome/SiteFooter.astro +201 -0
  43. package/apps/storefront/src/components/chrome/SiteHeader.astro +234 -0
  44. package/apps/storefront/src/components/chrome/UtilityNav.astro +79 -0
  45. package/apps/storefront/src/components/commerce/ArticleCard.astro +242 -0
  46. package/apps/storefront/src/components/commerce/BrandGrid.astro +175 -0
  47. package/apps/storefront/src/components/commerce/FoxyLoader.astro +23 -0
  48. package/apps/storefront/src/components/commerce/FoxySidecartStyles.astro +61 -0
  49. package/apps/storefront/src/components/commerce/PriceDisplay.astro +91 -0
  50. package/apps/storefront/src/components/commerce/ProductCarousel.astro +197 -0
  51. package/apps/storefront/src/components/commerce/ProductGrid.astro +75 -0
  52. package/apps/storefront/src/components/commerce/RatingStars.astro +58 -0
  53. package/apps/storefront/src/components/commerce/ReviewList.astro +54 -0
  54. package/apps/storefront/src/components/commerce/ReviewSummary.astro +44 -0
  55. package/apps/storefront/src/components/commerce/TagFilterCloud.astro +149 -0
  56. package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +37 -0
  57. package/apps/storefront/src/components/compliance/ComplianceNotice.astro +99 -0
  58. package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +45 -0
  59. package/apps/storefront/src/components/compliance/NicotineWarning.astro +33 -0
  60. package/apps/storefront/src/components/compliance/PactActNotice.astro +35 -0
  61. package/apps/storefront/src/components/compliance/Prop65Warning.astro +80 -0
  62. package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +38 -0
  63. package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +35 -0
  64. package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +53 -0
  65. package/apps/storefront/src/components/home/Hero.astro +164 -0
  66. package/apps/storefront/src/components/islands/AgeGate.tsx +109 -0
  67. package/apps/storefront/src/components/islands/ImageGallery.tsx +237 -0
  68. package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +73 -0
  69. package/apps/storefront/src/components/islands/MobileNav.tsx +239 -0
  70. package/apps/storefront/src/components/islands/QuickView.tsx +138 -0
  71. package/apps/storefront/src/components/islands/RecentlyViewed.tsx +122 -0
  72. package/apps/storefront/src/components/islands/SavedList.tsx +99 -0
  73. package/apps/storefront/src/components/islands/SearchTypeahead.tsx +248 -0
  74. package/apps/storefront/src/components/islands/VariantSelector.tsx +375 -0
  75. package/apps/storefront/src/components/marketing/CardGrid.astro +72 -0
  76. package/apps/storefront/src/components/marketing/CodeSample.astro +20 -0
  77. package/apps/storefront/src/components/marketing/CtaBand.astro +24 -0
  78. package/apps/storefront/src/components/marketing/Faq.astro +37 -0
  79. package/apps/storefront/src/components/marketing/Integrations.astro +63 -0
  80. package/apps/storefront/src/components/marketing/MarketingBlocks.astro +53 -0
  81. package/apps/storefront/src/components/marketing/MarketingCtas.astro +48 -0
  82. package/apps/storefront/src/components/marketing/MarketingHero.astro +72 -0
  83. package/apps/storefront/src/components/marketing/ProofStrip.astro +37 -0
  84. package/apps/storefront/src/components/marketing/SplitCompare.astro +53 -0
  85. package/apps/storefront/src/components/marketing/Steps.astro +36 -0
  86. package/apps/storefront/src/components/marketing/Testimonials.astro +38 -0
  87. package/apps/storefront/src/components/marketing/TrustBar.astro +22 -0
  88. package/apps/storefront/src/components/membership/IllustrativeLabel.astro +56 -0
  89. package/apps/storefront/src/components/membership/TierCards.astro +164 -0
  90. package/apps/storefront/src/components/membership/TierComparisonTable.astro +148 -0
  91. package/apps/storefront/src/components/plp/ActiveFilters.astro +79 -0
  92. package/apps/storefront/src/components/plp/FacetSidebar.astro +199 -0
  93. package/apps/storefront/src/components/plp/Pagination.astro +99 -0
  94. package/apps/storefront/src/components/plp/SortSelect.astro +64 -0
  95. package/apps/storefront/src/components/style-guide/StyleGuideNav.astro +95 -0
  96. package/apps/storefront/src/components/subscription/HowItWorksSteps.astro +67 -0
  97. package/apps/storefront/src/components/subscription/ManageSubscriptionEntry.astro +67 -0
  98. package/apps/storefront/src/components/subscription/SavingsExplainer.astro +101 -0
  99. package/apps/storefront/src/config/adminTargetTenant.ts +28 -0
  100. package/apps/storefront/src/config/devTenantSeed.ts +78 -0
  101. package/apps/storefront/src/config/devTenants.ts +16 -0
  102. package/apps/storefront/src/config/kvTenantResolver.ts +87 -0
  103. package/apps/storefront/src/config/resolver.ts +102 -0
  104. package/apps/storefront/src/config/tenants.ts +87 -0
  105. package/apps/storefront/src/layouts/Layout.astro +368 -0
  106. package/apps/storefront/src/lib/admin/README.md +122 -0
  107. package/apps/storefront/src/lib/admin/ai/approvalMode.ts +21 -0
  108. package/apps/storefront/src/lib/admin/ai/askEnvelope.ts +48 -0
  109. package/apps/storefront/src/lib/admin/ai/audit.ts +14 -0
  110. package/apps/storefront/src/lib/admin/ai/index.ts +6 -0
  111. package/apps/storefront/src/lib/admin/ai/operationalRuns.ts +155 -0
  112. package/apps/storefront/src/lib/admin/ai/recommendation.ts +20 -0
  113. package/apps/storefront/src/lib/admin/checkoutStyleInput.ts +172 -0
  114. package/apps/storefront/src/lib/admin/checkoutStyleTarget.ts +65 -0
  115. package/apps/storefront/src/lib/admin/envelope.ts +10 -0
  116. package/apps/storefront/src/lib/admin/evidence/evidenceReference.ts +32 -0
  117. package/apps/storefront/src/lib/admin/memoizeByEnvelope.ts +27 -0
  118. package/apps/storefront/src/lib/admin/orderClient.ts +146 -0
  119. package/apps/storefront/src/lib/admin/seed.ts +54 -0
  120. package/apps/storefront/src/lib/admin/services/mock/aiWorkflows.ts +59 -0
  121. package/apps/storefront/src/lib/admin/services/mock/customers.ts +86 -0
  122. package/apps/storefront/src/lib/admin/services/mock/evidence.ts +99 -0
  123. package/apps/storefront/src/lib/admin/services/mock/foxyCartSettings.ts +78 -0
  124. package/apps/storefront/src/lib/admin/services/mock/fulfillment.ts +62 -0
  125. package/apps/storefront/src/lib/admin/services/mock/index.ts +12 -0
  126. package/apps/storefront/src/lib/admin/services/mock/orders.ts +184 -0
  127. package/apps/storefront/src/lib/admin/services/mock/products.ts +105 -0
  128. package/apps/storefront/src/lib/admin/services/mock/reporting.ts +51 -0
  129. package/apps/storefront/src/lib/admin/services/mock/settings.ts +70 -0
  130. package/apps/storefront/src/lib/admin/services/mock/tenants.ts +29 -0
  131. package/apps/storefront/src/lib/admin/services/orders.ts +300 -0
  132. package/apps/storefront/src/lib/admin/viewmodels/aiWorkflows.ts +67 -0
  133. package/apps/storefront/src/lib/admin/viewmodels/customers.ts +56 -0
  134. package/apps/storefront/src/lib/admin/viewmodels/fulfillment.ts +49 -0
  135. package/apps/storefront/src/lib/admin/viewmodels/orders.ts +92 -0
  136. package/apps/storefront/src/lib/admin/viewmodels/products.ts +74 -0
  137. package/apps/storefront/src/lib/admin/viewmodels/reporting.ts +34 -0
  138. package/apps/storefront/src/lib/admin/viewmodels/settings.ts +64 -0
  139. package/apps/storefront/src/lib/adminTenantEnvelope.ts +90 -0
  140. package/apps/storefront/src/lib/analytics/index.ts +47 -0
  141. package/apps/storefront/src/lib/auth/brokerAssertion.ts +136 -0
  142. package/apps/storefront/src/lib/auth/devAuth.ts +90 -0
  143. package/apps/storefront/src/lib/auth/gatePage.ts +81 -0
  144. package/apps/storefront/src/lib/auth/identityToken.ts +341 -0
  145. package/apps/storefront/src/lib/auth/loginGate.ts +119 -0
  146. package/apps/storefront/src/lib/auth/route.ts +146 -0
  147. package/apps/storefront/src/lib/auth/session.ts +203 -0
  148. package/apps/storefront/src/lib/auth/totAccessClient.ts +503 -0
  149. package/apps/storefront/src/lib/basePath.ts +41 -0
  150. package/apps/storefront/src/lib/cfImage.ts +55 -0
  151. package/apps/storefront/src/lib/chrome/model.ts +244 -0
  152. package/apps/storefront/src/lib/chrome/parseConfig.ts +34 -0
  153. package/apps/storefront/src/lib/colors.ts +97 -0
  154. package/apps/storefront/src/lib/commerce/foxyCartSettings.ts +253 -0
  155. package/apps/storefront/src/lib/content-edit/applyDiff.ts +91 -0
  156. package/apps/storefront/src/lib/content-edit/client.ts +230 -0
  157. package/apps/storefront/src/lib/content-edit/index.ts +14 -0
  158. package/apps/storefront/src/lib/content-edit/route.ts +25 -0
  159. package/apps/storefront/src/lib/content-edit/types.ts +19 -0
  160. package/apps/storefront/src/lib/cspStaticHashes.ts +24 -0
  161. package/apps/storefront/src/lib/d1/catalog.ts +366 -0
  162. package/apps/storefront/src/lib/dashboard/staffAdmission.ts +43 -0
  163. package/apps/storefront/src/lib/dashboard/staffVendorAccess.ts +449 -0
  164. package/apps/storefront/src/lib/dashboard/tenantSelection.ts +136 -0
  165. package/apps/storefront/src/lib/dashboard/vendorQuery.ts +61 -0
  166. package/apps/storefront/src/lib/demoGate.ts +113 -0
  167. package/apps/storefront/src/lib/dev/activityIngestToken.ts +78 -0
  168. package/apps/storefront/src/lib/dev/activityStore.ts +72 -0
  169. package/apps/storefront/src/lib/dev/ai-widget-client.js +308 -0
  170. package/apps/storefront/src/lib/dev/apiBase.ts +14 -0
  171. package/apps/storefront/src/lib/dev/cliSignInCode.ts +155 -0
  172. package/apps/storefront/src/lib/dev/devDraft.ts +133 -0
  173. package/apps/storefront/src/lib/dev/hostedCockpit.ts +169 -0
  174. package/apps/storefront/src/lib/dev/livePreview.ts +77 -0
  175. package/apps/storefront/src/lib/dev/runtimeStore.ts +120 -0
  176. package/apps/storefront/src/lib/dev/storeStatus.ts +142 -0
  177. package/apps/storefront/src/lib/diag/redact.ts +20 -0
  178. package/apps/storefront/src/lib/edgeCache.ts +128 -0
  179. package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +62 -0
  180. package/apps/storefront/src/lib/env.ts +60 -0
  181. package/apps/storefront/src/lib/fixtures/sampleProducts.ts +130 -0
  182. package/apps/storefront/src/lib/format.ts +38 -0
  183. package/apps/storefront/src/lib/foxyCommerce.ts +49 -0
  184. package/apps/storefront/src/lib/imageAttrs.ts +55 -0
  185. package/apps/storefront/src/lib/jsonld.ts +166 -0
  186. package/apps/storefront/src/lib/maintenance.ts +71 -0
  187. package/apps/storefront/src/lib/membership/model.ts +97 -0
  188. package/apps/storefront/src/lib/memoryKv.ts +32 -0
  189. package/apps/storefront/src/lib/messaging/messagesClient.ts +143 -0
  190. package/apps/storefront/src/lib/placeholder.ts +99 -0
  191. package/apps/storefront/src/lib/previewReload.ts +125 -0
  192. package/apps/storefront/src/lib/priceBuckets.ts +33 -0
  193. package/apps/storefront/src/lib/rawChrome.ts +505 -0
  194. package/apps/storefront/src/lib/rawMarketingHtml.ts +136 -0
  195. package/apps/storefront/src/lib/search/index.ts +74 -0
  196. package/apps/storefront/src/lib/sections.ts +129 -0
  197. package/apps/storefront/src/lib/securityHeaders.ts +31 -0
  198. package/apps/storefront/src/lib/storyblok/content-model.ts +289 -0
  199. package/apps/storefront/src/lib/storyblok/provider.ts +607 -0
  200. package/apps/storefront/src/lib/subscription/model.ts +68 -0
  201. package/apps/storefront/src/lib/tenantRouting.ts +91 -0
  202. package/apps/storefront/src/lib/tot/ToTClient.ts +177 -0
  203. package/apps/storefront/src/lib/tot/d1Client.ts +62 -0
  204. package/apps/storefront/src/lib/tot/query.ts +249 -0
  205. package/apps/storefront/src/lib/tot/totClientInterface.ts +30 -0
  206. package/apps/storefront/src/lib/url.ts +142 -0
  207. package/apps/storefront/src/lib/wishlist.ts +63 -0
  208. package/apps/storefront/src/middleware/index.ts +455 -0
  209. package/apps/storefront/src/pages/404.astro +61 -0
  210. package/apps/storefront/src/pages/[...slug].astro +90 -0
  211. package/apps/storefront/src/pages/admin.astro +1675 -0
  212. package/apps/storefront/src/pages/api/admin/orders/[id].ts +53 -0
  213. package/apps/storefront/src/pages/api/admin/orders.ts +71 -0
  214. package/apps/storefront/src/pages/api/auth/logout.ts +21 -0
  215. package/apps/storefront/src/pages/api/auth/magic-exchange.ts +107 -0
  216. package/apps/storefront/src/pages/api/auth/send.ts +85 -0
  217. package/apps/storefront/src/pages/api/auth/verify.ts +135 -0
  218. package/apps/storefront/src/pages/api/cache-purge.ts +44 -0
  219. package/apps/storefront/src/pages/api/checkout-style.css.ts +43 -0
  220. package/apps/storefront/src/pages/api/cli/policy.ts +70 -0
  221. package/apps/storefront/src/pages/api/content-edit/ai-edit.ts +164 -0
  222. package/apps/storefront/src/pages/api/csp-report.ts +25 -0
  223. package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +124 -0
  224. package/apps/storefront/src/pages/api/dashboard/vendor-search.ts +120 -0
  225. package/apps/storefront/src/pages/api/dev/activity.ts +124 -0
  226. package/apps/storefront/src/pages/api/dev/cli-signin-code.ts +73 -0
  227. package/apps/storefront/src/pages/api/dev/diff.ts +68 -0
  228. package/apps/storefront/src/pages/api/dev/file.ts +57 -0
  229. package/apps/storefront/src/pages/api/dev/locate.ts +125 -0
  230. package/apps/storefront/src/pages/api/dev/publish.ts +128 -0
  231. package/apps/storefront/src/pages/api/dev/tree.ts +70 -0
  232. package/apps/storefront/src/pages/api/dev/write.ts +116 -0
  233. package/apps/storefront/src/pages/api/newsletter.ts +104 -0
  234. package/apps/storefront/src/pages/api/request-access.ts +172 -0
  235. package/apps/storefront/src/pages/auth/login.astro +149 -0
  236. package/apps/storefront/src/pages/auth/magic.astro +105 -0
  237. package/apps/storefront/src/pages/capabilities.astro +292 -0
  238. package/apps/storefront/src/pages/collections/[handle].astro +177 -0
  239. package/apps/storefront/src/pages/collections/index.astro +59 -0
  240. package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +100 -0
  241. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +154 -0
  242. package/apps/storefront/src/pages/dashboard/index.astro +160 -0
  243. package/apps/storefront/src/pages/index.astro +290 -0
  244. package/apps/storefront/src/pages/llms.txt.ts +92 -0
  245. package/apps/storefront/src/pages/products/[handle].astro +402 -0
  246. package/apps/storefront/src/pages/robots.txt.ts +24 -0
  247. package/apps/storefront/src/pages/saved.astro +35 -0
  248. package/apps/storefront/src/pages/search.astro +150 -0
  249. package/apps/storefront/src/pages/sitemap.xml.ts +78 -0
  250. package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +1280 -0
  251. package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +229 -0
  252. package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +144 -0
  253. package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +116 -0
  254. package/apps/storefront/src/pages/style-guide/index.astro +98 -0
  255. package/apps/storefront/src/pages/tenants/[id]/[...path].ts +57 -0
  256. package/apps/storefront/src/styles/global.css +292 -0
  257. package/apps/storefront/src/themes/reference.ts +68 -0
  258. package/apps/storefront/src/themes/schema.ts +111 -0
  259. package/apps/storefront/src/themes/tenants/index.ts +51 -0
  260. package/apps/storefront/tsconfig.json +16 -0
  261. package/apps/storefront/vitest.config.ts +22 -0
  262. package/package.json +26 -0
  263. package/packages/public-runtime/LICENSE +58 -0
  264. package/packages/public-runtime/package.json +22 -0
  265. package/packages/public-runtime/src/binary-path.ts +68 -0
  266. package/packages/public-runtime/src/capabilities.ts +89 -0
  267. package/packages/public-runtime/src/catalog-api.ts +81 -0
  268. package/packages/public-runtime/src/catalog-d1.ts +192 -0
  269. package/packages/public-runtime/src/checkout-style-publish.ts +200 -0
  270. package/packages/public-runtime/src/checkout-style.ts +375 -0
  271. package/packages/public-runtime/src/csp.ts +109 -0
  272. package/packages/public-runtime/src/customization-preview.ts +197 -0
  273. package/packages/public-runtime/src/customization-reconcile.ts +63 -0
  274. package/packages/public-runtime/src/customization-runtime.ts +157 -0
  275. package/packages/public-runtime/src/customization-scripts.ts +64 -0
  276. package/packages/public-runtime/src/customization-versioning.ts +95 -0
  277. package/packages/public-runtime/src/foxy-orders.ts +136 -0
  278. package/packages/public-runtime/src/foxy.ts +196 -0
  279. package/packages/public-runtime/src/hot-standby-readiness.ts +140 -0
  280. package/packages/public-runtime/src/index.ts +34 -0
  281. package/packages/public-runtime/src/product.ts +159 -0
  282. package/packages/public-runtime/src/search.ts +45 -0
  283. package/packages/public-runtime/src/tenant-assets.ts +444 -0
  284. package/packages/public-runtime/src/tenant.ts +384 -0
  285. package/packages/public-runtime/tsconfig.json +8 -0
  286. package/packages/public-runtime/vitest.config.ts +8 -0
  287. package/pnpm-workspace.yaml +7 -0
  288. package/scripts/build/copy-tenant-assets.mjs +69 -0
  289. package/scripts/dev/ai-edit.mjs +183 -0
  290. package/scripts/dev/checkout-watch.mjs +116 -0
  291. package/scripts/dev/file-browser.mjs +159 -0
  292. package/scripts/dev/file-writer.mjs +141 -0
  293. package/scripts/dev/git-status.mjs +171 -0
  294. package/scripts/dev/locate-handler.mjs +163 -0
  295. package/scripts/dev/locate.mjs +112 -0
  296. package/scripts/dev/port-check.mjs +48 -0
  297. package/scripts/dev/safe-path.mjs +109 -0
  298. package/scripts/dev/shot.mjs +46 -0
  299. package/scripts/dev/tenant-source-root.mjs +76 -0
  300. package/scripts/dev/unified-diff.mjs +81 -0
  301. package/scripts/tot-dev.mjs +376 -0
  302. package/tenants/README.md +14 -0
  303. package/tenants/home/content/chrome.json +7 -0
  304. package/tenants/home/content/home.html +58 -0
  305. package/tenants/home/content/home.json +11 -0
  306. package/tenants/home/public/js/storefront.js +210 -0
  307. package/tenants/home/public/logo-wordmark.png +0 -0
  308. package/tenants/home/public/pages/storefront.css +212 -0
  309. package/tenants/home/theme.json +6 -0
  310. package/tsconfig.base.json +20 -0
@@ -0,0 +1,531 @@
1
+ ---
2
+ /**
3
+ * AI Workflows tab (baseline §AI Workflows). Renders the 8 named workflow
4
+ * records from the live view model (lib/admin/services/mock, from
5
+ * data-view-contracts). Still NO real execution or external side effects:
6
+ * 3 of the 8 workflows (OPERATIONAL_WORKFLOW_KEYS) are "operational" in the
7
+ * baseline's sense — trigger → real mock source data → an evidence-backed,
8
+ * approval-gated AiRecommendation + run history (ai/operationalRuns.ts) —
9
+ * the other 5 stay scaffold-only until their own units connect real data.
10
+ * Every action affordance stays inert or navigational; nothing here mutates
11
+ * anything.
12
+ */
13
+ import { getAiWorkflowsViewModel } from "@/lib/admin/services/mock";
14
+ import type { ApprovalMode, WorkflowRecord, WorkflowStatus } from "@/lib/admin/viewmodels/aiWorkflows";
15
+ import type { AdminTenantEnvelope } from "@/lib/admin/envelope";
16
+ import { isOperational, runOperationalWorkflow } from "@/lib/admin/ai/operationalRuns";
17
+
18
+ interface Props {
19
+ envelope: AdminTenantEnvelope;
20
+ }
21
+
22
+ const { envelope } = Astro.props;
23
+ const cspNonce = Astro.locals.cspNonce;
24
+
25
+ const vm = getAiWorkflowsViewModel(envelope);
26
+
27
+ const STATUS_TONE: Record<WorkflowStatus, string> = {
28
+ scheduled: "teal",
29
+ running: "blue",
30
+ needs_review: "amber",
31
+ paused: "",
32
+ planned: "violet",
33
+ };
34
+
35
+ const STATUS_LABEL: Record<WorkflowStatus, string> = {
36
+ scheduled: "Scheduled",
37
+ running: "Running",
38
+ needs_review: "Needs review",
39
+ paused: "Paused",
40
+ planned: "Planned",
41
+ };
42
+
43
+ const APPROVAL_LABEL: Record<ApprovalMode, string> = {
44
+ draft_only: "Draft only",
45
+ approval_required: "Approval required",
46
+ guarded_automation: "Guarded automation",
47
+ };
48
+
49
+ const APPROVAL_TONE: Record<ApprovalMode, string> = {
50
+ draft_only: "blue",
51
+ approval_required: "amber",
52
+ guarded_automation: "green",
53
+ };
54
+
55
+ function viewKeysFor(workflow: WorkflowRecord): string[] {
56
+ const keys = ["all", workflow.approvalMode];
57
+ if (workflow.status === "needs_review") keys.push("needs_review");
58
+ return keys;
59
+ }
60
+
61
+ function formatTime(iso: string | null): string {
62
+ if (!iso) return "—";
63
+ return new Date(iso).toLocaleString([], { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
64
+ }
65
+
66
+ const needsReviewCount = vm.workflows.filter((w) => w.status === "needs_review").length;
67
+ const draftOnlyCount = vm.workflows.filter((w) => w.approvalMode === "draft_only").length;
68
+ const guardedCount = vm.workflows.filter((w) => w.approvalMode === "guarded_automation").length;
69
+
70
+ const defaultWorkflow = vm.workflows.find((w) => isOperational(w.key)) ?? vm.workflows[0] ?? null;
71
+ const operationalCount = vm.workflows.filter((w) => isOperational(w.key)).length;
72
+
73
+ const SAVED_VIEWS: { key: string; label: string }[] = [
74
+ { key: "all", label: "All" },
75
+ { key: "needs_review", label: "Needs review" },
76
+ { key: "draft_only", label: "Draft only" },
77
+ { key: "approval_required", label: "Approval required" },
78
+ { key: "guarded_automation", label: "Guarded automation" },
79
+ ];
80
+ ---
81
+
82
+ <section id="ai-workflows" class="band ai-workflows-tab" aria-labelledby="admin-tab-ai-workflows ai-workflows-title" data-admin-panel data-agent-scope="ai-workflows" role="tabpanel" data-workflows-target-tenant={vm.targetTenant}>
83
+ <div class="section-title">
84
+ <div>
85
+ <h2 id="ai-workflows-title">AI Workflows</h2>
86
+ <p>Scheduled, recurring, evidence-backed jobs — {operationalCount} of {vm.workflows.length} operational, no external side effects yet.</p>
87
+ </div>
88
+ <div class="actions">
89
+ <button class="btn primary" type="button"><svg><use href="#i-workflows"></use></svg>New workflow</button>
90
+ </div>
91
+ </div>
92
+
93
+ <div class="grid cols-4">
94
+ <div class="metric"><span>Workflows</span><strong>{vm.workflows.length}</strong><small>{operationalCount} run against mock data</small></div>
95
+ <div class="metric"><span>Needs review</span><strong>{needsReviewCount}</strong><small>Status flagged for review</small></div>
96
+ <div class="metric"><span>Draft only</span><strong>{draftOnlyCount}</strong><small>Never act without a human draft</small></div>
97
+ <div class="metric"><span>Guarded automation</span><strong>{guardedCount}</strong><small>Narrowest auto-action scope</small></div>
98
+ </div>
99
+
100
+ <div class="ship-gate amber ai-workflows-gate" aria-labelledby="ai-workflows-gate-title">
101
+ <div class="ship-gate-main">
102
+ <span class="seal"><svg><use href="#i-workflows"></use></svg></span>
103
+ <div>
104
+ <b id="ai-workflows-gate-title">{operationalCount} workflows operational — still no external side effects</b>
105
+ <span>Operational workflows trigger against real mock orders/products data and produce evidence-backed, approval-gated recommendations. Nothing here mutates anything — that's a later, explicitly gated unit.</span>
106
+ </div>
107
+ </div>
108
+ </div>
109
+
110
+ <div class="workflow-workspace">
111
+ <div class="panel workflow-list-panel">
112
+ <div class="panel-head workflow-panel-head">
113
+ <h3><svg><use href="#i-workflows"></use></svg>Workflow Queue</h3>
114
+ <span class="chip teal">{vm.workflows.length} workflows</span>
115
+ </div>
116
+ <div class="panel-body grid">
117
+ <div class="tabs" role="tablist" aria-label="AI workflow saved views" data-workflows-view-list>
118
+ {SAVED_VIEWS.map((view) => (
119
+ <button type="button" class:list={["tab", { active: view.key === "all" }]} data-workflows-view-button data-view-key={view.key}>{view.label}</button>
120
+ ))}
121
+ </div>
122
+
123
+ <div class="workflow-toolbar" aria-label="AI workflow controls">
124
+ <label class="workflow-search">
125
+ <span>Search</span>
126
+ <input type="search" placeholder="Search workflows, owners" aria-label="Search AI workflows" data-workflows-search />
127
+ </label>
128
+ </div>
129
+
130
+ <div class="table-wrap">
131
+ <table class="workflow-table">
132
+ <thead>
133
+ <tr>
134
+ <th>Workflow</th>
135
+ <th>Cadence / trigger</th>
136
+ <th>Last run / next run</th>
137
+ <th>Approval mode</th>
138
+ <th>Status</th>
139
+ <th>Owner</th>
140
+ <th class="action">Action</th>
141
+ </tr>
142
+ </thead>
143
+ <tbody data-workflows-tbody>
144
+ {vm.workflows.map((workflow) => (
145
+ <tr
146
+ class:list={[{ selected: workflow.key === defaultWorkflow?.key }]}
147
+ data-workflows-row
148
+ data-workflow-key={workflow.key}
149
+ data-view-keys={viewKeysFor(workflow).join(" ")}
150
+ data-search-haystack={`${workflow.name} ${workflow.owner}`.toLowerCase()}
151
+ >
152
+ <td>
153
+ <strong>{workflow.name}</strong>
154
+ {isOperational(workflow.key) && <span class="chip teal workflow-operational-badge">Operational</span>}
155
+ </td>
156
+ <td><strong>{workflow.cadence}</strong><span class="subtle">{workflow.triggerType}</span></td>
157
+ <td><span class="subtle">Last {formatTime(workflow.lastRunAt)}</span><span class="subtle">Next {formatTime(workflow.nextRunAt)}</span></td>
158
+ <td><span class:list={["chip", APPROVAL_TONE[workflow.approvalMode]]}>{APPROVAL_LABEL[workflow.approvalMode]}</span></td>
159
+ <td><span class:list={["chip", STATUS_TONE[workflow.status]]}>{STATUS_LABEL[workflow.status]}</span></td>
160
+ <td><strong>{workflow.owner}</strong></td>
161
+ <td class="action"><button type="button" class="btn" data-workflows-select-row={workflow.key}>Open</button></td>
162
+ </tr>
163
+ ))}
164
+ </tbody>
165
+ </table>
166
+ <p class="workflow-empty-state" data-workflows-empty hidden>No workflows match the current filters.</p>
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <aside class="panel workflow-detail-panel" aria-labelledby="workflow-detail-title" data-workflows-detail-root>
172
+ {vm.workflows.map((workflow) => {
173
+ const operational = isOperational(workflow.key);
174
+ const run = isOperational(workflow.key) ? runOperationalWorkflow(workflow.key, envelope, workflow.approvalMode) : null;
175
+ return (
176
+ <div class="workflow-detail-record" data-workflows-detail-record={workflow.key} hidden={workflow.key !== defaultWorkflow?.key}>
177
+ <div class="panel-head">
178
+ <h3 id={workflow.key === defaultWorkflow?.key ? "workflow-detail-title" : undefined}><svg><use href="#i-shield"></use></svg>{workflow.name}</h3>
179
+ <span class:list={["chip", operational ? "teal" : STATUS_TONE[workflow.status]]}>{operational ? "Operational" : STATUS_LABEL[workflow.status]}</span>
180
+ </div>
181
+ <div class="panel-body grid">
182
+ <div class="workflow-summary">
183
+ <span class="eyebrow">{workflow.triggerType}</span>
184
+ <strong>{workflow.cadence}</strong>
185
+ <p>{run?.recommendation.summary ?? "No suggested action yet — scaffold stage, no source data connected."}</p>
186
+ </div>
187
+
188
+ <div class="grid cols-2 workflow-detail-metrics">
189
+ <div class="field">
190
+ <label>Owner</label>
191
+ <strong>{run?.recommendation.owner ?? workflow.owner}</strong>
192
+ <p>Last run {formatTime(workflow.lastRunAt)}</p>
193
+ </div>
194
+ <div class="field">
195
+ <label>Approval mode</label>
196
+ <strong>{APPROVAL_LABEL[workflow.approvalMode]}</strong>
197
+ <p>Next run {formatTime(workflow.nextRunAt)}</p>
198
+ </div>
199
+ </div>
200
+
201
+ {run && (
202
+ <div class="field workflow-confidence">
203
+ <label>Confidence</label>
204
+ <strong>{Math.round(run.recommendation.confidence * 100)}%</strong>
205
+ <p>Derived from real mock source data this run, not a fixed number.</p>
206
+ </div>
207
+ )}
208
+
209
+ <div class="workflow-evidence">
210
+ <div class="detail-section-head">
211
+ <h4>Source data</h4>
212
+ <span class="chip">{workflow.sourceData.length}</span>
213
+ </div>
214
+ <div class="check-row">
215
+ <div><b>{workflow.sourceData.join(", ") || "None connected"}</b><p>{operational ? "Domains this run actually read from." : "Domains this workflow reads from once execution is wired."}</p></div>
216
+ <strong>{operational ? "Live" : "Scaffold"}</strong>
217
+ <span class:list={["chip", operational ? "teal" : ""]}>{operational ? "Connected" : "Read-only"}</span>
218
+ </div>
219
+ </div>
220
+
221
+ <div class="workflow-evidence">
222
+ <div class="detail-section-head">
223
+ <h4>Evidence links</h4>
224
+ <span class="chip">{run?.recommendation.evidenceRefs.length ?? workflow.evidenceLinks.length}</span>
225
+ </div>
226
+ {(run?.recommendation.evidenceRefs ?? workflow.evidenceLinks).map((link) => (
227
+ <div class="check-row">
228
+ <div><b>{link}</b><p>{operational ? "Resolved from the real evidence graph this run." : "Evidence reference — resolves once the evidence graph is wired."}</p></div>
229
+ <strong>{operational ? "Resolved" : "Linked"}</strong>
230
+ <span class="chip teal">OK</span>
231
+ </div>
232
+ ))}
233
+ </div>
234
+
235
+ <div class="workflow-evidence">
236
+ <div class="detail-section-head">
237
+ <h4>{operational ? "Run history" : "Audit trail"}</h4>
238
+ <span class="chip">{(run?.runHistory ?? workflow.auditTrail).length}</span>
239
+ </div>
240
+ {(run?.runHistory ?? workflow.auditTrail).map((event) => (
241
+ <div class="workflow-run-row">
242
+ <span>{formatTime(event.at)}</span>
243
+ <div><b>{event.action}</b><span class="subtle">{event.operator} · {event.targetTenant}</span></div>
244
+ </div>
245
+ ))}
246
+ {operational && run && run.runHistory.length === 0 && <p class="subtle">No runs recorded yet.</p>}
247
+ </div>
248
+
249
+ {operational && (
250
+ <div class="workflow-approval-gate" aria-label="Approval gate">
251
+ {workflow.approvalMode === "draft_only" && <p class="subtle">Draft only — this recommendation can never auto-apply; a human must author the action from it.</p>}
252
+ {workflow.approvalMode === "approval_required" && <button class="btn" type="button">Request approval</button>}
253
+ {workflow.approvalMode === "guarded_automation" && <button class="btn primary" type="button">Review guarded automation</button>}
254
+ </div>
255
+ )}
256
+ </div>
257
+ </div>
258
+ );
259
+ })}
260
+ </aside>
261
+ </div>
262
+
263
+ <div class="grid cols-3">
264
+ <div class="field workflow-guardrail">
265
+ <label>Mode</label>
266
+ <strong>Control plane only</strong>
267
+ <p>Every workflow here is scaffolded — cadence, owner, and approval mode are set, but nothing executes yet.</p>
268
+ </div>
269
+ <div class="field workflow-guardrail">
270
+ <label>Evidence</label>
271
+ <strong>Linked, not resolved</strong>
272
+ <p>Evidence references are recorded per workflow; resolving them to real records is a later unit.</p>
273
+ </div>
274
+ <div class="field workflow-guardrail">
275
+ <label>Approval</label>
276
+ <strong>Draft / approval / guarded</strong>
277
+ <p>Every workflow declares its approval mode now, so operational execution inherits the right guardrail from day one.</p>
278
+ </div>
279
+ </div>
280
+ </section>
281
+
282
+ <script is:inline nonce={cspNonce}>
283
+ (() => {
284
+ const root = document.querySelector('[data-workflows-target-tenant]');
285
+ if (!root) return;
286
+
287
+ const viewButtons = Array.from(root.querySelectorAll("[data-workflows-view-button]"));
288
+ const searchInput = root.querySelector("[data-workflows-search]");
289
+ const rows = Array.from(root.querySelectorAll("[data-workflows-row]"));
290
+ const emptyState = root.querySelector("[data-workflows-empty]");
291
+ const detailRoot = root.querySelector("[data-workflows-detail-root]");
292
+ const detailRecords = detailRoot ? Array.from(detailRoot.querySelectorAll("[data-workflows-detail-record]")) : [];
293
+
294
+ let activeView = "all";
295
+
296
+ const applyFilters = () => {
297
+ const term = searchInput ? searchInput.value.trim().toLowerCase() : "";
298
+ let visibleCount = 0;
299
+
300
+ for (const row of rows) {
301
+ const viewKeys = (row.dataset.viewKeys ?? "").split(" ");
302
+ const matchesView = viewKeys.includes(activeView);
303
+ const matchesSearch = !term || (row.dataset.searchHaystack ?? "").includes(term);
304
+ const visible = matchesView && matchesSearch;
305
+ row.hidden = !visible;
306
+ if (visible) visibleCount += 1;
307
+ }
308
+
309
+ if (emptyState) emptyState.hidden = visibleCount > 0;
310
+ };
311
+
312
+ const selectWorkflow = (key) => {
313
+ for (const row of rows) {
314
+ row.classList.toggle("selected", row.dataset.workflowKey === key);
315
+ }
316
+ for (const record of detailRecords) {
317
+ record.hidden = record.dataset.workflowsDetailRecord !== key;
318
+ }
319
+ };
320
+
321
+ viewButtons.forEach((button) => {
322
+ button.addEventListener("click", () => {
323
+ activeView = button.dataset.viewKey ?? "all";
324
+ viewButtons.forEach((b) => b.classList.toggle("active", b === button));
325
+ applyFilters();
326
+ });
327
+ });
328
+
329
+ searchInput?.addEventListener("input", applyFilters);
330
+
331
+ root.querySelectorAll("[data-workflows-select-row]").forEach((button) => {
332
+ button.addEventListener("click", () => {
333
+ const key = button.dataset.workflowsSelectRow;
334
+ if (key) selectWorkflow(key);
335
+ });
336
+ });
337
+
338
+ rows.forEach((row) => {
339
+ row.addEventListener("click", (event) => {
340
+ if (event.target instanceof Element && event.target.closest("[data-workflows-select-row]")) return;
341
+ const key = row.dataset.workflowKey;
342
+ if (key) selectWorkflow(key);
343
+ });
344
+ });
345
+
346
+ applyFilters();
347
+ })();
348
+ </script>
349
+
350
+ <style>
351
+ .ai-workflows-tab {
352
+ --workflow-control-bg: #fbfcfc;
353
+ }
354
+
355
+ .ai-workflows-gate .seal {
356
+ background: var(--admin-teal);
357
+ }
358
+
359
+ .workflow-workspace {
360
+ display: grid;
361
+ grid-template-columns: minmax(0, 1.32fr) minmax(320px, 0.68fr);
362
+ gap: 14px;
363
+ align-items: start;
364
+ }
365
+
366
+ .workflow-list-panel,
367
+ .workflow-detail-panel {
368
+ min-width: 0;
369
+ }
370
+
371
+ .workflow-panel-head {
372
+ flex-wrap: wrap;
373
+ }
374
+
375
+ .workflow-table tbody tr {
376
+ cursor: pointer;
377
+ }
378
+
379
+ .workflow-toolbar {
380
+ display: grid;
381
+ grid-template-columns: minmax(220px, 1fr);
382
+ gap: 10px;
383
+ padding: 10px;
384
+ border: 1px solid var(--admin-line);
385
+ border-radius: var(--admin-radius-sm);
386
+ background: var(--workflow-control-bg);
387
+ }
388
+
389
+ .workflow-toolbar label {
390
+ display: grid;
391
+ gap: 5px;
392
+ min-width: 0;
393
+ }
394
+
395
+ .workflow-toolbar span,
396
+ .eyebrow {
397
+ color: var(--admin-muted);
398
+ font-size: 11px;
399
+ font-weight: 760;
400
+ text-transform: uppercase;
401
+ }
402
+
403
+ .workflow-toolbar input {
404
+ min-width: 0;
405
+ min-height: 36px;
406
+ padding: 0 10px;
407
+ border: 1px solid var(--admin-line-strong);
408
+ border-radius: var(--admin-radius-sm);
409
+ background: var(--admin-surface);
410
+ color: var(--admin-ink);
411
+ }
412
+
413
+ .workflow-table {
414
+ min-width: 980px;
415
+ }
416
+
417
+ .workflow-table tr.selected td {
418
+ background: var(--admin-teal-soft);
419
+ }
420
+
421
+ .workflow-empty-state {
422
+ margin: 0;
423
+ padding: 24px 14px;
424
+ color: var(--admin-muted);
425
+ font-size: 13px;
426
+ text-align: center;
427
+ }
428
+
429
+ .workflow-summary {
430
+ display: grid;
431
+ gap: 5px;
432
+ padding: 12px;
433
+ border: 1px solid var(--admin-line);
434
+ border-radius: var(--admin-radius-sm);
435
+ background: var(--admin-surface-soft);
436
+ }
437
+
438
+ .workflow-summary strong {
439
+ font-size: 16px;
440
+ }
441
+
442
+ .workflow-summary p,
443
+ .workflow-run-row p {
444
+ margin: 0;
445
+ color: var(--admin-muted);
446
+ font-size: 12px;
447
+ }
448
+
449
+ .workflow-detail-metrics {
450
+ gap: 10px;
451
+ }
452
+
453
+ .workflow-evidence {
454
+ display: grid;
455
+ gap: 8px;
456
+ }
457
+
458
+ .detail-section-head {
459
+ display: flex;
460
+ align-items: center;
461
+ justify-content: space-between;
462
+ gap: 10px;
463
+ }
464
+
465
+ .detail-section-head h4 {
466
+ margin: 0;
467
+ font-size: 13px;
468
+ }
469
+
470
+ .workflow-run-row {
471
+ display: grid;
472
+ grid-template-columns: 120px minmax(0, 1fr);
473
+ gap: 10px;
474
+ align-items: center;
475
+ padding: 10px 0;
476
+ border-bottom: 1px solid var(--admin-line);
477
+ }
478
+
479
+ .workflow-run-row:last-child {
480
+ border-bottom: 0;
481
+ }
482
+
483
+ .workflow-run-row > span:first-child {
484
+ color: var(--admin-muted);
485
+ font-size: 12px;
486
+ font-weight: 760;
487
+ }
488
+
489
+ .workflow-run-row b {
490
+ display: block;
491
+ font-size: 13px;
492
+ }
493
+
494
+ .workflow-guardrail {
495
+ display: grid;
496
+ gap: 5px;
497
+ align-content: start;
498
+ }
499
+
500
+ .workflow-operational-badge {
501
+ margin-left: 6px;
502
+ }
503
+
504
+ .workflow-confidence {
505
+ display: grid;
506
+ gap: 3px;
507
+ }
508
+
509
+ .workflow-approval-gate {
510
+ padding-top: 4px;
511
+ }
512
+
513
+ .workflow-approval-gate .subtle {
514
+ margin: 0;
515
+ }
516
+
517
+ @media (max-width: 1180px) {
518
+ .workflow-workspace,
519
+ .workflow-toolbar {
520
+ grid-template-columns: 1fr;
521
+ }
522
+ }
523
+
524
+ @media (max-width: 760px) {
525
+ .workflow-run-row,
526
+ .detail-section-head {
527
+ align-items: flex-start;
528
+ grid-template-columns: 1fr;
529
+ }
530
+ }
531
+ </style>