astro-tractstack 2.0.0-rc.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 (427) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +56 -0
  3. package/astro.d.ts +64 -0
  4. package/bin/create-tractstack.js +483 -0
  5. package/dist/config.js +80 -0
  6. package/dist/index.js +2129 -0
  7. package/package.json +89 -0
  8. package/templates/artpacks/kCz/captainBreakfast_1080px.webp +0 -0
  9. package/templates/artpacks/kCz/captainBreakfast_1920px.webp +0 -0
  10. package/templates/artpacks/kCz/captainBreakfast_600px.webp +0 -0
  11. package/templates/artpacks/kCz/cleanDrips_1080px.webp +0 -0
  12. package/templates/artpacks/kCz/cleanDrips_1920px.webp +0 -0
  13. package/templates/artpacks/kCz/cleanDrips_600px.webp +0 -0
  14. package/templates/artpacks/kCz/crispwaves_1080px.webp +0 -0
  15. package/templates/artpacks/kCz/crispwaves_1920px.webp +0 -0
  16. package/templates/artpacks/kCz/crispwaves_600px.webp +0 -0
  17. package/templates/artpacks/kCz/dragonSkin_1080px.webp +0 -0
  18. package/templates/artpacks/kCz/dragonSkin_1920px.webp +0 -0
  19. package/templates/artpacks/kCz/dragonSkin_600px.webp +0 -0
  20. package/templates/artpacks/kCz/dragon_1080px.webp +0 -0
  21. package/templates/artpacks/kCz/dragon_1920px.webp +0 -0
  22. package/templates/artpacks/kCz/dragon_600px.webp +0 -0
  23. package/templates/artpacks/kCz/nightcity_1080px.webp +0 -0
  24. package/templates/artpacks/kCz/nightcity_1920px.webp +0 -0
  25. package/templates/artpacks/kCz/nightcity_600px.webp +0 -0
  26. package/templates/artpacks/kCz/pattern1_1080px.webp +0 -0
  27. package/templates/artpacks/kCz/pattern1_1920px.webp +0 -0
  28. package/templates/artpacks/kCz/pattern1_600px.webp +0 -0
  29. package/templates/artpacks/kCz/pattern2_1080px.webp +0 -0
  30. package/templates/artpacks/kCz/pattern2_1920px.webp +0 -0
  31. package/templates/artpacks/kCz/pattern2_600px.webp +0 -0
  32. package/templates/artpacks/kCz/skindrips_1080px.webp +0 -0
  33. package/templates/artpacks/kCz/skindrips_1920px.webp +0 -0
  34. package/templates/artpacks/kCz/skindrips_600px.webp +0 -0
  35. package/templates/artpacks/kCz/slimetime_1080px.webp +0 -0
  36. package/templates/artpacks/kCz/slimetime_1920px.webp +0 -0
  37. package/templates/artpacks/kCz/slimetime_600px.webp +0 -0
  38. package/templates/artpacks/kCz/snake_1080px.webp +0 -0
  39. package/templates/artpacks/kCz/snake_1920px.webp +0 -0
  40. package/templates/artpacks/kCz/snake_600px.webp +0 -0
  41. package/templates/artpacks/kCz/toxicshock_1080px.webp +0 -0
  42. package/templates/artpacks/kCz/toxicshock_1920px.webp +0 -0
  43. package/templates/artpacks/kCz/toxicshock_600px.webp +0 -0
  44. package/templates/artpacks/kCz/tractstack_1080px.webp +0 -0
  45. package/templates/artpacks/kCz/tractstack_1920px.webp +0 -0
  46. package/templates/artpacks/kCz/tractstack_600px.webp +0 -0
  47. package/templates/artpacks/kCz/tripdrips_1080px.webp +0 -0
  48. package/templates/artpacks/kCz/tripdrips_1920px.webp +0 -0
  49. package/templates/artpacks/kCz/tripdrips_600px.webp +0 -0
  50. package/templates/artpacks/kCz/wavedrips_1080px.webp +0 -0
  51. package/templates/artpacks/kCz/wavedrips_1920px.webp +0 -0
  52. package/templates/artpacks/kCz/wavedrips_600px.webp +0 -0
  53. package/templates/artpacks/t8k/beach_1080px.webp +0 -0
  54. package/templates/artpacks/t8k/beach_1920px.webp +0 -0
  55. package/templates/artpacks/t8k/beach_600px.webp +0 -0
  56. package/templates/artpacks/t8k/blast_1080px.webp +0 -0
  57. package/templates/artpacks/t8k/blast_1920px.webp +0 -0
  58. package/templates/artpacks/t8k/blast_600px.webp +0 -0
  59. package/templates/artpacks/t8k/bokeh_1080px.webp +0 -0
  60. package/templates/artpacks/t8k/bokeh_1920px.webp +0 -0
  61. package/templates/artpacks/t8k/bokeh_600px.webp +0 -0
  62. package/templates/artpacks/t8k/cartoon_1080px.webp +0 -0
  63. package/templates/artpacks/t8k/cartoon_1920px.webp +0 -0
  64. package/templates/artpacks/t8k/cartoon_600px.webp +0 -0
  65. package/templates/artpacks/t8k/darkeggshell_1080px.webp +0 -0
  66. package/templates/artpacks/t8k/darkeggshell_1920px.webp +0 -0
  67. package/templates/artpacks/t8k/darkeggshell_600px.webp +0 -0
  68. package/templates/artpacks/t8k/explosion_1080px.webp +0 -0
  69. package/templates/artpacks/t8k/explosion_1920px.webp +0 -0
  70. package/templates/artpacks/t8k/explosion_600px.webp +0 -0
  71. package/templates/artpacks/t8k/floral_1080px.webp +0 -0
  72. package/templates/artpacks/t8k/floral_1920px.webp +0 -0
  73. package/templates/artpacks/t8k/floral_600px.webp +0 -0
  74. package/templates/artpacks/t8k/flower_1080px.webp +0 -0
  75. package/templates/artpacks/t8k/flower_1920px.webp +0 -0
  76. package/templates/artpacks/t8k/flower_600px.webp +0 -0
  77. package/templates/artpacks/t8k/foliage_1080px.webp +0 -0
  78. package/templates/artpacks/t8k/foliage_1920px.webp +0 -0
  79. package/templates/artpacks/t8k/foliage_600px.webp +0 -0
  80. package/templates/artpacks/t8k/mist_1080px.webp +0 -0
  81. package/templates/artpacks/t8k/mist_1920px.webp +0 -0
  82. package/templates/artpacks/t8k/mist_600px.webp +0 -0
  83. package/templates/artpacks/t8k/portal_1080px.webp +0 -0
  84. package/templates/artpacks/t8k/portal_1920px.webp +0 -0
  85. package/templates/artpacks/t8k/portal_600px.webp +0 -0
  86. package/templates/artpacks/t8k/storytime_1080px.webp +0 -0
  87. package/templates/artpacks/t8k/storytime_1920px.webp +0 -0
  88. package/templates/artpacks/t8k/storytime_600px.webp +0 -0
  89. package/templates/artpacks/t8k/tacky_1080px.webp +0 -0
  90. package/templates/artpacks/t8k/tacky_1920px.webp +0 -0
  91. package/templates/artpacks/t8k/tacky_600px.webp +0 -0
  92. package/templates/artpacks/t8k/wallpaper_1080px.webp +0 -0
  93. package/templates/artpacks/t8k/wallpaper_1920px.webp +0 -0
  94. package/templates/artpacks/t8k/wallpaper_600px.webp +0 -0
  95. package/templates/brand/favicon.ico +0 -0
  96. package/templates/brand/logo.svg +19 -0
  97. package/templates/brand/static.jpg +0 -0
  98. package/templates/brand/wordmark.svg +4 -0
  99. package/templates/css/custom.css +51 -0
  100. package/templates/css/frontend.css +3519 -0
  101. package/templates/css/storykeep.css +92872 -0
  102. package/templates/custom/minimal/CodeHook.astro +53 -0
  103. package/templates/custom/minimal/CustomRoutes.astro +46 -0
  104. package/templates/custom/with-examples/CodeHook.astro +49 -0
  105. package/templates/custom/with-examples/CustomHero.astro +13 -0
  106. package/templates/custom/with-examples/CustomRoutes.astro +39 -0
  107. package/templates/custom/with-examples/pages/Collections.astro +110 -0
  108. package/templates/env.example +8 -0
  109. package/templates/fonts/Inter-Black.woff2 +0 -0
  110. package/templates/fonts/Inter-Bold.woff2 +0 -0
  111. package/templates/fonts/Inter-Regular.woff2 +0 -0
  112. package/templates/icons/h2.svg +1 -0
  113. package/templates/icons/h3.svg +1 -0
  114. package/templates/icons/h4.svg +1 -0
  115. package/templates/icons/h5.svg +1 -0
  116. package/templates/icons/image.svg +7 -0
  117. package/templates/icons/text.svg +6 -0
  118. package/templates/socials/codepen.svg +1 -0
  119. package/templates/socials/discord.svg +1 -0
  120. package/templates/socials/facebook.svg +1 -0
  121. package/templates/socials/github.svg +1 -0
  122. package/templates/socials/instagram.svg +1 -0
  123. package/templates/socials/linkedin.svg +1 -0
  124. package/templates/socials/mail.svg +1 -0
  125. package/templates/socials/rumble.svg +1 -0
  126. package/templates/socials/tiktok.svg +1 -0
  127. package/templates/socials/twitch.svg +1 -0
  128. package/templates/socials/twitter.svg +1 -0
  129. package/templates/socials/x.svg +1 -0
  130. package/templates/socials/youtube.svg +1 -0
  131. package/templates/src/client/analytics-events.ts +213 -0
  132. package/templates/src/client/belief-events.ts +205 -0
  133. package/templates/src/client/sse.ts +667 -0
  134. package/templates/src/components/Footer.astro +246 -0
  135. package/templates/src/components/Fragment.astro +70 -0
  136. package/templates/src/components/Header.astro +458 -0
  137. package/templates/src/components/Menu.tsx +196 -0
  138. package/templates/src/components/codehooks/BunnyVideoSetup.tsx +692 -0
  139. package/templates/src/components/codehooks/BunnyVideoWrapper.astro +78 -0
  140. package/templates/src/components/codehooks/EpinetDurationSelector.tsx +1020 -0
  141. package/templates/src/components/codehooks/EpinetTableView.tsx +594 -0
  142. package/templates/src/components/codehooks/EpinetWrapper.tsx +424 -0
  143. package/templates/src/components/codehooks/FeaturedContent.astro +273 -0
  144. package/templates/src/components/codehooks/FeaturedContentSetup.tsx +738 -0
  145. package/templates/src/components/codehooks/ListContent.astro +460 -0
  146. package/templates/src/components/codehooks/ListContentSetup.tsx +649 -0
  147. package/templates/src/components/codehooks/SankeyDiagram.tsx +359 -0
  148. package/templates/src/components/compositor/Compositor.tsx +144 -0
  149. package/templates/src/components/compositor/Node.tsx +415 -0
  150. package/templates/src/components/compositor/NodeWithGuid.tsx +25 -0
  151. package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +87 -0
  152. package/templates/src/components/compositor/elements/Belief.tsx +148 -0
  153. package/templates/src/components/compositor/elements/BgImage.tsx +118 -0
  154. package/templates/src/components/compositor/elements/BgVisualBreak.tsx +102 -0
  155. package/templates/src/components/compositor/elements/BunnyVideo.tsx +63 -0
  156. package/templates/src/components/compositor/elements/IdentifyAs.tsx +66 -0
  157. package/templates/src/components/compositor/elements/PlayButton.tsx +19 -0
  158. package/templates/src/components/compositor/elements/SignUp.tsx +179 -0
  159. package/templates/src/components/compositor/elements/Svg.tsx +33 -0
  160. package/templates/src/components/compositor/elements/ToggleBelief.tsx +36 -0
  161. package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +33 -0
  162. package/templates/src/components/compositor/nodes/BgPaneWrapper.tsx +35 -0
  163. package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +189 -0
  164. package/templates/src/components/compositor/nodes/Markdown.tsx +179 -0
  165. package/templates/src/components/compositor/nodes/Pane.tsx +277 -0
  166. package/templates/src/components/compositor/nodes/Pane_eraser.tsx +69 -0
  167. package/templates/src/components/compositor/nodes/Pane_layout.tsx +77 -0
  168. package/templates/src/components/compositor/nodes/RenderChildren.tsx +19 -0
  169. package/templates/src/components/compositor/nodes/StoryFragment.tsx +35 -0
  170. package/templates/src/components/compositor/nodes/TagElement.tsx +14 -0
  171. package/templates/src/components/compositor/nodes/Widget.tsx +115 -0
  172. package/templates/src/components/compositor/nodes/tagElements/NodeA.tsx +4 -0
  173. package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +26 -0
  174. package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +248 -0
  175. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +684 -0
  176. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +62 -0
  177. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +120 -0
  178. package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +62 -0
  179. package/templates/src/components/compositor/nodes/tagElements/NodeButton.tsx +5 -0
  180. package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +26 -0
  181. package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +28 -0
  182. package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +18 -0
  183. package/templates/src/components/compositor/nodes/tagElements/TabIndicator.tsx +51 -0
  184. package/templates/src/components/compositor/preview/FeaturedContentPreview.tsx +128 -0
  185. package/templates/src/components/compositor/preview/ListContentPreview.tsx +213 -0
  186. package/templates/src/components/compositor/preview/OgImagePreview.tsx +223 -0
  187. package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +199 -0
  188. package/templates/src/components/compositor/preview/PanesPreviewGenerator.tsx +123 -0
  189. package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +154 -0
  190. package/templates/src/components/edit/Header.tsx +181 -0
  191. package/templates/src/components/edit/PanelSwitch.tsx +446 -0
  192. package/templates/src/components/edit/SettingsPanel.tsx +70 -0
  193. package/templates/src/components/edit/ToolBar.tsx +101 -0
  194. package/templates/src/components/edit/ToolMode.tsx +121 -0
  195. package/templates/src/components/edit/context/ContextPaneConfig.tsx +91 -0
  196. package/templates/src/components/edit/context/ContextPaneConfig_slug.tsx +174 -0
  197. package/templates/src/components/edit/context/ContextPaneConfig_title.tsx +186 -0
  198. package/templates/src/components/edit/pane/AddPanePanel.tsx +136 -0
  199. package/templates/src/components/edit/pane/AddPanePanel_break.tsx +470 -0
  200. package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +264 -0
  201. package/templates/src/components/edit/pane/AddPanePanel_new.tsx +623 -0
  202. package/templates/src/components/edit/pane/AddPanePanel_newAICopy.tsx +107 -0
  203. package/templates/src/components/edit/pane/AddPanePanel_newAICopy_modal.tsx +217 -0
  204. package/templates/src/components/edit/pane/AddPanePanel_newCopyMode.tsx +109 -0
  205. package/templates/src/components/edit/pane/AddPanePanel_newCustomCopy.tsx +39 -0
  206. package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +445 -0
  207. package/templates/src/components/edit/pane/ConfigPanePanel.tsx +245 -0
  208. package/templates/src/components/edit/pane/PageGen.tsx +485 -0
  209. package/templates/src/components/edit/pane/PageGenSelector.tsx +238 -0
  210. package/templates/src/components/edit/pane/PageGenSpecial.tsx +362 -0
  211. package/templates/src/components/edit/pane/PageGen_preview.tsx +495 -0
  212. package/templates/src/components/edit/pane/PanePanel_impression.tsx +258 -0
  213. package/templates/src/components/edit/pane/PanePanel_path.tsx +268 -0
  214. package/templates/src/components/edit/pane/PanePanel_slug.tsx +219 -0
  215. package/templates/src/components/edit/pane/PanePanel_title.tsx +142 -0
  216. package/templates/src/components/edit/panels/StyleBreakPanel.tsx +182 -0
  217. package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +439 -0
  218. package/templates/src/components/edit/panels/StyleElementPanel.tsx +177 -0
  219. package/templates/src/components/edit/panels/StyleElementPanel_add.tsx +349 -0
  220. package/templates/src/components/edit/panels/StyleElementPanel_remove.tsx +159 -0
  221. package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +320 -0
  222. package/templates/src/components/edit/panels/StyleImagePanel.tsx +460 -0
  223. package/templates/src/components/edit/panels/StyleImagePanel_add.tsx +296 -0
  224. package/templates/src/components/edit/panels/StyleImagePanel_remove.tsx +153 -0
  225. package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +312 -0
  226. package/templates/src/components/edit/panels/StyleLiElementPanel.tsx +273 -0
  227. package/templates/src/components/edit/panels/StyleLiElementPanel_add.tsx +301 -0
  228. package/templates/src/components/edit/panels/StyleLiElementPanel_remove.tsx +132 -0
  229. package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +313 -0
  230. package/templates/src/components/edit/panels/StyleLinkPanel.tsx +346 -0
  231. package/templates/src/components/edit/panels/StyleLinkPanel_add.tsx +265 -0
  232. package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +240 -0
  233. package/templates/src/components/edit/panels/StyleLinkPanel_remove.tsx +94 -0
  234. package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +110 -0
  235. package/templates/src/components/edit/panels/StyleParentPanel.tsx +263 -0
  236. package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +275 -0
  237. package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +112 -0
  238. package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +87 -0
  239. package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +141 -0
  240. package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +428 -0
  241. package/templates/src/components/edit/panels/StyleWidgetPanel_add.tsx +292 -0
  242. package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +190 -0
  243. package/templates/src/components/edit/panels/StyleWidgetPanel_remove.tsx +152 -0
  244. package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +308 -0
  245. package/templates/src/components/edit/state/SaveModal.tsx +811 -0
  246. package/templates/src/components/edit/state/StylesMemory.tsx +310 -0
  247. package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +289 -0
  248. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +320 -0
  249. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +888 -0
  250. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +269 -0
  251. package/templates/src/components/edit/storyfragment/StoryFragmentPanel_title.tsx +190 -0
  252. package/templates/src/components/edit/widgets/BeliefWidget.tsx +183 -0
  253. package/templates/src/components/edit/widgets/BunnyWidget.tsx +134 -0
  254. package/templates/src/components/edit/widgets/IdentifyAsWidget.tsx +193 -0
  255. package/templates/src/components/edit/widgets/SignupWidget.tsx +177 -0
  256. package/templates/src/components/edit/widgets/ToggleWidget.tsx +152 -0
  257. package/templates/src/components/edit/widgets/YouTubeWidget.tsx +65 -0
  258. package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +353 -0
  259. package/templates/src/components/fields/ArtpackImage.tsx +480 -0
  260. package/templates/src/components/fields/BackgroundImage.tsx +530 -0
  261. package/templates/src/components/fields/BackgroundImageWrapper.tsx +192 -0
  262. package/templates/src/components/fields/BooleanParam.tsx +67 -0
  263. package/templates/src/components/fields/BunnyMomentSelector.tsx +56 -0
  264. package/templates/src/components/fields/ColorPickerCombo.tsx +284 -0
  265. package/templates/src/components/fields/ImageUpload.tsx +405 -0
  266. package/templates/src/components/fields/MultiParam.tsx +75 -0
  267. package/templates/src/components/fields/PaneBreakCollectionSelector.tsx +97 -0
  268. package/templates/src/components/fields/PaneBreakShapeSelector.tsx +134 -0
  269. package/templates/src/components/fields/SelectedTailwindClass.tsx +44 -0
  270. package/templates/src/components/fields/SingleParam.tsx +73 -0
  271. package/templates/src/components/fields/ViewportComboBox.tsx +252 -0
  272. package/templates/src/components/form/ActionBuilderField.tsx +282 -0
  273. package/templates/src/components/form/ActionBuilderSlugSelector.tsx +182 -0
  274. package/templates/src/components/form/BooleanToggle.tsx +94 -0
  275. package/templates/src/components/form/ColorPicker.tsx +153 -0
  276. package/templates/src/components/form/DateTimeInput.tsx +638 -0
  277. package/templates/src/components/form/EnumSelect.tsx +88 -0
  278. package/templates/src/components/form/FileUpload.tsx +465 -0
  279. package/templates/src/components/form/MagicPathBuilder.tsx +546 -0
  280. package/templates/src/components/form/NumberInput.tsx +101 -0
  281. package/templates/src/components/form/ParagraphArrayInput.tsx +207 -0
  282. package/templates/src/components/form/StringArrayInput.tsx +163 -0
  283. package/templates/src/components/form/StringInput.tsx +88 -0
  284. package/templates/src/components/form/UnsavedChangesBar.tsx +295 -0
  285. package/templates/src/components/form/advanced/APIConfigSection.tsx +69 -0
  286. package/templates/src/components/form/advanced/AuthConfigSection.tsx +97 -0
  287. package/templates/src/components/form/brand/BrandAssetsSection.tsx +93 -0
  288. package/templates/src/components/form/brand/BrandColorsSection.tsx +201 -0
  289. package/templates/src/components/form/brand/SEOSection.tsx +101 -0
  290. package/templates/src/components/form/brand/SiteConfigSection.tsx +61 -0
  291. package/templates/src/components/form/brand/SocialLinksSection.tsx +393 -0
  292. package/templates/src/components/profile/ProfileConsent.tsx +65 -0
  293. package/templates/src/components/profile/ProfileCreate.tsx +462 -0
  294. package/templates/src/components/profile/ProfileEdit.tsx +409 -0
  295. package/templates/src/components/profile/ProfileSwitch.tsx +255 -0
  296. package/templates/src/components/profile/ProfileUnlock.tsx +221 -0
  297. package/templates/src/components/storykeep/Dashboard.tsx +160 -0
  298. package/templates/src/components/storykeep/Dashboard_Activity.tsx +56 -0
  299. package/templates/src/components/storykeep/Dashboard_Advanced.tsx +165 -0
  300. package/templates/src/components/storykeep/Dashboard_Analytics.tsx +451 -0
  301. package/templates/src/components/storykeep/Dashboard_Branding.tsx +95 -0
  302. package/templates/src/components/storykeep/Dashboard_Content.tsx +191 -0
  303. package/templates/src/components/storykeep/controls/UsageCell.tsx +71 -0
  304. package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +378 -0
  305. package/templates/src/components/storykeep/controls/content/BeliefTable.tsx +329 -0
  306. package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +385 -0
  307. package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +149 -0
  308. package/templates/src/components/storykeep/controls/content/KnownResourceForm.tsx +397 -0
  309. package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +260 -0
  310. package/templates/src/components/storykeep/controls/content/ManageContent.tsx +439 -0
  311. package/templates/src/components/storykeep/controls/content/MenuForm.tsx +239 -0
  312. package/templates/src/components/storykeep/controls/content/MenuTable.tsx +332 -0
  313. package/templates/src/components/storykeep/controls/content/ResourceBulkIngest.tsx +724 -0
  314. package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +355 -0
  315. package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +222 -0
  316. package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +482 -0
  317. package/templates/src/components/storykeep/state/BrandingWrapper.tsx +42 -0
  318. package/templates/src/components/storykeep/state/FetchAnalytics.tsx +350 -0
  319. package/templates/src/components/storykeep/widgets/ResponsiveLine.tsx +319 -0
  320. package/templates/src/components/storykeep/widgets/Wizard.tsx +278 -0
  321. package/templates/src/components/tenant/RegistrationForm.tsx +447 -0
  322. package/templates/src/components/widgets/BunnyVideoHero.astro +775 -0
  323. package/templates/src/components/widgets/Impression.tsx +102 -0
  324. package/templates/src/components/widgets/ImpressionWrapper.tsx +214 -0
  325. package/templates/src/constants/beliefs.ts +61 -0
  326. package/templates/src/constants/brandThemes.ts +133 -0
  327. package/templates/src/constants/prompts.json +55 -0
  328. package/templates/src/constants/shapes.ts +556 -0
  329. package/templates/src/constants/stopWords.ts +116 -0
  330. package/templates/src/constants/tailwindColors.json +344 -0
  331. package/templates/src/constants.ts +274 -0
  332. package/templates/src/hooks/useFormState.ts +203 -0
  333. package/templates/src/layouts/Layout.astro +290 -0
  334. package/templates/src/lib/session.ts +126 -0
  335. package/templates/src/lib/storyData.ts +56 -0
  336. package/templates/src/middleware.ts +52 -0
  337. package/templates/src/pages/404.astro +54 -0
  338. package/templates/src/pages/[...slug]/edit.astro +216 -0
  339. package/templates/src/pages/[...slug].astro +148 -0
  340. package/templates/src/pages/api/auth/decode.ts +101 -0
  341. package/templates/src/pages/api/auth/login.ts +122 -0
  342. package/templates/src/pages/api/auth/logout.ts +37 -0
  343. package/templates/src/pages/api/auth/profile.ts +76 -0
  344. package/templates/src/pages/api/orphan-analysis.ts +106 -0
  345. package/templates/src/pages/api/tailwind.ts +116 -0
  346. package/templates/src/pages/collections/[param1].astro +65 -0
  347. package/templates/src/pages/context/[...contextSlug]/edit.astro +207 -0
  348. package/templates/src/pages/context/[...contextSlug].astro +161 -0
  349. package/templates/src/pages/llms.txt.ts +122 -0
  350. package/templates/src/pages/maint.astro +183 -0
  351. package/templates/src/pages/media/[...slug].astro +67 -0
  352. package/templates/src/pages/robots.txt.ts +36 -0
  353. package/templates/src/pages/sandbox/activate.astro +258 -0
  354. package/templates/src/pages/sandbox/register.astro +44 -0
  355. package/templates/src/pages/sandbox/success.astro +179 -0
  356. package/templates/src/pages/sitemap.xml.ts +119 -0
  357. package/templates/src/pages/storykeep/advanced.astro +69 -0
  358. package/templates/src/pages/storykeep/branding.astro +57 -0
  359. package/templates/src/pages/storykeep/content.astro +71 -0
  360. package/templates/src/pages/storykeep/init.astro +36 -0
  361. package/templates/src/pages/storykeep/login.astro +266 -0
  362. package/templates/src/pages/storykeep/logout.astro +84 -0
  363. package/templates/src/pages/storykeep/profile.astro +98 -0
  364. package/templates/src/pages/storykeep.astro +81 -0
  365. package/templates/src/stores/analytics.ts +171 -0
  366. package/templates/src/stores/backend.ts +16 -0
  367. package/templates/src/stores/navigation.ts +149 -0
  368. package/templates/src/stores/nodes.ts +2390 -0
  369. package/templates/src/stores/nodesHistory.ts +85 -0
  370. package/templates/src/stores/notificationSystem.ts +41 -0
  371. package/templates/src/stores/orphanAnalysis.ts +409 -0
  372. package/templates/src/stores/storykeep.ts +247 -0
  373. package/templates/src/types/astro.ts +86 -0
  374. package/templates/src/types/compositorTypes.ts +456 -0
  375. package/templates/src/types/formTypes.ts +281 -0
  376. package/templates/src/types/multiTenant.ts +77 -0
  377. package/templates/src/types/nodeProps.ts +66 -0
  378. package/templates/src/types/tractstack.ts +445 -0
  379. package/templates/src/utils/aai/getTitleSlug.ts +72 -0
  380. package/templates/src/utils/actions/actionButton.ts +101 -0
  381. package/templates/src/utils/actions/lispLexer.ts +57 -0
  382. package/templates/src/utils/actions/preParse_Action.ts +85 -0
  383. package/templates/src/utils/actions/preParse_Bunny.ts +50 -0
  384. package/templates/src/utils/actions/preParse_Clicked.ts +87 -0
  385. package/templates/src/utils/actions/preParse_Impression.ts +71 -0
  386. package/templates/src/utils/api/advancedConfig.ts +66 -0
  387. package/templates/src/utils/api/advancedHelpers.ts +134 -0
  388. package/templates/src/utils/api/beliefConfig.ts +87 -0
  389. package/templates/src/utils/api/beliefHelpers.ts +196 -0
  390. package/templates/src/utils/api/brandConfig.ts +126 -0
  391. package/templates/src/utils/api/brandHelpers.ts +155 -0
  392. package/templates/src/utils/api/fileHelpers.ts +306 -0
  393. package/templates/src/utils/api/menuConfig.ts +57 -0
  394. package/templates/src/utils/api/menuHelpers.ts +156 -0
  395. package/templates/src/utils/api/resourceConfig.ts +158 -0
  396. package/templates/src/utils/api/resourceHelpers.ts +72 -0
  397. package/templates/src/utils/api/tenantConfig.ts +97 -0
  398. package/templates/src/utils/api/tenantHelpers.ts +172 -0
  399. package/templates/src/utils/api.ts +183 -0
  400. package/templates/src/utils/auth.ts +150 -0
  401. package/templates/src/utils/backend.ts +243 -0
  402. package/templates/src/utils/compositor/TemplateMarkdowns.ts +118 -0
  403. package/templates/src/utils/compositor/TemplateNodes.ts +138 -0
  404. package/templates/src/utils/compositor/TemplatePanes.ts +100 -0
  405. package/templates/src/utils/compositor/allowInsert.ts +100 -0
  406. package/templates/src/utils/compositor/domHelpers.ts +37 -0
  407. package/templates/src/utils/compositor/handleClickEvent.ts +131 -0
  408. package/templates/src/utils/compositor/nodesHelper.ts +491 -0
  409. package/templates/src/utils/compositor/nodesMarkdownGenerator.ts +292 -0
  410. package/templates/src/utils/compositor/processMarkdown.ts +431 -0
  411. package/templates/src/utils/compositor/reduceNodesClassNames.ts +192 -0
  412. package/templates/src/utils/compositor/tailwindClasses.ts +1795 -0
  413. package/templates/src/utils/compositor/tailwindColors.ts +227 -0
  414. package/templates/src/utils/compositor/templateMarkdownStyles.ts +1265 -0
  415. package/templates/src/utils/compositor/typeGuards.ts +193 -0
  416. package/templates/src/utils/etl/extractor.ts +119 -0
  417. package/templates/src/utils/etl/index.ts +88 -0
  418. package/templates/src/utils/etl/loader.ts +36 -0
  419. package/templates/src/utils/etl/transformer.ts +286 -0
  420. package/templates/src/utils/helpers.ts +435 -0
  421. package/templates/src/utils/layout.ts +209 -0
  422. package/templates/src/utils/profileStorage.ts +306 -0
  423. package/templates/src/utils/useInterval.ts +27 -0
  424. package/templates/tailwind.config.cjs +169 -0
  425. package/utils/create-resolver.ts +10 -0
  426. package/utils/inject-files.ts +2140 -0
  427. package/utils/validate-config.ts +43 -0
