@decocms/start 0.19.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 (185) hide show
  1. package/.cursor/skills/deco-api-call-dedup/SKILL.md +443 -0
  2. package/.cursor/skills/deco-apps-architecture/SKILL.md +255 -0
  3. package/.cursor/skills/deco-apps-architecture/app-pattern.md +288 -0
  4. package/.cursor/skills/deco-apps-architecture/commerce-types.md +239 -0
  5. package/.cursor/skills/deco-apps-architecture/new-app-guide.md +268 -0
  6. package/.cursor/skills/deco-apps-architecture/scripts-codegen.md +148 -0
  7. package/.cursor/skills/deco-apps-architecture/shared-utils.md +181 -0
  8. package/.cursor/skills/deco-apps-architecture/vtex-deep-structure.md +253 -0
  9. package/.cursor/skills/deco-apps-architecture/website-app.md +169 -0
  10. package/.cursor/skills/deco-apps-vtex-porting/SKILL.md +189 -0
  11. package/.cursor/skills/deco-apps-vtex-porting/adaptation-patterns.md +335 -0
  12. package/.cursor/skills/deco-apps-vtex-porting/commerce-porting.md +155 -0
  13. package/.cursor/skills/deco-apps-vtex-porting/cookie-auth-patterns.md +148 -0
  14. package/.cursor/skills/deco-apps-vtex-porting/structure-map.md +234 -0
  15. package/.cursor/skills/deco-apps-vtex-porting/transform-mapping.md +99 -0
  16. package/.cursor/skills/deco-apps-vtex-porting/website-porting.md +194 -0
  17. package/.cursor/skills/deco-apps-vtex-review/SKILL.md +234 -0
  18. package/.cursor/skills/deco-async-rendering-architecture/SKILL.md +270 -0
  19. package/.cursor/skills/deco-async-rendering-site-guide/SKILL.md +417 -0
  20. package/.cursor/skills/deco-cms-layout-caching/SKILL.md +293 -0
  21. package/.cursor/skills/deco-cms-route-config/SKILL.md +388 -0
  22. package/.cursor/skills/deco-core-architecture/SKILL.md +185 -0
  23. package/.cursor/skills/deco-core-architecture/blocks.md +196 -0
  24. package/.cursor/skills/deco-core-architecture/deco-vs-deco-start.md +191 -0
  25. package/.cursor/skills/deco-core-architecture/engine.md +220 -0
  26. package/.cursor/skills/deco-core-architecture/hooks-components.md +157 -0
  27. package/.cursor/skills/deco-core-architecture/plugins-clients.md +136 -0
  28. package/.cursor/skills/deco-core-architecture/runtime.md +116 -0
  29. package/.cursor/skills/deco-core-architecture/site-usage.md +165 -0
  30. package/.cursor/skills/deco-e2e-testing/SKILL.md +372 -0
  31. package/.cursor/skills/deco-e2e-testing/discovery.md +337 -0
  32. package/.cursor/skills/deco-e2e-testing/scripts/scaffold.sh +81 -0
  33. package/.cursor/skills/deco-e2e-testing/selectors.md +175 -0
  34. package/.cursor/skills/deco-e2e-testing/templates/package.json +18 -0
  35. package/.cursor/skills/deco-e2e-testing/templates/playwright.config.ts +65 -0
  36. package/.cursor/skills/deco-e2e-testing/templates/scripts/baseline.ts +279 -0
  37. package/.cursor/skills/deco-e2e-testing/templates/scripts/run-e2e.ts +194 -0
  38. package/.cursor/skills/deco-e2e-testing/templates/specs/ecommerce-flow.spec.ts +612 -0
  39. package/.cursor/skills/deco-e2e-testing/templates/tsconfig.json +12 -0
  40. package/.cursor/skills/deco-e2e-testing/templates/utils/metrics-collector.ts +918 -0
  41. package/.cursor/skills/deco-e2e-testing/troubleshooting.md +602 -0
  42. package/.cursor/skills/deco-edge-caching/SKILL.md +316 -0
  43. package/.cursor/skills/deco-full-analysis/SKILL.md +898 -0
  44. package/.cursor/skills/deco-full-analysis/checklists/asset-optimization.md +251 -0
  45. package/.cursor/skills/deco-full-analysis/checklists/bug-fix.md +189 -0
  46. package/.cursor/skills/deco-full-analysis/checklists/cache-strategy.md +144 -0
  47. package/.cursor/skills/deco-full-analysis/checklists/dependency-update.md +150 -0
  48. package/.cursor/skills/deco-full-analysis/checklists/hydration-fix.md +191 -0
  49. package/.cursor/skills/deco-full-analysis/checklists/image-optimization.md +180 -0
  50. package/.cursor/skills/deco-full-analysis/checklists/loader-optimization.md +165 -0
  51. package/.cursor/skills/deco-full-analysis/checklists/seo-fix.md +183 -0
  52. package/.cursor/skills/deco-full-analysis/checklists/site-cleanup.md +281 -0
  53. package/.cursor/skills/deco-full-analysis/discovery.md +548 -0
  54. package/.cursor/skills/deco-incident-debugging/SKILL.md +378 -0
  55. package/.cursor/skills/deco-incident-debugging/headless-mode.md +510 -0
  56. package/.cursor/skills/deco-incident-debugging/learnings-index.md +227 -0
  57. package/.cursor/skills/deco-incident-debugging/triage-workflow.md +312 -0
  58. package/.cursor/skills/deco-islands-migration/SKILL.md +251 -0
  59. package/.cursor/skills/deco-loader-n-plus-1-detector/SKILL.md +275 -0
  60. package/.cursor/skills/deco-performance-audit/SKILL.md +530 -0
  61. package/.cursor/skills/deco-performance-audit/tools-reference.md +428 -0
  62. package/.cursor/skills/deco-performance-audit/workflow.md +457 -0
  63. package/.cursor/skills/deco-server-functions-invoke/SKILL.md +92 -0
  64. package/.cursor/skills/deco-server-functions-invoke/architecture.md +166 -0
  65. package/.cursor/skills/deco-server-functions-invoke/generator.md +122 -0
  66. package/.cursor/skills/deco-server-functions-invoke/problem.md +98 -0
  67. package/.cursor/skills/deco-server-functions-invoke/troubleshooting.md +110 -0
  68. package/.cursor/skills/deco-site-deployment/SKILL.md +396 -0
  69. package/.cursor/skills/deco-site-memory-debugging/SKILL.md +121 -0
  70. package/.cursor/skills/deco-site-memory-debugging/cdp-connection.md +222 -0
  71. package/.cursor/skills/deco-site-memory-debugging/memory-analysis.md +362 -0
  72. package/.cursor/skills/deco-site-patterns/SKILL.md +124 -0
  73. package/.cursor/skills/deco-site-patterns/app-composition.md +337 -0
  74. package/.cursor/skills/deco-site-patterns/client-patterns.md +341 -0
  75. package/.cursor/skills/deco-site-patterns/cms-wiring.md +230 -0
  76. package/.cursor/skills/deco-site-patterns/section-patterns.md +340 -0
  77. package/.cursor/skills/deco-site-scaling-tuning/SKILL.md +240 -0
  78. package/.cursor/skills/deco-site-scaling-tuning/analysis-scripts.md +267 -0
  79. package/.cursor/skills/deco-start-architecture/SKILL.md +218 -0
  80. package/.cursor/skills/deco-start-architecture/admin-protocol.md +156 -0
  81. package/.cursor/skills/deco-start-architecture/cms-resolution.md +201 -0
  82. package/.cursor/skills/deco-start-architecture/code-quality.md +158 -0
  83. package/.cursor/skills/deco-start-architecture/gap-analysis.md +129 -0
  84. package/.cursor/skills/deco-start-architecture/sdk-utilities.md +197 -0
  85. package/.cursor/skills/deco-start-architecture/worker-entry-caching.md +154 -0
  86. package/.cursor/skills/deco-startup-analysis/SKILL.md +248 -0
  87. package/.cursor/skills/deco-storefront-test-checklist/SKILL.md +369 -0
  88. package/.cursor/skills/deco-tanstack-hydration-fixes/SKILL.md +468 -0
  89. package/.cursor/skills/deco-tanstack-navigation/SKILL.md +681 -0
  90. package/.cursor/skills/deco-tanstack-search/SKILL.md +411 -0
  91. package/.cursor/skills/deco-tanstack-storefront-patterns/SKILL.md +1013 -0
  92. package/.cursor/skills/deco-to-tanstack-migration/SKILL.md +518 -0
  93. package/.cursor/skills/deco-to-tanstack-migration/references/codemod-commands.md +174 -0
  94. package/.cursor/skills/deco-to-tanstack-migration/references/commerce/README.md +78 -0
  95. package/.cursor/skills/deco-to-tanstack-migration/references/deco-framework/README.md +128 -0
  96. package/.cursor/skills/deco-to-tanstack-migration/references/gotchas.md +719 -0
  97. package/.cursor/skills/deco-to-tanstack-migration/references/imports/README.md +70 -0
  98. package/.cursor/skills/deco-to-tanstack-migration/references/platform-hooks/README.md +154 -0
  99. package/.cursor/skills/deco-to-tanstack-migration/references/signals/README.md +220 -0
  100. package/.cursor/skills/deco-to-tanstack-migration/references/vite-config/README.md +78 -0
  101. package/.cursor/skills/deco-to-tanstack-migration/templates/package-json.md +55 -0
  102. package/.cursor/skills/deco-to-tanstack-migration/templates/root-route.md +110 -0
  103. package/.cursor/skills/deco-to-tanstack-migration/templates/router.md +96 -0
  104. package/.cursor/skills/deco-to-tanstack-migration/templates/setup-ts.md +167 -0
  105. package/.cursor/skills/deco-to-tanstack-migration/templates/vite-config.md +122 -0
  106. package/.cursor/skills/deco-to-tanstack-migration/templates/worker-entry.md +67 -0
  107. package/.cursor/skills/deco-typescript-fixes/SKILL.md +178 -0
  108. package/.cursor/skills/deco-typescript-fixes/common-fixes.md +330 -0
  109. package/.cursor/skills/deco-typescript-fixes/strategy.md +148 -0
  110. package/.cursor/skills/deco-variant-selection-perf/SKILL.md +272 -0
  111. package/.cursor/skills/deco-vtex-fetch-cache/SKILL.md +225 -0
  112. package/.cursor/skills/find-skills/SKILL.md +133 -0
  113. package/.cursor/skills/incident-report/SKILL.md +179 -0
  114. package/.cursor/skills/incident-report/references/5-whys.md +75 -0
  115. package/.cursor/skills/incident-report/templates/client-report.md +187 -0
  116. package/.cursor/skills/incident-report/templates/internal-report.md +206 -0
  117. package/.cursor/skills/template-skill/SKILL.md +38 -0
  118. package/.github/workflows/release.yml +32 -0
  119. package/.releaserc.json +25 -0
  120. package/CLAUDE.md +135 -0
  121. package/GAP_ANALYSIS.md +224 -0
  122. package/GAP_ANALYSIS_V2.md +1013 -0
  123. package/biome.json +39 -0
  124. package/knip.json +5 -0
  125. package/package.json +87 -0
  126. package/scripts/generate-blocks.ts +69 -0
  127. package/scripts/generate-invoke.ts +378 -0
  128. package/scripts/generate-schema.ts +657 -0
  129. package/src/admin/cors.ts +29 -0
  130. package/src/admin/decofile.ts +72 -0
  131. package/src/admin/index.ts +24 -0
  132. package/src/admin/invoke.ts +163 -0
  133. package/src/admin/liveControls.ts +29 -0
  134. package/src/admin/meta.ts +70 -0
  135. package/src/admin/render.ts +205 -0
  136. package/src/admin/schema.ts +686 -0
  137. package/src/admin/setup.ts +44 -0
  138. package/src/cms/index.ts +59 -0
  139. package/src/cms/loader.ts +180 -0
  140. package/src/cms/registry.ts +162 -0
  141. package/src/cms/resolve.ts +1005 -0
  142. package/src/cms/sectionLoaders.ts +294 -0
  143. package/src/hooks/DecoPageRenderer.tsx +444 -0
  144. package/src/hooks/LazySection.tsx +109 -0
  145. package/src/hooks/LiveControls.tsx +108 -0
  146. package/src/hooks/SectionErrorFallback.tsx +85 -0
  147. package/src/hooks/index.ts +8 -0
  148. package/src/index.ts +5 -0
  149. package/src/matchers/builtins.ts +184 -0
  150. package/src/matchers/posthog.ts +154 -0
  151. package/src/middleware/decoState.ts +55 -0
  152. package/src/middleware/healthMetrics.ts +131 -0
  153. package/src/middleware/index.ts +80 -0
  154. package/src/middleware/liveness.ts +21 -0
  155. package/src/middleware/observability.ts +205 -0
  156. package/src/routes/adminRoutes.ts +83 -0
  157. package/src/routes/cmsRoute.ts +302 -0
  158. package/src/routes/components.tsx +34 -0
  159. package/src/routes/index.ts +15 -0
  160. package/src/sdk/analytics.ts +72 -0
  161. package/src/sdk/cacheHeaders.ts +268 -0
  162. package/src/sdk/cachedLoader.ts +206 -0
  163. package/src/sdk/clx.ts +3 -0
  164. package/src/sdk/cookie.ts +39 -0
  165. package/src/sdk/createInvoke.ts +57 -0
  166. package/src/sdk/csp.ts +59 -0
  167. package/src/sdk/env.ts +27 -0
  168. package/src/sdk/index.ts +63 -0
  169. package/src/sdk/instrumentedFetch.ts +137 -0
  170. package/src/sdk/invoke.ts +133 -0
  171. package/src/sdk/mergeCacheControl.ts +150 -0
  172. package/src/sdk/redirects.ts +217 -0
  173. package/src/sdk/requestContext.ts +184 -0
  174. package/src/sdk/serverTimings.ts +68 -0
  175. package/src/sdk/signal.ts +41 -0
  176. package/src/sdk/sitemap.ts +143 -0
  177. package/src/sdk/urlUtils.ts +117 -0
  178. package/src/sdk/useDevice.ts +82 -0
  179. package/src/sdk/useId.ts +7 -0
  180. package/src/sdk/useScript.ts +101 -0
  181. package/src/sdk/workerEntry.ts +703 -0
  182. package/src/sdk/wrapCaughtErrors.ts +107 -0
  183. package/src/types/index.ts +39 -0
  184. package/src/types/widgets.ts +13 -0
  185. package/tsconfig.json +13 -0
