@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.
- package/.cursor/skills/deco-api-call-dedup/SKILL.md +443 -0
- package/.cursor/skills/deco-apps-architecture/SKILL.md +255 -0
- package/.cursor/skills/deco-apps-architecture/app-pattern.md +288 -0
- package/.cursor/skills/deco-apps-architecture/commerce-types.md +239 -0
- package/.cursor/skills/deco-apps-architecture/new-app-guide.md +268 -0
- package/.cursor/skills/deco-apps-architecture/scripts-codegen.md +148 -0
- package/.cursor/skills/deco-apps-architecture/shared-utils.md +181 -0
- package/.cursor/skills/deco-apps-architecture/vtex-deep-structure.md +253 -0
- package/.cursor/skills/deco-apps-architecture/website-app.md +169 -0
- package/.cursor/skills/deco-apps-vtex-porting/SKILL.md +189 -0
- package/.cursor/skills/deco-apps-vtex-porting/adaptation-patterns.md +335 -0
- package/.cursor/skills/deco-apps-vtex-porting/commerce-porting.md +155 -0
- package/.cursor/skills/deco-apps-vtex-porting/cookie-auth-patterns.md +148 -0
- package/.cursor/skills/deco-apps-vtex-porting/structure-map.md +234 -0
- package/.cursor/skills/deco-apps-vtex-porting/transform-mapping.md +99 -0
- package/.cursor/skills/deco-apps-vtex-porting/website-porting.md +194 -0
- package/.cursor/skills/deco-apps-vtex-review/SKILL.md +234 -0
- package/.cursor/skills/deco-async-rendering-architecture/SKILL.md +270 -0
- package/.cursor/skills/deco-async-rendering-site-guide/SKILL.md +417 -0
- package/.cursor/skills/deco-cms-layout-caching/SKILL.md +293 -0
- package/.cursor/skills/deco-cms-route-config/SKILL.md +388 -0
- package/.cursor/skills/deco-core-architecture/SKILL.md +185 -0
- package/.cursor/skills/deco-core-architecture/blocks.md +196 -0
- package/.cursor/skills/deco-core-architecture/deco-vs-deco-start.md +191 -0
- package/.cursor/skills/deco-core-architecture/engine.md +220 -0
- package/.cursor/skills/deco-core-architecture/hooks-components.md +157 -0
- package/.cursor/skills/deco-core-architecture/plugins-clients.md +136 -0
- package/.cursor/skills/deco-core-architecture/runtime.md +116 -0
- package/.cursor/skills/deco-core-architecture/site-usage.md +165 -0
- package/.cursor/skills/deco-e2e-testing/SKILL.md +372 -0
- package/.cursor/skills/deco-e2e-testing/discovery.md +337 -0
- package/.cursor/skills/deco-e2e-testing/scripts/scaffold.sh +81 -0
- package/.cursor/skills/deco-e2e-testing/selectors.md +175 -0
- package/.cursor/skills/deco-e2e-testing/templates/package.json +18 -0
- package/.cursor/skills/deco-e2e-testing/templates/playwright.config.ts +65 -0
- package/.cursor/skills/deco-e2e-testing/templates/scripts/baseline.ts +279 -0
- package/.cursor/skills/deco-e2e-testing/templates/scripts/run-e2e.ts +194 -0
- package/.cursor/skills/deco-e2e-testing/templates/specs/ecommerce-flow.spec.ts +612 -0
- package/.cursor/skills/deco-e2e-testing/templates/tsconfig.json +12 -0
- package/.cursor/skills/deco-e2e-testing/templates/utils/metrics-collector.ts +918 -0
- package/.cursor/skills/deco-e2e-testing/troubleshooting.md +602 -0
- package/.cursor/skills/deco-edge-caching/SKILL.md +316 -0
- package/.cursor/skills/deco-full-analysis/SKILL.md +898 -0
- package/.cursor/skills/deco-full-analysis/checklists/asset-optimization.md +251 -0
- package/.cursor/skills/deco-full-analysis/checklists/bug-fix.md +189 -0
- package/.cursor/skills/deco-full-analysis/checklists/cache-strategy.md +144 -0
- package/.cursor/skills/deco-full-analysis/checklists/dependency-update.md +150 -0
- package/.cursor/skills/deco-full-analysis/checklists/hydration-fix.md +191 -0
- package/.cursor/skills/deco-full-analysis/checklists/image-optimization.md +180 -0
- package/.cursor/skills/deco-full-analysis/checklists/loader-optimization.md +165 -0
- package/.cursor/skills/deco-full-analysis/checklists/seo-fix.md +183 -0
- package/.cursor/skills/deco-full-analysis/checklists/site-cleanup.md +281 -0
- package/.cursor/skills/deco-full-analysis/discovery.md +548 -0
- package/.cursor/skills/deco-incident-debugging/SKILL.md +378 -0
- package/.cursor/skills/deco-incident-debugging/headless-mode.md +510 -0
- package/.cursor/skills/deco-incident-debugging/learnings-index.md +227 -0
- package/.cursor/skills/deco-incident-debugging/triage-workflow.md +312 -0
- package/.cursor/skills/deco-islands-migration/SKILL.md +251 -0
- package/.cursor/skills/deco-loader-n-plus-1-detector/SKILL.md +275 -0
- package/.cursor/skills/deco-performance-audit/SKILL.md +530 -0
- package/.cursor/skills/deco-performance-audit/tools-reference.md +428 -0
- package/.cursor/skills/deco-performance-audit/workflow.md +457 -0
- package/.cursor/skills/deco-server-functions-invoke/SKILL.md +92 -0
- package/.cursor/skills/deco-server-functions-invoke/architecture.md +166 -0
- package/.cursor/skills/deco-server-functions-invoke/generator.md +122 -0
- package/.cursor/skills/deco-server-functions-invoke/problem.md +98 -0
- package/.cursor/skills/deco-server-functions-invoke/troubleshooting.md +110 -0
- package/.cursor/skills/deco-site-deployment/SKILL.md +396 -0
- package/.cursor/skills/deco-site-memory-debugging/SKILL.md +121 -0
- package/.cursor/skills/deco-site-memory-debugging/cdp-connection.md +222 -0
- package/.cursor/skills/deco-site-memory-debugging/memory-analysis.md +362 -0
- package/.cursor/skills/deco-site-patterns/SKILL.md +124 -0
- package/.cursor/skills/deco-site-patterns/app-composition.md +337 -0
- package/.cursor/skills/deco-site-patterns/client-patterns.md +341 -0
- package/.cursor/skills/deco-site-patterns/cms-wiring.md +230 -0
- package/.cursor/skills/deco-site-patterns/section-patterns.md +340 -0
- package/.cursor/skills/deco-site-scaling-tuning/SKILL.md +240 -0
- package/.cursor/skills/deco-site-scaling-tuning/analysis-scripts.md +267 -0
- package/.cursor/skills/deco-start-architecture/SKILL.md +218 -0
- package/.cursor/skills/deco-start-architecture/admin-protocol.md +156 -0
- package/.cursor/skills/deco-start-architecture/cms-resolution.md +201 -0
- package/.cursor/skills/deco-start-architecture/code-quality.md +158 -0
- package/.cursor/skills/deco-start-architecture/gap-analysis.md +129 -0
- package/.cursor/skills/deco-start-architecture/sdk-utilities.md +197 -0
- package/.cursor/skills/deco-start-architecture/worker-entry-caching.md +154 -0
- package/.cursor/skills/deco-startup-analysis/SKILL.md +248 -0
- package/.cursor/skills/deco-storefront-test-checklist/SKILL.md +369 -0
- package/.cursor/skills/deco-tanstack-hydration-fixes/SKILL.md +468 -0
- package/.cursor/skills/deco-tanstack-navigation/SKILL.md +681 -0
- package/.cursor/skills/deco-tanstack-search/SKILL.md +411 -0
- package/.cursor/skills/deco-tanstack-storefront-patterns/SKILL.md +1013 -0
- package/.cursor/skills/deco-to-tanstack-migration/SKILL.md +518 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/codemod-commands.md +174 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/commerce/README.md +78 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/deco-framework/README.md +128 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/gotchas.md +719 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/imports/README.md +70 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/platform-hooks/README.md +154 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/signals/README.md +220 -0
- package/.cursor/skills/deco-to-tanstack-migration/references/vite-config/README.md +78 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/package-json.md +55 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/root-route.md +110 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/router.md +96 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/setup-ts.md +167 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/vite-config.md +122 -0
- package/.cursor/skills/deco-to-tanstack-migration/templates/worker-entry.md +67 -0
- package/.cursor/skills/deco-typescript-fixes/SKILL.md +178 -0
- package/.cursor/skills/deco-typescript-fixes/common-fixes.md +330 -0
- package/.cursor/skills/deco-typescript-fixes/strategy.md +148 -0
- package/.cursor/skills/deco-variant-selection-perf/SKILL.md +272 -0
- package/.cursor/skills/deco-vtex-fetch-cache/SKILL.md +225 -0
- package/.cursor/skills/find-skills/SKILL.md +133 -0
- package/.cursor/skills/incident-report/SKILL.md +179 -0
- package/.cursor/skills/incident-report/references/5-whys.md +75 -0
- package/.cursor/skills/incident-report/templates/client-report.md +187 -0
- package/.cursor/skills/incident-report/templates/internal-report.md +206 -0
- package/.cursor/skills/template-skill/SKILL.md +38 -0
- package/.github/workflows/release.yml +32 -0
- package/.releaserc.json +25 -0
- package/CLAUDE.md +135 -0
- package/GAP_ANALYSIS.md +224 -0
- package/GAP_ANALYSIS_V2.md +1013 -0
- package/biome.json +39 -0
- package/knip.json +5 -0
- package/package.json +87 -0
- package/scripts/generate-blocks.ts +69 -0
- package/scripts/generate-invoke.ts +378 -0
- package/scripts/generate-schema.ts +657 -0
- package/src/admin/cors.ts +29 -0
- package/src/admin/decofile.ts +72 -0
- package/src/admin/index.ts +24 -0
- package/src/admin/invoke.ts +163 -0
- package/src/admin/liveControls.ts +29 -0
- package/src/admin/meta.ts +70 -0
- package/src/admin/render.ts +205 -0
- package/src/admin/schema.ts +686 -0
- package/src/admin/setup.ts +44 -0
- package/src/cms/index.ts +59 -0
- package/src/cms/loader.ts +180 -0
- package/src/cms/registry.ts +162 -0
- package/src/cms/resolve.ts +1005 -0
- package/src/cms/sectionLoaders.ts +294 -0
- package/src/hooks/DecoPageRenderer.tsx +444 -0
- package/src/hooks/LazySection.tsx +109 -0
- package/src/hooks/LiveControls.tsx +108 -0
- package/src/hooks/SectionErrorFallback.tsx +85 -0
- package/src/hooks/index.ts +8 -0
- package/src/index.ts +5 -0
- package/src/matchers/builtins.ts +184 -0
- package/src/matchers/posthog.ts +154 -0
- package/src/middleware/decoState.ts +55 -0
- package/src/middleware/healthMetrics.ts +131 -0
- package/src/middleware/index.ts +80 -0
- package/src/middleware/liveness.ts +21 -0
- package/src/middleware/observability.ts +205 -0
- package/src/routes/adminRoutes.ts +83 -0
- package/src/routes/cmsRoute.ts +302 -0
- package/src/routes/components.tsx +34 -0
- package/src/routes/index.ts +15 -0
- package/src/sdk/analytics.ts +72 -0
- package/src/sdk/cacheHeaders.ts +268 -0
- package/src/sdk/cachedLoader.ts +206 -0
- package/src/sdk/clx.ts +3 -0
- package/src/sdk/cookie.ts +39 -0
- package/src/sdk/createInvoke.ts +57 -0
- package/src/sdk/csp.ts +59 -0
- package/src/sdk/env.ts +27 -0
- package/src/sdk/index.ts +63 -0
- package/src/sdk/instrumentedFetch.ts +137 -0
- package/src/sdk/invoke.ts +133 -0
- package/src/sdk/mergeCacheControl.ts +150 -0
- package/src/sdk/redirects.ts +217 -0
- package/src/sdk/requestContext.ts +184 -0
- package/src/sdk/serverTimings.ts +68 -0
- package/src/sdk/signal.ts +41 -0
- package/src/sdk/sitemap.ts +143 -0
- package/src/sdk/urlUtils.ts +117 -0
- package/src/sdk/useDevice.ts +82 -0
- package/src/sdk/useId.ts +7 -0
- package/src/sdk/useScript.ts +101 -0
- package/src/sdk/workerEntry.ts +703 -0
- package/src/sdk/wrapCaughtErrors.ts +107 -0
- package/src/types/index.ts +39 -0
- package/src/types/widgets.ts +13 -0
- 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()`) |
|