@@ -0,0 +1,85 @@
1
+ import { atom, type WritableAtom } from 'nanostores';
2
+ import type { NodesContext } from '@/stores/nodes.ts';
3
+
4
+ export enum PatchOp {
5
+ ADD,
6
+ REMOVE,
7
+ REPLACE,
8
+ }
9
+
10
+ export type HistoryPatch = {
11
+ op: PatchOp;
12
+ undo: (ctx: NodesContext) => void;
13
+ redo: (ctx: NodesContext) => void;
14
+ };
15
+
16
+ export class NodesHistory {
17
+ public history: WritableAtom<HistoryPatch[]> = atom([]);
18
+ public headIndex: WritableAtom<number> = atom(0);
19
+
20
+ protected _ctx: NodesContext;
21
+ protected _maxBuffer: number;
22
+ private _debounceTimer: ReturnType<typeof setTimeout> | null = null;
23
+ private _pendingPatch: HistoryPatch | null = null;
24
+
25
+ constructor(ctx: NodesContext, maxBuffer: number) {
26
+ this._ctx = ctx;
27
+ this._maxBuffer = maxBuffer;
28
+ }
29
+
30
+ canUndo(): boolean {
31
+ return (
32
+ this.history.get().length > 0 &&
33
+ this.headIndex.get() < this.history.get().length
34
+ );
35
+ }
36
+
37
+ canRedo(): boolean {
38
+ return this.history.get().length > 0 && this.headIndex.get() > 0;
39
+ }
40
+
41
+ addPatch(patch: HistoryPatch) {
42
+ this._pendingPatch = patch;
43
+
44
+ if (this._debounceTimer) {
45
+ clearTimeout(this._debounceTimer);
46
+ }
47
+
48
+ this._debounceTimer = setTimeout(() => {
49
+ if (this._pendingPatch) {
50
+ // Original addPatch logic
51
+ while (this.headIndex.get() !== 0) {
52
+ this.history.get().shift();
53
+ this.headIndex.set(this.headIndex.get() - 1);
54
+ }
55
+
56
+ this.history.get().unshift(this._pendingPatch);
57
+ if (this.history.get().length > this._maxBuffer) {
58
+ this.history.get().pop();
59
+ }
60
+ this.history.set([...this.history.get()]);
61
+
62
+ this._pendingPatch = null;
63
+ }
64
+ }, 300);
65
+ }
66
+
67
+ undo() {
68
+ if (this.headIndex.get() < this.history.get().length) {
69
+ this.history.get()[this.headIndex.get()].undo(this._ctx);
70
+ this.headIndex.set(this.headIndex.get() + 1);
71
+ }
72
+ }
73
+
74
+ redo() {
75
+ if (this.headIndex.get() > 0) {
76
+ this.history.get()[this.headIndex.get() - 1].redo(this._ctx);
77
+ this.headIndex.set(this.headIndex.get() - 1);
78
+ }
79
+ }
80
+
81
+ clearHistory() {
82
+ this.history.set([]);
83
+ this.headIndex.set(0);
84
+ }
85
+ }
@@ -0,0 +1,41 @@
1
+ export type Callback<T> = (payload?: T) => void;
2
+
3
+ export class NotificationSystem<T> {
4
+ private subscriptions: Map<string, Set<Callback<T>>> = new Map();
5
+
6
+ /**
7
+ * Subscribe to a specific key
8
+ * @param key - The key to listen for updates
9
+ * @param callback - The callback to invoke on updates
10
+ * @returns Unsubscribe function
11
+ */
12
+ subscribe(key: string, callback: Callback<T>): () => void {
13
+ if (!this.subscriptions.has(key)) {
14
+ this.subscriptions.set(key, new Set());
15
+ }
16
+ this.subscriptions.get(key)!.add(callback);
17
+
18
+ return () => {
19
+ this.subscriptions.get(key)?.delete(callback);
20
+ if (this.subscriptions.get(key)?.size === 0) {
21
+ this.subscriptions.delete(key);
22
+ }
23
+ };
24
+ }
25
+
26
+ clear(): void {
27
+ this.subscriptions.clear();
28
+ }
29
+
30
+ /**
31
+ * Notify subscribers for a specific key with a payload
32
+ * @param key - The key to notify about
33
+ * @param payload - The payload to send to subscribers
34
+ */
35
+ notify(key: string, payload?: T): void {
36
+ const subscribers = this.subscriptions.get(key);
37
+ if (subscribers) {
38
+ subscribers.forEach((callback) => callback(payload));
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,409 @@
1
+ import { atom } from 'nanostores';
2
+
3
+ export interface OrphanAnalysisData {
4
+ storyFragments: Record<string, string[]>;
5
+ panes: Record<string, string[]>;
6
+ menus: Record<string, string[]>;
7
+ files: Record<string, string[]>;
8
+ resources: Record<string, string[]>;
9
+ beliefs: Record<string, string[]>;
10
+ epinets: Record<string, string[]>;
11
+ tractstacks: Record<string, string[]>;
12
+ status: 'loading' | 'complete';
13
+ }
14
+
15
+ export interface OrphanAnalysisState {
16
+ data: OrphanAnalysisData | null;
17
+ isLoading: boolean;
18
+ error: string | null;
19
+ lastFetched: number | null;
20
+ }
21
+
22
+ // Internal tenant-keyed storage
23
+ const tenantOrphanAnalysis = atom<Record<string, OrphanAnalysisState>>({});
24
+
25
+ // Helper to get current tenant ID
26
+ function getCurrentTenantId(): string {
27
+ if (typeof window !== 'undefined' && window.TRACTSTACK_CONFIG?.tenantId) {
28
+ return window.TRACTSTACK_CONFIG.tenantId;
29
+ }
30
+ return import.meta.env.PUBLIC_TENANTID || 'default';
31
+ }
32
+
33
+ // Default state
34
+ const defaultOrphanState: OrphanAnalysisState = {
35
+ data: null,
36
+ isLoading: false,
37
+ error: null,
38
+ lastFetched: null,
39
+ };
40
+
41
+ // Create tenant-aware store that works with useStore
42
+ const createOrphanAnalysisStore = () => {
43
+ const store = {
44
+ get: () => {
45
+ const tenantId = getCurrentTenantId();
46
+ return tenantOrphanAnalysis.get()[tenantId] || defaultOrphanState;
47
+ },
48
+
49
+ subscribe: (callback: (value: OrphanAnalysisState) => void) => {
50
+ const tenantId = getCurrentTenantId();
51
+ return tenantOrphanAnalysis.subscribe((analysis) => {
52
+ callback(analysis[tenantId] || defaultOrphanState);
53
+ });
54
+ },
55
+
56
+ // Required nanostore properties for useStore
57
+ lc: 0,
58
+ listen: function (callback: any) {
59
+ return this.subscribe(callback);
60
+ },
61
+ notify: function () {},
62
+ off: function () {},
63
+ get value() {
64
+ return this.get();
65
+ },
66
+ set: function () {}, // Orphan store is read-only for components
67
+ };
68
+
69
+ return store;
70
+ };
71
+
72
+ export const orphanAnalysisStore = createOrphanAnalysisStore();
73
+
74
+ // Helper to update state for specific tenant
75
+ function updateTenantState(
76
+ tenantId: string,
77
+ updates: Partial<OrphanAnalysisState>
78
+ ): void {
79
+ const currentStates = tenantOrphanAnalysis.get();
80
+ const currentState = currentStates[tenantId] || defaultOrphanState;
81
+
82
+ tenantOrphanAnalysis.set({
83
+ ...currentStates,
84
+ [tenantId]: {
85
+ ...currentState,
86
+ ...updates,
87
+ },
88
+ });
89
+ }
90
+
91
+ // Helper function to count orphans from the analysis data
92
+ export function countOrphans(data: OrphanAnalysisData | null): number {
93
+ if (!data) return 0;
94
+
95
+ let orphanCount = 0;
96
+
97
+ Object.values(data.storyFragments || {}).forEach((deps) => {
98
+ if (deps.length === 0) orphanCount++;
99
+ });
100
+
101
+ Object.values(data.panes || {}).forEach((deps) => {
102
+ if (deps.length === 0) orphanCount++;
103
+ });
104
+
105
+ Object.values(data.menus || {}).forEach((deps) => {
106
+ if (deps.length === 0) orphanCount++;
107
+ });
108
+
109
+ Object.values(data.files || {}).forEach((deps) => {
110
+ if (deps.length === 0) orphanCount++;
111
+ });
112
+
113
+ Object.values(data.resources || {}).forEach((deps) => {
114
+ if (deps.length === 0) orphanCount++;
115
+ });
116
+
117
+ Object.values(data.beliefs || {}).forEach((deps) => {
118
+ if (deps.length === 0) orphanCount++;
119
+ });
120
+
121
+ Object.values(data.epinets || {}).forEach((deps) => {
122
+ if (deps.length === 0) orphanCount++;
123
+ });
124
+
125
+ Object.values(data.tractstacks || {}).forEach((deps) => {
126
+ if (deps.length === 0) orphanCount++;
127
+ });
128
+
129
+ return orphanCount;
130
+ }
131
+
132
+ // API function to fetch orphan analysis
133
+ export async function fetchOrphanAnalysis(): Promise<OrphanAnalysisData> {
134
+ const response = await fetch('/api/orphan-analysis', {
135
+ method: 'GET',
136
+ headers: {
137
+ 'Content-Type': 'application/json',
138
+ 'X-Tenant-ID': getCurrentTenantId(),
139
+ },
140
+ });
141
+
142
+ if (!response.ok) {
143
+ const errorText = await response.text();
144
+ throw new Error(
145
+ `Failed to fetch orphan analysis: ${response.status} ${errorText}`
146
+ );
147
+ }
148
+
149
+ return await response.json();
150
+ }
151
+
152
+ // Enhanced polling state management (per tenant)
153
+ const pollingIntervals = new Map<string, NodeJS.Timeout>();
154
+ const pollingState = new Map<
155
+ string,
156
+ {
157
+ attempts: number;
158
+ startTime: number;
159
+ consecutiveErrors: number;
160
+ lastAttemptTime: number;
161
+ }
162
+ >();
163
+
164
+ // Constants for polling configuration
165
+ const MAX_POLLING_ATTEMPTS = 10;
166
+ const MAX_POLLING_DURATION = 5 * 60 * 1000; // 5 minutes in milliseconds
167
+ const BASE_POLLING_INTERVAL = 2000; // 2 seconds base interval
168
+ const MAX_POLLING_INTERVAL = 32000; // 32 seconds max interval
169
+
170
+ const fetchingStates = new Map<string, boolean>();
171
+
172
+ export async function loadOrphanAnalysis(): Promise<void> {
173
+ const tenantId = getCurrentTenantId();
174
+ const currentState =
175
+ tenantOrphanAnalysis.get()[tenantId] || defaultOrphanState;
176
+
177
+ // Don't reload if we've fetched in the last 5 minutes and it's complete
178
+ const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;
179
+ if (
180
+ currentState.lastFetched &&
181
+ currentState.lastFetched > fiveMinutesAgo &&
182
+ currentState.data &&
183
+ currentState.data.status === 'complete'
184
+ ) {
185
+ return;
186
+ }
187
+
188
+ // Prevent duplicate concurrent requests
189
+ if (fetchingStates.get(tenantId)) {
190
+ return;
191
+ }
192
+
193
+ fetchingStates.set(tenantId, true);
194
+
195
+ // Set loading state
196
+ updateTenantState(tenantId, {
197
+ isLoading: true,
198
+ error: null,
199
+ });
200
+
201
+ try {
202
+ const data = await fetchOrphanAnalysis();
203
+
204
+ updateTenantState(tenantId, {
205
+ data,
206
+ isLoading: false,
207
+ error: null,
208
+ lastFetched: Date.now(),
209
+ });
210
+
211
+ // If status is still "loading", start polling
212
+ if (data.status === 'loading') {
213
+ startPolling(tenantId);
214
+ } else {
215
+ stopPolling(tenantId);
216
+ }
217
+ } catch (error) {
218
+ updateTenantState(tenantId, {
219
+ data: null,
220
+ isLoading: false,
221
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
222
+ lastFetched: null,
223
+ });
224
+ stopPolling(tenantId);
225
+ } finally {
226
+ fetchingStates.set(tenantId, false);
227
+ }
228
+ }
229
+
230
+ function startPolling(tenantId: string): void {
231
+ stopPolling(tenantId);
232
+
233
+ // Initialize polling state
234
+ const startTime = Date.now();
235
+ pollingState.set(tenantId, {
236
+ attempts: 0,
237
+ startTime,
238
+ consecutiveErrors: 0,
239
+ lastAttemptTime: startTime,
240
+ });
241
+
242
+ // Start the first poll immediately
243
+ scheduleNextPoll(tenantId);
244
+ }
245
+
246
+ function scheduleNextPoll(tenantId: string): void {
247
+ const state = pollingState.get(tenantId);
248
+ if (!state) return;
249
+
250
+ // Check if we've exceeded maximum attempts
251
+ if (state.attempts >= MAX_POLLING_ATTEMPTS) {
252
+ console.warn(
253
+ `Orphan analysis polling stopped: Maximum attempts (${MAX_POLLING_ATTEMPTS}) reached for tenant ${tenantId}`
254
+ );
255
+ handlePollingFailure(tenantId, 'Maximum polling attempts reached');
256
+ return;
257
+ }
258
+
259
+ // Check if we've exceeded maximum duration
260
+ const elapsed = Date.now() - state.startTime;
261
+ if (elapsed >= MAX_POLLING_DURATION) {
262
+ console.warn(
263
+ `Orphan analysis polling stopped: Maximum duration (${MAX_POLLING_DURATION}ms) exceeded for tenant ${tenantId}`
264
+ );
265
+ handlePollingFailure(tenantId, 'Polling timeout exceeded');
266
+ return;
267
+ }
268
+
269
+ // Calculate delay using exponential backoff for consecutive errors
270
+ let delay = BASE_POLLING_INTERVAL;
271
+ if (state.consecutiveErrors > 0) {
272
+ // Exponential backoff: 2s → 4s → 8s → 16s → 32s (capped)
273
+ delay = Math.min(
274
+ BASE_POLLING_INTERVAL * Math.pow(2, state.consecutiveErrors),
275
+ MAX_POLLING_INTERVAL
276
+ );
277
+ }
278
+
279
+ // Schedule the next poll
280
+ const timeoutId = setTimeout(() => executePoll(tenantId), delay);
281
+ pollingIntervals.set(tenantId, timeoutId);
282
+ }
283
+
284
+ async function executePoll(tenantId: string): Promise<void> {
285
+ const state = pollingState.get(tenantId);
286
+ if (!state) return;
287
+
288
+ // Update attempt count and last attempt time
289
+ state.attempts++;
290
+ state.lastAttemptTime = Date.now();
291
+
292
+ try {
293
+ const data = await fetchOrphanAnalysis();
294
+
295
+ // Update tenant state with successful fetch
296
+ updateTenantState(tenantId, {
297
+ data,
298
+ lastFetched: Date.now(),
299
+ error: null, // Clear any previous errors
300
+ });
301
+
302
+ // Reset consecutive errors on success
303
+ state.consecutiveErrors = 0;
304
+
305
+ // Check if analysis is complete
306
+ if (data.status === 'complete') {
307
+ stopPolling(tenantId);
308
+ return;
309
+ }
310
+
311
+ // If still loading, schedule next poll
312
+ if (data.status === 'loading') {
313
+ scheduleNextPoll(tenantId);
314
+ } else {
315
+ // Unexpected status - stop polling
316
+ console.warn(
317
+ `Unexpected orphan analysis status: ${data.status} for tenant ${tenantId}`
318
+ );
319
+ handlePollingFailure(tenantId, `Unexpected status: ${data.status}`);
320
+ }
321
+ } catch (error) {
322
+ console.error(`Polling error for tenant ${tenantId}:`, error);
323
+
324
+ // Increment consecutive errors
325
+ state.consecutiveErrors++;
326
+
327
+ // Update tenant state with error
328
+ const errorMessage =
329
+ error instanceof Error ? error.message : 'Unknown polling error';
330
+ updateTenantState(tenantId, {
331
+ error: `Polling error (attempt ${state.attempts}/${MAX_POLLING_ATTEMPTS}): ${errorMessage}`,
332
+ lastFetched: Date.now(),
333
+ });
334
+
335
+ // Check if we should stop polling due to consecutive errors
336
+ if (state.consecutiveErrors >= 5) {
337
+ console.warn(
338
+ `Stopping polling due to ${state.consecutiveErrors} consecutive errors for tenant ${tenantId}`
339
+ );
340
+ handlePollingFailure(
341
+ tenantId,
342
+ `Too many consecutive errors (${state.consecutiveErrors})`
343
+ );
344
+ return;
345
+ }
346
+
347
+ // Schedule next poll with exponential backoff
348
+ scheduleNextPoll(tenantId);
349
+ }
350
+ }
351
+
352
+ function handlePollingFailure(tenantId: string, reason: string): void {
353
+ console.error(
354
+ `Orphan analysis polling failed for tenant ${tenantId}: ${reason}`
355
+ );
356
+
357
+ // Update tenant state with final error
358
+ updateTenantState(tenantId, {
359
+ isLoading: false,
360
+ error: `Orphan analysis polling failed: ${reason}. Please try refreshing the page or contact support if the issue persists.`,
361
+ lastFetched: Date.now(),
362
+ });
363
+
364
+ // Clean up polling state
365
+ stopPolling(tenantId);
366
+ }
367
+
368
+ function stopPolling(tenantId: string): void {
369
+ // Clear any active interval
370
+ const intervalId = pollingIntervals.get(tenantId);
371
+ if (intervalId) {
372
+ clearTimeout(intervalId);
373
+ pollingIntervals.delete(tenantId);
374
+ }
375
+
376
+ // Clean up polling state
377
+ pollingState.delete(tenantId);
378
+ }
379
+
380
+ export function clearOrphanAnalysis(): void {
381
+ const tenantId = getCurrentTenantId();
382
+ stopPolling(tenantId);
383
+ fetchingStates.set(tenantId, false);
384
+
385
+ updateTenantState(tenantId, defaultOrphanState);
386
+ }
387
+
388
+ // Enhanced utility function to get polling status for debugging
389
+ export function getPollingStatus(tenantId?: string): Record<string, any> {
390
+ const targetTenantId = tenantId || getCurrentTenantId();
391
+ const state = pollingState.get(targetTenantId);
392
+ const isActive = pollingIntervals.has(targetTenantId);
393
+
394
+ if (!state && !isActive) {
395
+ return { status: 'inactive', tenantId: targetTenantId };
396
+ }
397
+
398
+ return {
399
+ status: isActive ? 'active' : 'stopped',
400
+ tenantId: targetTenantId,
401
+ attempts: state?.attempts || 0,
402
+ maxAttempts: MAX_POLLING_ATTEMPTS,
403
+ consecutiveErrors: state?.consecutiveErrors || 0,
404
+ startTime: state?.startTime,
405
+ lastAttemptTime: state?.lastAttemptTime,
406
+ elapsed: state?.startTime ? Date.now() - state.startTime : 0,
407
+ maxDuration: MAX_POLLING_DURATION,
408
+ };
409
+ }