@thorprovider/storefront 0.3.1 → 0.4.0-mvp.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/CHANGELOG.md +23 -0
- package/README.md +248 -99
- package/assets/templates/app/app/[[...slug]]/page.tsx +13 -2
- package/assets/templates/app/app/layout.tsx +18 -4
- package/assets/templates/app/app/robots.ts +13 -0
- package/assets/templates/app/app/sitemap.ts +12 -0
- package/assets/templates/app/lib/__STOREFRONT__/actions.ts +542 -0
- package/assets/templates/app/lib/__STOREFRONT__/cart-state.ts +66 -0
- package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +40 -57
- package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +608 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +165 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.ts +5 -36
- package/assets/templates/app/lib/__STOREFRONT__/icon-map.ts +27 -0
- package/assets/templates/app/lib/__STOREFRONT__/mappers.ts +13 -11
- package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +232 -51
- package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +3 -3
- package/assets/templates/app/lib/__STOREFRONT__/schema.ts +121 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.core.ts +470 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.ts +169 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/content.ts +96 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +34 -0
- package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +100 -11
- package/assets/templates/app/lib/__STOREFRONT__/spec/page-root.ts +5 -1
- package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +26 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.core.ts +257 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.ts +7 -31
- package/assets/templates/app/lib/__STOREFRONT__/store-context.ts +142 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.client.tsx +25 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.tsx +16 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.client.tsx +24 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.tsx +5 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/index.ts +17 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/logoCloud.tsx +26 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/pricing.tsx +36 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.cta.ts +19 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.faq.ts +18 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/statistics.tsx +35 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/testimonials.tsx +31 -13
- package/assets/templates/app/lib/__STOREFRONT__/views/types.ts +5 -3
- package/assets/templates/features/checkout/handlers.ts +153 -0
- package/assets/templates/features/checkout/state.ts +61 -0
- package/assets/templates/features/customer-auth/handlers.ts +59 -0
- package/assets/templates/features/customer-auth/state.ts +36 -0
- package/assets/templates/features/recommendations/state.ts +11 -0
- package/assets/templates/views/account/content.ts +35 -0
- package/assets/templates/views/account/index.tsx +114 -0
- package/assets/templates/views/account/registry.tsx +378 -0
- package/assets/templates/views/account/schema.ts +52 -0
- package/assets/templates/views/category/assembly/assembly.json +28 -0
- package/assets/templates/views/category/assembly/index.skeleton.tsx +193 -0
- package/assets/templates/views/category/assembly/registry.skeleton.tsx +33 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/catalog.part +5 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/element.part +34 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/registry.part +71 -0
- package/assets/templates/views/category/content.ts +30 -0
- package/assets/templates/views/category/data.ts +12 -0
- package/assets/templates/views/category/index.tsx +230 -0
- package/assets/templates/views/category/props.ts +16 -0
- package/assets/templates/views/category/registry.tsx +103 -0
- package/assets/templates/views/category/schema.ts +78 -0
- package/assets/templates/views/checkout/content.ts +105 -0
- package/assets/templates/views/checkout/data.ts +23 -0
- package/assets/templates/views/checkout/index.tsx +111 -0
- package/assets/templates/views/checkout/props.ts +49 -0
- package/assets/templates/views/checkout/registry.tsx +217 -0
- package/assets/templates/views/checkout/schema.ts +229 -0
- package/assets/templates/views/home/assembly/assembly.json +24 -0
- package/assets/templates/views/home/assembly/index.skeleton.tsx +72 -0
- package/assets/templates/views/home/assembly/registry.skeleton.tsx +25 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/registry.part +11 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/registry.part +10 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/registry.part +16 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/registry.part +26 -0
- package/assets/templates/views/home/content.ts +70 -0
- package/assets/templates/views/home/data.ts +15 -0
- package/assets/templates/views/home/index.tsx +38 -84
- package/assets/templates/views/home/props.ts +22 -0
- package/assets/templates/views/home/registry.tsx +38 -22
- package/assets/templates/views/home/schema.ts +93 -0
- package/assets/templates/views/product/content.ts +25 -0
- package/assets/templates/views/product/data.ts +48 -0
- package/assets/templates/views/product/index.tsx +104 -0
- package/assets/templates/views/product/props.ts +20 -0
- package/assets/templates/views/product/registry.tsx +78 -0
- package/assets/templates/views/product/schema.ts +108 -0
- package/assets/templates/views/static/content.ts +99 -0
- package/assets/templates/views/static/index.tsx +60 -0
- package/assets/templates/views/static/registry.tsx +66 -0
- package/assets/templates/views/static/schema.ts +45 -0
- package/{skills/sf-view-gen/assets → assets}/templates/views/user-panel/index.tsx +8 -70
- package/{skills/sf-view-gen/assets → assets}/templates/views/user-panel/registry.tsx +23 -18
- package/assets/templates/views/user-panel/schema.ts +79 -0
- package/bin/storefront.js +1278 -79
- package/commands/sf-add-view.md +44 -13
- package/commands/sf-feature.md +28 -0
- package/commands/sf-theme.md +14 -8
- package/commands/sf-view.md +54 -12
- package/package.json +6 -4
- package/recipes/archetypes.json +28 -1
- package/recipes/catalog.json +361 -0
- package/recipes/catalog.mjs +128 -0
- package/recipes/catalog.schema.json +64 -0
- package/recipes/feature.schema.json +89 -0
- package/recipes/features.json +139 -0
- package/recipes/manifest.schema.json +69 -0
- package/recipes/operations.schema.json +43 -0
- package/recipes/recipe.schema.json +11 -2
- package/recipes/recipes.json +60 -5
- package/recipes/sections.json +24 -5
- package/recipes/validate.mjs +784 -32
- package/scripts/candidate.mjs +236 -0
- package/scripts/composers.mjs +140 -0
- package/scripts/file-classes.mjs +116 -0
- package/scripts/logical-controls.mjs +61 -0
- package/scripts/manifest.mjs +298 -0
- package/scripts/operation-registry.mjs +256 -0
- package/scripts/operations.mjs +720 -0
- package/scripts/ownership-conflict.mjs +356 -0
- package/scripts/pinning.mjs +504 -0
- package/scripts/plan-apply.mjs +843 -0
- package/scripts/preflight.mjs +51 -0
- package/scripts/reconcile.mjs +511 -0
- package/scripts/render-templates.mjs +245 -28
- package/scripts/schema-validate.mjs +132 -0
- package/scripts/section-compat.mjs +300 -0
- package/scripts/section-operations.mjs +508 -0
- package/scripts/sync-assets.mjs +22 -15
- package/scripts/view-assembly.mjs +291 -0
- package/scripts/view-selection.mjs +211 -0
- package/skills/sf-feature/SKILL.md +67 -0
- package/skills/sf-theme-gen/SKILL.md +12 -5
- package/skills/sf-view-gen/SKILL.md +123 -93
- package/skills/sf-view-gen/assets/recipes/archetypes.json +28 -1
- package/skills/sf-view-gen/assets/recipes/catalog.json +361 -0
- package/skills/sf-view-gen/assets/recipes/catalog.schema.json +64 -0
- package/skills/sf-view-gen/assets/recipes/features.json +139 -0
- package/skills/sf-view-gen/assets/recipes/recipes.json +60 -5
- package/skills/sf-view-gen/assets/recipes/sections.json +24 -5
- package/skills/sf-view-gen/assets/templates/views/sections/cta.client.tsx +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/cta.tsx +16 -0
- package/skills/sf-view-gen/assets/templates/views/sections/faq.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/faq.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.client.tsx +12 -8
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.client.tsx +14 -10
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.tsx +2 -9
- package/skills/sf-view-gen/assets/templates/views/sections/schema.cta.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.faq.ts +18 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.logoCloud.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.pricing.ts +26 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.statistics.ts +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.testimonials.ts +23 -0
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.client.tsx +16 -8
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.tsx +2 -5
- package/skills/sf-view-gen/references/views.md +44 -10
- package/skills/sf-view-gen/scripts/catalog.mjs +128 -0
- package/skills/sf-view-gen/scripts/schema-validate.mjs +132 -0
- package/skills/sf-view-gen/scripts/validate.mjs +784 -32
- package/skills/storefront-workflow/SKILL.md +116 -0
- package/skills/sf-view-gen/assets/templates/views/category/index.tsx +0 -86
- package/skills/sf-view-gen/assets/templates/views/category/registry.tsx +0 -48
- package/skills/sf-view-gen/assets/templates/views/checkout/index.tsx +0 -192
- package/skills/sf-view-gen/assets/templates/views/checkout/registry.tsx +0 -45
- package/skills/sf-view-gen/assets/templates/views/product/index.tsx +0 -122
- package/skills/sf-view-gen/assets/templates/views/product/registry.tsx +0 -49
|
@@ -1,116 +1,146 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-view-gen
|
|
3
|
-
description: Add a
|
|
3
|
+
description: Add or remove a Thor Commerce storefront view, compose a view's faq/cta sections, or customize a view's user-owned files. Use when the user runs /sf-add-view or /sf-view, or asks to add/remove a view, add/remove/reorder a section, or change a view's content, props, or data. Delegates every structural write to the `storefront` CLI.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# sf-view-gen
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Choose a view's composition **by meaning**, delegate the structural write to the
|
|
9
|
+
`storefront` CLI, and edit only the user-owned files it leaves behind. The
|
|
10
|
+
manifest (`storefront.config.json`) is the structural authority; the CLI is the
|
|
11
|
+
only writer of derived files.
|
|
9
12
|
|
|
10
|
-
##
|
|
13
|
+
## Read the registry through the CLI (never from memory)
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
Run from the storefront project root. The CLI resolves the project from the
|
|
16
|
+
current directory; do not pass a directory.
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- the values returned by the wizard (view name, description of what the view should contain or emphasize)
|
|
20
|
-
|
|
21
|
-
## Outputs (what this skill produces)
|
|
18
|
+
```bash
|
|
19
|
+
npx @thorprovider/storefront views --json # views, routes, supported intents/variants, installed
|
|
20
|
+
npx @thorprovider/storefront recipes --json # whole curated registry (views + features)
|
|
21
|
+
npx @thorprovider/storefront features --json # feature bundles and what they own
|
|
22
|
+
```
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
The `--json` output is the same registry the CLI validates against, so it cannot
|
|
25
|
+
advertise a selection the reconciler will not honour. `views --json` and
|
|
26
|
+
`recipes --json` also report, per view, `registeredSlots` (the non-removable core
|
|
27
|
+
slots), `allowedSections` (the section types the view may host), and
|
|
28
|
+
`maxSections` (the editorial-instance bound), plus a top-level `sectionTypes`
|
|
29
|
+
list marking each type `executable` or `held` with a reason. Do not read the JSON
|
|
30
|
+
files directly; they are an implementation detail.
|
|
31
|
+
|
|
32
|
+
## Curated MVP set
|
|
33
|
+
|
|
34
|
+
- **Standalone views:** `home`, `category`, `product` — add with `view add`.
|
|
35
|
+
- **Feature-owned view:** `checkout` is owned by the `checkout` feature. A direct
|
|
36
|
+
`view add checkout` is rejected; run `feature add checkout` instead (see the
|
|
37
|
+
`sf-feature` skill).
|
|
38
|
+
- **Held post-MVP:** `user-panel` and recommendations are rejected before any
|
|
39
|
+
write. Do not try to install them. (Sections are composable — see below.)
|
|
40
|
+
|
|
41
|
+
## Add a view
|
|
42
|
+
|
|
43
|
+
1. Read `views --json`. If the view is held or feature-owned, stop and explain
|
|
44
|
+
the correct path.
|
|
45
|
+
2. Choose an **intent by meaning** for each slot from the view's
|
|
46
|
+
`supportedIntents` (e.g. a "dense grid" description → the matching intent).
|
|
47
|
+
If the description is silent, use the default. Only use
|
|
48
|
+
`--variant slot=Name` when the user names an exact supported variant.
|
|
49
|
+
3. Delegate the write:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx @thorprovider/storefront view add <name> [--intent slot=intent] [--variant slot=Variant]
|
|
53
|
+
```
|
|
26
54
|
|
|
27
|
-
|
|
55
|
+
The CLI validates, updates the manifest, and reconciles the derived files.
|
|
56
|
+
If it exits non-zero, show its message and the supported options; do not
|
|
57
|
+
hand-edit derived files to work around it.
|
|
58
|
+
4. Report the created view and its route.
|
|
28
59
|
|
|
29
|
-
|
|
30
|
-
- `assets/recipes/sections.json` — optional sections → `elementType`, `variants`, `defaultVariant`, `propsHint`
|
|
31
|
-
- `assets/recipes/archetypes.json` — the **archetype (intent) layer**: per slot (`<view>.<slot>`) a set of named **intents**, each with a `variant` and a `when` usage hint, plus the slot `default` intent
|
|
32
|
-
- `assets/templates/views/<view>/` — the view modules it copies
|
|
33
|
-
- `assets/templates/views/sections/` — the optional-section fragments
|
|
34
|
-
- `scripts/validate.mjs` — the validator
|
|
35
|
-
- `references/views.md` — the view composition contract
|
|
36
|
-
- `../json-render-core/` — vendored catalog/schema/spec reference
|
|
37
|
-
- `../json-render-react/` — vendored registry/action reference
|
|
60
|
+
## Remove a view
|
|
38
61
|
|
|
39
|
-
Paths are relative to this `SKILL.md`. Run the validator from here:
|
|
40
62
|
```bash
|
|
41
|
-
|
|
42
|
-
node scripts/validate.mjs show <view>
|
|
43
|
-
node scripts/validate.mjs archetypes
|
|
44
|
-
node scripts/validate.mjs resolve <view> <slot> <intent>
|
|
45
|
-
node scripts/validate.mjs validate '<composition-json>'
|
|
63
|
+
npx @thorprovider/storefront view remove <name>
|
|
46
64
|
```
|
|
47
65
|
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
The CLI removes the derived wrapper and wiring. If it prints a preserved
|
|
67
|
+
user-owned file, relay that path to the user.
|
|
68
|
+
|
|
69
|
+
## Compose sections (the agent selects, the CLI writes)
|
|
70
|
+
|
|
71
|
+
A view's ordered composition mixes its **registered slots** (core presentation
|
|
72
|
+
slots, mandatory and non-removable) with **editorial section instances**. The
|
|
73
|
+
agent selects the options and runs the CLI; the user describes the change in
|
|
74
|
+
natural language and never types a command.
|
|
75
|
+
|
|
76
|
+
1. Read `views --json`. For the target view use `registeredSlots` (the core
|
|
77
|
+
slots), `allowedSections` (the host allowlist), and `maxSections`; read the
|
|
78
|
+
top-level `sectionTypes` list for which types are available.
|
|
79
|
+
2. Only `faq` and `cta` are `executable`. Held types (`testimonials`,
|
|
80
|
+
`statistics`, `logoCloud`, `pricing`) are refused with a bounded reason. Never
|
|
81
|
+
present a held type as available, and never invent a reason — relay the
|
|
82
|
+
`reason` the registry reports.
|
|
83
|
+
3. Compose through the CLI's section operations, carried in the operations
|
|
84
|
+
envelope `{ "formatVersion": 1, "operations": [ ... ] }`. Write the envelope
|
|
85
|
+
to a file, plan it, then apply the plan:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx @thorprovider/storefront plan --operations operations.json --out plan.json
|
|
89
|
+
npx @thorprovider/storefront apply --plan plan.json
|
|
90
|
+
```
|
|
50
91
|
|
|
51
|
-
|
|
92
|
+
- `{ "op": "section.add", "view": "home", "type": "faq" }` — optional `id`,
|
|
93
|
+
`variant`, and `at` (0-based insertion index, default append). Omit `id` to
|
|
94
|
+
auto-mint one; a `variant` must be declared by the section type.
|
|
95
|
+
- `{ "op": "section.remove", "view": "home", "id": "home-faq-1" }` — removes an
|
|
96
|
+
editorial instance. A registered slot (`slot:<slot>`) cannot be removed.
|
|
97
|
+
- `{ "op": "section.reorder", "view": "home", "order": ["slot:hero", "home-faq-1", "slot:benefits", "slot:categories"] }` —
|
|
98
|
+
`order` must be a permutation of the view's current entry ids: every current
|
|
99
|
+
id exactly once, and every registered slot present.
|
|
100
|
+
|
|
101
|
+
4. `plan` is read-only and validates the whole intended state; `apply --plan` is
|
|
102
|
+
the only writer. On success the CLI updates the manifest and reconciles derived
|
|
103
|
+
files. If either exits non-zero, relay its diagnostic (it names the offending
|
|
104
|
+
field) and the supported options; do not hand-edit the manifest or derived
|
|
105
|
+
files to work around it.
|
|
106
|
+
5. A removed instance's content is preserved in the view's user-owned
|
|
107
|
+
`content.ts`; re-adding the same `id` rebinds it, while an auto-minted id never
|
|
108
|
+
rebinds preserved content.
|
|
109
|
+
|
|
110
|
+
## Customize a view (the `/sf-view` workflow)
|
|
111
|
+
|
|
112
|
+
Only **user-owned** files may be edited by hand. They are consumed by thin
|
|
113
|
+
derived wrappers, so `sync` regenerates the wrappers around your edits.
|
|
114
|
+
|
|
115
|
+
User-owned (edit these): `lib/<name>/views/<view>/content.ts`, `props.ts`,
|
|
116
|
+
`data.ts`, `schema.ts`, and `lib/<name>/mappers.ts`.
|
|
117
|
+
|
|
118
|
+
Derived (never edit; the CLI regenerates them): `index.tsx`, `registry.tsx`,
|
|
119
|
+
`lib/<name>/views/index.ts`, `lib/<name>/views/registry.ts`, `catalog.ts`,
|
|
120
|
+
`runtime.ts`, `spec/index.ts`, `state.ts`, `handlers.ts`.
|
|
121
|
+
|
|
122
|
+
1. Read the current user-owned files for the view.
|
|
123
|
+
2. Apply the requested change there. Preserve exported names, element ids, and
|
|
124
|
+
the event/prop contracts the derived wrapper imports.
|
|
125
|
+
3. Regenerate the wrappers: `npx @thorprovider/storefront sync`.
|
|
126
|
+
4. If the change needs a different block variant or a new view, use the CLI
|
|
127
|
+
(`view add`/`remove`); never edit the derived `index.tsx` to swap a variant.
|
|
52
128
|
|
|
53
|
-
##
|
|
129
|
+
## Stack constraints
|
|
54
130
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
131
|
+
- UI components only from `@thorprovider/blocks`.
|
|
132
|
+
- Data only through `@thorprovider/adapters` + `@thorprovider/runtime/commerce`.
|
|
133
|
+
- Never `@thorprovider/medusa-extended`.
|
|
134
|
+
- No custom blocks without explicit user authorization.
|
|
59
135
|
|
|
60
|
-
|
|
61
|
-
- `../json-render-react/` — registry mapping and action wiring (`defineRegistry`, `Renderer`, `useStateStore`)
|
|
136
|
+
## Workflow model
|
|
62
137
|
|
|
63
|
-
|
|
138
|
+
Read `../storefront-workflow/SKILL.md` for the four phases (bootstrap → compose
|
|
139
|
+
→ customize → verify), the ownership classes, and the CLI/agent authority.
|
|
64
140
|
|
|
65
|
-
|
|
66
|
-
node scripts/validate.mjs resolve home hero showcase # -> StorefrontHero2
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Stack constraints
|
|
70
|
-
- UI: only `@thorprovider/blocks`
|
|
71
|
-
- Data: only `@thorprovider/adapters` + `@thorprovider/runtime/commerce`
|
|
72
|
-
- Never `@thorprovider/medusa-extended`
|
|
73
|
-
- No custom blocks without explicit user authorization
|
|
74
|
-
- **Two-file view split (RSC):** `index.tsx` is a pure Server Component module (name, elements, zod catalog, route, loader) and imports `registry` from the sibling `registry.tsx` as data. `registry.tsx` is the **`'use client'`** module and is the only place that imports values from `@json-render/react` or `@thorprovider/blocks`. Never add those imports to `index.tsx` — `@json-render/react` calls `createContext` at module scope, which breaks the RSC server graph.
|
|
75
|
-
- Every element `type` used in a spec MUST be registered in the view's zod catalog (`index.tsx`) AND its client registry (`registry.tsx`); the shared `catalog.ts` / `registry.tsx` compose both through the barrel and are never hand-edited
|
|
76
|
-
|
|
77
|
-
## Add-view workflow
|
|
78
|
-
|
|
79
|
-
1. Parse `$ARGUMENTS` → view name (+ optional description). Validate name. Confirm `lib/<name>/` exists (else run `npx @thorprovider/storefront create` to scaffold it).
|
|
80
|
-
2. `node scripts/validate.mjs show <view>` — read slots, allowed variants + sections. `node scripts/validate.mjs archetypes` — read slots with their named intents.
|
|
81
|
-
3. Choose an intent per slot by meaning from the description (defaults if silent), resolve each with `node scripts/validate.mjs resolve <view> <slot> <intent>`, choose optional sections the same way, then validate the full composition with `node scripts/validate.mjs validate '<json>'` **before writing anything**. On failure → stop, show the allowed options.
|
|
82
|
-
4. Copy the view template: `assets/templates/views/<view>/` → `lib/<name>/views/<view>/`. Each template is the two-file split: `index.tsx` (server spec) + `registry.tsx` ('use client' component mappings).
|
|
83
|
-
5. Register it in the barrel `lib/<name>/views/index.ts` — ONE import and ONE array entry:
|
|
84
|
-
```ts
|
|
85
|
-
import { <view> } from './<view>'
|
|
86
|
-
export const views: ViewModule[] = [home, <view>]
|
|
87
|
-
```
|
|
88
|
-
6. Substitute variants: each slot's block is imported under a stable alias (e.g. `ProductOverview1 as ProductOverviewBlock`), shipping the recipe default. Replace **only the imported identifier** with the resolved variant — never the alias, never the props:
|
|
89
|
-
```ts
|
|
90
|
-
import { ProductOverview5 as ProductOverviewBlock } from '@thorprovider/blocks'
|
|
91
|
-
```
|
|
92
|
-
7. Include any chosen optional section — fragments live at `assets/templates/views/sections/` as a two-file split:
|
|
93
|
-
- `<section>.tsx` (server): exports the section object with `elementType`, the zod `catalog` entry, and `registryModule: './<section>.client'`.
|
|
94
|
-
- `<section>.client.tsx` ('use client'): exports `registry: ViewRegistry` with the component mapping.
|
|
95
|
-
Import the section object from `<section>` into `index.tsx` and merge its elements/catalog into the view; put the component mapping from `<section>.client` into the view's `registry.tsx` (re-exporting the fragment's registry).
|
|
96
|
-
8. Verify: `yarn typecheck`. Do NOT hand-edit `catalog.ts`, `registry.tsx`, `runtime.ts`, or `spec/index.ts` — they compose whatever the barrel exports.
|
|
97
|
-
|
|
98
|
-
## Modify workflow (`/sf-view`)
|
|
99
|
-
|
|
100
|
-
1. Parse view name + change. Validate name.
|
|
101
|
-
2. Read `lib/<name>/views/<view>/index.tsx` (server spec) and `registry.tsx` (client mappings) fully.
|
|
102
|
-
3. Apply ONLY the change. Preserve ids, `type`, untouched `props`, `$state`, `on` wiring, route/loader, and the barrel entry.
|
|
103
|
-
4. If new blocks are needed, choose intents from `archetypes.json`, resolve to allowed variants, and validate before writing.
|
|
104
|
-
5. Re-run `yarn typecheck`.
|
|
105
|
-
|
|
106
|
-
## Generation headers
|
|
107
|
-
Every generated/edited file gets:
|
|
108
|
-
```
|
|
109
|
-
// Generated by @thorprovider/storefront (sf-view-gen) from recipes/<view>
|
|
110
|
-
```
|
|
141
|
+
## Completion criteria
|
|
111
142
|
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
|
|
115
|
-
-
|
|
116
|
-
- Type errors → fix before finishing; never leave broken specs.
|
|
143
|
+
- The manifest reflects the requested composition and `sync` reports no drift.
|
|
144
|
+
- Only user-owned files were hand-edited; every derived file was written by the
|
|
145
|
+
CLI.
|
|
146
|
+
- The CLI command's exit status was checked and reported.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Archetype (intent) layer. Maps a slot to named intents so selection is by meaning, not by variant ordinal. Each intent resolves to a variant that MUST be allowed by the recipe for that slot.",
|
|
5
5
|
"slots": {
|
|
6
6
|
"home.hero": {
|
|
7
|
-
"default": "
|
|
7
|
+
"default": "compact",
|
|
8
8
|
"intents": {
|
|
9
9
|
"compact": {
|
|
10
10
|
"variant": "StorefrontHero1",
|
|
@@ -122,6 +122,33 @@
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
},
|
|
125
|
+
"account.login": {
|
|
126
|
+
"default": "signIn",
|
|
127
|
+
"intents": {
|
|
128
|
+
"signIn": {
|
|
129
|
+
"variant": "LoginPage1",
|
|
130
|
+
"when": "A full sign-in page with email and password and a link to create an account."
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"account.register": {
|
|
135
|
+
"default": "signUp",
|
|
136
|
+
"intents": {
|
|
137
|
+
"signUp": {
|
|
138
|
+
"variant": "SignUpPage1",
|
|
139
|
+
"when": "A full registration page with name, email, and password and a link to sign in."
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"account.orders": {
|
|
144
|
+
"default": "viewOrders",
|
|
145
|
+
"intents": {
|
|
146
|
+
"viewOrders": {
|
|
147
|
+
"variant": "OrderHistory2",
|
|
148
|
+
"when": "A signed-in shopper's order history with per-order totals and detail on demand."
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
125
152
|
"user-panel.shell": {
|
|
126
153
|
"default": "standard",
|
|
127
154
|
"intents": {
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./catalog.schema.json",
|
|
3
|
+
"catalogVersion": 1,
|
|
4
|
+
"description": "Initial semantic executable catalog (E1 tasks 1.2-1.3), classified by source-shape inspection of the @thorprovider/blocks prop contracts and the view templates. Scope: every slot the curated MVP views (home, product, category, checkout, account) render by default, covering both the selectable archetype slots declared by recipes/archetypes.json and the nested default slots that have no archetype (category.productCard, checkout.confirmation) so no legacy default support is dropped. The account view (change: storefront-customer-auth) declares the login/register slots: LoginPage1/SignUpPage1 are executable while LoginPage2 is held for its divergent callback contract. A variant is `executable` only when the slot's canonical data shape can feed its block props without a prop bridge and without inventing data; every other non-default variant is `held` with the specific reason. The one executable non-default swap is home.benefits Feature1 -> Feature2 (identical item contract, no bridge). user-panel (non-MVP view) is outside this initial catalog scope. E2 task 6.1 declares the base listing slot category.filter CategoryFilter2 as the single controlled listing (dataShape `CatalogQuery & CatalogResults`, state controlled) with the search/filter controls contributed by the logical mounts category.search / category.filters (no second block). Source-shape compatibility is not end-to-end backend behavior proof: the render is executable, but the category.search.apply / category.filter.apply actions remain held under the capability catalog (owner: storefront-catalog-search-filters, E2) until a real runtime proof. The `capabilities` map declares those operational capabilities with their requirements and verification state; E1 declares the held category.filter.apply action, E2 adds the held category.search.apply action and the held category.price.range capability that gates the category-filters showPrice option; no capability is claimed verified.",
|
|
5
|
+
"slots": {
|
|
6
|
+
"home.hero": {
|
|
7
|
+
"default": "StorefrontHero1",
|
|
8
|
+
"variants": {
|
|
9
|
+
"StorefrontHero1": {
|
|
10
|
+
"status": "executable",
|
|
11
|
+
"block": "StorefrontHero",
|
|
12
|
+
"dataShape": "FeaturedProduct[]",
|
|
13
|
+
"events": ["addToCart", "buyNow", "selectColor"],
|
|
14
|
+
"state": "uncontrolled",
|
|
15
|
+
"requirements": ["heroProducts"]
|
|
16
|
+
},
|
|
17
|
+
"StorefrontHero2": {
|
|
18
|
+
"status": "held",
|
|
19
|
+
"reason": "block requires a product with reviews/trending/tag and emits a search event; the canonical FeaturedProduct shape carries rating/reviewCount but not trending/tag, and no verified prop bridge exists",
|
|
20
|
+
"block": "StorefrontHero",
|
|
21
|
+
"dataShape": "StorefrontHero2FeaturedProduct[]",
|
|
22
|
+
"events": ["search", "productClick"],
|
|
23
|
+
"state": "uncontrolled",
|
|
24
|
+
"requirements": ["heroProducts"]
|
|
25
|
+
},
|
|
26
|
+
"StorefrontHero5": {
|
|
27
|
+
"status": "held",
|
|
28
|
+
"reason": "featuredDeals[].description is absent from the canonical product shape and Department.count would require inventing counts; no truthful prop bridge can be derived from source",
|
|
29
|
+
"block": "StorefrontHero",
|
|
30
|
+
"dataShape": "FeaturedDeal[] & Department[]",
|
|
31
|
+
"events": ["departmentClick", "shopNow", "locateStores"],
|
|
32
|
+
"state": "uncontrolled",
|
|
33
|
+
"requirements": ["featuredDeals", "departments"]
|
|
34
|
+
},
|
|
35
|
+
"StorefrontHero6": {
|
|
36
|
+
"status": "held",
|
|
37
|
+
"reason": "block requires deals with discount/endTime and categories with a required count; the canonical shape supplies neither without invention and no verified prop bridge exists",
|
|
38
|
+
"block": "StorefrontHero",
|
|
39
|
+
"dataShape": "HeroDeal[] & HeroCategory[]",
|
|
40
|
+
"events": ["shopNow", "categoryClick"],
|
|
41
|
+
"state": "uncontrolled",
|
|
42
|
+
"requirements": ["deals", "categories"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"home.benefits": {
|
|
47
|
+
"default": "Feature1",
|
|
48
|
+
"variants": {
|
|
49
|
+
"Feature1": {
|
|
50
|
+
"status": "executable",
|
|
51
|
+
"block": "Feature",
|
|
52
|
+
"dataShape": "BenefitsItem[]",
|
|
53
|
+
"events": ["ctaClick", "learnMore"],
|
|
54
|
+
"state": "uncontrolled",
|
|
55
|
+
"requirements": []
|
|
56
|
+
},
|
|
57
|
+
"Feature2": {
|
|
58
|
+
"status": "executable",
|
|
59
|
+
"block": "Feature",
|
|
60
|
+
"dataShape": "BenefitsItem[]",
|
|
61
|
+
"events": [],
|
|
62
|
+
"state": "uncontrolled",
|
|
63
|
+
"requirements": []
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"home.categories": {
|
|
68
|
+
"default": "ProductCategory2",
|
|
69
|
+
"variants": {
|
|
70
|
+
"ProductCategory2": {
|
|
71
|
+
"status": "executable",
|
|
72
|
+
"block": "CategoryCards",
|
|
73
|
+
"dataShape": "CategoryCard[]",
|
|
74
|
+
"events": ["browse"],
|
|
75
|
+
"state": "uncontrolled",
|
|
76
|
+
"requirements": ["categories"]
|
|
77
|
+
},
|
|
78
|
+
"ProductCategory1": {
|
|
79
|
+
"status": "held",
|
|
80
|
+
"reason": "block requires categories with a subtitle and a named icon, which the canonical CategoryCard shape does not supply; no verified prop bridge exists",
|
|
81
|
+
"block": "CategoryCards",
|
|
82
|
+
"dataShape": "ProductCategory1Category[]",
|
|
83
|
+
"events": [],
|
|
84
|
+
"state": "uncontrolled",
|
|
85
|
+
"requirements": ["categories"]
|
|
86
|
+
},
|
|
87
|
+
"ProductCategory4": {
|
|
88
|
+
"status": "held",
|
|
89
|
+
"reason": "block requires categories with title/icon/customers/products/avatarImages, which the canonical CategoryCard shape does not supply; no verified prop bridge exists",
|
|
90
|
+
"block": "CategoryCards",
|
|
91
|
+
"dataShape": "ProductCategory4Category[]",
|
|
92
|
+
"events": ["categoryClick"],
|
|
93
|
+
"state": "uncontrolled",
|
|
94
|
+
"requirements": ["categories"]
|
|
95
|
+
},
|
|
96
|
+
"ProductCategory5": {
|
|
97
|
+
"status": "held",
|
|
98
|
+
"reason": "block requires categories with subcategories and a required itemCount plus a search control, which the canonical CategoryCard shape does not supply; no verified prop bridge exists",
|
|
99
|
+
"block": "CategoryCards",
|
|
100
|
+
"dataShape": "ProductCategory5Category[]",
|
|
101
|
+
"events": ["browse", "viewAll"],
|
|
102
|
+
"state": "uncontrolled",
|
|
103
|
+
"requirements": ["categories"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"product.overview": {
|
|
108
|
+
"default": "ProductOverview1",
|
|
109
|
+
"variants": {
|
|
110
|
+
"ProductOverview1": {
|
|
111
|
+
"status": "executable",
|
|
112
|
+
"block": "ProductOverview",
|
|
113
|
+
"dataShape": "ProductDetailProduct",
|
|
114
|
+
"events": ["selectVariant", "quantityChange", "addToCart", "toggleWishlist"],
|
|
115
|
+
"state": "controlled",
|
|
116
|
+
"requirements": ["selectedProduct", "selectedVariantId"]
|
|
117
|
+
},
|
|
118
|
+
"ProductOverview2": {
|
|
119
|
+
"status": "held",
|
|
120
|
+
"reason": "block requires a product with brand/sku/sizes/colors and wishlist events, a shape the canonical ProductDetailProduct does not supply; no verified prop bridge exists",
|
|
121
|
+
"block": "ProductOverview",
|
|
122
|
+
"dataShape": "ProductOverview2Product",
|
|
123
|
+
"events": ["addToCart", "toggleWishlist"],
|
|
124
|
+
"state": "uncontrolled",
|
|
125
|
+
"requirements": ["selectedProduct"]
|
|
126
|
+
},
|
|
127
|
+
"ProductOverview5": {
|
|
128
|
+
"status": "held",
|
|
129
|
+
"reason": "block requires specifications/features/mainImages/galleryImages/userReviews, a shape the canonical ProductDetailProduct does not supply; no verified prop bridge exists",
|
|
130
|
+
"block": "ProductOverview",
|
|
131
|
+
"dataShape": "ProductOverview5Product",
|
|
132
|
+
"events": ["addToCart", "toggleWishlist"],
|
|
133
|
+
"state": "uncontrolled",
|
|
134
|
+
"requirements": ["selectedProduct"]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"product.reviews": {
|
|
139
|
+
"default": "ReviewRating1",
|
|
140
|
+
"variants": {
|
|
141
|
+
"ReviewRating1": {
|
|
142
|
+
"status": "executable",
|
|
143
|
+
"block": "Reviews",
|
|
144
|
+
"dataShape": "Review[]",
|
|
145
|
+
"events": ["toggleReviewLike", "submitReview"],
|
|
146
|
+
"state": "uncontrolled",
|
|
147
|
+
"requirements": ["productReviews"]
|
|
148
|
+
},
|
|
149
|
+
"ReviewRating2": {
|
|
150
|
+
"status": "held",
|
|
151
|
+
"reason": "block requires an aggregate averageRating/ratingDistribution and carousel controls the canonical Review[] shape does not supply; no verified prop bridge exists",
|
|
152
|
+
"block": "Reviews",
|
|
153
|
+
"dataShape": "Review[] & RatingSummary",
|
|
154
|
+
"events": ["like", "comment"],
|
|
155
|
+
"state": "uncontrolled",
|
|
156
|
+
"requirements": ["productReviews"]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"category.filter": {
|
|
161
|
+
"default": "CategoryFilter2",
|
|
162
|
+
"variants": {
|
|
163
|
+
"CategoryFilter2": {
|
|
164
|
+
"status": "executable",
|
|
165
|
+
"block": "CategoryFilter",
|
|
166
|
+
"dataShape": "CatalogQuery & CatalogResults",
|
|
167
|
+
"events": [
|
|
168
|
+
"productClick",
|
|
169
|
+
"pageChange",
|
|
170
|
+
"pageSizeChange",
|
|
171
|
+
"sortChange",
|
|
172
|
+
"filterChange",
|
|
173
|
+
"searchChange",
|
|
174
|
+
"clearFilters",
|
|
175
|
+
"repair",
|
|
176
|
+
"retry",
|
|
177
|
+
"removeFilter"
|
|
178
|
+
],
|
|
179
|
+
"state": "controlled",
|
|
180
|
+
"requirements": ["categoryProducts", "categoryQuery", "facetSupport"]
|
|
181
|
+
},
|
|
182
|
+
"CategoryFilter1": {
|
|
183
|
+
"status": "held",
|
|
184
|
+
"reason": "block requires categories/priceRanges/sortOptions with counts the canonical CardProduct[] listing does not supply; no verified prop bridge exists",
|
|
185
|
+
"block": "CategoryFilter",
|
|
186
|
+
"dataShape": "CategoryFilter1Filters",
|
|
187
|
+
"events": ["filterChange"],
|
|
188
|
+
"state": "uncontrolled",
|
|
189
|
+
"requirements": ["categoryProducts"]
|
|
190
|
+
},
|
|
191
|
+
"CategoryFilter4": {
|
|
192
|
+
"status": "held",
|
|
193
|
+
"reason": "block requires an advanced facets contract (modelTypes/rangeBands/frameSizes/colourways/features) the canonical listing does not supply; no verified prop bridge exists",
|
|
194
|
+
"block": "CategoryFilter",
|
|
195
|
+
"dataShape": "CategoryFilter4Facets",
|
|
196
|
+
"events": ["filterChange"],
|
|
197
|
+
"state": "uncontrolled",
|
|
198
|
+
"requirements": ["categoryProducts"]
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"category.productCard": {
|
|
203
|
+
"default": "ProductCard1",
|
|
204
|
+
"variants": {
|
|
205
|
+
"ProductCard1": {
|
|
206
|
+
"status": "executable",
|
|
207
|
+
"block": "ProductCard",
|
|
208
|
+
"dataShape": "CardProduct[]",
|
|
209
|
+
"events": ["addToCart", "openProduct"],
|
|
210
|
+
"state": "uncontrolled",
|
|
211
|
+
"requirements": ["categoryProducts"]
|
|
212
|
+
},
|
|
213
|
+
"ProductCard2": {
|
|
214
|
+
"status": "held",
|
|
215
|
+
"reason": "block requires a product with a required rating, a shape the canonical CardProduct listing does not supply; no verified prop bridge exists",
|
|
216
|
+
"block": "ProductCard",
|
|
217
|
+
"dataShape": "ProductCard2Product[]",
|
|
218
|
+
"events": [],
|
|
219
|
+
"state": "uncontrolled",
|
|
220
|
+
"requirements": ["categoryProducts"]
|
|
221
|
+
},
|
|
222
|
+
"ProductCard3": {
|
|
223
|
+
"status": "held",
|
|
224
|
+
"reason": "block requires a product with subtitle/originalPrice/reviewCount/discountPercentage and a badge, a shape the canonical CardProduct listing does not supply; no verified prop bridge exists",
|
|
225
|
+
"block": "ProductCard",
|
|
226
|
+
"dataShape": "ProductCard3Product[]",
|
|
227
|
+
"events": ["toggleWishlist", "viewSimilar", "productClick"],
|
|
228
|
+
"state": "controlled",
|
|
229
|
+
"requirements": ["categoryProducts"]
|
|
230
|
+
},
|
|
231
|
+
"ProductCard5": {
|
|
232
|
+
"status": "held",
|
|
233
|
+
"reason": "block requires a product with name/category/stock/specifications/brand, a shape the canonical CardProduct listing does not supply; no verified prop bridge exists",
|
|
234
|
+
"block": "ProductCard",
|
|
235
|
+
"dataShape": "ProductCard5Product[]",
|
|
236
|
+
"events": ["toggleWishlist", "addToCart", "quickView", "compare", "export"],
|
|
237
|
+
"state": "controlled",
|
|
238
|
+
"requirements": ["categoryProducts"]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
"checkout.checkout": {
|
|
243
|
+
"default": "CheckoutForm1",
|
|
244
|
+
"variants": {
|
|
245
|
+
"CheckoutForm1": {
|
|
246
|
+
"status": "executable",
|
|
247
|
+
"block": "Checkout",
|
|
248
|
+
"dataShape": "CheckoutForm1FormData",
|
|
249
|
+
"events": ["retryTotals", "selectShippingOption", "applyPromo", "submit"],
|
|
250
|
+
"state": "controlled",
|
|
251
|
+
"requirements": ["checkoutCountries", "checkoutPaymentMethods"]
|
|
252
|
+
},
|
|
253
|
+
"CheckoutForm2": {
|
|
254
|
+
"status": "held",
|
|
255
|
+
"reason": "unproven checkout variant: E1 keeps only the default CheckoutForm1, whose behavior is unchanged; no verified prop bridge exists",
|
|
256
|
+
"block": "Checkout",
|
|
257
|
+
"dataShape": "CheckoutForm2Data",
|
|
258
|
+
"events": ["submit"],
|
|
259
|
+
"state": "controlled",
|
|
260
|
+
"requirements": ["checkoutCountries", "checkoutPaymentMethods"]
|
|
261
|
+
},
|
|
262
|
+
"CheckoutForm3": {
|
|
263
|
+
"status": "held",
|
|
264
|
+
"reason": "unproven checkout variant: E1 keeps only the default CheckoutForm1, whose behavior is unchanged; no verified prop bridge exists",
|
|
265
|
+
"block": "Checkout",
|
|
266
|
+
"dataShape": "CheckoutForm3FormData",
|
|
267
|
+
"events": ["submit"],
|
|
268
|
+
"state": "controlled",
|
|
269
|
+
"requirements": ["checkoutCountries", "checkoutPaymentMethods"]
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
"checkout.confirmation": {
|
|
274
|
+
"default": "CheckoutConfirmation",
|
|
275
|
+
"variants": {
|
|
276
|
+
"CheckoutConfirmation": {
|
|
277
|
+
"status": "executable",
|
|
278
|
+
"block": "CheckoutConfirmation",
|
|
279
|
+
"dataShape": "Receipt",
|
|
280
|
+
"events": ["continueShopping"],
|
|
281
|
+
"state": "uncontrolled",
|
|
282
|
+
"requirements": ["lastReceipt"]
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
"account.login": {
|
|
287
|
+
"default": "LoginPage1",
|
|
288
|
+
"variants": {
|
|
289
|
+
"LoginPage1": {
|
|
290
|
+
"status": "executable",
|
|
291
|
+
"block": "LoginPage1",
|
|
292
|
+
"dataShape": "LoginPage1FormData & AccountAuthResult",
|
|
293
|
+
"events": ["submit", "createAccount"],
|
|
294
|
+
"state": "controlled",
|
|
295
|
+
"requirements": ["accountCustomer", "accountAuthenticated"]
|
|
296
|
+
},
|
|
297
|
+
"LoginPage2": {
|
|
298
|
+
"status": "held",
|
|
299
|
+
"reason": "block's onSubmit takes positional (email, password) with no remember-me field and renders a 2-column social grid; no verified prop bridge from the account element contract exists",
|
|
300
|
+
"block": "LoginPage2",
|
|
301
|
+
"dataShape": "LoginPage2Credentials & AccountAuthResult",
|
|
302
|
+
"events": ["submit", "forgotPassword", "signUp"],
|
|
303
|
+
"state": "controlled",
|
|
304
|
+
"requirements": ["accountCustomer", "accountAuthenticated"]
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"account.register": {
|
|
309
|
+
"default": "SignUpPage1",
|
|
310
|
+
"variants": {
|
|
311
|
+
"SignUpPage1": {
|
|
312
|
+
"status": "executable",
|
|
313
|
+
"block": "SignUpPage1",
|
|
314
|
+
"dataShape": "SignUpPage1Data & AccountAuthResult",
|
|
315
|
+
"events": ["submit", "signIn"],
|
|
316
|
+
"state": "controlled",
|
|
317
|
+
"requirements": ["accountCustomer", "accountAuthenticated"]
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"account.orders": {
|
|
322
|
+
"default": "OrderHistory2",
|
|
323
|
+
"variants": {
|
|
324
|
+
"OrderHistory2": {
|
|
325
|
+
"status": "executable",
|
|
326
|
+
"block": "OrderHistory2",
|
|
327
|
+
"dataShape": "AccountOrderView[] & OrderHistory2Labels",
|
|
328
|
+
"events": ["viewDetails"],
|
|
329
|
+
"state": "controlled",
|
|
330
|
+
"requirements": ["accountCustomer", "accountAuthenticated"]
|
|
331
|
+
},
|
|
332
|
+
"OrderHistory1": {
|
|
333
|
+
"status": "held",
|
|
334
|
+
"reason": "block models one row per order item (an item-row list), the wrong shape for an order-level history; the canonical order list cannot feed it without inventing an aggregate row",
|
|
335
|
+
"block": "OrderHistory1",
|
|
336
|
+
"dataShape": "OrderHistory1Order[]",
|
|
337
|
+
"events": [],
|
|
338
|
+
"state": "controlled",
|
|
339
|
+
"requirements": ["accountCustomer", "accountAuthenticated"]
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
"capabilities": {
|
|
345
|
+
"category.search.apply": {
|
|
346
|
+
"requirements": ["adapter.getCatalogProducts(query).text"],
|
|
347
|
+
"verification": "unverified",
|
|
348
|
+
"owner": "storefront-catalog-search-filters"
|
|
349
|
+
},
|
|
350
|
+
"category.filter.apply": {
|
|
351
|
+
"requirements": ["adapter.getProducts(query)"],
|
|
352
|
+
"verification": "unverified",
|
|
353
|
+
"owner": "storefront-catalog-search-filters"
|
|
354
|
+
},
|
|
355
|
+
"category.price.range": {
|
|
356
|
+
"requirements": ["adapter.getAvailableFilters(query).priceRange"],
|
|
357
|
+
"verification": "unverified",
|
|
358
|
+
"owner": "storefront-catalog-search-filters"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|