@@ -0,0 +1,316 @@
1
+ ---
2
+ name: deco-edge-caching
3
+ description: Configure edge caching for Deco storefronts on Cloudflare Workers using createDecoWorkerEntry, cacheHeaders, detectCacheProfile, and routeCacheDefaults from @decocms/start. Use when setting up worker-entry caching, tuning Cache-Control headers, adding cache profiles for commerce page types (PDP, PLP, search), configuring staleTime for TanStack Router routes, debugging cache HITs/MISSes, or implementing cache purge APIs.
4
+ ---
5
+
6
+ # Deco Edge Caching
7
+
8
+ Complete caching infrastructure for Deco storefronts on Cloudflare Workers, provided by `@decocms/start/sdk`.
9
+
10
+ ## Architecture Overview
11
+
12
+ Three caching layers work together:
13
+
14
+ | Layer | What | Where | TTL Control |
15
+ |-------|------|-------|-------------|
16
+ | **Edge cache** | Full HTML responses | Cloudflare Cache API + CDN | `cacheHeaders(profile)` via worker-entry |
17
+ | **Loader cache** | VTEX/Shopify API data | In-memory per-isolate (V8) | `createCachedLoader()` in setup.ts |
18
+ | **Client cache** | Route data after navigation | TanStack Router memory | `routeCacheDefaults(profile)` on routes |
19
+
20
+ The **worker-entry** is the authority for edge caching. Routes declare intent via `headers()` and `staleTime`, but the worker-entry overrides Cache-Control based on URL-detected profiles.
21
+
22
+ ## Cache Profiles
23
+
24
+ | Profile | Browser `max-age` | Edge `s-maxage` | SWR | Client `staleTime` |
25
+ |---------|------------------|-----------------|-----|---------------------|
26
+ | `static` | 1 hour | 1 day | 1 day | 5 min |
27
+ | `product` | 60s | 5 min | 1 hour | 1 min |
28
+ | `listing` | 30s | 2 min | 10 min | 1 min |
29
+ | `search` | 0 | 60s | 5 min | 30s |
30
+ | `cart` | private | — | — | 0 |
31
+ | `private` | private | — | — | 0 |
32
+ | `none` | private | — | — | 0 |
33
+
34
+ ## URL-to-Profile Detection (built-in)
35
+
36
+ | URL Pattern | Detected Profile |
37
+ |-------------|-----------------|
38
+ | `/` | `static` |
39
+ | `*/p` (ends with /p) | `product` |
40
+ | `/s`, `/s/*`, `?q=` | `search` |
41
+ | `/cart`, `/checkout`, `/account`, `/login` | `private` |
42
+ | `/api/*`, `/deco/*`, `/_server`, `/_build` | `none` |
43
+ | Everything else | `listing` (conservative default) |
44
+
45
+ ## Site Worker Entry (10 lines)
46
+
47
+ **CRITICAL**: `wrangler.jsonc` must point to this custom file, NOT to `@tanstack/react-start/server-entry`. TanStack Start's Cloudflare adapter completely ignores custom `export default` — it generates its own handler that calls `createStartHandler` directly. Without a separate worker-entry, none of the caching, admin routes, or purge logic will execute in production.
48
+
49
+ ```jsonc
50
+ // wrangler.jsonc
51
+ {
52
+ "main": "./src/worker-entry.ts"
53
+ // NOT: "main": "@tanstack/react-start/server-entry"
54
+ }
55
+ ```
56
+
57
+ ```ts
58
+ // src/worker-entry.ts
59
+ import "./setup";
60
+ import handler, { createServerEntry } from "@tanstack/react-start/server-entry";
61
+ import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
62
+
63
+ const serverEntry = createServerEntry({
64
+ async fetch(request) {
65
+ return await handler.fetch(request);
66
+ },
67
+ });
68
+
69
+ export default createDecoWorkerEntry(serverEntry);
70
+ ```
71
+
72
+ ### With Custom Overrides
73
+
74
+ ```ts
75
+ export default createDecoWorkerEntry(serverEntry, {
76
+ // Override profile for specific URLs
77
+ detectProfile: (url) => {
78
+ if (url.pathname.startsWith("/institucional")) return "static";
79
+ return null; // fall through to built-in detection
80
+ },
81
+ // Disable mobile/desktop cache key splitting
82
+ deviceSpecificKeys: false,
83
+ // Custom purge token env var
84
+ purgeTokenEnv: "MY_PURGE_TOKEN",
85
+ // Add extra bypass paths
86
+ extraBypassPaths: ["/preview/"],
87
+ });
88
+ ```
89
+
90
+ ## Route Setup
91
+
92
+ ```ts
93
+ import { createFileRoute } from "@tanstack/react-router";
94
+ import { cacheHeaders, routeCacheDefaults } from "@decocms/start/sdk/cacheHeaders";
95
+
96
+ export const Route = createFileRoute("/")({
97
+ ...routeCacheDefaults("static"),
98
+ headers: () => cacheHeaders("static"),
99
+ loader: () => loadPage(),
100
+ component: HomePage,
101
+ });
102
+ ```
103
+
104
+ For the CMS catch-all route:
105
+
106
+ ```ts
107
+ export const Route = createFileRoute("/$")({
108
+ ...routeCacheDefaults("listing"),
109
+ headers: () => cacheHeaders("listing"),
110
+ loader: async ({ params }) => { /* ... */ },
111
+ component: CmsPage,
112
+ });
113
+ ```
114
+
115
+ The worker-entry overrides the route's Cache-Control with the correct profile for each URL (PDP gets `product`, search gets `search`, etc.), so the route's `headers()` serves as a fallback for client-side navigation responses via `/_server`.
116
+
117
+ ## Registering Custom Patterns
118
+
119
+ ```ts
120
+ // In setup.ts or worker-entry.ts
121
+ import { registerCachePattern } from "@decocms/start/sdk/cacheHeaders";
122
+
123
+ registerCachePattern({
124
+ test: (pathname) => pathname.startsWith("/blog"),
125
+ profile: "static",
126
+ });
127
+ ```
128
+
129
+ Custom patterns evaluate before built-in ones.
130
+
131
+ ## Factory Features
132
+
133
+ `createDecoWorkerEntry` provides:
134
+
135
+ 1. **Cache API integration** — `caches.default.match()` / `.put()` for edge caching
136
+ 2. **Device-specific keys** — mobile/desktop get separate cached HTML (`__cf_device` param)
137
+ 3. **Per-URL profiles** — `detectCacheProfile(url)` selects the right Cache-Control
138
+ 4. **Immutable static assets** — `/_build/assets/*-{hash}.*` get `immutable, max-age=31536000`
139
+ 5. **Private path protection** — strips public Cache-Control from cart/checkout/account responses
140
+ 6. **Cache API TTL fix** — stores with `max-age={sMaxAge}` since Cache API ignores `s-maxage`
141
+ 7. **Purge API** — `POST /_cache/purge` with bearer token to invalidate paths
142
+ 8. **Diagnostic headers** — `X-Cache: HIT|MISS` and `X-Cache-Profile: {profile}`
143
+
144
+ ## Debugging Cache
145
+
146
+ ```bash
147
+ # Check profile and cache status
148
+ curl -s -D - -o /dev/null "https://site.com/category-slug" | grep -iE "cache-control|x-cache"
149
+
150
+ # Expected first hit:
151
+ # cache-control: public, max-age=30, s-maxage=120, stale-while-revalidate=600
152
+ # x-cache: MISS
153
+ # x-cache-profile: listing
154
+
155
+ # Expected second hit:
156
+ # cf-cache-status: HIT
157
+ # x-cache: HIT
158
+ # age: 3
159
+
160
+ # Purge cache
161
+ curl -X POST "https://site.com/_cache/purge" \
162
+ -H "Authorization: Bearer $PURGE_TOKEN" \
163
+ -H "Content-Type: application/json" \
164
+ -d '{"paths": ["/", "/vedacao-externa"]}'
165
+ ```
166
+
167
+ **Important**: Use GET requests for testing (not `curl -I` which sends HEAD). The worker-entry only caches GET requests.
168
+
169
+ ## Loader Cache (Server-Side SWR)
170
+
171
+ In `setup.ts`, wrap commerce loaders with `createCachedLoader`:
172
+
173
+ ```ts
174
+ import { createCachedLoader } from "@decocms/start/sdk/cachedLoader";
175
+
176
+ const cachedPLP = createCachedLoader("vtex/plp", vtexPLP, {
177
+ policy: "stale-while-revalidate",
178
+ maxAge: 60_000,
179
+ });
180
+ ```
181
+
182
+ This is per-isolate in-memory cache (V8 Map). Resets on cold start. Includes request deduplication (single-flight) and LRU eviction at 500 entries.
183
+
184
+ ## Cache Versioning with BUILD_HASH
185
+
186
+ Deploy-time cache busting uses a `BUILD_HASH` environment variable (typically the git short SHA) passed to `wrangler deploy`. The worker-entry appends this to cache keys so deploying a new version automatically serves fresh content.
187
+
188
+ ```yaml
189
+ # .github/workflows/deploy.yml
190
+ - name: Deploy to Cloudflare Workers
191
+ run: npx wrangler deploy
192
+ env:
193
+ BUILD_HASH: ${{ github.sha }}
194
+ ```
195
+
196
+ The worker-entry reads `env.BUILD_HASH` and injects it into cache keys. On new deploys, old cache entries simply expire naturally — no purge needed.
197
+
198
+ ## Site-Level Cache Pattern Registration
199
+
200
+ For sites with known institutional/static pages that would otherwise get the conservative 2-min "listing" TTL, register explicit patterns in `setup.ts`:
201
+
202
+ ```ts
203
+ // setup.ts
204
+ import { registerCachePattern } from "@decocms/start/sdk/cacheHeaders";
205
+
206
+ // Institutional pages — content changes rarely, promote to 24h edge TTL
207
+ registerCachePattern({
208
+ test: (p) =>
209
+ p.startsWith("/institucional") ||
210
+ p.startsWith("/central-de-atendimento") ||
211
+ p.startsWith("/politica-de-") ||
212
+ p.startsWith("/termos-") ||
213
+ p === "/fale-conosco" ||
214
+ p === "/trabalhe-conosco" ||
215
+ p === "/cadastro" ||
216
+ p === "/televendas",
217
+ profile: "static",
218
+ });
219
+
220
+ // Promotional/collection pages — already listing-like, but explicit is better
221
+ registerCachePattern({
222
+ test: (p) =>
223
+ p.startsWith("/ofertas") ||
224
+ p.startsWith("/b/") ||
225
+ p.startsWith("/festival-"),
226
+ profile: "listing",
227
+ });
228
+ ```
229
+
230
+ Custom patterns are evaluated before built-in ones. This is the recommended way to tune caching per-site without modifying the framework.
231
+
232
+ ## Client-Side Route Caching (routeCacheDefaults)
233
+
234
+ Without `routeCacheDefaults`, every SPA navigation triggers a fresh server request even if the data was just loaded. This is the most common cause of "slow navigation" reports.
235
+
236
+ The catch-all route `$.tsx` MUST include `routeCacheDefaults`:
237
+
238
+ ```ts
239
+ export const Route = createFileRoute("/$")({
240
+ ...routeCacheDefaults("listing"), // <-- client-side cache: 1min stale, 5min gc
241
+ loaderDeps: routeConfig.loaderDeps,
242
+ loader: routeConfig.loader,
243
+ headers: ({ loaderData }) => {
244
+ return cacheHeaders(loaderData?.cacheProfile ?? "listing");
245
+ },
246
+ component: CmsPage,
247
+ });
248
+ ```
249
+
250
+ The homepage should use `cmsHomeRouteConfig` which already includes `routeCacheDefaults("static")`:
251
+
252
+ ```ts
253
+ export const Route = createFileRoute("/")({
254
+ ...cmsHomeRouteConfig({ defaultTitle: "My Store" }),
255
+ component: HomePage,
256
+ });
257
+ ```
258
+
259
+ ## Cache Analysis & Debugging with Stats Lake
260
+
261
+ Deco sites emit CDN usage data to a ClickHouse stats-lake. This enables cache performance analysis:
262
+
263
+ ```sql
264
+ -- Cache status breakdown for a site
265
+ SELECT
266
+ JSONExtractString(extra, 'cacheStatus') AS cache_status,
267
+ count() AS requests,
268
+ round(count() * 100.0 / sum(count()) OVER (), 2) AS pct
269
+ FROM fact_usage_daily
270
+ WHERE site_id = <site_id>
271
+ AND date >= today() - 7
272
+ GROUP BY cache_status
273
+ ORDER BY requests DESC;
274
+ ```
275
+
276
+ ### Understanding "unknown" Cache Status
277
+
278
+ When the Cloudflare Worker uses `caches.default.match()/put()` to serve cached responses internally, the outer CDN reports `cf-cache-status: DYNAMIC` because the Worker is the origin. The stats-lake logs this as "unknown" or empty.
279
+
280
+ This means a high "unknown" percentage does NOT indicate a caching problem — it means the Worker's internal Cache API is handling the request before it reaches the origin CDN layer. This is expected and desirable behavior.
281
+
282
+ To verify actual cache performance:
283
+ 1. Check `X-Cache: HIT|MISS` header (set by the worker-entry)
284
+ 2. Check `X-Cache-Profile` header (shows which profile was detected)
285
+ 3. Query stats-lake grouping by `cacheStatus` AND response status codes
286
+
287
+ ### Comparing Staging vs Production Cache
288
+
289
+ When migrating to TanStack Workers, compare cache metrics:
290
+ - Production (Deno/Fresh on Kubernetes) typically shows high HIT rates because traffic volume keeps caches warm
291
+ - Staging Workers may show lower HIT rates due to lower traffic, plus "unknown" status from internal Cache API
292
+ - The "unknown" requests on Workers are functionally equivalent to HITs — they're served from the Worker's Cache API without hitting the origin server function
293
+
294
+ ## Key Constraints
295
+
296
+ - **Cache API ignores `s-maxage`** — the factory uses `max-age` equal to `sMaxAge` when storing in Cache API
297
+ - **In-memory loader cache is ephemeral** — resets when Workers isolates recycle (~30s idle)
298
+ - **Device keys add a query param** — `__cf_device=mobile|desktop` is appended to cache keys, so purging must clear both
299
+ - **Non-200 responses are never cached** — only 200 OK goes into Cache API
300
+ - **`/_server` paths always bypass cache** — TanStack Start RPC requests are never edge-cached
301
+ - **UTM parameters are stripped** — `utm_*`, `gclid`, `fbclid` are removed from cache keys to improve hit rates
302
+ - **Segment hashing** — user segments (from matchers/flags) are hashed into the cache key so different audiences get different cached responses
303
+
304
+ ## Package Exports
305
+
306
+ ```ts
307
+ // Headers and profiles
308
+ import { cacheHeaders, routeCacheDefaults, detectCacheProfile } from "@decocms/start/sdk/cacheHeaders";
309
+ import { getCacheProfileConfig, registerCachePattern } from "@decocms/start/sdk/cacheHeaders";
310
+
311
+ // Worker entry factory
312
+ import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
313
+
314
+ // Loader cache
315
+ import { createCachedLoader, clearLoaderCache } from "@decocms/start/sdk/cachedLoader";
316
+ ```