diff --git a/apps/marketing/package.json b/apps/marketing/package.json
index 12f6f250354..17efeeb2000 100644
--- a/apps/marketing/package.json
+++ b/apps/marketing/package.json
@@ -40,7 +40,6 @@
"next-mdx-remote": "6.0.0",
"next-themes": "0.4.6",
"posthog-js": "1.310.1",
- "posthog-node": "5.28.8",
"react": "19.2.3",
"react-day-picker": "9.14.0",
"react-dom": "19.2.3",
diff --git a/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx b/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx
index 5b93f8cc263..9d6d6cd3cb3 100644
--- a/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx
+++ b/apps/marketing/src/app/[lang]/components/Footer/Footer.tsx
@@ -22,7 +22,6 @@ import { usePathname } from "next/navigation";
import type { ReactNode } from "react";
import { FaApple } from "react-icons/fa";
import { track } from "@/lib/analytics";
-import { useIsMobileLaunched } from "../../providers/MobileLaunchProvider";
import { Soc2Badge } from "../Soc2Badge";
import { SocialLinks } from "../SocialLinks";
@@ -51,16 +50,15 @@ interface FooterLink {
external?: boolean;
}
-const MOBILE_LINK: FooterLink = {
- href: "/mobile",
- label: Mobile,
-};
-
const PRODUCT_LINKS: FooterLink[] = [
{
href: "/download",
label: Download,
},
+ {
+ href: "/mobile",
+ label: Mobile,
+ },
{
href: "/#how-it-works",
label: How it works,
@@ -170,7 +168,6 @@ export function Footer({
locale?: SupportedLocale;
year: number;
}) {
- const isMobileLaunched = useIsMobileLaunched();
const pathname = usePathname();
if (pathname === "/download") return null;
@@ -223,18 +220,7 @@ export function Footer({
- Product}
- links={
- isMobileLaunched
- ? [
- ...PRODUCT_LINKS.slice(0, 1),
- MOBILE_LINK,
- ...PRODUCT_LINKS.slice(1),
- ]
- : PRODUCT_LINKS
- }
- />
+ Product} links={PRODUCT_LINKS} />
Company} links={COMPANY_LINKS} />
Resources}
diff --git a/apps/marketing/src/app/[lang]/components/Header/components/DesktopNav/DesktopNav.tsx b/apps/marketing/src/app/[lang]/components/Header/components/DesktopNav/DesktopNav.tsx
index cad86a584e2..22a6a9e0366 100644
--- a/apps/marketing/src/app/[lang]/components/Header/components/DesktopNav/DesktopNav.tsx
+++ b/apps/marketing/src/app/[lang]/components/Header/components/DesktopNav/DesktopNav.tsx
@@ -13,10 +13,9 @@ import {
import { cn } from "@superset/ui/utils";
import Link from "next/link";
import { useState } from "react";
-import { useIsMobileLaunched } from "../../../../providers/MobileLaunchProvider";
import {
type NavLink,
- productLinks,
+ PRODUCT_LINKS,
RESOURCE_LINKS,
TOP_LEVEL_LINKS,
} from "../../constants";
@@ -27,7 +26,6 @@ const triggerClass = cn(
);
export function DesktopNav() {
- const isMobileLaunched = useIsMobileLaunched();
// Radix's NavigationMenu is uncontrolled by default, so a hover-opened
// trigger and a click on that same trigger both race to set its shared
// internal `value`. A click toggles, so clicking a menu that hover just
@@ -52,7 +50,7 @@ export function DesktopNav() {
- {productLinks(isMobileLaunched).map((link) => (
+ {PRODUCT_LINKS.map((link) => (
))}
diff --git a/apps/marketing/src/app/[lang]/components/Header/components/MobileNav/MobileNav.tsx b/apps/marketing/src/app/[lang]/components/Header/components/MobileNav/MobileNav.tsx
index cd323ce6edd..9a146cd2a6e 100644
--- a/apps/marketing/src/app/[lang]/components/Header/components/MobileNav/MobileNav.tsx
+++ b/apps/marketing/src/app/[lang]/components/Header/components/MobileNav/MobileNav.tsx
@@ -6,10 +6,9 @@ import { Menu, X } from "lucide-react";
import Link from "next/link";
import type { ReactNode } from "react";
import { useState } from "react";
-import { useIsMobileLaunched } from "../../../../providers/MobileLaunchProvider";
import {
type NavLink,
- productLinks,
+ PRODUCT_LINKS,
RESOURCE_LINKS,
TOP_LEVEL_LINKS,
} from "../../constants";
@@ -21,7 +20,6 @@ interface MobileNavProps {
export function MobileNav({ ctaButtons, starCounter }: MobileNavProps) {
const { t } = useLingui();
- const isMobileLaunched = useIsMobileLaunched();
const [isOpen, setIsOpen] = useState(false);
const close = () => setIsOpen(false);
@@ -54,7 +52,7 @@ export function MobileNav({ ctaButtons, starCounter }: MobileNavProps) {
Product}
- links={productLinks(isMobileLaunched)}
+ links={PRODUCT_LINKS}
onNavigate={close}
/>
Mobile,
- description: Run your agents from your phone.,
-};
-
-export function productLinks(isMobileLaunched: boolean): NavLink[] {
- if (!isMobileLaunched) return PRODUCT_LINKS;
- const [overview, ...rest] = PRODUCT_LINKS;
- return overview ? [overview, MOBILE_LINK, ...rest] : [MOBILE_LINK];
-}
-
-const PRODUCT_LINKS: NavLink[] = [
+export const PRODUCT_LINKS: NavLink[] = [
{
href: "/",
label: Overview,
description: Orchestrate any coding agent.,
},
+ {
+ href: "/mobile",
+ label: Mobile,
+ description: Run your agents from your phone.,
+ },
{
href: "/changelog",
label: Changelog,
diff --git a/apps/marketing/src/app/[lang]/layout.tsx b/apps/marketing/src/app/[lang]/layout.tsx
index 06254f0ad03..15a815cceac 100644
--- a/apps/marketing/src/app/[lang]/layout.tsx
+++ b/apps/marketing/src/app/[lang]/layout.tsx
@@ -12,13 +12,11 @@ import {
WebsiteJsonLd,
} from "@/components/JsonLd";
import { REDDIT_PIXEL_ID } from "@/lib/constants";
-import { isMobileLaunched } from "@/lib/site-flags";
import { CTAButtons } from "./components/CTAButtons";
import { Footer } from "./components/Footer";
import { GitHubStarCounter } from "./components/GitHubStarCounter";
import { Header } from "./components/Header";
-import { MobileLaunchProvider } from "./providers/MobileLaunchProvider";
import "../globals.css";
import { initServerI18n } from "../i18n-server";
import { Providers } from "../providers";
@@ -124,7 +122,6 @@ export default async function RootLayout({
}>) {
const locale = await initServerI18n();
const messages = await getLocaleMessages(locale);
- const isLaunched = await isMobileLaunched();
return (
-
-
-
-
- }
- starCounter={}
- />
- {children}
-
-
-
-
+
+
+
+ }
+ starCounter={}
+ />
+ {children}
+
+
+
diff --git a/apps/marketing/src/app/[lang]/mobile/page.tsx b/apps/marketing/src/app/[lang]/mobile/page.tsx
index 14eb111f5de..6b470b07f44 100644
--- a/apps/marketing/src/app/[lang]/mobile/page.tsx
+++ b/apps/marketing/src/app/[lang]/mobile/page.tsx
@@ -7,7 +7,6 @@ import { PhoneShowcase } from "@/app/[lang]/components/PhoneShowcase";
import { StoreBadges } from "@/app/[lang]/components/StoreBadges";
import { localizedAlternates } from "@/app/[lang]/metadata";
import { initServerI18n } from "@/app/i18n-server";
-import { isMobileLaunched } from "@/lib/site-flags";
import { AppStoreQr } from "./components/AppStoreQr";
import { MobileTestimonials } from "./components/MobileTestimonials";
import { MobileWaitlist } from "./components/MobileWaitlist";
@@ -15,20 +14,15 @@ import { MobileWaitlist } from "./components/MobileWaitlist";
export async function generateMetadata(): Promise {
const lang = await initServerI18n();
const i18n = getI18nInstance(lang);
- const isLaunched = await isMobileLaunched();
return {
title: i18n._(msg({ message: "Superset for iPhone" })),
+ description: i18n._(
+ msg({
+ message:
+ "Start coding agents, follow them live, and review the diff from your phone. Available on the App Store; Android is coming soon.",
+ }),
+ ),
alternates: localizedAlternates(lang, "/mobile"),
- ...(isLaunched
- ? {
- description: i18n._(
- msg({
- message:
- "Start coding agents, follow them live, and review the diff from your phone. Available on the App Store; Android is coming soon.",
- }),
- ),
- }
- : { robots: { index: false, follow: true } }),
};
}
diff --git a/apps/marketing/src/app/[lang]/providers/MobileLaunchProvider/MobileLaunchProvider.tsx b/apps/marketing/src/app/[lang]/providers/MobileLaunchProvider/MobileLaunchProvider.tsx
deleted file mode 100644
index 423a4c6cf50..00000000000
--- a/apps/marketing/src/app/[lang]/providers/MobileLaunchProvider/MobileLaunchProvider.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-"use client";
-
-import { createContext, type ReactNode, useContext } from "react";
-
-const MobileLaunchContext = createContext(false);
-
-interface MobileLaunchProviderProps {
- isLaunched: boolean;
- children: ReactNode;
-}
-
-export function MobileLaunchProvider({
- isLaunched,
- children,
-}: MobileLaunchProviderProps) {
- return (
-
- {children}
-
- );
-}
-
-export function useIsMobileLaunched(): boolean {
- return useContext(MobileLaunchContext);
-}
diff --git a/apps/marketing/src/app/[lang]/providers/MobileLaunchProvider/index.ts b/apps/marketing/src/app/[lang]/providers/MobileLaunchProvider/index.ts
deleted file mode 100644
index 29bca0a2541..00000000000
--- a/apps/marketing/src/app/[lang]/providers/MobileLaunchProvider/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export {
- MobileLaunchProvider,
- useIsMobileLaunched,
-} from "./MobileLaunchProvider";
diff --git a/apps/marketing/src/app/sitemap.test.ts b/apps/marketing/src/app/sitemap.test.ts
index 66c2d4b0529..341bd8322ce 100644
--- a/apps/marketing/src/app/sitemap.test.ts
+++ b/apps/marketing/src/app/sitemap.test.ts
@@ -12,11 +12,6 @@ mock.module("@/app/[lang]/utils/fetchLeaderboard", () => ({
],
}));
-let isMobileLaunched = false;
-mock.module("@/lib/site-flags", () => ({
- isMobileLaunched: async () => isMobileLaunched,
-}));
-
const { default: sitemap } = await import("./sitemap");
describe("marketing sitemap", () => {
@@ -107,16 +102,9 @@ describe("marketing sitemap", () => {
expect(new Set(urls).size).toBe(urls.length);
});
- test("lists /mobile only once the launch flag is on", async () => {
- const mobileUrl = `${COMPANY.MARKETING_URL}/mobile`;
-
- isMobileLaunched = false;
- const before = (await sitemap()).map((entry) => entry.url);
- expect(before).not.toContain(mobileUrl);
-
- isMobileLaunched = true;
- const after = (await sitemap()).map((entry) => entry.url);
- expect(after).toContain(mobileUrl);
- expect(after).toContain(`${COMPANY.MARKETING_URL}/fr/mobile`);
+ test("lists /mobile in every locale", async () => {
+ const urls = (await sitemap()).map((entry) => entry.url);
+ expect(urls).toContain(`${COMPANY.MARKETING_URL}/mobile`);
+ expect(urls).toContain(`${COMPANY.MARKETING_URL}/fr/mobile`);
});
});
diff --git a/apps/marketing/src/app/sitemap.ts b/apps/marketing/src/app/sitemap.ts
index b4d3534863f..1d665e41880 100644
--- a/apps/marketing/src/app/sitemap.ts
+++ b/apps/marketing/src/app/sitemap.ts
@@ -10,7 +10,6 @@ import { getComparisonPages } from "@/lib/compare";
import { getAllLegalSlugs, getLegalPage } from "@/lib/legal";
import { themeListings } from "@/lib/marketplace";
import { getAllPeople } from "@/lib/people";
-import { isMobileLaunched } from "@/lib/site-flags";
async function listProfileHandles() {
"use cache";
@@ -19,7 +18,6 @@ async function listProfileHandles() {
export default async function sitemap(): Promise {
const baseUrl = COMPANY.MARKETING_URL;
- const isLaunched = await isMobileLaunched();
const staticPages: MetadataRoute.Sitemap = [
{
@@ -27,15 +25,11 @@ export default async function sitemap(): Promise {
changeFrequency: "monthly",
priority: 0.8,
},
- ...(isLaunched
- ? [
- {
- url: `${baseUrl}/mobile`,
- changeFrequency: "monthly" as const,
- priority: 0.8,
- },
- ]
- : []),
+ {
+ url: `${baseUrl}/mobile`,
+ changeFrequency: "monthly",
+ priority: 0.8,
+ },
{
url: baseUrl,
changeFrequency: "weekly",
diff --git a/apps/marketing/src/lib/posthog-server.ts b/apps/marketing/src/lib/posthog-server.ts
deleted file mode 100644
index 51847d59a38..00000000000
--- a/apps/marketing/src/lib/posthog-server.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import "server-only";
-
-import { PostHog } from "posthog-node";
-import { env } from "@/env";
-
-// flushAt: 1 / flushInterval: 0 because serverless functions are short-lived
-// and would otherwise drop buffered events.
-export const posthogServer = new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
- host: env.NEXT_PUBLIC_POSTHOG_HOST,
- flushAt: 1,
- flushInterval: 0,
-});
diff --git a/apps/marketing/src/lib/site-flags.ts b/apps/marketing/src/lib/site-flags.ts
deleted file mode 100644
index 6b2f2aa653c..00000000000
--- a/apps/marketing/src/lib/site-flags.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import "server-only";
-
-import { FEATURE_FLAGS } from "@superset/shared/constants";
-import { cacheLife } from "next/cache";
-import { posthogServer } from "./posthog-server";
-
-const SITE_DISTINCT_ID = "marketing-site";
-const REVALIDATE_SECONDS = 60;
-
-/** A flag evaluated once for the whole site. Any failure reads as off. */
-export async function getSiteFlag(flag: string): Promise {
- "use cache";
- cacheLife({ revalidate: REVALIDATE_SECONDS });
- try {
- return Boolean(
- await posthogServer.getFeatureFlag(flag, SITE_DISTINCT_ID, {
- sendFeatureFlagEvents: false,
- }),
- );
- } catch (error) {
- console.error(`[site-flags] Failed to load ${flag}`, error);
- return false;
- }
-}
-
-export function isMobileLaunched(): Promise {
- return getSiteFlag(FEATURE_FLAGS.MOBILE_LAUNCH);
-}
diff --git a/bun.lock b/bun.lock
index 6eef9ce2f7c..71da99135ac 100644
--- a/bun.lock
+++ b/bun.lock
@@ -483,7 +483,6 @@
"next-mdx-remote": "6.0.0",
"next-themes": "0.4.6",
"posthog-js": "1.310.1",
- "posthog-node": "5.28.8",
"react": "19.2.3",
"react-day-picker": "9.14.0",
"react-dom": "19.2.3",