@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,201 @@
1
+ # CMS Block Resolution
2
+
3
+ The CMS layer handles loading content blocks from the decofile, resolving `__resolveType` references, and rendering pages.
4
+
5
+ ## Block Loading (`cms/loader.ts`)
6
+
7
+ ### Core Functions
8
+
9
+ ```typescript
10
+ loadBlocks(): Record<string, any> // Reads .deco/blocks/*.json
11
+ setBlocks(blocks: Record<string, any>): void // Updates in-memory state + revision + notifies listeners
12
+ findPageByPath(path: string, blocks): Page // Matches URL path to CMS page
13
+ getAllPages(blocks): Page[] // Returns all page blocks
14
+ withBlocksOverride(blocks, fn): T // AsyncLocalStorage override for preview
15
+ getRevision(): string // Returns content-hash revision of current blocks
16
+ onChange(listener: () => void): () => void // Register callback for block changes (returns unsubscribe)
17
+ ```
18
+
19
+ ### Revision Tracking
20
+
21
+ `setBlocks()` now computes a content-based hash (DJB2) of all block keys/types, stored as the current revision. This revision is:
22
+ - Returned by `getRevision()` for use as ETags
23
+ - Included in `GET /.decofile` responses
24
+ - Used by `handleMeta()` to auto-invalidate cached schema when content changes
25
+
26
+ ### onChange Listeners
27
+
28
+ Register callbacks that fire whenever `setBlocks()` is called:
29
+
30
+ ```typescript
31
+ const unsubscribe = onChange(() => {
32
+ console.log("Blocks updated, new revision:", getRevision());
33
+ });
34
+ ```
35
+
36
+ Used internally by `handleMeta()` to invalidate its cached ETag when blocks change.
37
+
38
+ ## Section Registry (`cms/registry.ts`)
39
+
40
+ Registers React section components by key:
41
+
42
+ ```typescript
43
+ registerSection(key: string, component: React.ComponentType, schema?: any): void
44
+ getSection(key: string): SectionEntry | undefined
45
+ getSectionOptions(): string[]
46
+ getSectionRegistry(): Map<string, SectionEntry>
47
+ ```
48
+
49
+ Site's `setup.ts` registers all sections at startup:
50
+
51
+ ```typescript
52
+ import Hero from "./sections/Hero.tsx";
53
+ registerSection("site/sections/Hero.tsx", Hero);
54
+ ```
55
+
56
+ ## Resolution (`cms/resolve.ts`)
57
+
58
+ ### resolveDecoPage
59
+
60
+ Main resolver that walks the page tree, resolving all `__resolveType` references:
61
+
62
+ ```typescript
63
+ resolveDecoPage(page: Page, request: Request, options?: { select?: string }): Promise<ResolvedPage>
64
+ ```
65
+
66
+ Pipeline:
67
+ 1. Get page sections from the decofile
68
+ 2. Evaluate multivariate flags (A/B testing)
69
+ 3. For each section, walk props recursively via `internalResolve()`
70
+ 4. When `__resolveType` is found, resolve recursively (generic resolver, not just commerce loaders)
71
+ 5. Per-request memoization prevents duplicate calls to the same resolver
72
+ 6. Depth protection (max 10 levels) prevents infinite recursion
73
+ 7. DanglingReference handler for unresolvable `__resolveType` (configurable fallback)
74
+ 8. Apply `select` filtering if specified
75
+ 9. Return resolved sections ready for rendering
76
+
77
+ ### Generic Recursive Resolver (`internalResolve`)
78
+
79
+ The resolution engine now handles any `__resolveType`, not just registered commerce loaders:
80
+
81
+ ```typescript
82
+ // ResolveContext tracks per-request state
83
+ interface ResolveContext {
84
+ memo: Map<string, unknown>; // memoization cache
85
+ depth: number; // current recursion depth (max: 10)
86
+ }
87
+ ```
88
+
89
+ Resolution order:
90
+ 1. Check commerce loaders registry (`commerceLoaders`)
91
+ 2. Check decofile blocks (for CMS-defined references)
92
+ 3. If neither matches → call `onDanglingReference` handler (configurable)
93
+
94
+ ### Error & Fallback Handlers
95
+
96
+ ```typescript
97
+ setResolveErrorHandler(handler: (error: Error, key: string) => void): void
98
+ setDanglingReferenceHandler(handler: (key: string, props: any) => unknown): void
99
+ addSkipResolveType(type: string): void // Dynamically add types to skip during resolution
100
+ ```
101
+
102
+ ### registerCommerceLoader
103
+
104
+ ```typescript
105
+ registerCommerceLoader(key: string, loader: CommerceLoader): void
106
+ ```
107
+
108
+ Site's `setup.ts`:
109
+
110
+ ```typescript
111
+ import { productList } from "@decocms/apps/vtex/inline-loaders";
112
+ registerCommerceLoader("vtex/loaders/productList.ts", productList);
113
+ ```
114
+
115
+ ### Select / Field Filtering
116
+
117
+ Resolved values can be filtered using `applySelect`:
118
+
119
+ ```typescript
120
+ // Only return specific fields from resolved data
121
+ resolveValue(blocks, request, { select: "name,price,images" });
122
+ ```
123
+
124
+ ### registerMatcher
125
+
126
+ ```typescript
127
+ registerMatcher(key: string, matcher: MatcherFn): void
128
+ ```
129
+
130
+ ### Built-in Matchers
131
+
132
+ Registered via `registerBuiltinMatchers()` from `matchers/builtins.ts`:
133
+
134
+ | Matcher | Key | Purpose |
135
+ |---------|-----|---------|
136
+ | always | website/matchers/always.ts | Always true (also resolves `$live/matchers/MatchAlways.ts`) |
137
+ | never | website/matchers/never.ts | Always false |
138
+ | device | website/matchers/device.ts | Mobile/desktop/tablet |
139
+ | random | website/matchers/random.ts | Traffic percentage |
140
+ | utm | website/matchers/utm.ts | UTM parameter matching |
141
+ | cookie | website/matchers/cookie.ts | Cookie value matching |
142
+ | cron | website/matchers/cron.ts | Time/date range |
143
+ | host | website/matchers/host.ts | Hostname matching |
144
+ | pathname | website/matchers/pathname.ts | URL pattern matching |
145
+ | queryString | website/matchers/queryString.ts | Query param matching |
146
+
147
+ Matcher context now includes enhanced properties:
148
+
149
+ ```typescript
150
+ interface MatcherContext {
151
+ request: Request;
152
+ headers: Headers;
153
+ siteId: number;
154
+ site: string;
155
+ }
156
+ ```
157
+
158
+ ### Multivariate Flags
159
+
160
+ The resolver handles `website/flags/multivariate.ts` blocks:
161
+
162
+ ```json
163
+ {
164
+ "__resolveType": "website/flags/multivariate.ts",
165
+ "variants": [
166
+ {
167
+ "rule": { "__resolveType": "website/matchers/device.ts", "mobile": true },
168
+ "value": { "sections": ["...mobile sections..."] }
169
+ },
170
+ {
171
+ "rule": { "__resolveType": "website/matchers/always.ts" },
172
+ "value": { "sections": ["...default sections..."] }
173
+ }
174
+ ]
175
+ }
176
+ ```
177
+
178
+ ### SKIP_RESOLVE_TYPES
179
+
180
+ Types intentionally skipped during resolution (handled differently in TanStack).
181
+ Default list includes:
182
+ - `website/loaders/redirects.ts`
183
+ - `commerce/sections/Seo/SeoPDPV2.tsx`
184
+ - `commerce/sections/Seo/SeoPLPV2.tsx`
185
+
186
+ Additional types can be added dynamically at runtime:
187
+
188
+ ```typescript
189
+ import { addSkipResolveType } from "@decocms/start/cms";
190
+ addSkipResolveType("custom/loaders/myCustomLoader.ts");
191
+ ```
192
+
193
+ ### PostHog Matchers (`matchers/posthog.ts`)
194
+
195
+ Server-side PostHog feature flag evaluation:
196
+
197
+ ```typescript
198
+ createPostHogMatcher(config): MatcherFn
199
+ configurePostHogMatcher(apiKey, personalApiKey): void
200
+ createServerPostHogAdapter(): PostHogAdapter
201
+ ```
@@ -0,0 +1,158 @@
1
+ # Code Quality
2
+
3
+ Current state and recommendations for code quality tooling in `@decocms/start`.
4
+
5
+ ## Current State
6
+
7
+ | Tool | Status |
8
+ |------|--------|
9
+ | TypeScript | Present (`tsc --noEmit` via `typecheck`) |
10
+ | `strictNullChecks` | Enabled |
11
+ | `strict` mode | NOT enabled (only `strictNullChecks`) |
12
+ | ESLint | ABSENT |
13
+ | Prettier | ABSENT |
14
+ | Knip | ABSENT |
15
+ | Vitest/Jest | ABSENT |
16
+ | Husky/lint-staged | ABSENT |
17
+ | Biome | ABSENT |
18
+
19
+ ## Current Scripts
20
+
21
+ ```json
22
+ {
23
+ "build": "tsc",
24
+ "typecheck": "tsc --noEmit"
25
+ }
26
+ ```
27
+
28
+ ## CI/CD
29
+
30
+ Only `release.yml` exists - runs `npm install` then `npx semantic-release`. No build, typecheck, lint, or test step before release.
31
+
32
+ ## Recommendations
33
+
34
+ ### 1. TypeScript Strict Mode
35
+
36
+ Enable full strict mode in `tsconfig.json`:
37
+
38
+ ```json
39
+ {
40
+ "compilerOptions": {
41
+ "strict": true
42
+ }
43
+ }
44
+ ```
45
+
46
+ This enables: `strictNullChecks` (already on), `strictFunctionTypes`, `strictBindCallApply`, `strictPropertyInitialization`, `noImplicitAny`, `noImplicitThis`, `alwaysStrict`, `useUnknownInCatchVariables`.
47
+
48
+ ### 2. Knip (Dead Code Detection)
49
+
50
+ ```json
51
+ // knip.json
52
+ {
53
+ "entry": ["src/index.ts", "scripts/*.ts"],
54
+ "project": ["src/**/*.{ts,tsx}", "scripts/**/*.ts"],
55
+ "ignoreBinaries": ["semantic-release"]
56
+ }
57
+ ```
58
+
59
+ Script: `"lint:unused": "knip"`
60
+
61
+ ### 3. Biome (Lint + Format)
62
+
63
+ Biome is faster than ESLint + Prettier combined and works well for pure TypeScript projects:
64
+
65
+ ```json
66
+ // biome.json
67
+ {
68
+ "$schema": "https://biomejs.dev/schemas/2.0/schema.json",
69
+ "organizeImports": { "enabled": true },
70
+ "linter": {
71
+ "enabled": true,
72
+ "rules": {
73
+ "recommended": true,
74
+ "correctness": {
75
+ "noUnusedVariables": "warn",
76
+ "noUnusedImports": "warn"
77
+ }
78
+ }
79
+ },
80
+ "formatter": {
81
+ "enabled": true,
82
+ "indentStyle": "space",
83
+ "indentWidth": 2
84
+ },
85
+ "files": {
86
+ "include": ["src/**", "scripts/**"]
87
+ }
88
+ }
89
+ ```
90
+
91
+ Scripts:
92
+ ```json
93
+ {
94
+ "lint": "biome check src/ scripts/",
95
+ "lint:fix": "biome check --write src/ scripts/",
96
+ "format": "biome format src/ scripts/",
97
+ "format:fix": "biome format --write src/ scripts/"
98
+ }
99
+ ```
100
+
101
+ ### 4. CI Pipeline
102
+
103
+ Add build + quality checks before release:
104
+
105
+ ```yaml
106
+ # .github/workflows/ci.yml
107
+ name: CI
108
+ on: [push, pull_request]
109
+
110
+ jobs:
111
+ check:
112
+ runs-on: ubuntu-latest
113
+ steps:
114
+ - uses: actions/checkout@v4
115
+ - uses: actions/setup-node@v4
116
+ with:
117
+ node-version: 22
118
+ - run: npm install
119
+ - run: npm run typecheck
120
+ - run: npm run lint
121
+ - run: npm run lint:unused
122
+ ```
123
+
124
+ Update `release.yml` to run checks before release:
125
+
126
+ ```yaml
127
+ - run: npm install
128
+ - run: npm run typecheck
129
+ - run: npm run lint
130
+ - run: npm run lint:unused
131
+ - name: Release
132
+ run: npx semantic-release
133
+ ```
134
+
135
+ ### 5. Recommended package.json Scripts
136
+
137
+ ```json
138
+ {
139
+ "scripts": {
140
+ "build": "tsc",
141
+ "typecheck": "tsc --noEmit",
142
+ "lint": "biome check src/ scripts/",
143
+ "lint:fix": "biome check --write src/ scripts/",
144
+ "lint:unused": "knip",
145
+ "format": "biome format --check src/ scripts/",
146
+ "format:fix": "biome format --write src/ scripts/",
147
+ "check": "npm run typecheck && npm run lint && npm run lint:unused && npm run format"
148
+ }
149
+ }
150
+ ```
151
+
152
+ ### 6. Priority Order
153
+
154
+ 1. **Knip** (immediate) - find and remove dead code
155
+ 2. **Biome** (immediate) - consistent lint + format
156
+ 3. **CI pipeline** (immediate) - prevent regressions
157
+ 4. **TypeScript strict** (next) - may require fixes
158
+ 5. **Vitest** (later) - when test coverage becomes a priority
@@ -0,0 +1,129 @@
1
+ # Gap Analysis: deco-cx/deco vs @decocms/start
2
+
3
+ Feature-by-feature comparison with implementation status and roadmap.
4
+
5
+ ## Status Summary
6
+
7
+ | Status | Count | Meaning |
8
+ |--------|-------|---------|
9
+ | PORTED | 24 | Fully implemented and working |
10
+ | PARTIAL | 5 | Exists but incomplete |
11
+ | MISSING | 4 | Not yet ported |
12
+ | NOT NEEDED | 4 | Architectural difference |
13
+
14
+ ## Feature Comparison Table
15
+
16
+ | # | Feature | Status |
17
+ |---|---------|--------|
18
+ | 1 | Resolution engine | PORTED (generic resolver with memoization, depth protection, DanglingReference handler, select support) |
19
+ | 2 | Sections | PORTED (registry + DecoPageRenderer) |
20
+ | 3 | Loaders | PORTED (registerCommerceLoader) |
21
+ | 4 | Actions | PORTED (via invoke handler) |
22
+ | 5 | Handlers | NOT NEEDED (TanStack Router) |
23
+ | 6 | Flags | PORTED (multivariate in resolve.ts) |
24
+ | 7 | Matchers | PORTED (12 matchers registered) |
25
+ | 8 | Apps | NOT NEEDED (npm packages) |
26
+ | 9 | Workflows | MISSING |
27
+ | 10 | /live/invoke | PORTED |
28
+ | 11 | /deco/render | NOT NEEDED (TanStack Query) |
29
+ | 12 | /live/_meta | PORTED |
30
+ | 13 | /live/release | MISSING |
31
+ | 14 | /.decofile | PORTED |
32
+ | 15 | /live/inspect | MISSING |
33
+ | 16 | /live/previews | PORTED |
34
+ | 17 | /styles.css | NOT NEEDED (Vite) |
35
+ | 18 | /deco/_liveness + /deco/_health | PORTED (liveness + detailed health with uptime, memory, request counts, cache stats) |
36
+ | 19 | CORS middleware | PORTED |
37
+ | 20 | Cache-control | PORTED |
38
+ | 21 | Segment | PORTED |
39
+ | 22 | Observability | PORTED (TracerAdapter + MeterAdapter, named metrics, context propagation, request/cache recording) |
40
+ | 23 | useSection | PARTIAL (stub) |
41
+ | 24 | usePartialSection | PARTIAL (stub) |
42
+ | 25 | useScript | PORTED (with lightweight minification + LRU cache) |
43
+ | 26 | useDevice | PORTED (server-side via User-Agent + RequestContext, detectDevice, checkMobile/Tablet/Desktop) |
44
+ | 27 | useSetEarlyHints | MISSING |
45
+ | 28 | LiveControls | PORTED |
46
+ | 29 | SectionContext | MISSING |
47
+ | 30 | ErrorBoundary | PORTED |
48
+ | 31 | LazySection | PORTED |
49
+ | 32 | Schema generation | PORTED (dynamic registries for loaders + matchers, runtime composition) |
50
+ | 33 | Client invoke | PARTIAL (no withManifest, no SSE) |
51
+ | 34 | DecofileProvider | PORTED (revision tracking, onChange callbacks, hot-reload with cache invalidation) |
52
+ | 35 | Caching | PARTIAL (no LRU/Redis/tiered) |
53
+ | 36 | Edge caching | PORTED (unique to deco-start) |
54
+ | 37 | Manifest generation | PARTIAL (generate-blocks.ts) |
55
+
56
+ ## Implemented Roadmap
57
+
58
+ ### Tier 0 -- Production Blocking: ALL DONE
59
+ 1. VTEX proxy routes
60
+ 2. VTEX middleware (segment + login-aware cache)
61
+ 3. Redirect system
62
+ 4. Sitemap generation
63
+ 5. SEO JSON-LD components
64
+
65
+ ### Tier 1 -- Quality: ALL DONE
66
+ 6. Segment-aware cache keys
67
+ 7. Priority matchers (cookie, pathname, cron, host, queryString)
68
+ 8. Top searches + search validator
69
+ 9. Product extension pipeline
70
+ 10. LazySection component
71
+ 11. UTM param stripping + canonical URLs
72
+ 12. wrapCaughtErrors
73
+ 13. CSP headers
74
+ 14. Cache-Control merge
75
+
76
+ ### Tier 2 -- DX and Completeness: ALL DONE
77
+ 15. Schema gen improvements
78
+ 16. Client-side hooks (useCart, useUser, useWishlist) in apps-start
79
+ 17. Image/Picture components in apps-start
80
+ 18. RequestContext (AsyncLocalStorage)
81
+ 19. Commerce loader request context
82
+ 20. Remaining VTEX loaders in apps-start
83
+ 21. Admin schema composition (composeMeta)
84
+
85
+ ### Tier 2.5 -- Framework Improvements (PR #3): ALL DONE
86
+ 22. Dynamic schema registries (loaders + matchers) — no more hardcoded KNOWN_LOADERS
87
+ 23. Generic recursive resolver with memoization, depth protection, DanglingReference
88
+ 24. useDevice server-side (User-Agent + RequestContext)
89
+ 25. Health probe `/deco/_health` with uptime, memory, cache stats, request metrics
90
+ 26. Enhanced observability: MeterAdapter, MetricNames, context propagation
91
+ 27. Enhanced invoke: FormData/URLEncoded parsing, `?select=`, actions, nested `__resolveType`
92
+ 28. Decofile revision tracking + onChange listeners + meta auto-invalidation
93
+ 29. useScript minification + LRU cache
94
+
95
+ ### Tier 3 -- Future / Deferred
96
+ 30. Admin live preview (WebSocket)
97
+ 31. Hot reload authenticated endpoint
98
+ 32. SSE streaming reader
99
+ 33. sectionMiddleware / transformProps
100
+ 34. Shopify draft order, proxy routes
101
+ 35. Geo/location matchers
102
+
103
+ ## Intentional Divergences
104
+
105
+ | deco-cx/deco | @decocms/start | Reason |
106
+ |-------------|----------------|--------|
107
+ | Section loader/action exports | Pure React components | Idiomatic React |
108
+ | HTMX partials | TanStack Query + Router | React reconciliation |
109
+ | Fresh islands | Full React SPA + SSR | TanStack Start model |
110
+ | Deno runtime | Node.js / CF Workers | Deployment target |
111
+ | Import maps | npm packages | Standard resolution |
112
+ | Global fetch monkey-patch | Explicit instrumented fetch | Predictable |
113
+ | Per-loader Vary | Segment cache keys | Simpler, CF Cache API |
114
+
115
+ ## Unique to @decocms/start
116
+
117
+ | Feature | Description |
118
+ |---------|-------------|
119
+ | Cloudflare Workers | createDecoWorkerEntry with Cache API |
120
+ | Edge caching profiles | detectCacheProfile, URL-based TTL rules |
121
+ | invokeQueryOptions | TanStack Query integration |
122
+ | LazySection (IntersectionObserver) | Client-side lazy loading |
123
+ | PostHog matchers | Server-side feature flags |
124
+ | Sitemap/Redirects SDK | Built-in utilities |
125
+ | Dynamic schema registries | Runtime loader/matcher registration (no hardcoded lists) |
126
+ | Health metrics endpoint | `/deco/_health` with uptime, memory, cache stats |
127
+ | Pluggable MeterAdapter | Counter/gauge/histogram abstraction for any metrics backend |
128
+ | useScript minification | Lightweight JS minification with LRU cache |
129
+ | Decofile revision tracking | Content-hash based revisions with onChange callbacks |
@@ -0,0 +1,197 @@
1
+ # SDK Utilities
2
+
3
+ All utilities exported from `@decocms/start/sdk/*`.
4
+
5
+ ## useScript (`sdk/useScript.ts`)
6
+
7
+ Serialize functions as inline scripts for SSR with lightweight minification:
8
+
9
+ ```typescript
10
+ function useScript<T extends (...args: any[]) => void>(fn: T, ...args: Parameters<T>): string
11
+ function useScriptAsDataURI<T extends (...args: any[]) => void>(fn: T, ...args: Parameters<T>): string
12
+ ```
13
+
14
+ Features:
15
+ - **Minification**: `minifyJs()` removes comments (single-line + multi-line), collapses whitespace, trims lines
16
+ - **LRU Cache**: Minified function bodies are cached (128 entries) to avoid redundant work across renders
17
+ - Properly typed with generic constraints on function parameters
18
+
19
+ Also exports stubs for partial section support:
20
+
21
+ ```typescript
22
+ function usePartialSection<T>(options: { props?: Partial<T> }): Record<string, string>
23
+ function useSection<T>(options: { props?: Partial<T> }): string
24
+ ```
25
+
26
+ Note: These are stubs. Use TanStack Query + Router navigation instead.
27
+
28
+ ## useDevice (`sdk/useDevice.ts`)
29
+
30
+ Server-side device detection based on User-Agent via RequestContext:
31
+
32
+ ```typescript
33
+ type Device = "mobile" | "tablet" | "desktop";
34
+
35
+ function detectDevice(userAgent: string | null): Device // Pure function, no context needed
36
+ function useDevice(): Device // Hook using RequestContext
37
+ function checkMobile(): boolean // Direct context access
38
+ function checkTablet(): boolean // Direct context access
39
+ function checkDesktop(): boolean // Direct context access
40
+ ```
41
+
42
+ - `detectDevice` is a standalone pure function (usable in middleware, workers, etc.)
43
+ - `useDevice` reads from `RequestContext.current` (server-side via AsyncLocalStorage)
44
+ - `checkMobile`/`checkTablet`/`checkDesktop` access `RequestContext` directly (not hooks)
45
+
46
+ Export path: `@decocms/start/sdk/useDevice`
47
+
48
+ ## Signal (`sdk/signal.ts`)
49
+
50
+ Reactive signal replacing `@preact/signals`, backed by `@tanstack/store`:
51
+
52
+ ```typescript
53
+ function signal<T>(initialValue: T): ReactiveSignal<T>
54
+ ```
55
+
56
+ ## Analytics (`sdk/analytics.ts`)
57
+
58
+ Client-side event tracking via `data-event` attributes:
59
+
60
+ ```typescript
61
+ function useSendEvent(events: AnalyticsEvent[]): string
62
+ const ANALYTICS_SCRIPT: string
63
+ function gtmScript(containerId: string): string
64
+ ```
65
+
66
+ ## Cookie (`sdk/cookie.ts`)
67
+
68
+ Universal cookie utilities:
69
+
70
+ ```typescript
71
+ function getCookie(name: string): string | undefined // client
72
+ function setCookie(name: string, value: string, opts?): void // client
73
+ function deleteCookie(name: string): void // client
74
+ function getServerSideCookie(header: string, name: string): string | undefined
75
+ function decodeCookie(value: string): string
76
+ ```
77
+
78
+ ## Invoke (`sdk/invoke.ts`)
79
+
80
+ Client-side RPC proxy for calling server loaders:
81
+
82
+ ```typescript
83
+ function createInvokeProxy<T>(baseUrl?: string): InvokeProxy<T>
84
+ function batchInvoke(calls: InvokeCall[]): Promise<any[]>
85
+ function invokeQueryOptions(key: string, props?: any): UseQueryOptions
86
+ ```
87
+
88
+ Integrates with TanStack Query: `useQuery(invokeQueryOptions("vtex/loaders/productList.ts", { query }))`.
89
+
90
+ ## Redirects (`sdk/redirects.ts`)
91
+
92
+ CMS-managed redirect system supporting CMS blocks and CSV import:
93
+
94
+ ```typescript
95
+ function loadRedirects(blocks: Record<string, any>): Map<string, Redirect>
96
+ function matchRedirect(path: string, redirects: Map): Redirect | null
97
+ function parseRedirectsCsv(csv: string): Redirect[]
98
+ function addRedirects(redirects: Redirect[]): void
99
+ ```
100
+
101
+ ## Sitemap (`sdk/sitemap.ts`)
102
+
103
+ XML sitemap generation:
104
+
105
+ ```typescript
106
+ function getCMSSitemapEntries(blocks: Record<string, any>): SitemapEntry[]
107
+ function generateSitemapXml(entries: SitemapEntry[]): string
108
+ function generateSitemapIndexXml(sitemaps: string[]): string
109
+ ```
110
+
111
+ ## RequestContext (`sdk/requestContext.ts`)
112
+
113
+ AsyncLocalStorage-based per-request context:
114
+
115
+ ```typescript
116
+ const RequestContext: {
117
+ bind<T>(data: RequestContextData, fn: () => T): T;
118
+ get(): RequestContextData | undefined;
119
+ }
120
+ ```
121
+
122
+ ## Server Timings (`sdk/serverTimings.ts`)
123
+
124
+ HTTP Server-Timing header utility.
125
+
126
+ ## Instrumented Fetch (`sdk/instrumentedFetch.ts`)
127
+
128
+ Fetch wrapper with logging and tracing:
129
+
130
+ ```typescript
131
+ function createInstrumentedFetch(options?: { tracer?: Tracer }): typeof fetch
132
+ function instrumentFetch(tracer?: Tracer): void
133
+ ```
134
+
135
+ ## Observability (`middleware/observability.ts`)
136
+
137
+ Pluggable tracing and metrics infrastructure:
138
+
139
+ ```typescript
140
+ // Tracer (existing)
141
+ interface TracerAdapter { startSpan(name, fn): T; activeSpan(): Span | undefined }
142
+ function configureTracer(tracer: TracerAdapter): void
143
+ function withTracing<T>(name: string, fn: () => T): T
144
+
145
+ // Meter (new)
146
+ interface MeterAdapter {
147
+ counterInc(name: string, value?: number, labels?: Record<string, string>): void
148
+ gaugeSet(name: string, value: number, labels?: Record<string, string>): void
149
+ histogramRecord(name: string, value: number, labels?: Record<string, string>): void
150
+ }
151
+ function configureMeter(meter: MeterAdapter): void
152
+ function getMeter(): MeterAdapter | undefined
153
+
154
+ // Standardized metric names
155
+ const MetricNames = {
156
+ HTTP_REQUESTS_TOTAL, HTTP_REQUEST_DURATION, HTTP_INFLIGHT,
157
+ CACHE_HITS_TOTAL, CACHE_MISSES_TOTAL,
158
+ RESOLVE_DURATION, RESOLVE_ERRORS, INVOKE_DURATION
159
+ }
160
+
161
+ // Convenience recorders
162
+ function recordRequestMetric(method, path, status, duration): void
163
+ function recordCacheMetric(hit: boolean, source: string): void
164
+
165
+ // Enhanced logging
166
+ function logRequest(method, url, status, duration): void // Includes trace ID if available
167
+ ```
168
+
169
+ ## Health Metrics (`middleware/healthMetrics.ts`)
170
+
171
+ Request tracking and health probe endpoint:
172
+
173
+ ```typescript
174
+ function trackRequest(): { start(): void; end(status: number): void }
175
+ function getHealthMetrics(): HealthMetrics
176
+ function handleHealthCheck(request: Request): Response
177
+ ```
178
+
179
+ `/deco/_health` returns JSON with:
180
+ - `uptime`: seconds since process start
181
+ - `requests`: total, inflight, errors, statusCodes breakdown
182
+ - `cache`: stats from `getLoaderCacheStats()` (hits, misses, size, hitRate)
183
+ - `memory`: RSS, heap total/used (if `process.memoryUsage` available)
184
+
185
+ Export path: `@decocms/start/middleware/healthMetrics`
186
+
187
+ ## Other Utilities
188
+
189
+ | Utility | File | Purpose |
190
+ |---------|------|---------|
191
+ | `clx` | `sdk/clx.ts` | CSS class combiner (like `clsx`) |
192
+ | `useId` | `sdk/useId.ts` | React `useId` wrapper |
193
+ | `wrapCaughtErrors` | `sdk/wrapCaughtErrors.ts` | Deferred error proxy for resilient rendering |
194
+ | `setCSPHeaders` | `sdk/csp.ts` | CSP frame-ancestors for admin iframe |
195
+ | `stripTrackingParams` | `sdk/urlUtils.ts` | Remove UTM/tracking params from URLs |
196
+ | `mergeCacheControl` | `sdk/mergeCacheControl.ts` | Merge Cache-Control headers (most restrictive wins) |
197
+ | `createCachedLoader` | `sdk/cachedLoader.ts` | In-memory SWR cache for loaders (with `getLoaderCacheStats()` and `clearLoaderCache()`) |