feat(website): migrate website app from Fresh/Deno to TanStack Start#17
feat(website): migrate website app from Fresh/Deno to TanStack Start#17JonasJesus42 merged 4 commits intomainfrom
Conversation
…TanStack Start Port the website app (~34 modules) from the Fresh/Deno ecosystem to TanStack Start/React/Node, following the existing AppModContract pattern. Includes: - App scaffold (mod.ts, client.ts, types.ts, index.ts) - 4 components: Seo, Theme, Analytics, Video (Preact → React 19) - 5 loaders: googleFonts, local fonts, secret, secretString, environment - 16 matchers: always, never, cookie, cron, date, device, environment, host, location, multi, negate, pathname, queryString, random, site, userAgent - 8 flags: flag, everyone, audience, multivariate (image/message/page/section) - 3 sections: Seo, SeoV2, Analytics - 3 utils: html, location, multivariate - 97 new tests covering all modules (222 total tests pass) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
9 issues found across 55 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="website/components/Analytics.tsx">
<violation number="1" location="website/components/Analytics.tsx:9">
P1: Guard URL parsing in `getGTMIdFromSrc`; malformed `src` currently throws and can break rendering.</violation>
<violation number="2" location="website/components/Analytics.tsx:61">
P1: Escape `trackingId` before injecting into inline GTAG script to avoid script-injection via malformed IDs.</violation>
</file>
<file name="website/matchers/pathname.ts">
<violation number="1" location="website/matchers/pathname.ts:43">
P2: Escape regex metacharacters in template literals before building the `RegExp`; otherwise Template matching can produce false positives for paths containing characters like `.` or `+`.</violation>
</file>
<file name="website/loaders/secret.ts">
<violation number="1" location="website/loaders/secret.ts:32">
P2: Env var resolution incorrectly treats empty-string values as missing due to a truthiness check.</violation>
</file>
<file name="website/utils/html.ts">
<violation number="1" location="website/utils/html.ts:1">
P2: The tag-stripping regex is too broad and will remove non-HTML text between `<` and `>`, causing unintended data loss.</violation>
</file>
<file name="website/matchers/random.ts">
<violation number="1" location="website/matchers/random.ts:17">
P1: `traffic` is treated as a 0-1 probability, but the API/docs describe it as percentage; values like `50` will incorrectly match all traffic.</violation>
</file>
<file name="website/components/Theme.tsx">
<violation number="1" location="website/components/Theme.tsx:33">
P1: Avoid `dangerouslySetInnerHTML` for stylesheet content coming from props; render CSS as text children of `<style>` to prevent HTML/script injection.</violation>
</file>
<file name="website/matchers/cron.ts">
<violation number="1" location="website/matchers/cron.ts:97">
P2: Numeric weekday `7` never matches because parsed DOW values are compared directly to `Date.getDay()` (0-6).</violation>
</file>
<file name="website/matchers/location.ts">
<violation number="1" location="website/matchers/location.ts:58">
P1: Coordinate-based matching incorrectly passes when user coordinates are missing.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| * @icon arrow-split | ||
| */ | ||
| const MatchRandom = ({ traffic }: Props) => { | ||
| return Math.random() < traffic; |
There was a problem hiding this comment.
P1: traffic is treated as a 0-1 probability, but the API/docs describe it as percentage; values like 50 will incorrectly match all traffic.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/matchers/random.ts, line 17:
<comment>`traffic` is treated as a 0-1 probability, but the API/docs describe it as percentage; values like `50` will incorrectly match all traffic.</comment>
<file context>
@@ -0,0 +1,24 @@
+ * @icon arrow-split
+ */
+const MatchRandom = ({ traffic }: Props) => {
+ return Math.random() < traffic;
+};
+
</file context>
| <> | ||
| {fonts?.map(({ styleSheet }, idx) => | ||
| styleSheet ? ( | ||
| <style key={idx} type="text/css" dangerouslySetInnerHTML={{ __html: styleSheet }} /> |
There was a problem hiding this comment.
P1: Avoid dangerouslySetInnerHTML for stylesheet content coming from props; render CSS as text children of <style> to prevent HTML/script injection.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/components/Theme.tsx, line 33:
<comment>Avoid `dangerouslySetInnerHTML` for stylesheet content coming from props; render CSS as text children of `<style>` to prevent HTML/script injection.</comment>
<file context>
@@ -0,0 +1,47 @@
+ <>
+ {fonts?.map(({ styleSheet }, idx) =>
+ styleSheet ? (
+ <style key={idx} type="text/css" dangerouslySetInnerHTML={{ __html: styleSheet }} />
+ ) : null,
+ )}
</file context>
| } | ||
| let result = !target.regionCode || target.regionCode === source.regionCode; | ||
| result &&= | ||
| !source.coordinates || |
There was a problem hiding this comment.
P1: Coordinate-based matching incorrectly passes when user coordinates are missing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/matchers/location.ts, line 58:
<comment>Coordinate-based matching incorrectly passes when user coordinates are missing.</comment>
<file context>
@@ -0,0 +1,113 @@
+ }
+ let result = !target.regionCode || target.regionCode === source.regionCode;
+ result &&=
+ !source.coordinates ||
+ !target.coordinates ||
+ haversine(source.coordinates, target.coordinates) <= Number(target.coordinates.split(",")[2]);
</file context>
| @@ -0,0 +1 @@ | |||
| export const stripHTML = (str: string) => str.replace(/(<([^>]+)>)/gi, ""); | |||
There was a problem hiding this comment.
P2: The tag-stripping regex is too broad and will remove non-HTML text between < and >, causing unintended data loss.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/utils/html.ts, line 1:
<comment>The tag-stripping regex is too broad and will remove non-HTML text between `<` and `>`, causing unintended data loss.</comment>
<file context>
@@ -0,0 +1 @@
+export const stripHTML = (str: string) => str.replace(/(<([^>]+)>)/gi, "");
</file context>
Remove unused variables in cron matcher, fix parseInt radix, auto-fix import ordering and formatting across website tests and manifests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Guard URL parsing in getGTMIdFromSrc with try/catch - Sanitize trackingId in GTAG to prevent script injection - Escape regex metacharacters in pathname Template matcher - Fix empty-string env var treated as missing in secret loader - Handle cron weekday 7 as alias for Sunday (0) - Add tests for new edge cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
🎉 This PR is included in version 1.3.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
Summary
websiteapp from deco-cx/apps (Fresh/Deno) to @decocms/apps-start (TanStack Start/React/Node), following the existingAppModContractpattern<Head>to React 19 native head hoistingMatchContext,Matcher,FlagObj,MultivariateFlag) — no dependency on@deco/decoTest plan
tsc --noEmit— zero type errorsbiome check— zero errors (warnings only, same as other apps)vitest run— 222 tests pass (125 existing + 97 new)🤖 Generated with Claude Code
Summary by cubic
Migrates the website app from Fresh/Deno to TanStack Start/React (
@decocms/apps-start) while keeping theAppModContract. Also hardens GTM/GA ID handling, escapes pathname templates, fixes cron weekday 7, improves secret/env loaders, and adds edge‑case tests.New Features
Seo,Theme,Analytics,VideoSeo,SeoV2,Analytics)MatchContext,Matcher,FlagObj,MultivariateFlag) with no@deco/decodependencywebsite/mod,client,types,index,website/manifest.gen.ts)MatchContextto the “Everyone” flag matcherMigration
@decocms/apps/website/*entry points in TanStack Start appsnpm run generate:manifeststo include thewebsiteappSeo,Theme, andAnalyticsrender, and matchers evaluate correctly with live request contextWritten for commit 72c8a3d. Summary will update on new commits.