@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,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deco-core-architecture
|
|
3
|
+
description: Architecture reference for deco-cx/deco — the core Deco framework for Fresh/Deno. Covers the resolution engine (Resolvable → Resolver pipeline), block system (sections, loaders, actions, flags, matchers, handlers, apps, workflows), runtime request flow (Hono + Fresh/HTMX), DecofileProvider (state management), manifest generation, plugin system, hooks (useSection, useScript, useDevice), client-side invoke proxy, and the relationship between deco-cx/deco (Fresh/Deno) and @decocms/start (TanStack/Node). Use when exploring the deco repo, understanding how the framework works, building new block types, debugging resolution issues, or porting deco internals to TanStack Start.
|
|
4
|
+
globs:
|
|
5
|
+
- "**/deco.ts"
|
|
6
|
+
- "**/manifest.gen.ts"
|
|
7
|
+
- "**/mod.ts"
|
|
8
|
+
- "**/runtime.ts"
|
|
9
|
+
- "**/fresh.config.ts"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Sub-documents
|
|
13
|
+
|
|
14
|
+
| Document | Topic |
|
|
15
|
+
|----------|-------|
|
|
16
|
+
| [engine.md](./engine.md) | Resolution engine — Resolvable, Resolver, DecofileProvider, resolve pipeline |
|
|
17
|
+
| [blocks.md](./blocks.md) | Block system — all block types, adapt/decorate, manifest registration |
|
|
18
|
+
| [runtime.md](./runtime.md) | Runtime request flow — Hono, middleware chain, routes, rendering |
|
|
19
|
+
| [hooks-components.md](./hooks-components.md) | Hooks, components, and client-side code |
|
|
20
|
+
| [plugins-clients.md](./plugins-clients.md) | Fresh plugins, client-side invoke proxy, formdata utils |
|
|
21
|
+
| [site-usage.md](./site-usage.md) | How a Deco site uses the framework — osklenbr as reference |
|
|
22
|
+
| [deco-vs-deco-start.md](./deco-vs-deco-start.md) | Mapping deco-cx/deco (Fresh) → @decocms/start (TanStack) |
|
|
23
|
+
|
|
24
|
+
# deco-cx/deco Core Architecture
|
|
25
|
+
|
|
26
|
+
Reference for the `deco-cx/deco` repository — the core Deco framework powering Fresh/Deno storefronts.
|
|
27
|
+
|
|
28
|
+
## Repository Overview
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
deco/
|
|
32
|
+
├── mod.ts # Main entry — re-exports engine, runtime, blocks, context
|
|
33
|
+
├── mod.web.ts # Web/client entry — invoke proxy, stream reader
|
|
34
|
+
├── deco.ts # DecoContext, RequestContext, AsyncLocalStorage bindings
|
|
35
|
+
├── live.ts # Re-export of deco.ts (legacy alias)
|
|
36
|
+
├── types.ts # DecoManifest, DecoState, block type constants
|
|
37
|
+
├── deps.ts # External deps (OpenTelemetry, std, durable, inspect)
|
|
38
|
+
├── deno.json # v1.177.5 — imports, exports, tasks
|
|
39
|
+
│
|
|
40
|
+
├── engine/ # Resolution engine (45 files)
|
|
41
|
+
│ ├── core/ # Resolver, Resolvable, resolve pipeline
|
|
42
|
+
│ ├── manifest/ # Manifest builder, generation, defaults
|
|
43
|
+
│ ├── decofile/ # State providers (filesystem, JSON, realtime)
|
|
44
|
+
│ ├── schema/ # JSON Schema generation and introspection
|
|
45
|
+
│ └── importmap/ # Import map builder for blocks
|
|
46
|
+
│
|
|
47
|
+
├── blocks/ # Block definitions (15 files)
|
|
48
|
+
│ ├── section.ts # UI components with optional loader/action
|
|
49
|
+
│ ├── loader.ts # Data fetching blocks (cached, single-flight)
|
|
50
|
+
│ ├── action.ts # Mutation blocks
|
|
51
|
+
│ ├── handler.ts # HTTP request handlers
|
|
52
|
+
│ ├── flag.ts # Feature flags
|
|
53
|
+
│ ├── matcher.ts # Audience targeting predicates
|
|
54
|
+
│ ├── page.tsx # Page-level sections
|
|
55
|
+
│ ├── app.ts # App containers with manifest + state
|
|
56
|
+
│ ├── workflow.ts # Durable workflows
|
|
57
|
+
│ └── function.ts # Legacy loader format
|
|
58
|
+
│
|
|
59
|
+
├── runtime/ # Request handling (51 files)
|
|
60
|
+
│ ├── mod.ts # Deco class — main runtime entry
|
|
61
|
+
│ ├── handler.tsx # Hono app setup, route registration
|
|
62
|
+
│ ├── middleware.ts # Middleware chain (liveness, state, o11y, response)
|
|
63
|
+
│ ├── routes/ # Built-in routes (/live/invoke, /deco/render, etc.)
|
|
64
|
+
│ ├── features/ # Invoke, render, meta, preview, styles
|
|
65
|
+
│ ├── fresh/ # Fresh framework plugin + Bindings
|
|
66
|
+
│ ├── htmx/ # HTMX framework (alternative renderer)
|
|
67
|
+
│ ├── fetch/ # Instrumented fetch (logging, caching)
|
|
68
|
+
│ └── caches/ # LRU, Redis, tiered, filesystem caches
|
|
69
|
+
│
|
|
70
|
+
├── hooks/ # Server-side hooks (6 files)
|
|
71
|
+
├── components/ # Framework components (5 files)
|
|
72
|
+
├── plugins/ # Fresh plugins (3 files)
|
|
73
|
+
├── clients/ # Client-side invoke proxy (3 files)
|
|
74
|
+
├── commons/ # JWT, workflows
|
|
75
|
+
├── utils/ # HTTP, cookies, timings, invoke helpers
|
|
76
|
+
├── observability/ # OpenTelemetry instrumentation
|
|
77
|
+
├── daemon/ # Sidecar/embedded daemon for dev
|
|
78
|
+
├── dev/ # Dev server utilities
|
|
79
|
+
├── hypervisor/ # Multi-site orchestration
|
|
80
|
+
└── scripts/ # Release, dev, bundle scripts
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Core Concepts
|
|
84
|
+
|
|
85
|
+
### 1. Everything is a Resolvable
|
|
86
|
+
|
|
87
|
+
The fundamental unit in Deco is a **Resolvable** — an object with a `__resolveType` field pointing to a resolver:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// A resolvable stored in the decofile (CMS state)
|
|
91
|
+
{
|
|
92
|
+
"__resolveType": "site/loaders/productList.ts",
|
|
93
|
+
"query": "shoes",
|
|
94
|
+
"count": 12
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The engine recursively resolves all props, then invokes the matching resolver function.
|
|
99
|
+
|
|
100
|
+
### 2. Blocks define the type system
|
|
101
|
+
|
|
102
|
+
Each block type (section, loader, action, etc.) defines how modules are adapted into resolvers:
|
|
103
|
+
|
|
104
|
+
- **section** → wraps a Preact component, adding SSR + optional data loading
|
|
105
|
+
- **loader** → wraps a function with caching, single-flight dedup, and tracing
|
|
106
|
+
- **action** → wraps a mutation function with tracing
|
|
107
|
+
- **handler** → produces an HTTP handler from config
|
|
108
|
+
- **matcher** → evaluates a predicate against request context
|
|
109
|
+
- **flag** → combines matchers with variants for feature flags
|
|
110
|
+
- **app** → bundles manifest + state + dependencies
|
|
111
|
+
|
|
112
|
+
### 3. DecofileProvider manages state
|
|
113
|
+
|
|
114
|
+
The decofile is the CMS state — a `Record<string, Resolvable>`. Providers can be:
|
|
115
|
+
- **Filesystem** (`newFsProvider`) — reads from local `.json`/`.jsonl` files
|
|
116
|
+
- **Realtime** — connects to CMS websocket for live updates
|
|
117
|
+
- **JSON** — static in-memory state
|
|
118
|
+
|
|
119
|
+
### 4. Request flow
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Request → Hono
|
|
123
|
+
→ bindings middleware (RENDER_FN, GLOBALS)
|
|
124
|
+
→ liveness probe (/deco/_liveness)
|
|
125
|
+
→ state builder (prepareState, debug, echo)
|
|
126
|
+
→ observability (OpenTelemetry trace/span)
|
|
127
|
+
→ main middleware (CORS, headers, cache, segment)
|
|
128
|
+
→ route matching:
|
|
129
|
+
/styles.css → tailwind CSS
|
|
130
|
+
/live/_meta → schema + manifest
|
|
131
|
+
/live/invoke/* → single/batch invoke
|
|
132
|
+
/deco/render → partial section render
|
|
133
|
+
* (catch-all) → page handler → resolve → render
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 5. Two rendering frameworks
|
|
137
|
+
|
|
138
|
+
| Framework | Islands | Partials | Usage |
|
|
139
|
+
|-----------|---------|----------|-------|
|
|
140
|
+
| **Fresh** | Preact islands | `<Partial>` + `f-partial` | Standard Deco sites |
|
|
141
|
+
| **HTMX** | None (no JS) | `hx-get/hx-swap` | Lightweight alternative |
|
|
142
|
+
|
|
143
|
+
### 6. Invoke system
|
|
144
|
+
|
|
145
|
+
Client-side code calls server loaders/actions via the invoke API:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Client-side (runtime.ts in a site)
|
|
149
|
+
import { proxy } from "@deco/deco/web";
|
|
150
|
+
const invoke = proxy<Manifest>();
|
|
151
|
+
|
|
152
|
+
// Calls POST /live/invoke/site/loaders/productList.ts
|
|
153
|
+
const products = await invoke["site/loaders/productList.ts"]({ query: "shoes" });
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Key Exports
|
|
157
|
+
|
|
158
|
+
### `mod.ts` (main)
|
|
159
|
+
- `Context` — AsyncLocalStorage-based context
|
|
160
|
+
- `$live`, `initContext`, `newContext` — engine initialization
|
|
161
|
+
- `Deco`, `PageData` — runtime class and page data type
|
|
162
|
+
- `Block`, `BlockFunc`, `Resolvable`, `Resolved` — type system
|
|
163
|
+
- `asResolved`, `isDeferred`, `isResolvable` — resolution utilities
|
|
164
|
+
- `allowCorsFor` — CORS utility
|
|
165
|
+
- `JsonViewer`, `Framework` — components
|
|
166
|
+
|
|
167
|
+
### `mod.web.ts` (client)
|
|
168
|
+
- `proxy`, `withManifest`, `forApp` — invoke proxy builders
|
|
169
|
+
- `readFromStream` — SSE stream reader
|
|
170
|
+
- `InvokeAwaiter` — chainable invoke proxy
|
|
171
|
+
|
|
172
|
+
### `deco.ts` (context)
|
|
173
|
+
- `DecoContext` — site, siteId, deploymentId, platform, release, runtime
|
|
174
|
+
- `RequestContext` — signal, framework
|
|
175
|
+
- `Context.active()` — current context
|
|
176
|
+
- `Context.bind(ctx, fn)` — run fn with context
|
|
177
|
+
|
|
178
|
+
## Dependencies
|
|
179
|
+
|
|
180
|
+
- **Runtime**: Deno, Fresh 1.6.8, Preact 10.23.1
|
|
181
|
+
- **Observability**: OpenTelemetry (api, sdk-trace, sdk-metrics, sdk-logs)
|
|
182
|
+
- **Framework**: Hono (HTTP router)
|
|
183
|
+
- **Deco ecosystem**: `@deco/durable`, `@deco/inspect-vscode`, `@deco/warp`
|
|
184
|
+
- **Std**: `@std/assert`, `@std/async`, `@std/crypto`, `@std/encoding`, `@std/http`
|
|
185
|
+
- **Compiler**: `jsx: "react-jsx"`, `jsxImportSource: "preact"`
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Block System (`blocks/`)
|
|
2
|
+
|
|
3
|
+
Blocks are the type system of Deco. Each block type defines how a module is adapted into a resolver, previewed, and invoked.
|
|
4
|
+
|
|
5
|
+
## Block Interface
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface Block<TBlockModule> {
|
|
9
|
+
type: string; // manifest key: "sections", "loaders", etc.
|
|
10
|
+
introspect?: {
|
|
11
|
+
funcNames?: string[];
|
|
12
|
+
includeReturn?: boolean;
|
|
13
|
+
};
|
|
14
|
+
adapt?: (mod: TBlockModule, key: string) => Resolver | Resolver[];
|
|
15
|
+
decorate?: (mod: TBlockModule, key: string) => TBlockModule;
|
|
16
|
+
defaultDanglingRecover?: Resolver;
|
|
17
|
+
defaultPreview?: Resolver;
|
|
18
|
+
defaultInvoke?: Resolver;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## BlockModule Convention
|
|
23
|
+
|
|
24
|
+
Every block module can export:
|
|
25
|
+
|
|
26
|
+
| Export | Purpose |
|
|
27
|
+
|--------|---------|
|
|
28
|
+
| `default` | Main function (loader, action, component, handler factory) |
|
|
29
|
+
| `invoke` | Custom invocation handler (for `/live/invoke`) |
|
|
30
|
+
| `preview` / `Preview` | Admin preview component |
|
|
31
|
+
| `onBeforeResolveProps` | Transform props before resolution |
|
|
32
|
+
|
|
33
|
+
## Block Types
|
|
34
|
+
|
|
35
|
+
### Section (`section.ts`)
|
|
36
|
+
|
|
37
|
+
UI components that render on the page. The most common block type.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// type: "sections"
|
|
41
|
+
export default function MySection(props: Props) {
|
|
42
|
+
return <div>{props.title}</div>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// With server-side data loading:
|
|
46
|
+
export const loader = async (props: Props, req: Request, ctx: AppContext) => {
|
|
47
|
+
const data = await fetchData(props);
|
|
48
|
+
return { ...props, data };
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default function MySection({ data, title }: LoaderReturn) {
|
|
52
|
+
return <div>{title}: {data}</div>;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Features: wraps Preact component as resolver returning `PreactComponent`, supports `loader` for SSR, `action` for forms, ErrorBoundary + SectionContext wrapper.
|
|
57
|
+
|
|
58
|
+
### Loader (`loader.ts`)
|
|
59
|
+
|
|
60
|
+
Data fetching functions with caching and single-flight dedup.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// type: "loaders"
|
|
64
|
+
export default async function myLoader(
|
|
65
|
+
props: Props,
|
|
66
|
+
req: Request,
|
|
67
|
+
ctx: AppContext
|
|
68
|
+
): Promise<Product[]> {
|
|
69
|
+
return await ctx.invoke("vtex/loaders/productList.ts", props);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Features: cached (single-flight), OpenTelemetry tracing, invocable via `/live/invoke`.
|
|
74
|
+
|
|
75
|
+
### Action (`action.ts`)
|
|
76
|
+
|
|
77
|
+
Mutation functions (not cached).
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// type: "actions"
|
|
81
|
+
export default async function addToCart(
|
|
82
|
+
props: { sku: string; quantity: number },
|
|
83
|
+
req: Request,
|
|
84
|
+
ctx: AppContext
|
|
85
|
+
): Promise<Cart> {
|
|
86
|
+
return await ctx.invoke("vtex/actions/cart/addItems.ts", {
|
|
87
|
+
orderItems: [{ id: props.sku, quantity: props.quantity, seller: "1" }]
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Handler (`handler.ts`)
|
|
93
|
+
|
|
94
|
+
HTTP request handlers using a factory pattern.
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// type: "handlers"
|
|
98
|
+
export default function proxy(config: { url: string }) {
|
|
99
|
+
return async (req: Request, ctx: ConnInfo): Promise<Response> => {
|
|
100
|
+
return await fetch(new URL(req.url).pathname, { ...config });
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Used for proxies, redirects, sitemaps, and custom routes.
|
|
106
|
+
|
|
107
|
+
### Flag (`flag.ts`)
|
|
108
|
+
|
|
109
|
+
Feature flags with variant selection.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// type: "flags"
|
|
113
|
+
// Simple boolean flag:
|
|
114
|
+
export default function myFlag(config: { percentage: number }) {
|
|
115
|
+
return { name: "my-experiment", value: Math.random() < config.percentage };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Multivariate:
|
|
119
|
+
export default function mvFlag(config: Config) {
|
|
120
|
+
return {
|
|
121
|
+
name: "checkout-v2",
|
|
122
|
+
variants: [
|
|
123
|
+
{ value: "control", rule: { traffic: 0.5 } },
|
|
124
|
+
{ value: "experiment", rule: { traffic: 0.5 } },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Matcher (`matcher.ts`)
|
|
131
|
+
|
|
132
|
+
Predicates for audience segmentation.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// type: "matchers"
|
|
136
|
+
export default function device(config: { mobile: boolean }) {
|
|
137
|
+
return (ctx: MatchContext): boolean => {
|
|
138
|
+
return ctx.device === "mobile" === config.mobile;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Built-in matchers: MatchDevice, MatchCookie, MatchDate, MatchLocation, MatchHost, MatchRandom, MatchUserAgent, MatchSite, MatchMulti.
|
|
144
|
+
|
|
145
|
+
### App (`app.ts`)
|
|
146
|
+
|
|
147
|
+
Container that bundles manifest + state + dependencies.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// type: "apps"
|
|
151
|
+
export default function MyApp(props: Props): App<Manifest, State> {
|
|
152
|
+
return {
|
|
153
|
+
manifest,
|
|
154
|
+
state: { /* clients, config */ },
|
|
155
|
+
dependencies: [otherApp(props)],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`buildRuntime` processes the manifest, creating resolvers for each block module.
|
|
161
|
+
|
|
162
|
+
### Page (`page.tsx`)
|
|
163
|
+
|
|
164
|
+
Like section but page-level. Same mechanism.
|
|
165
|
+
|
|
166
|
+
### Workflow (`workflow.ts`)
|
|
167
|
+
|
|
168
|
+
Durable workflows using `@deco/durable`. Type: "workflows".
|
|
169
|
+
|
|
170
|
+
### Function (`function.ts`)
|
|
171
|
+
|
|
172
|
+
Legacy loader format. Deprecated in favor of `loader.ts`.
|
|
173
|
+
|
|
174
|
+
### Account (`account.ts`)
|
|
175
|
+
|
|
176
|
+
Platform configuration blocks. Returns account/config object.
|
|
177
|
+
|
|
178
|
+
## Block Registration Flow
|
|
179
|
+
|
|
180
|
+
1. `decoManifestBuilder()` scans directories matching block types
|
|
181
|
+
2. `manifest.gen.ts` is generated with imports and block keys
|
|
182
|
+
3. At startup, `buildRuntime()` processes each block:
|
|
183
|
+
- `block.adapt(mod, key)` for each module
|
|
184
|
+
- `block.decorate(mod, key)` applied before adapt
|
|
185
|
+
- Resolvers registered: `key`, `Preview@key`, `Invoke@key`
|
|
186
|
+
- `defaultDanglingRecover` registered per block type
|
|
187
|
+
4. All resolvers passed to `ReleaseResolver`
|
|
188
|
+
|
|
189
|
+
## Block Resolution Priority
|
|
190
|
+
|
|
191
|
+
When resolving `__resolveType`:
|
|
192
|
+
1. Check `resolvables[type]` (decofile state) then recurse
|
|
193
|
+
2. Check `resolvers[type]` (block resolvers) then invoke
|
|
194
|
+
3. Check `overrides[type]` then redirect
|
|
195
|
+
4. Fall back to `DanglingRecover@{blockType}` (StubSection)
|
|
196
|
+
5. Throw `DanglingReference` error
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# deco-cx/deco vs @decocms/start
|
|
2
|
+
|
|
3
|
+
Mapping between the original Deco framework (Fresh/Deno) and its TanStack/Node counterpart.
|
|
4
|
+
|
|
5
|
+
## Architecture Comparison
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
deco-cx/deco (Fresh/Deno) @decocms/start (TanStack/Node)
|
|
9
|
+
───────────────────────── ──────────────────────────────
|
|
10
|
+
Deno runtime Node.js / Cloudflare Workers
|
|
11
|
+
Fresh 1.6.8 framework TanStack Start + Vite
|
|
12
|
+
Preact 10.23.1 React 18/19
|
|
13
|
+
Hono (internal router) TanStack Router (file-based)
|
|
14
|
+
manifest.gen.ts Explicit imports + admin protocol
|
|
15
|
+
DecofileProvider Admin SDK (CMS state fetching)
|
|
16
|
+
Resolution engine (Resolvable) Direct function calls
|
|
17
|
+
Block system (adapt/resolve) Pure async functions
|
|
18
|
+
@preact/signals @tanstack/react-store / React state
|
|
19
|
+
deno.json (import map) package.json + npm
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Module Mapping
|
|
23
|
+
|
|
24
|
+
### Entry Points
|
|
25
|
+
|
|
26
|
+
| deco-cx/deco | @decocms/start | Notes |
|
|
27
|
+
|-------------|----------------|-------|
|
|
28
|
+
| `mod.ts` | `src/index.ts` | Main exports |
|
|
29
|
+
| `mod.web.ts` | Not needed | Client invoke is direct imports |
|
|
30
|
+
| `deco.ts` (Context) | Admin context/config | No AsyncLocalStorage pattern |
|
|
31
|
+
| `live.ts` | N/A (legacy) | — |
|
|
32
|
+
| `types.ts` | TypeScript types from packages | — |
|
|
33
|
+
|
|
34
|
+
### Engine → Generic Resolver
|
|
35
|
+
|
|
36
|
+
Both frameworks now have a resolution engine, but `@decocms/start`'s is simpler and purpose-built:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// deco-cx/deco: full resolution engine with hints, single-flight, monitoring
|
|
40
|
+
// decofile state:
|
|
41
|
+
{ "__resolveType": "vtex/loaders/productList.ts", "query": "shoes", "count": 12 }
|
|
42
|
+
// → engine.resolve() → find resolver → invoke with resolved props → hints → monitoring
|
|
43
|
+
|
|
44
|
+
// @decocms/start: generic recursive resolver (internalResolve)
|
|
45
|
+
// Same __resolveType decofile format, resolved via:
|
|
46
|
+
// 1. Check commerce loaders registry
|
|
47
|
+
// 2. Check decofile blocks
|
|
48
|
+
// 3. DanglingReference fallback (configurable)
|
|
49
|
+
// + Per-request memoization + depth protection (max 10)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Key differences:
|
|
53
|
+
- `deco-cx/deco` has full-featured single-flight, hints, monitoring
|
|
54
|
+
- `@decocms/start` has simpler memoization + configurable error handlers (`setResolveErrorHandler`, `setDanglingReferenceHandler`)
|
|
55
|
+
- `@decocms/start` supports `select` field filtering on resolved values
|
|
56
|
+
- `@decocms/start` allows dynamically adding skip types via `addSkipResolveType()`
|
|
57
|
+
|
|
58
|
+
### Blocks → Functions/Components
|
|
59
|
+
|
|
60
|
+
| deco Block | TanStack Equivalent |
|
|
61
|
+
|-----------|---------------------|
|
|
62
|
+
| Section block | React component (direct import) |
|
|
63
|
+
| Loader block (cached, single-flight) | Server function + React Query (with staleTime) |
|
|
64
|
+
| Action block | Server function + React Query mutation |
|
|
65
|
+
| Handler block | TanStack Router route handler |
|
|
66
|
+
| Flag block | Feature flag config (edge-level) |
|
|
67
|
+
| Matcher block | Middleware or route guard |
|
|
68
|
+
| App block | `configure*()` function (e.g., `configureVtex()`) |
|
|
69
|
+
| Workflow block | Background task (platform-specific) |
|
|
70
|
+
|
|
71
|
+
### Runtime → TanStack Start
|
|
72
|
+
|
|
73
|
+
| deco Runtime | TanStack Start |
|
|
74
|
+
|-------------|---------------|
|
|
75
|
+
| Hono router | TanStack Router |
|
|
76
|
+
| Fresh middleware chain | TanStack Start middleware |
|
|
77
|
+
| `/live/invoke/*` | API routes or server functions |
|
|
78
|
+
| `/deco/render` | React Server Components or loader revalidation |
|
|
79
|
+
| `entrypoint.tsx` catch-all | `__root.tsx` + route tree |
|
|
80
|
+
| `Deco` class | Vite plugin + start config |
|
|
81
|
+
|
|
82
|
+
### Hooks → React Equivalents
|
|
83
|
+
|
|
84
|
+
| deco Hook | TanStack Equivalent |
|
|
85
|
+
|-----------|---------------------|
|
|
86
|
+
| `useSection()` | React Query revalidation + state updates (stub in `@decocms/start`) |
|
|
87
|
+
| `usePartialSection()` | TanStack Router Link / navigate (stub in `@decocms/start`) |
|
|
88
|
+
| `useScript()` | `@decocms/start/sdk/useScript` — with lightweight minification + LRU cache |
|
|
89
|
+
| `useScriptAsDataURI()` | `@decocms/start/sdk/useScript` — same, data URI variant |
|
|
90
|
+
| `useDevice()` | `@decocms/start/sdk/useDevice` — server-side via User-Agent + RequestContext, also `detectDevice`, `checkMobile/Tablet/Desktop` |
|
|
91
|
+
| `useSetEarlyHints()` | Response headers in server middleware |
|
|
92
|
+
|
|
93
|
+
### Plugins → Config
|
|
94
|
+
|
|
95
|
+
| deco Plugin | TanStack Equivalent |
|
|
96
|
+
|------------|---------------------|
|
|
97
|
+
| `plugins/deco.ts` (Fresh plugin) | `@decocms/start` Vite plugin + entry |
|
|
98
|
+
| `plugins/fresh.ts` (Tailwind + Deco) | Tailwind via Vite plugin |
|
|
99
|
+
| `plugins/styles.ts` (global CSS) | CSS in `__root.tsx` or global stylesheet |
|
|
100
|
+
|
|
101
|
+
### Clients → Direct Imports
|
|
102
|
+
|
|
103
|
+
| deco Client | TanStack Equivalent |
|
|
104
|
+
|------------|---------------------|
|
|
105
|
+
| `proxy<Manifest>()` | Direct function imports |
|
|
106
|
+
| `invoke["key"](props)` | `await loaderFn(props)` or `/deco/invoke` with FormData/URLEncoded/JSON |
|
|
107
|
+
| `readFromStream()` | `fetch()` + ReadableStream |
|
|
108
|
+
| `formDataToProps()` | Built into invoke handler (auto-parses multipart/form-data and URL-encoded) |
|
|
109
|
+
|
|
110
|
+
### Components → React Components
|
|
111
|
+
|
|
112
|
+
| deco Component | TanStack Equivalent |
|
|
113
|
+
|---------------|---------------------|
|
|
114
|
+
| `LiveControls.tsx` | `LiveControls.tsx` in `@decocms/start` (adapted) |
|
|
115
|
+
| `SectionContext` | React context per section |
|
|
116
|
+
| `ErrorBoundary` | React Error Boundary |
|
|
117
|
+
| `StubSection` | Fallback component |
|
|
118
|
+
| `JsonViewer` | JSON display component |
|
|
119
|
+
|
|
120
|
+
## State Management Comparison
|
|
121
|
+
|
|
122
|
+
### deco-cx/deco
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
CMS Admin → publish → DecofileProvider.onChange()
|
|
126
|
+
→ ReleaseResolver rebuilds
|
|
127
|
+
→ New resolvables available
|
|
128
|
+
→ Next request uses new state
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### @decocms/start
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
CMS Admin → publish → POST /.decofile (hot-reload)
|
|
135
|
+
→ setBlocks() updates in-memory state
|
|
136
|
+
→ Revision recomputed (content-hash)
|
|
137
|
+
→ onChange listeners notified (meta cache invalidated)
|
|
138
|
+
→ clearLoaderCache() ensures fresh data
|
|
139
|
+
→ Edge cache purge (Cloudflare)
|
|
140
|
+
→ Next request uses new state + fresh schema
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Rendering Comparison
|
|
144
|
+
|
|
145
|
+
### deco-cx/deco (SSR + Islands)
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Request → Fresh handler
|
|
149
|
+
→ Resolve page sections (engine)
|
|
150
|
+
→ Preact renderToString (server)
|
|
151
|
+
→ Hydrate islands only (client)
|
|
152
|
+
→ Partial updates via useSection + /deco/render
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### @decocms/start (SSR + Full Hydration)
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
Request → TanStack Start handler
|
|
159
|
+
→ Route loader runs (server function)
|
|
160
|
+
→ React renderToString (server)
|
|
161
|
+
→ Full hydration (client)
|
|
162
|
+
→ Client-side navigation via TanStack Router
|
|
163
|
+
→ Data updates via React Query revalidation
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Caching Comparison
|
|
167
|
+
|
|
168
|
+
| Aspect | deco-cx/deco | @decocms/start |
|
|
169
|
+
|--------|-------------|---------------|
|
|
170
|
+
| Loader cache | In-process single-flight + LRU | React Query staleTime + Cloudflare cache |
|
|
171
|
+
| Page cache | CDN + Deco edge | Cloudflare Workers cache API |
|
|
172
|
+
| Static assets | Fresh static serving | Vite build + CDN |
|
|
173
|
+
| Cache invalidation | DecofileProvider onChange | `setBlocks` → onChange listeners + `clearLoaderCache()` + edge purge |
|
|
174
|
+
|
|
175
|
+
## Key Takeaways for Porting
|
|
176
|
+
|
|
177
|
+
1. **Simpler resolution engine**: `@decocms/start` now has a generic recursive resolver (`internalResolve`) for `__resolveType`, but it's simpler than `deco-cx/deco`'s full engine (no hints, no single-flight). It resolves commerce loaders, decofile blocks, and has configurable fallback for dangling references.
|
|
178
|
+
|
|
179
|
+
2. **No manifest**: Instead of auto-generated manifests with lazy imports, `@decocms/apps-start` uses explicit exports that sites import directly.
|
|
180
|
+
|
|
181
|
+
3. **No islands architecture**: React hydrates everything. Optimize with React.lazy, Suspense, and code splitting instead.
|
|
182
|
+
|
|
183
|
+
4. **Enhanced invoke**: The `/deco/invoke` endpoint now supports FormData, URL-encoded bodies, `?select=` filtering, batch execution, actions registration, and nested `__resolveType` resolution.
|
|
184
|
+
|
|
185
|
+
5. **CMS integration**: `@decocms/start` provides the admin protocol (LiveControls, section editing) through its own SDK. Schema registries are dynamic (loaders + matchers registered at runtime).
|
|
186
|
+
|
|
187
|
+
6. **Edge-first**: `@decocms/start` is designed for Cloudflare Workers, with caching handled at the edge rather than in-process.
|
|
188
|
+
|
|
189
|
+
7. **Observability parity**: `@decocms/start` now has pluggable `TracerAdapter` + `MeterAdapter`, standardized `MetricNames`, and a `/deco/_health` endpoint with uptime, memory, cache stats, and request metrics.
|
|
190
|
+
|
|
191
|
+
8. **Server-side device detection**: `useDevice()` works server-side via `RequestContext` + User-Agent parsing, matching `deco-cx/deco`'s functionality.
|