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.
- package/LICENSE +110 -0
- package/README.md +56 -0
- package/astro.d.ts +64 -0
- package/bin/create-tractstack.js +483 -0
- package/dist/config.js +80 -0
- package/dist/index.js +2129 -0
- package/package.json +89 -0
- package/templates/artpacks/kCz/captainBreakfast_1080px.webp +0 -0
- package/templates/artpacks/kCz/captainBreakfast_1920px.webp +0 -0
- package/templates/artpacks/kCz/captainBreakfast_600px.webp +0 -0
- package/templates/artpacks/kCz/cleanDrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/cleanDrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/cleanDrips_600px.webp +0 -0
- package/templates/artpacks/kCz/crispwaves_1080px.webp +0 -0
- package/templates/artpacks/kCz/crispwaves_1920px.webp +0 -0
- package/templates/artpacks/kCz/crispwaves_600px.webp +0 -0
- package/templates/artpacks/kCz/dragonSkin_1080px.webp +0 -0
- package/templates/artpacks/kCz/dragonSkin_1920px.webp +0 -0
- package/templates/artpacks/kCz/dragonSkin_600px.webp +0 -0
- package/templates/artpacks/kCz/dragon_1080px.webp +0 -0
- package/templates/artpacks/kCz/dragon_1920px.webp +0 -0
- package/templates/artpacks/kCz/dragon_600px.webp +0 -0
- package/templates/artpacks/kCz/nightcity_1080px.webp +0 -0
- package/templates/artpacks/kCz/nightcity_1920px.webp +0 -0
- package/templates/artpacks/kCz/nightcity_600px.webp +0 -0
- package/templates/artpacks/kCz/pattern1_1080px.webp +0 -0
- package/templates/artpacks/kCz/pattern1_1920px.webp +0 -0
- package/templates/artpacks/kCz/pattern1_600px.webp +0 -0
- package/templates/artpacks/kCz/pattern2_1080px.webp +0 -0
- package/templates/artpacks/kCz/pattern2_1920px.webp +0 -0
- package/templates/artpacks/kCz/pattern2_600px.webp +0 -0
- package/templates/artpacks/kCz/skindrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/skindrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/skindrips_600px.webp +0 -0
- package/templates/artpacks/kCz/slimetime_1080px.webp +0 -0
- package/templates/artpacks/kCz/slimetime_1920px.webp +0 -0
- package/templates/artpacks/kCz/slimetime_600px.webp +0 -0
- package/templates/artpacks/kCz/snake_1080px.webp +0 -0
- package/templates/artpacks/kCz/snake_1920px.webp +0 -0
- package/templates/artpacks/kCz/snake_600px.webp +0 -0
- package/templates/artpacks/kCz/toxicshock_1080px.webp +0 -0
- package/templates/artpacks/kCz/toxicshock_1920px.webp +0 -0
- package/templates/artpacks/kCz/toxicshock_600px.webp +0 -0
- package/templates/artpacks/kCz/tractstack_1080px.webp +0 -0
- package/templates/artpacks/kCz/tractstack_1920px.webp +0 -0
- package/templates/artpacks/kCz/tractstack_600px.webp +0 -0
- package/templates/artpacks/kCz/tripdrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/tripdrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/tripdrips_600px.webp +0 -0
- package/templates/artpacks/kCz/wavedrips_1080px.webp +0 -0
- package/templates/artpacks/kCz/wavedrips_1920px.webp +0 -0
- package/templates/artpacks/kCz/wavedrips_600px.webp +0 -0
- package/templates/artpacks/t8k/beach_1080px.webp +0 -0
- package/templates/artpacks/t8k/beach_1920px.webp +0 -0
- package/templates/artpacks/t8k/beach_600px.webp +0 -0
- package/templates/artpacks/t8k/blast_1080px.webp +0 -0
- package/templates/artpacks/t8k/blast_1920px.webp +0 -0
- package/templates/artpacks/t8k/blast_600px.webp +0 -0
- package/templates/artpacks/t8k/bokeh_1080px.webp +0 -0
- package/templates/artpacks/t8k/bokeh_1920px.webp +0 -0
- package/templates/artpacks/t8k/bokeh_600px.webp +0 -0
- package/templates/artpacks/t8k/cartoon_1080px.webp +0 -0
- package/templates/artpacks/t8k/cartoon_1920px.webp +0 -0
- package/templates/artpacks/t8k/cartoon_600px.webp +0 -0
- package/templates/artpacks/t8k/darkeggshell_1080px.webp +0 -0
- package/templates/artpacks/t8k/darkeggshell_1920px.webp +0 -0
- package/templates/artpacks/t8k/darkeggshell_600px.webp +0 -0
- package/templates/artpacks/t8k/explosion_1080px.webp +0 -0
- package/templates/artpacks/t8k/explosion_1920px.webp +0 -0
- package/templates/artpacks/t8k/explosion_600px.webp +0 -0
- package/templates/artpacks/t8k/floral_1080px.webp +0 -0
- package/templates/artpacks/t8k/floral_1920px.webp +0 -0
- package/templates/artpacks/t8k/floral_600px.webp +0 -0
- package/templates/artpacks/t8k/flower_1080px.webp +0 -0
- package/templates/artpacks/t8k/flower_1920px.webp +0 -0
- package/templates/artpacks/t8k/flower_600px.webp +0 -0
- package/templates/artpacks/t8k/foliage_1080px.webp +0 -0
- package/templates/artpacks/t8k/foliage_1920px.webp +0 -0
- package/templates/artpacks/t8k/foliage_600px.webp +0 -0
- package/templates/artpacks/t8k/mist_1080px.webp +0 -0
- package/templates/artpacks/t8k/mist_1920px.webp +0 -0
- package/templates/artpacks/t8k/mist_600px.webp +0 -0
- package/templates/artpacks/t8k/portal_1080px.webp +0 -0
- package/templates/artpacks/t8k/portal_1920px.webp +0 -0
- package/templates/artpacks/t8k/portal_600px.webp +0 -0
- package/templates/artpacks/t8k/storytime_1080px.webp +0 -0
- package/templates/artpacks/t8k/storytime_1920px.webp +0 -0
- package/templates/artpacks/t8k/storytime_600px.webp +0 -0
- package/templates/artpacks/t8k/tacky_1080px.webp +0 -0
- package/templates/artpacks/t8k/tacky_1920px.webp +0 -0
- package/templates/artpacks/t8k/tacky_600px.webp +0 -0
- package/templates/artpacks/t8k/wallpaper_1080px.webp +0 -0
- package/templates/artpacks/t8k/wallpaper_1920px.webp +0 -0
- package/templates/artpacks/t8k/wallpaper_600px.webp +0 -0
- package/templates/brand/favicon.ico +0 -0
- package/templates/brand/logo.svg +19 -0
- package/templates/brand/static.jpg +0 -0
- package/templates/brand/wordmark.svg +4 -0
- package/templates/css/custom.css +51 -0
- package/templates/css/frontend.css +3519 -0
- package/templates/css/storykeep.css +92872 -0
- package/templates/custom/minimal/CodeHook.astro +53 -0
- package/templates/custom/minimal/CustomRoutes.astro +46 -0
- package/templates/custom/with-examples/CodeHook.astro +49 -0
- package/templates/custom/with-examples/CustomHero.astro +13 -0
- package/templates/custom/with-examples/CustomRoutes.astro +39 -0
- package/templates/custom/with-examples/pages/Collections.astro +110 -0
- package/templates/env.example +8 -0
- package/templates/fonts/Inter-Black.woff2 +0 -0
- package/templates/fonts/Inter-Bold.woff2 +0 -0
- package/templates/fonts/Inter-Regular.woff2 +0 -0
- package/templates/icons/h2.svg +1 -0
- package/templates/icons/h3.svg +1 -0
- package/templates/icons/h4.svg +1 -0
- package/templates/icons/h5.svg +1 -0
- package/templates/icons/image.svg +7 -0
- package/templates/icons/text.svg +6 -0
- package/templates/socials/codepen.svg +1 -0
- package/templates/socials/discord.svg +1 -0
- package/templates/socials/facebook.svg +1 -0
- package/templates/socials/github.svg +1 -0
- package/templates/socials/instagram.svg +1 -0
- package/templates/socials/linkedin.svg +1 -0
- package/templates/socials/mail.svg +1 -0
- package/templates/socials/rumble.svg +1 -0
- package/templates/socials/tiktok.svg +1 -0
- package/templates/socials/twitch.svg +1 -0
- package/templates/socials/twitter.svg +1 -0
- package/templates/socials/x.svg +1 -0
- package/templates/socials/youtube.svg +1 -0
- package/templates/src/client/analytics-events.ts +213 -0
- package/templates/src/client/belief-events.ts +205 -0
- package/templates/src/client/sse.ts +667 -0
- package/templates/src/components/Footer.astro +246 -0
- package/templates/src/components/Fragment.astro +70 -0
- package/templates/src/components/Header.astro +458 -0
- package/templates/src/components/Menu.tsx +196 -0
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +692 -0
- package/templates/src/components/codehooks/BunnyVideoWrapper.astro +78 -0
- package/templates/src/components/codehooks/EpinetDurationSelector.tsx +1020 -0
- package/templates/src/components/codehooks/EpinetTableView.tsx +594 -0
- package/templates/src/components/codehooks/EpinetWrapper.tsx +424 -0
- package/templates/src/components/codehooks/FeaturedContent.astro +273 -0
- package/templates/src/components/codehooks/FeaturedContentSetup.tsx +738 -0
- package/templates/src/components/codehooks/ListContent.astro +460 -0
- package/templates/src/components/codehooks/ListContentSetup.tsx +649 -0
- package/templates/src/components/codehooks/SankeyDiagram.tsx +359 -0
- package/templates/src/components/compositor/Compositor.tsx +144 -0
- package/templates/src/components/compositor/Node.tsx +415 -0
- package/templates/src/components/compositor/NodeWithGuid.tsx +25 -0
- package/templates/src/components/compositor/PanelVisibilityWrapper.tsx +87 -0
- package/templates/src/components/compositor/elements/Belief.tsx +148 -0
- package/templates/src/components/compositor/elements/BgImage.tsx +118 -0
- package/templates/src/components/compositor/elements/BgVisualBreak.tsx +102 -0
- package/templates/src/components/compositor/elements/BunnyVideo.tsx +63 -0
- package/templates/src/components/compositor/elements/IdentifyAs.tsx +66 -0
- package/templates/src/components/compositor/elements/PlayButton.tsx +19 -0
- package/templates/src/components/compositor/elements/SignUp.tsx +179 -0
- package/templates/src/components/compositor/elements/Svg.tsx +33 -0
- package/templates/src/components/compositor/elements/ToggleBelief.tsx +36 -0
- package/templates/src/components/compositor/elements/YouTubeWrapper.tsx +33 -0
- package/templates/src/components/compositor/nodes/BgPaneWrapper.tsx +35 -0
- package/templates/src/components/compositor/nodes/GhostInsertBlock.tsx +189 -0
- package/templates/src/components/compositor/nodes/Markdown.tsx +179 -0
- package/templates/src/components/compositor/nodes/Pane.tsx +277 -0
- package/templates/src/components/compositor/nodes/Pane_eraser.tsx +69 -0
- package/templates/src/components/compositor/nodes/Pane_layout.tsx +77 -0
- package/templates/src/components/compositor/nodes/RenderChildren.tsx +19 -0
- package/templates/src/components/compositor/nodes/StoryFragment.tsx +35 -0
- package/templates/src/components/compositor/nodes/TagElement.tsx +14 -0
- package/templates/src/components/compositor/nodes/Widget.tsx +115 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeA.tsx +4 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeA_eraser.tsx +26 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeAnchorComponent.tsx +248 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +684 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_eraser.tsx +62 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_insert.tsx +120 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag_settings.tsx +62 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeButton.tsx +5 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeButton_eraser.tsx +26 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeImg.tsx +28 -0
- package/templates/src/components/compositor/nodes/tagElements/NodeText.tsx +18 -0
- package/templates/src/components/compositor/nodes/tagElements/TabIndicator.tsx +51 -0
- package/templates/src/components/compositor/preview/FeaturedContentPreview.tsx +128 -0
- package/templates/src/components/compositor/preview/ListContentPreview.tsx +213 -0
- package/templates/src/components/compositor/preview/OgImagePreview.tsx +223 -0
- package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +199 -0
- package/templates/src/components/compositor/preview/PanesPreviewGenerator.tsx +123 -0
- package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +154 -0
- package/templates/src/components/edit/Header.tsx +181 -0
- package/templates/src/components/edit/PanelSwitch.tsx +446 -0
- package/templates/src/components/edit/SettingsPanel.tsx +70 -0
- package/templates/src/components/edit/ToolBar.tsx +101 -0
- package/templates/src/components/edit/ToolMode.tsx +121 -0
- package/templates/src/components/edit/context/ContextPaneConfig.tsx +91 -0
- package/templates/src/components/edit/context/ContextPaneConfig_slug.tsx +174 -0
- package/templates/src/components/edit/context/ContextPaneConfig_title.tsx +186 -0
- package/templates/src/components/edit/pane/AddPanePanel.tsx +136 -0
- package/templates/src/components/edit/pane/AddPanePanel_break.tsx +470 -0
- package/templates/src/components/edit/pane/AddPanePanel_codehook.tsx +264 -0
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +623 -0
- package/templates/src/components/edit/pane/AddPanePanel_newAICopy.tsx +107 -0
- package/templates/src/components/edit/pane/AddPanePanel_newAICopy_modal.tsx +217 -0
- package/templates/src/components/edit/pane/AddPanePanel_newCopyMode.tsx +109 -0
- package/templates/src/components/edit/pane/AddPanePanel_newCustomCopy.tsx +39 -0
- package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +445 -0
- package/templates/src/components/edit/pane/ConfigPanePanel.tsx +245 -0
- package/templates/src/components/edit/pane/PageGen.tsx +485 -0
- package/templates/src/components/edit/pane/PageGenSelector.tsx +238 -0
- package/templates/src/components/edit/pane/PageGenSpecial.tsx +362 -0
- package/templates/src/components/edit/pane/PageGen_preview.tsx +495 -0
- package/templates/src/components/edit/pane/PanePanel_impression.tsx +258 -0
- package/templates/src/components/edit/pane/PanePanel_path.tsx +268 -0
- package/templates/src/components/edit/pane/PanePanel_slug.tsx +219 -0
- package/templates/src/components/edit/pane/PanePanel_title.tsx +142 -0
- package/templates/src/components/edit/panels/StyleBreakPanel.tsx +182 -0
- package/templates/src/components/edit/panels/StyleCodeHookPanel.tsx +439 -0
- package/templates/src/components/edit/panels/StyleElementPanel.tsx +177 -0
- package/templates/src/components/edit/panels/StyleElementPanel_add.tsx +349 -0
- package/templates/src/components/edit/panels/StyleElementPanel_remove.tsx +159 -0
- package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +320 -0
- package/templates/src/components/edit/panels/StyleImagePanel.tsx +460 -0
- package/templates/src/components/edit/panels/StyleImagePanel_add.tsx +296 -0
- package/templates/src/components/edit/panels/StyleImagePanel_remove.tsx +153 -0
- package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +312 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel.tsx +273 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel_add.tsx +301 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel_remove.tsx +132 -0
- package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +313 -0
- package/templates/src/components/edit/panels/StyleLinkPanel.tsx +346 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_add.tsx +265 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +240 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_remove.tsx +94 -0
- package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +110 -0
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +263 -0
- package/templates/src/components/edit/panels/StyleParentPanel_add.tsx +275 -0
- package/templates/src/components/edit/panels/StyleParentPanel_deleteLayer.tsx +112 -0
- package/templates/src/components/edit/panels/StyleParentPanel_remove.tsx +87 -0
- package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +141 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel.tsx +428 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_add.tsx +292 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +190 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_remove.tsx +152 -0
- package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +308 -0
- package/templates/src/components/edit/state/SaveModal.tsx +811 -0
- package/templates/src/components/edit/state/StylesMemory.tsx +310 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +289 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +320 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +888 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +269 -0
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_title.tsx +190 -0
- package/templates/src/components/edit/widgets/BeliefWidget.tsx +183 -0
- package/templates/src/components/edit/widgets/BunnyWidget.tsx +134 -0
- package/templates/src/components/edit/widgets/IdentifyAsWidget.tsx +193 -0
- package/templates/src/components/edit/widgets/SignupWidget.tsx +177 -0
- package/templates/src/components/edit/widgets/ToggleWidget.tsx +152 -0
- package/templates/src/components/edit/widgets/YouTubeWidget.tsx +65 -0
- package/templates/src/components/fields/ActionBuilderTimeSelector.tsx +353 -0
- package/templates/src/components/fields/ArtpackImage.tsx +480 -0
- package/templates/src/components/fields/BackgroundImage.tsx +530 -0
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +192 -0
- package/templates/src/components/fields/BooleanParam.tsx +67 -0
- package/templates/src/components/fields/BunnyMomentSelector.tsx +56 -0
- package/templates/src/components/fields/ColorPickerCombo.tsx +284 -0
- package/templates/src/components/fields/ImageUpload.tsx +405 -0
- package/templates/src/components/fields/MultiParam.tsx +75 -0
- package/templates/src/components/fields/PaneBreakCollectionSelector.tsx +97 -0
- package/templates/src/components/fields/PaneBreakShapeSelector.tsx +134 -0
- package/templates/src/components/fields/SelectedTailwindClass.tsx +44 -0
- package/templates/src/components/fields/SingleParam.tsx +73 -0
- package/templates/src/components/fields/ViewportComboBox.tsx +252 -0
- package/templates/src/components/form/ActionBuilderField.tsx +282 -0
- package/templates/src/components/form/ActionBuilderSlugSelector.tsx +182 -0
- package/templates/src/components/form/BooleanToggle.tsx +94 -0
- package/templates/src/components/form/ColorPicker.tsx +153 -0
- package/templates/src/components/form/DateTimeInput.tsx +638 -0
- package/templates/src/components/form/EnumSelect.tsx +88 -0
- package/templates/src/components/form/FileUpload.tsx +465 -0
- package/templates/src/components/form/MagicPathBuilder.tsx +546 -0
- package/templates/src/components/form/NumberInput.tsx +101 -0
- package/templates/src/components/form/ParagraphArrayInput.tsx +207 -0
- package/templates/src/components/form/StringArrayInput.tsx +163 -0
- package/templates/src/components/form/StringInput.tsx +88 -0
- package/templates/src/components/form/UnsavedChangesBar.tsx +295 -0
- package/templates/src/components/form/advanced/APIConfigSection.tsx +69 -0
- package/templates/src/components/form/advanced/AuthConfigSection.tsx +97 -0
- package/templates/src/components/form/brand/BrandAssetsSection.tsx +93 -0
- package/templates/src/components/form/brand/BrandColorsSection.tsx +201 -0
- package/templates/src/components/form/brand/SEOSection.tsx +101 -0
- package/templates/src/components/form/brand/SiteConfigSection.tsx +61 -0
- package/templates/src/components/form/brand/SocialLinksSection.tsx +393 -0
- package/templates/src/components/profile/ProfileConsent.tsx +65 -0
- package/templates/src/components/profile/ProfileCreate.tsx +462 -0
- package/templates/src/components/profile/ProfileEdit.tsx +409 -0
- package/templates/src/components/profile/ProfileSwitch.tsx +255 -0
- package/templates/src/components/profile/ProfileUnlock.tsx +221 -0
- package/templates/src/components/storykeep/Dashboard.tsx +160 -0
- package/templates/src/components/storykeep/Dashboard_Activity.tsx +56 -0
- package/templates/src/components/storykeep/Dashboard_Advanced.tsx +165 -0
- package/templates/src/components/storykeep/Dashboard_Analytics.tsx +451 -0
- package/templates/src/components/storykeep/Dashboard_Branding.tsx +95 -0
- package/templates/src/components/storykeep/Dashboard_Content.tsx +191 -0
- package/templates/src/components/storykeep/controls/UsageCell.tsx +71 -0
- package/templates/src/components/storykeep/controls/content/BeliefForm.tsx +378 -0
- package/templates/src/components/storykeep/controls/content/BeliefTable.tsx +329 -0
- package/templates/src/components/storykeep/controls/content/ContentBrowser.tsx +385 -0
- package/templates/src/components/storykeep/controls/content/ContentSummary.tsx +149 -0
- package/templates/src/components/storykeep/controls/content/KnownResourceForm.tsx +397 -0
- package/templates/src/components/storykeep/controls/content/KnownResourceTable.tsx +260 -0
- package/templates/src/components/storykeep/controls/content/ManageContent.tsx +439 -0
- package/templates/src/components/storykeep/controls/content/MenuForm.tsx +239 -0
- package/templates/src/components/storykeep/controls/content/MenuTable.tsx +332 -0
- package/templates/src/components/storykeep/controls/content/ResourceBulkIngest.tsx +724 -0
- package/templates/src/components/storykeep/controls/content/ResourceForm.tsx +355 -0
- package/templates/src/components/storykeep/controls/content/ResourceTable.tsx +222 -0
- package/templates/src/components/storykeep/controls/content/StoryFragmentTable.tsx +482 -0
- package/templates/src/components/storykeep/state/BrandingWrapper.tsx +42 -0
- package/templates/src/components/storykeep/state/FetchAnalytics.tsx +350 -0
- package/templates/src/components/storykeep/widgets/ResponsiveLine.tsx +319 -0
- package/templates/src/components/storykeep/widgets/Wizard.tsx +278 -0
- package/templates/src/components/tenant/RegistrationForm.tsx +447 -0
- package/templates/src/components/widgets/BunnyVideoHero.astro +775 -0
- package/templates/src/components/widgets/Impression.tsx +102 -0
- package/templates/src/components/widgets/ImpressionWrapper.tsx +214 -0
- package/templates/src/constants/beliefs.ts +61 -0
- package/templates/src/constants/brandThemes.ts +133 -0
- package/templates/src/constants/prompts.json +55 -0
- package/templates/src/constants/shapes.ts +556 -0
- package/templates/src/constants/stopWords.ts +116 -0
- package/templates/src/constants/tailwindColors.json +344 -0
- package/templates/src/constants.ts +274 -0
- package/templates/src/hooks/useFormState.ts +203 -0
- package/templates/src/layouts/Layout.astro +290 -0
- package/templates/src/lib/session.ts +126 -0
- package/templates/src/lib/storyData.ts +56 -0
- package/templates/src/middleware.ts +52 -0
- package/templates/src/pages/404.astro +54 -0
- package/templates/src/pages/[...slug]/edit.astro +216 -0
- package/templates/src/pages/[...slug].astro +148 -0
- package/templates/src/pages/api/auth/decode.ts +101 -0
- package/templates/src/pages/api/auth/login.ts +122 -0
- package/templates/src/pages/api/auth/logout.ts +37 -0
- package/templates/src/pages/api/auth/profile.ts +76 -0
- package/templates/src/pages/api/orphan-analysis.ts +106 -0
- package/templates/src/pages/api/tailwind.ts +116 -0
- package/templates/src/pages/collections/[param1].astro +65 -0
- package/templates/src/pages/context/[...contextSlug]/edit.astro +207 -0
- package/templates/src/pages/context/[...contextSlug].astro +161 -0
- package/templates/src/pages/llms.txt.ts +122 -0
- package/templates/src/pages/maint.astro +183 -0
- package/templates/src/pages/media/[...slug].astro +67 -0
- package/templates/src/pages/robots.txt.ts +36 -0
- package/templates/src/pages/sandbox/activate.astro +258 -0
- package/templates/src/pages/sandbox/register.astro +44 -0
- package/templates/src/pages/sandbox/success.astro +179 -0
- package/templates/src/pages/sitemap.xml.ts +119 -0
- package/templates/src/pages/storykeep/advanced.astro +69 -0
- package/templates/src/pages/storykeep/branding.astro +57 -0
- package/templates/src/pages/storykeep/content.astro +71 -0
- package/templates/src/pages/storykeep/init.astro +36 -0
- package/templates/src/pages/storykeep/login.astro +266 -0
- package/templates/src/pages/storykeep/logout.astro +84 -0
- package/templates/src/pages/storykeep/profile.astro +98 -0
- package/templates/src/pages/storykeep.astro +81 -0
- package/templates/src/stores/analytics.ts +171 -0
- package/templates/src/stores/backend.ts +16 -0
- package/templates/src/stores/navigation.ts +149 -0
- package/templates/src/stores/nodes.ts +2390 -0
- package/templates/src/stores/nodesHistory.ts +85 -0
- package/templates/src/stores/notificationSystem.ts +41 -0
- package/templates/src/stores/orphanAnalysis.ts +409 -0
- package/templates/src/stores/storykeep.ts +247 -0
- package/templates/src/types/astro.ts +86 -0
- package/templates/src/types/compositorTypes.ts +456 -0
- package/templates/src/types/formTypes.ts +281 -0
- package/templates/src/types/multiTenant.ts +77 -0
- package/templates/src/types/nodeProps.ts +66 -0
- package/templates/src/types/tractstack.ts +445 -0
- package/templates/src/utils/aai/getTitleSlug.ts +72 -0
- package/templates/src/utils/actions/actionButton.ts +101 -0
- package/templates/src/utils/actions/lispLexer.ts +57 -0
- package/templates/src/utils/actions/preParse_Action.ts +85 -0
- package/templates/src/utils/actions/preParse_Bunny.ts +50 -0
- package/templates/src/utils/actions/preParse_Clicked.ts +87 -0
- package/templates/src/utils/actions/preParse_Impression.ts +71 -0
- package/templates/src/utils/api/advancedConfig.ts +66 -0
- package/templates/src/utils/api/advancedHelpers.ts +134 -0
- package/templates/src/utils/api/beliefConfig.ts +87 -0
- package/templates/src/utils/api/beliefHelpers.ts +196 -0
- package/templates/src/utils/api/brandConfig.ts +126 -0
- package/templates/src/utils/api/brandHelpers.ts +155 -0
- package/templates/src/utils/api/fileHelpers.ts +306 -0
- package/templates/src/utils/api/menuConfig.ts +57 -0
- package/templates/src/utils/api/menuHelpers.ts +156 -0
- package/templates/src/utils/api/resourceConfig.ts +158 -0
- package/templates/src/utils/api/resourceHelpers.ts +72 -0
- package/templates/src/utils/api/tenantConfig.ts +97 -0
- package/templates/src/utils/api/tenantHelpers.ts +172 -0
- package/templates/src/utils/api.ts +183 -0
- package/templates/src/utils/auth.ts +150 -0
- package/templates/src/utils/backend.ts +243 -0
- package/templates/src/utils/compositor/TemplateMarkdowns.ts +118 -0
- package/templates/src/utils/compositor/TemplateNodes.ts +138 -0
- package/templates/src/utils/compositor/TemplatePanes.ts +100 -0
- package/templates/src/utils/compositor/allowInsert.ts +100 -0
- package/templates/src/utils/compositor/domHelpers.ts +37 -0
- package/templates/src/utils/compositor/handleClickEvent.ts +131 -0
- package/templates/src/utils/compositor/nodesHelper.ts +491 -0
- package/templates/src/utils/compositor/nodesMarkdownGenerator.ts +292 -0
- package/templates/src/utils/compositor/processMarkdown.ts +431 -0
- package/templates/src/utils/compositor/reduceNodesClassNames.ts +192 -0
- package/templates/src/utils/compositor/tailwindClasses.ts +1795 -0
- package/templates/src/utils/compositor/tailwindColors.ts +227 -0
- package/templates/src/utils/compositor/templateMarkdownStyles.ts +1265 -0
- package/templates/src/utils/compositor/typeGuards.ts +193 -0
- package/templates/src/utils/etl/extractor.ts +119 -0
- package/templates/src/utils/etl/index.ts +88 -0
- package/templates/src/utils/etl/loader.ts +36 -0
- package/templates/src/utils/etl/transformer.ts +286 -0
- package/templates/src/utils/helpers.ts +435 -0
- package/templates/src/utils/layout.ts +209 -0
- package/templates/src/utils/profileStorage.ts +306 -0
- package/templates/src/utils/useInterval.ts +27 -0
- package/templates/tailwind.config.cjs +169 -0
- package/utils/create-resolver.ts +10 -0
- package/utils/inject-files.ts +2140 -0
- package/utils/validate-config.ts +43 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { APIRoute } from '@/types/astro';
|
|
2
|
+
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ request }) => {
|
|
5
|
+
// Get tenant ID from headers (set by middleware)
|
|
6
|
+
const tenantId = request.headers.get('X-Tenant-ID') || 'default';
|
|
7
|
+
|
|
8
|
+
// Fetch content map from backend
|
|
9
|
+
const goBackend =
|
|
10
|
+
import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
11
|
+
|
|
12
|
+
let contentMap = [];
|
|
13
|
+
let brandConfig = null;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// Fetch content map
|
|
17
|
+
const contentResponse = await fetch(
|
|
18
|
+
`${goBackend}/api/v1/content/full-map`,
|
|
19
|
+
{
|
|
20
|
+
headers: {
|
|
21
|
+
'X-Tenant-ID': tenantId,
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (contentResponse.ok) {
|
|
27
|
+
const contentData = await contentResponse.json();
|
|
28
|
+
contentMap = contentData.data?.data || [];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Fetch brand config
|
|
32
|
+
brandConfig = await getBrandConfig(tenantId);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('Error fetching data for llms.txt:', error);
|
|
35
|
+
// Continue with empty data rather than failing
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Filter for public content (StoryFragments and context Panes)
|
|
39
|
+
const publicContent = contentMap.filter(
|
|
40
|
+
(c: any) => c.type === 'StoryFragment' || (c.type === 'Pane' && c.isContext)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Build the content URLs
|
|
44
|
+
const siteUrl = brandConfig?.SITE_URL || 'https://example.com';
|
|
45
|
+
const homeSlug = brandConfig?.HOME_SLUG || 'home';
|
|
46
|
+
|
|
47
|
+
const contentUrls = publicContent
|
|
48
|
+
.map((c: any) => {
|
|
49
|
+
if (c.type === 'StoryFragment') {
|
|
50
|
+
return c.slug === homeSlug
|
|
51
|
+
? new URL('/', siteUrl).href
|
|
52
|
+
: new URL(c.slug, siteUrl).href;
|
|
53
|
+
}
|
|
54
|
+
if (c.type === 'Pane' && c.isContext) {
|
|
55
|
+
return new URL(`context/${c.slug}`, siteUrl).href;
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
.filter(Boolean) as string[];
|
|
59
|
+
|
|
60
|
+
// Use the brand config values
|
|
61
|
+
const siteTitle = brandConfig?.OGTITLE || brandConfig?.SLOGAN || 'Website';
|
|
62
|
+
const siteDescription =
|
|
63
|
+
brandConfig?.OGDESC ||
|
|
64
|
+
brandConfig?.FOOTER ||
|
|
65
|
+
'A website built with TractStack';
|
|
66
|
+
const siteName = brandConfig?.OGAUTHOR || siteTitle;
|
|
67
|
+
const theme = brandConfig?.THEME || 'Default';
|
|
68
|
+
const openDemo = brandConfig?.OPEN_DEMO || false;
|
|
69
|
+
|
|
70
|
+
const llmsTxt = `# ${siteTitle} - LLMs.txt
|
|
71
|
+
|
|
72
|
+
## About this site
|
|
73
|
+
${siteDescription}
|
|
74
|
+
|
|
75
|
+
## Site Information
|
|
76
|
+
- URL: ${siteUrl}
|
|
77
|
+
- Title: ${siteTitle}
|
|
78
|
+
- Author: ${siteName}
|
|
79
|
+
- Description: ${siteDescription}
|
|
80
|
+
- Slogan: ${brandConfig?.SLOGAN || ''}
|
|
81
|
+
- Theme: ${theme}
|
|
82
|
+
|
|
83
|
+
## Available Content
|
|
84
|
+
This site contains ${publicContent.length} publicly accessible pages:
|
|
85
|
+
${contentUrls.map((url: string) => `- ${url}`).join('\n')}
|
|
86
|
+
|
|
87
|
+
## Technical Information
|
|
88
|
+
- Built with: TractStack
|
|
89
|
+
- Theme: ${theme}
|
|
90
|
+
- Demo Mode Enabled: ${openDemo ? 'Yes' : 'No'}
|
|
91
|
+
|
|
92
|
+
## Usage Guidelines
|
|
93
|
+
This content is available for AI training and indexing. Please respect the site's robots.txt file and terms of service.
|
|
94
|
+
|
|
95
|
+
## Contact
|
|
96
|
+
For questions about this content, please visit: ${siteUrl}
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
Generated on: ${new Date().toISOString()}
|
|
100
|
+
Content last updated: ${new Date().toISOString()}`.trim();
|
|
101
|
+
|
|
102
|
+
return new Response(llmsTxt, {
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
105
|
+
'Cache-Control': 'public, max-age=3600',
|
|
106
|
+
'X-Content-Type-Options': 'nosniff',
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const HEAD: APIRoute = async () => {
|
|
112
|
+
// For HEAD requests, return the same headers but no body
|
|
113
|
+
return new Response(null, {
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
116
|
+
'Cache-Control': 'public, max-age=3600',
|
|
117
|
+
'X-Content-Type-Options': 'nosniff',
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const prerender = false;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
3
|
+
|
|
4
|
+
const originalUrl = Astro.url.searchParams.get('from') || '/';
|
|
5
|
+
const goBackend = import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
6
|
+
const tenantId =
|
|
7
|
+
Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default';
|
|
8
|
+
const brandConfig = await getBrandConfig(tenantId);
|
|
9
|
+
const getAssetPath = (configPath: string, fallback: string) => {
|
|
10
|
+
// Always prioritize brandConfig values when they exist
|
|
11
|
+
if (configPath && configPath !== '') {
|
|
12
|
+
return configPath;
|
|
13
|
+
}
|
|
14
|
+
return fallback;
|
|
15
|
+
};
|
|
16
|
+
const logo = getAssetPath(brandConfig?.LOGO, '/brand/logo.svg');
|
|
17
|
+
const wordmark = getAssetPath(brandConfig?.WORDMARK, '/brand/wordmark.svg');
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<!doctype html>
|
|
21
|
+
<html lang="en" class="bg-mywhite h-full">
|
|
22
|
+
<head>
|
|
23
|
+
<meta charset="UTF-8" />
|
|
24
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
25
|
+
<title>Service Maintenance | TractStack</title>
|
|
26
|
+
<link rel="stylesheet" href="/styles/custom.css" />
|
|
27
|
+
<link rel="stylesheet" href="/styles/storykeep.css" />
|
|
28
|
+
</head>
|
|
29
|
+
<body class="h-full">
|
|
30
|
+
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
|
31
|
+
<div class="mx-auto pb-6">
|
|
32
|
+
<div class="flex flex-col items-center justify-center gap-4">
|
|
33
|
+
<div class="h-16 w-auto">
|
|
34
|
+
<img
|
|
35
|
+
src={logo}
|
|
36
|
+
class="pointer-events-none h-full w-auto"
|
|
37
|
+
alt="Logo"
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="h-16 w-auto">
|
|
41
|
+
<img
|
|
42
|
+
src={wordmark}
|
|
43
|
+
class="pointer-events-none h-full w-auto max-w-48 md:max-w-72"
|
|
44
|
+
alt="Wordmark"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<h2
|
|
50
|
+
class="text-mydarkgrey mt-6 text-center text-2xl font-bold leading-9 tracking-tight"
|
|
51
|
+
>
|
|
52
|
+
Service Temporarily Unavailable
|
|
53
|
+
</h2>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="mx-auto">
|
|
57
|
+
<div class="rounded-lg bg-white px-6 py-12 shadow-inner">
|
|
58
|
+
<div class="space-y-6 text-center">
|
|
59
|
+
<div class="text-myorange mx-auto h-12 w-12">
|
|
60
|
+
<svg
|
|
61
|
+
fill="none"
|
|
62
|
+
stroke="currentColor"
|
|
63
|
+
viewBox="0 0 24 24"
|
|
64
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
65
|
+
>
|
|
66
|
+
<path
|
|
67
|
+
stroke-linecap="round"
|
|
68
|
+
stroke-linejoin="round"
|
|
69
|
+
stroke-width="2"
|
|
70
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
71
|
+
></path>
|
|
72
|
+
</svg>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<p class="text-mydarkgrey text-sm">
|
|
76
|
+
We're experiencing technical difficulties. The service will be
|
|
77
|
+
restored automatically.
|
|
78
|
+
</p>
|
|
79
|
+
|
|
80
|
+
<div
|
|
81
|
+
id="status-indicator"
|
|
82
|
+
class="border-mylightgrey inline-flex items-center rounded-md border bg-white px-4 py-2 shadow-sm"
|
|
83
|
+
>
|
|
84
|
+
<div class="text-myorange -ml-1 mr-3 h-5 w-5 animate-spin">
|
|
85
|
+
<svg fill="none" viewBox="0 0 24 24">
|
|
86
|
+
<circle
|
|
87
|
+
class="opacity-25"
|
|
88
|
+
cx="12"
|
|
89
|
+
cy="12"
|
|
90
|
+
r="10"
|
|
91
|
+
stroke="currentColor"
|
|
92
|
+
stroke-width="4"></circle>
|
|
93
|
+
<path
|
|
94
|
+
class="opacity-75"
|
|
95
|
+
fill="currentColor"
|
|
96
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
97
|
+
></path>
|
|
98
|
+
</svg>
|
|
99
|
+
</div>
|
|
100
|
+
<span class="text-mydarkgrey text-sm"
|
|
101
|
+
>Checking service status...</span
|
|
102
|
+
>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div class="text-mylightgrey text-center text-xs">
|
|
106
|
+
<p>
|
|
107
|
+
This page will automatically refresh when the service is
|
|
108
|
+
available
|
|
109
|
+
</p>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<script is:inline define:vars={{ goBackend, tenantId, originalUrl }}>
|
|
117
|
+
let checkCount = 0;
|
|
118
|
+
const maxChecks = 240;
|
|
119
|
+
|
|
120
|
+
function updateStatus(message, isChecking = true) {
|
|
121
|
+
const indicator = document.getElementById('status-indicator');
|
|
122
|
+
const spinner = indicator.querySelector('.animate-spin');
|
|
123
|
+
const text = indicator.querySelector('span');
|
|
124
|
+
|
|
125
|
+
if (isChecking) {
|
|
126
|
+
spinner.style.display = 'block';
|
|
127
|
+
} else {
|
|
128
|
+
spinner.style.display = 'none';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
text.textContent = message;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function checkBackendHealth() {
|
|
135
|
+
checkCount++;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const response = await fetch(`${goBackend}/api/v1/health`, {
|
|
139
|
+
method: 'GET',
|
|
140
|
+
headers: {
|
|
141
|
+
'X-Tenant-ID': tenantId,
|
|
142
|
+
},
|
|
143
|
+
signal: AbortSignal.timeout(5000),
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
if (response.ok) {
|
|
147
|
+
const data = await response.json();
|
|
148
|
+
if (data.healthy) {
|
|
149
|
+
updateStatus('Service restored! Redirecting...', false);
|
|
150
|
+
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
window.location.href = originalUrl;
|
|
153
|
+
}, 1000);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.log('Health check failed:', error.message);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (checkCount < 5) {
|
|
162
|
+
updateStatus('Checking service status...');
|
|
163
|
+
} else if (checkCount < 20) {
|
|
164
|
+
updateStatus('Service still unavailable, continuing to check...');
|
|
165
|
+
} else if (checkCount < maxChecks) {
|
|
166
|
+
updateStatus(`Still checking... (attempt ${checkCount})`);
|
|
167
|
+
} else {
|
|
168
|
+
updateStatus(
|
|
169
|
+
'Extended outage detected. Please contact support.',
|
|
170
|
+
false
|
|
171
|
+
);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
setTimeout(checkBackendHealth, 30000);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
179
|
+
checkBackendHealth();
|
|
180
|
+
});
|
|
181
|
+
</script>
|
|
182
|
+
</body>
|
|
183
|
+
</html>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
// DO NOT USE IN PRODUCTION !!!
|
|
6
|
+
// this is a stop-gap for dev testing ...
|
|
7
|
+
|
|
8
|
+
// configure nginx to serve files on /media !!
|
|
9
|
+
// see the docs
|
|
10
|
+
|
|
11
|
+
export const prerender = false;
|
|
12
|
+
|
|
13
|
+
const MIME_TYPES: Record<string, string> = {
|
|
14
|
+
'.css': 'text/css',
|
|
15
|
+
'.js': 'application/javascript',
|
|
16
|
+
'.json': 'application/json',
|
|
17
|
+
'.svg': 'image/svg+xml',
|
|
18
|
+
'.png': 'image/png',
|
|
19
|
+
'.jpg': 'image/jpeg',
|
|
20
|
+
'.jpeg': 'image/jpeg',
|
|
21
|
+
'.gif': 'image/gif',
|
|
22
|
+
'.webp': 'image/webp',
|
|
23
|
+
'.woff': 'font/woff',
|
|
24
|
+
'.woff2': 'font/woff2',
|
|
25
|
+
'.ttf': 'font/ttf',
|
|
26
|
+
'.otf': 'font/otf',
|
|
27
|
+
'.ico': 'image/x-icon',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const { slug } = Astro.params;
|
|
31
|
+
|
|
32
|
+
const tenant =
|
|
33
|
+
Astro.locals.tenant?.id || import.meta.env.PUBLIC_TENANTID || 'default';
|
|
34
|
+
|
|
35
|
+
const baseServerPath = import.meta.env.PRIVATE_GO_BACKEND_PATH;
|
|
36
|
+
if (!baseServerPath) {
|
|
37
|
+
console.error(
|
|
38
|
+
'[ERROR] PRIVATE_GO_BACKEND_PATH environment variable is not set.'
|
|
39
|
+
);
|
|
40
|
+
return new Response('Server configuration error', { status: 500 });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!slug) throw new Error(`Invalid path for tenant "${tenant}".`);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// Construct the file path using the correct tenant ID
|
|
47
|
+
const fullPath = path.join(baseServerPath, 'config', tenant, 'media', slug);
|
|
48
|
+
|
|
49
|
+
// Security check to prevent path traversal
|
|
50
|
+
const tenantMediaRoot = path.join(baseServerPath, 'config', tenant, 'media');
|
|
51
|
+
if (!path.resolve(fullPath).startsWith(path.resolve(tenantMediaRoot))) {
|
|
52
|
+
throw new Error(`Invalid path for tenant "${tenant}".`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const fileBuffer = await fs.readFile(fullPath);
|
|
56
|
+
const extension = path.extname(slug).toLowerCase();
|
|
57
|
+
const mimeType = MIME_TYPES[extension] || 'application/octet-stream';
|
|
58
|
+
|
|
59
|
+
return new Response(fileBuffer, {
|
|
60
|
+
status: 200,
|
|
61
|
+
headers: { 'Content-Type': mimeType },
|
|
62
|
+
});
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(`Could not serve media file: ${slug} for tenant ${tenant}.`);
|
|
65
|
+
return new Response(null, { status: 404, statusText: 'Not Found' });
|
|
66
|
+
}
|
|
67
|
+
---
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { APIRoute } from '@/types/astro';
|
|
2
|
+
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
3
|
+
|
|
4
|
+
export const GET: APIRoute = async ({ request }) => {
|
|
5
|
+
// Get tenant ID from headers (set by middleware)
|
|
6
|
+
const tenantId = request.headers.get('X-Tenant-ID') || 'default';
|
|
7
|
+
|
|
8
|
+
// Fetch brand config
|
|
9
|
+
let brandConfig = null;
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
brandConfig = await getBrandConfig(tenantId);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error('Error fetching brand config for robots.txt:', error);
|
|
15
|
+
// Continue with default values
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const siteUrl = brandConfig?.SITE_URL || 'https://example.com';
|
|
19
|
+
|
|
20
|
+
const robotsTxt = `
|
|
21
|
+
User-agent: *
|
|
22
|
+
Disallow: /storykeep/
|
|
23
|
+
Disallow: /storykeep/*
|
|
24
|
+
Allow: /
|
|
25
|
+
|
|
26
|
+
Sitemap: ${new URL('sitemap.xml', siteUrl).href}
|
|
27
|
+
`.trim();
|
|
28
|
+
|
|
29
|
+
return new Response(robotsTxt, {
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const prerender = false;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Layout from '@/layouts/Layout.astro';
|
|
3
|
+
import { getBrandConfig } from '@/utils/api/brandConfig';
|
|
4
|
+
import { preHealthCheck } from '@/utils/backend';
|
|
5
|
+
|
|
6
|
+
const tenantId = 'default'; // For registration, always use default
|
|
7
|
+
|
|
8
|
+
const healthCheckRedirect = await preHealthCheck(tenantId);
|
|
9
|
+
if (healthCheckRedirect !== undefined) {
|
|
10
|
+
return healthCheckRedirect;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const goBackend = import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
14
|
+
|
|
15
|
+
// Check if multi-tenant is enabled
|
|
16
|
+
const isMultiTenantEnabled =
|
|
17
|
+
import.meta.env.PUBLIC_ENABLE_MULTI_TENANT === 'true';
|
|
18
|
+
if (!isMultiTenantEnabled) {
|
|
19
|
+
return Astro.redirect('/?error=multi-tenant-disabled');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Dev mode detection
|
|
23
|
+
const isDev = import.meta.env.DEV;
|
|
24
|
+
|
|
25
|
+
// Get activation token from URL
|
|
26
|
+
const url = new URL(Astro.request.url);
|
|
27
|
+
const token = url.searchParams.get('token');
|
|
28
|
+
|
|
29
|
+
let activationResult = {
|
|
30
|
+
success: false,
|
|
31
|
+
error: null as string | null,
|
|
32
|
+
tenantId: null as string | null,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (!token) {
|
|
36
|
+
activationResult.error =
|
|
37
|
+
'Missing activation token. Please check your email link.';
|
|
38
|
+
console.log('ERROR: No token provided');
|
|
39
|
+
} else {
|
|
40
|
+
// Attempt activation
|
|
41
|
+
try {
|
|
42
|
+
// Get tenantId BEFORE calling activation
|
|
43
|
+
let tenantId: string;
|
|
44
|
+
|
|
45
|
+
if (isDev) {
|
|
46
|
+
// In dev mode, get tenant ID from URL param or use default
|
|
47
|
+
tenantId = url.searchParams.get('tenantId') || 'localhost';
|
|
48
|
+
} else {
|
|
49
|
+
// Extract tenant ID from current domain in production
|
|
50
|
+
const hostname = Astro.request.headers.get('host') || '';
|
|
51
|
+
const parts = hostname.split('.');
|
|
52
|
+
if (parts.length >= 4 && parts[1] === 'sandbox') {
|
|
53
|
+
tenantId = parts[0];
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error('Could not determine tenant ID from domain');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Make direct fetch call to Go backend (like other .astro files)
|
|
60
|
+
const response = await fetch(`${goBackend}/api/v1/tenant/activation`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
'X-Tenant-ID': tenantId,
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify({ token }),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const responseText = await response.text();
|
|
70
|
+
|
|
71
|
+
if (response.ok) {
|
|
72
|
+
activationResult.success = true;
|
|
73
|
+
activationResult.tenantId = tenantId;
|
|
74
|
+
} else {
|
|
75
|
+
let errorData;
|
|
76
|
+
try {
|
|
77
|
+
errorData = JSON.parse(responseText);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
errorData = { error: responseText };
|
|
80
|
+
}
|
|
81
|
+
activationResult.error = errorData.error || 'Activation failed';
|
|
82
|
+
console.log('FAILED: Activation error:', activationResult.error);
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
activationResult.error =
|
|
86
|
+
error instanceof Error ? error.message : 'Activation failed';
|
|
87
|
+
console.log('EXCEPTION:', error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const brandConfig = await getBrandConfig('default');
|
|
92
|
+
const title = activationResult.success
|
|
93
|
+
? 'Tenant Activated | TractStack'
|
|
94
|
+
: 'Activation Error | TractStack';
|
|
95
|
+
|
|
96
|
+
// Build dashboard URL based on environment
|
|
97
|
+
const getDashboardUrl = (tenantId: string) => {
|
|
98
|
+
if (isDev) {
|
|
99
|
+
return '/storykeep';
|
|
100
|
+
}
|
|
101
|
+
return `https://${tenantId}.sandbox.freewebpress.com/storykeep`;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Build display URL based on environment
|
|
105
|
+
const getDisplayUrl = (tenantId: string) => {
|
|
106
|
+
if (isDev) {
|
|
107
|
+
return 'localhost:4321';
|
|
108
|
+
}
|
|
109
|
+
return `https://${tenantId}.sandbox.freewebpress.com`;
|
|
110
|
+
};
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
<Layout title={title} slug="tenant-activate" brandConfig={brandConfig}>
|
|
114
|
+
<main
|
|
115
|
+
id="main-content"
|
|
116
|
+
class="flex min-h-screen items-center justify-center bg-gray-50"
|
|
117
|
+
>
|
|
118
|
+
<div class="mx-auto max-w-2xl p-6">
|
|
119
|
+
{
|
|
120
|
+
activationResult.success ? (
|
|
121
|
+
<div class="rounded-lg bg-white p-8 text-center shadow-lg">
|
|
122
|
+
<div class="mx-auto mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-green-100">
|
|
123
|
+
<svg
|
|
124
|
+
class="h-8 w-8 text-green-600"
|
|
125
|
+
fill="none"
|
|
126
|
+
stroke="currentColor"
|
|
127
|
+
viewBox="0 0 24 24"
|
|
128
|
+
>
|
|
129
|
+
<path
|
|
130
|
+
stroke-linecap="round"
|
|
131
|
+
stroke-linejoin="round"
|
|
132
|
+
stroke-width="2"
|
|
133
|
+
d="M5 13l4 4L19 7"
|
|
134
|
+
/>
|
|
135
|
+
</svg>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<h2 class="mb-4 text-2xl font-bold text-gray-900">
|
|
139
|
+
🎉 Tenant Activated Successfully!
|
|
140
|
+
</h2>
|
|
141
|
+
|
|
142
|
+
<p class="mb-6 text-gray-600">
|
|
143
|
+
Your TractStack tenant has been activated and is ready to use.
|
|
144
|
+
</p>
|
|
145
|
+
|
|
146
|
+
{activationResult.tenantId && (
|
|
147
|
+
<div class="mb-6 rounded-lg border border-orange-200 bg-orange-50 p-4">
|
|
148
|
+
<p class="mb-2 text-sm font-bold text-orange-800">
|
|
149
|
+
Your tenant URL:
|
|
150
|
+
</p>
|
|
151
|
+
<p class="break-all font-mono text-orange-700">
|
|
152
|
+
{getDisplayUrl(activationResult.tenantId)}
|
|
153
|
+
</p>
|
|
154
|
+
</div>
|
|
155
|
+
)}
|
|
156
|
+
|
|
157
|
+
<div class="space-y-4">
|
|
158
|
+
{activationResult.tenantId ? (
|
|
159
|
+
<a
|
|
160
|
+
href={getDashboardUrl(activationResult.tenantId)}
|
|
161
|
+
class="inline-block rounded-lg bg-orange-600 px-6 py-3 font-bold text-white transition-colors hover:bg-orange-700"
|
|
162
|
+
id="dashboard-button"
|
|
163
|
+
>
|
|
164
|
+
Access Your Dashboard
|
|
165
|
+
</a>
|
|
166
|
+
) : (
|
|
167
|
+
<div class="text-gray-500">
|
|
168
|
+
<p class="mb-2">Unable to determine tenant URL</p>
|
|
169
|
+
<p class="text-sm">Please contact support</p>
|
|
170
|
+
</div>
|
|
171
|
+
)}
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
) : (
|
|
175
|
+
<div class="rounded-lg bg-white p-8 text-center shadow-lg">
|
|
176
|
+
<div class="mx-auto mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-red-100">
|
|
177
|
+
<svg
|
|
178
|
+
class="h-8 w-8 text-red-600"
|
|
179
|
+
fill="none"
|
|
180
|
+
stroke="currentColor"
|
|
181
|
+
viewBox="0 0 24 24"
|
|
182
|
+
>
|
|
183
|
+
<path
|
|
184
|
+
stroke-linecap="round"
|
|
185
|
+
stroke-linejoin="round"
|
|
186
|
+
stroke-width="2"
|
|
187
|
+
d="M6 18L18 6M6 6l12 12"
|
|
188
|
+
/>
|
|
189
|
+
</svg>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<h2 class="mb-4 text-2xl font-bold text-gray-900">
|
|
193
|
+
Activation Failed
|
|
194
|
+
</h2>
|
|
195
|
+
|
|
196
|
+
<p class="mb-6 text-gray-600">{activationResult.error}</p>
|
|
197
|
+
|
|
198
|
+
<div class="mb-6 rounded-lg border border-yellow-200 bg-yellow-50 p-4">
|
|
199
|
+
<h3 class="mb-2 text-sm font-bold text-yellow-800">
|
|
200
|
+
Common Issues:
|
|
201
|
+
</h3>
|
|
202
|
+
<ul class="space-y-1 text-left text-sm text-yellow-700">
|
|
203
|
+
<li>• The activation link may have expired</li>
|
|
204
|
+
<li>• The token may have already been used</li>
|
|
205
|
+
<li>• There may be a temporary server issue</li>
|
|
206
|
+
</ul>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<div class="space-y-4">
|
|
210
|
+
<a
|
|
211
|
+
href="/sandbox/register"
|
|
212
|
+
class="inline-block rounded-lg bg-orange-600 px-6 py-3 font-bold text-white transition-colors hover:bg-orange-700"
|
|
213
|
+
>
|
|
214
|
+
Register New Tenant
|
|
215
|
+
</a>
|
|
216
|
+
|
|
217
|
+
<div class="text-center">
|
|
218
|
+
<a
|
|
219
|
+
href="mailto:support@tractstack.com"
|
|
220
|
+
class="text-sm text-orange-600 underline hover:text-orange-800"
|
|
221
|
+
>
|
|
222
|
+
Contact Support
|
|
223
|
+
</a>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
</div>
|
|
230
|
+
</main>
|
|
231
|
+
</Layout>
|
|
232
|
+
|
|
233
|
+
<script>
|
|
234
|
+
// Auto-redirect to dashboard after successful activation with countdown
|
|
235
|
+
const dashboardButton = document.getElementById('dashboard-button');
|
|
236
|
+
if (dashboardButton) {
|
|
237
|
+
let countdown = 5;
|
|
238
|
+
|
|
239
|
+
// Update button text with countdown
|
|
240
|
+
const updateButton = () => {
|
|
241
|
+
dashboardButton.textContent = `Access Your Dashboard (${countdown}s)`;
|
|
242
|
+
countdown--;
|
|
243
|
+
|
|
244
|
+
if (countdown < 0) {
|
|
245
|
+
dashboardButton.click();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Start countdown immediately
|
|
250
|
+
updateButton();
|
|
251
|
+
const interval = setInterval(updateButton, 1000);
|
|
252
|
+
|
|
253
|
+
// Clear interval if user clicks button manually
|
|
254
|
+
dashboardButton.addEventListener('click', () => {
|
|
255
|
+
clearInterval(interval);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
</script>
|