@feeef.dev/cli 0.2.2 → 0.2.3

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.
@@ -7,8 +7,8 @@ Feeef has **two** reuse layers. Use the right one.
7
7
  ```mermaid
8
8
  flowchart TB
9
9
  subgraph authoring [Theme authoring - template-kit]
10
- sharedDisk["shared/components/footer"]
11
- placement["pages/.../component.json\n$ref: shared.footer"]
10
+ sharedDisk["shared/components/footer.tsx"]
11
+ placement["pages/.../footer.json\n$ref: shared.footer"]
12
12
  build["template:build"]
13
13
  dataJson["dist/data.json\nfully inlined components"]
14
14
  sharedDisk --> build
@@ -30,13 +30,21 @@ flowchart TB
30
30
  storeMeta --> resolve
31
31
  ```
32
32
 
33
- ## 1. Theme shared library (compile-time) — **prefer this for kit themes**
33
+ ## 1. Theme shared library (compile-time) — **prefer this**
34
34
 
35
- **Path:** `templates/<theme>/shared/components/<id>/`
35
+ ### Paths (flat TSX required for leaves)
36
36
 
37
- Same shape as any component (`component.json` + optional `component.jsx` + slots/children).
37
+ | Kind | Path |
38
+ |---|---|
39
+ | **Leaf custom (preferred)** | `shared/components/<id>.tsx` — `export const meta` + `function App()` |
40
+ | **Leaf built-in / $ref stub** | `shared/components/<id>.json` or placement `.json` |
41
+ | **With slots/children** | `shared/components/<id>/<id>.tsx` + `slots/` / `children/` |
42
+
43
+ Do **not** ship customs as `component.json` + `component.jsx` pairs anymore. Meta belongs in `export const meta` inside the `.tsx` file.
38
44
 
39
- **Placement** (thin stub — do not copy JSX):
45
+ ### Placement (thin stub — do not copy JSX)
46
+
47
+ Place next to other page components (flat stack) or inside a shell’s `slots/`:
40
48
 
41
49
  ```json
42
50
  {
@@ -44,101 +52,61 @@ Same shape as any component (`component.json` + optional `component.jsx` + slots
44
52
  "$ref": "shared.footer",
45
53
  "instanceId": "contact_footer_1",
46
54
  "title": null,
47
- "props": {
48
- "social_media": [{ "platform": "instagram", "url": "https://instagram.com/feeef.dz" }]
49
- }
55
+ "props": {}
50
56
  }
51
57
  ```
52
58
 
53
59
  Shorthand: `"shared": "footer"` instead of `"$ref": "shared.footer"`.
54
60
 
61
+ Example page stack (no nested Dawn-style shell required):
62
+
63
+ ```
64
+ pages/home/components/
65
+ header.json → { "$ref": "shared.header", "order": 0, … }
66
+ hero.tsx
67
+ product-rail.tsx
68
+ footer.json → { "$ref": "shared.footer", "order": 99, … }
69
+ ```
70
+
55
71
  ### What build does
56
72
 
57
- 1. Loads every `shared/components/<id>/` into a catalog.
73
+ 1. Loads every entry under `shared/components/` (flat `.tsx` / `.json` or folders).
58
74
  2. Expands each placement: clone shared definition → deep-merge `props` → keep placement `instanceId` / `title` / slot overrides.
59
75
  3. Writes a normal `TemplateData` blob (**no `$ref` left** in `dist/data.json`).
60
76
 
61
- Lithium never needs to know about `$ref` — the storefront only sees full components.
62
-
63
77
  ### Why this exists
64
78
 
65
- - **One place to change design** (footer columns, navbar nav items, Dawn chrome) → every page updates on rebuild.
66
- - Git-friendly: edit `shared/footer/component.jsx` once.
67
- - Matches `defaults.json`’s historical `"$ref": "shared.navbar"` idea, but as real folders.
79
+ - **One place to change design** → every page updates on rebuild.
80
+ - Git-friendly: edit `shared/components/header.tsx` once.
81
+ - Matches historical `"$ref": "shared.navbar"` ideas as real disk files.
68
82
 
69
- ### Dawn theme shared ids (current)
83
+ **Rule of thumb:** if the same UI appears on 2+ pages, it **must** live under `shared/` and be referenced — do not paste duplicate JSX.
70
84
 
71
- | Id | Role |
72
- |---|---|
73
- | `dawn-footer` | Custom Dawn footer (JSX) |
74
- | `dawn-header-bar` | Custom Dawn header bar (JSX) — chrome only, not a page shell |
75
- | `dawn-storefront-shell` | Thin home/products page shell (`header` \| `sections` \| `footer`) |
76
- | `dawn-thanks-shell` | Thin `/thanks` page shell (`header` \| `body` \| `footer`) |
77
- | `dawn-order-form` | Legacy single-file COD (prefer field kit below) |
78
- | `dawn-order-offers` | Offer list tiles (`price × minQuantity`) + per-slot variant loop (`" \| "`) |
79
- | `dawn-order-qty` | Order form quantity |
80
- | `dawn-order-name` | Order form name (+ section title) |
81
- | `dawn-order-phone` | Order form phone (drives draft) |
82
- | `dawn-order-email` | Order form email |
83
- | `dawn-order-geo` | State + city row (slots: `stateSlot`, `citySlot`) |
84
- | `dawn-order-state` / `dawn-order-city` | Wilaya / commune selects |
85
- | `dawn-order-shipping` | Delivery type cards |
86
- | `dawn-order-address` / `dawn-order-note` | Street + customer note |
87
- | `dawn-order-actions` | Add to cart + Buy (place **last** in form content) |
88
- | `dawn-order-success` | Post-order success UI |
89
-
90
- **Also ship matching entries under `library/components/`** for editor drag-drop (docs/10). Keep library JSX in sync with `shared/` — library is copy-on-drop, not a live `$ref`.
91
-
92
- Order-form fields are **shared + slot-ordered** on the PDP form manager — hide via `props.hide`, reorder by changing `order` / folder siblings, add/remove by adding/removing `$ref` placements. Behavior contract: [`08-ORDER-FORM.md`](./08-ORDER-FORM.md).
93
-
94
- **Rule of thumb:** if the same UI appears on 2+ pages, it **must** live under `shared/` and be referenced — do not paste duplicate `component.jsx` / props.
85
+ Also ship matching entries under `library/components/` for editor drag-drop ([10-SCHEMA-LIBRARY.md](./10-SCHEMA-LIBRARY.md)). Library is **copy-on-drop**, not a live `$ref`.
95
86
 
96
87
  ## 2. Backend library references (runtime)
97
88
 
98
89
  ```json
99
90
  {
100
91
  "type": "reference",
101
- "refId": "cuid_of_template_components_row",
102
- "refVersion": 3,
103
- "instanceId": "hero_on_home",
104
- "props": { "title": "Override" },
105
- "slots": {}
92
+ "refId": "",
93
+ "props": {}
106
94
  }
107
95
  ```
108
96
 
109
- - Source of truth: per-store (or public) rows in `template_components`.
110
- - Resolved in `getTemplate()` by `materializeTemplateReferences()` → becomes `type: "custom"`.
111
- - Merchants reuse library blocks across stores; editing the library updates all refs (subject to versioning/policy).
112
-
113
- **Do not confuse** `refId` (backend) with `$ref: "shared.*"` (disk kit). Different planes.
114
-
115
- | | Kit `$ref` / `shared` | Runtime `type: "reference"` |
116
- |---|---|---|
117
- | When resolved | `template:build` | SSR `getTemplate` |
118
- | Storage | Folders on disk | DB `template_components` |
119
- | Audience | Theme engineers | Merchants / marketplace |
120
- | In `data.json` | Expanded away | Kept until SSR |
121
-
122
- ## 3. Defaults.json `$ref` (legacy blank store)
97
+ Used after publish / marketplace install. Authoring-time `$ref: "shared.*"` is expanded at **build** and is different from runtime `type: "reference"`.
123
98
 
124
- `(platform)` still has a top-level `"shared"` map and `"$ref": "shared.navbar"` inside page trees. New themes should use disk `shared/components` instead of a JSON shared map.
99
+ ## Anti-patterns
125
100
 
126
- ## 4. Consistency checklist
127
-
128
- When adding UI to a theme:
129
-
130
- 1. Search `shared/components/` reuse if it exists.
131
- 2. If copying a block to a second page → **promote** it to `shared/components/<id>/` first, then `$ref` from both places.
132
- 3. Page-specific differences → **props overrides only** on the placement (URLs, labels), not a fork of the JSX.
133
- 4. Global look (colors, corners, fonts) → root `props.json` / CSS variables — not hardcoded in every custom component.
134
- 5. After edits: `npm run build` and spot-check every page that refs the shared id.
101
+ | Wrong | Right |
102
+ |---|---|
103
+ | Copy-paste header JSX onto home + products | One `shared/components/header.tsx` + two `$ref` stubs |
104
+ | `shared/components/header/component.json` + `component.jsx` for a leaf | Flat `shared/components/header.tsx` with `export const meta` |
105
+ | Invent deep `home-shell/slots/…` trees by hand when siblings work | Flat `pages/<page>/components/*` stack + `$ref` |
106
+ | Duplicate `instanceId` across placements | Unique `instanceId` per placement |
135
107
 
136
- ## 5. Anti-patterns
108
+ ## Related
137
109
 
138
- | Bad | Good |
139
- |---|---|
140
- | Copy-paste `component.jsx` onto home + products | One `shared/x` + two `$ref` stubs |
141
- | Fork shared by duplicating folder “footer2” | Override `props` on the placement |
142
- | Leave `$ref` in published `data.json` manually | Always run `template:build` |
143
- | Use `type: "reference"` for local theme files | Kit `$ref` for themes; `reference` for DB library |
144
- | Change shared + forget rebuild | `template:watch` / `template:dev` |
110
+ - Flat TSX authoring: [03-CUSTOM-COMPONENTS.md](./03-CUSTOM-COMPONENTS.md)
111
+ - Workflow: [04-WORKFLOW.md](./04-WORKFLOW.md)
112
+ - Order form fields as shared slots: [08-ORDER-FORM.md](./08-ORDER-FORM.md)
@@ -10,7 +10,7 @@ Canonical native implementation:
10
10
  - Security: storefront order-create security checks
11
11
  - Scope API: `docs/03-CUSTOM-COMPONENTS.md`
12
12
 
13
- When writing a **custom** order form (`type: "custom"` / `component.jsx`), you must reproduce this contract. Styling may change; behavior must not.
13
+ When writing a **custom** order form (`type: "custom"` / flat `.tsx`), you must reproduce this contract. Styling may change; behavior must not.
14
14
 
15
15
  The shared Dawn form (`shared/components/dawn-order-form/`) is a **simplified visual reference** — it is **incomplete** vs native (no draft, no wilaya cascade, no security, calls `ff.orders.send` directly). Do **not** copy it as the behavioral source of truth.
16
16
 
@@ -1,5 +1,7 @@
1
1
  # Schema Library (`schema.library.json`)
2
2
 
3
+ > Theme package copy — paths assume this theme folder is the project root.
4
+
3
5
  Theme-bundled **drag-drop catalog** for the merchant template editor.
4
6
 
5
7
  Components listed here can be **unused in `data.json`**. That is intentional: the theme ships extras the merchant can add later from the UI.
@@ -22,7 +24,7 @@ Components listed here can be **unused in `data.json`**. That is intentional: th
22
24
  flowchart LR
23
25
  schemaTs["schema.ts overlay"]
24
26
  lithium["Lithium built-ins"]
25
- disk["library/components/id/"]
27
+ disk["library/components/id.tsx"]
26
28
  build["template:build"]
27
29
  schema["dist/schema.json"]
28
30
  editor["Flutter Theme tab"]
@@ -35,93 +37,43 @@ flowchart LR
35
37
  editor -->|"copy-on-drop"| data
36
38
  ```
37
39
 
38
- ## Authoring (template-kit)
40
+ ## Authoring (flat TSX)
39
41
 
40
42
  ```
41
- templates/dawn-src/
42
- library/components/<id>/
43
- component.json # type, code meta, props, schemas + catalog fields
44
- component.jsx # optional
45
- slots/… children/…
46
- dist/
47
- schema.library.json
48
- data.json
43
+ library/components/
44
+ promo-banner.tsx # preferred leaf: export const meta + App
45
+ # OR folder only when slots/children needed:
46
+ rich-block/
47
+ <id>.tsx
48
+ slots/…
49
49
  ```
50
50
 
51
- ### Catalog fields on `component.json`
51
+ ### Catalog fields (from `export const meta` or legacy `.json`)
52
52
 
53
53
  | Field | Role |
54
54
  |---|---|
55
- | `libraryId` / folder name | Stable `id` in the library list |
55
+ | folder / file name | Stable `id` in the library list (`libraryId`) |
56
56
  | `title`, `subtitle`, `category`, `tags`, `imageUrl` | Editor card |
57
57
  | `type` | Usually `custom`; may be a built-in registry type |
58
58
  | `props` | Becomes `propsDefault` on drop |
59
- | `code` / `component.jsx` | Custom JSX |
59
+ | `code` (built from `.tsx`) | Custom JSX |
60
60
  | `propsSchema`, `slotsSchema`, `slotsLayout`, `slots`, `children` | Seeded on drop |
61
61
 
62
62
  Build:
63
63
 
64
64
  ```bash
65
- cd storefront && npm run template:build
65
+ npm run build
66
66
  # → dist/schema.library.json
67
67
  ```
68
68
 
69
- ## Wire shape
70
-
71
- ```json
72
- {
73
- "version": "1.0",
74
- "components": [
75
- {
76
- "id": "dawn-promo-banner",
77
- "title": "Promo Banner",
78
- "subtitle": null,
79
- "category": "marketing",
80
- "tags": ["banner"],
81
- "imageUrl": null,
82
- "type": "custom",
83
- "code": "function App() { return <div>{props.text}</div>; }",
84
- "propsSchema": { "text": { "type": "string" } },
85
- "propsDefault": { "text": "Sale" },
86
- "slotsSchema": null,
87
- "slotsDefault": null,
88
- "slotsLayout": null,
89
- "children": null
90
- }
91
- ]
92
- }
93
- ```
94
-
95
- ## Serving
69
+ ## Anti-patterns
96
70
 
97
- | Endpoint | Behavior |
71
+ | Wrong | Right |
98
72
  |---|---|
99
- | `GET /api/template/schema` | Lithium `schema.json` **plus** `library: [...]` from `template/schema.library.json` |
100
- | `GET /api/template/library` | Standalone library document |
101
- | Dev | `FEEEF_TEMPLATE_LIBRARY_PATH` → kit `dist/schema.library.json` |
102
-
103
- `StoreTemplate.schema` should include the same `library` array when publishing a theme so `TemplateFetchResult.fromStoreTemplate` exposes it via `rawSchema['library']`.
104
-
105
- ## Editor behavior
106
-
107
- - Tab **Theme** lists `controller.themeLibraryEntries` (`rawSchema['library']`).
108
- - Drop / tap → **inline copy** into `templateData` (`buildThemeLibraryComponent`).
109
- - Not a live link to the theme file: later theme updates do **not** rewrite existing placements (unlike DB `reference`).
110
- - Prefer `shared/` + `$ref` for compile-time consistency across pages you ship in `data.json`; use **library** for optional blocks merchants may add.
111
-
112
- ## vs `shared/`
113
-
114
- | | `shared/components` | `library/components` |
115
- |---|---|---|
116
- | Purpose | DRY placements already in the theme tree | Optional catalog for the editor |
117
- | Build | Inlined into `data.json` via `$ref` | Emitted as `schema.library.json` |
118
- | Unused OK? | No (only if referenced) | **Yes** |
119
-
120
- A component can exist in **both** (shared for shipped pages + library for drag-drop of the same block elsewhere).
73
+ | `library/components/x/component.json` + `component.jsx` for a leaf | Flat `library/components/x.tsx` |
74
+ | Duplicating library JSX into every page | Keep library for drag-drop; use `shared/` + `$ref` for live chrome |
121
75
 
122
- ## Rules for AI
76
+ ## Related
123
77
 
124
- 1. New optional theme UI → add under `library/components/<id>/`, rebuild.
125
- 2. Do not put library-only blocks into `data.json` unless the blank theme should include them.
126
- 3. When packing a `StoreTemplate`, merge `library` into `schema`.
127
- 4. Flutter insert = copy-on-drop, not `type: "reference"` (no DB id).
78
+ - Shared chrome: [07-SHARED-COMPONENTS.md](./07-SHARED-COMPONENTS.md)
79
+ - Custom TSX: [03-CUSTOM-COMPONENTS.md](./03-CUSTOM-COMPONENTS.md)
@@ -1,38 +1,50 @@
1
- # Template Pages — checkout, thanks, product PDP
1
+ # Template Pages — single `main` + slots
2
2
 
3
3
  > Theme package copy — paths assume this theme folder is the project root.
4
4
 
5
- Canonical routes and the **single-`main`-section** pattern.
5
+ Canonical routes and the **single-`main`-section** pattern (preferred for all new themes).
6
6
 
7
7
  ## Page matrix
8
8
 
9
- | Page id | Path | Sections | Notes |
9
+ | Page id | Path | Authoring | Notes |
10
10
  |---|---|---|---|
11
- | `product` | `/p/:id` **and** `/products/:id` | **`main` only** | Both URLs render the same PDP. Prefer `/p/` for links; `/products/:id` is an alias. |
12
- | `checkout` | `/checkout` | **`main` only** | Cart checkout. Prefer registry `cart_order_form` in a form slot. |
13
- | `thank_you` | `/thanks` | **`main` only** | Optional post-order page. Query params carry order context. Legacy `/thank-you` redirects. |
14
- | `not_found` | Next.js not-found | **`main` only** | Editable 404 (`type: "not_found"` or custom). |
15
- | `products` | `/products` | multi | Collection / PLP (unchanged). |
16
- | `home` / `contact` / | | multi | Unchanged. |
11
+ | `home` | `/` | **`main` preferred** | Flat disk: `pages/home/components/`. Legacy `header\|hero\|main\|footer` still renders when `main` is empty. |
12
+ | `product` | `/p/:id` **and** `/products/:id` | **`main` only** | Both URLs render the same PDP. Prefer `/p/` for links. |
13
+ | `checkout` | `/checkout` | **`main` only** | Prefer registry `cart_order_form` in a form slot. |
14
+ | `thank_you` | `/thanks` | **`main` only** | Query params carry order context. Legacy `/thank-you` redirects. |
15
+ | `products` | `/products` | **`main` preferred** | Legacy multi-section keys when `main` empty. |
16
+ | `contact` | `/contact` | **`main` preferred** | Legacy named sections when `main` empty. |
17
17
 
18
- ## Pattern: one section, layout in slots
18
+ ## Pattern: published `main` + optional slots
19
+
20
+ **Preferred disk layout for marketing pages** — flat sibling stack (builds to `sections.main`):
19
21
 
20
22
  ```text
21
- pages.<id>.sections.main.components[0] ← page shell (custom)
22
- slots.header[]
23
- slots.body[] | slots.form[]
24
- slots.footer[]
23
+ pages/home/components/
24
+ header.json # $ref shared.header
25
+ hero.tsx
26
+ rail.tsx
27
+ footer.json # $ref shared.footer
25
28
  ```
26
29
 
27
- Next.js page components only render `sections.main`. They do **not** invent header/footer section keys.
30
+ **When you need a shell with slots** (typical for product / checkout / thanks):
31
+
32
+ ```text
33
+ pages/product/components/product-shell/
34
+ product-shell.tsx # export const meta + slotsSchema
35
+ slots/header/….json # $ref
36
+ slots/body/….tsx
37
+ slots/form/….json # cart_order_form / product_order_form
38
+ slots/footer/….json
39
+ ```
28
40
 
29
- Use a single `main` section; put chrome in slots.
41
+ Do **not** invent deep nested trees by hand when a flat sibling stack is enough.
30
42
 
31
43
  ### Product runtime fallback
32
44
 
33
45
  `ProductPageContent` prefers `main`. If `main` is empty, it still renders the legacy multi-section tree (`header` / `top` / `start` / `end` / `bottom` / `footer`) for older store blobs.
34
46
 
35
- New themes (Dawn) ship `main` + slots only.
47
+ Home / products / contact use the same prefer-`main` rule via `lib/template/prefer-main-section.ts`.
36
48
 
37
49
  ## `/checkout`
38
50
 
@@ -68,14 +80,17 @@ New themes (Dawn) ship `main` + slots only.
68
80
 
69
81
  ## Authoring checklist
70
82
 
71
- 1. Add / edit under `pages/<page>/sections/main/…`
72
- 2. Keep a single root (or a short stack) in `main`; put chrome in slots
73
- 3. `npm run build`
74
- 4. Preview with `npm run dev`
75
- 5. Do **not** reintroduce multi-section keys on these three pages in new themes
83
+ 1. Prefer flat `pages/<page>/components/<name>.tsx` (or a short stack of siblings + `$ref`)
84
+ 2. For product / checkout / thanks: one shell **folder** only if you need slots (`header` | `body`/`form` | `footer`); otherwise flat stack
85
+ 3. Chrome reused on 2+ pages → `shared/components/<id>.tsx` + `$ref` placements
86
+ 4. `npm run build` then preview with `npm run dev` / `npm run dev`
87
+ 5. Do **not** reintroduce multi-section keys on new themes
88
+ 6. Do **not** invent deep nested shell trees when flat siblings work
76
89
 
77
90
  ## Related
78
91
 
79
92
  - Order / COD contract: [08-ORDER-FORM.md](./08-ORDER-FORM.md)
80
93
  - Architecture pages list: [01-ARCHITECTURE.md](./01-ARCHITECTURE.md)
81
94
  - Schema library (optional drag-drop blocks): [10-SCHEMA-LIBRARY.md](./10-SCHEMA-LIBRARY.md)
95
+ - Folder kit: [04-WORKFLOW.md](./04-WORKFLOW.md)
96
+ - Flat TSX: [03-CUSTOM-COMPONENTS.md](./03-CUSTOM-COMPONENTS.md)
@@ -9,28 +9,54 @@ exposes top-level `function App()` — the same contract as plain JSX.
9
9
  ## What you write
10
10
 
11
11
  ```
12
- # Preferred (page-level → sections.main)
12
+ # Required default (page-level → sections.main)
13
13
  pages/home/components/hero.tsx
14
14
 
15
- # Folder when you need colocated helpers or slots/children
16
- pages/home/components/hero/
17
- component.tsx
18
- labels.ts
15
+ # Shared leaf
16
+ shared/components/header.tsx
19
17
 
20
- # Legacy multi-section (still supported)
18
+ # Folder ONLY when you need slots/children or colocated helpers
19
+ pages/product/components/product-shell/
20
+ product-shell.tsx
21
+ slots/body/gallery.tsx
22
+
23
+ # Legacy multi-section (compat only — do not use for new themes)
21
24
  pages/home/sections/main/components/hero.tsx
22
25
  ```
23
26
 
27
+ ```tsx
28
+ const propsSchema = {
29
+ heading: { type: "string", name: "Heading" },
30
+ } as const;
31
+
32
+ export const meta = {
33
+ type: "custom",
34
+ title: "Hero",
35
+ order: 0,
36
+ propsSchema,
37
+ props: { heading: "" },
38
+ } as const satisfies FeeefComponentMeta<typeof propsSchema>;
39
+
40
+ type Props = FeeefLivePropsOf<typeof propsSchema>;
41
+
42
+ function App() {
43
+ const p = props as Props;
44
+ return <h1>{p.heading}</h1>;
45
+ }
46
+ ```
47
+
48
+ Local/`npm` imports are allowed in authoring files and are **bundled** into `code`:
49
+
24
50
  ```tsx
25
51
  import clsx from "clsx";
26
52
  import { bannerLabel } from "./labels";
27
53
 
28
- function App(): JSX.Element {
29
- const text: string = bannerLabel("Feeef");
30
- return <div className={clsx("hero")}>{text}</div>;
54
+ function App() {
55
+ return <div className={clsx("hero")}>{bannerLabel("Feeef")}</div>;
31
56
  }
32
57
  ```
33
58
 
59
+ Keep `export const meta` in the same entry file (or the kit cannot load propsSchema).
34
60
  ## What the storefront receives
35
61
 
36
62
  Build emits bundled / transpiled JS with:
@@ -60,14 +86,12 @@ npm install clsx # example
60
86
 
61
87
  ## Plain JSX (legacy)
62
88
 
63
- `component.jsx` with **no** imports is copied into `code` unchanged (fast path).
64
-
65
- ## Init
66
-
67
- This package came from `feeef template init`. Re-read `AGENTS.md` after upgrading the CLI.
89
+ Older `component.jsx` with **no** imports is still copied into `code` unchanged (fast path). **New work must use flat `.tsx` + `export const meta`.**
68
90
 
69
91
  ## Do not
70
92
 
71
93
  - Expect browser-side bundling of theme `node_modules` — only build-time inlining
72
94
  - Bundle `react` into component `code`
73
95
  - Rely on Node builtins or server-only packages inside components
96
+ - Author customs as `component.json` + `component.jsx` pairs
97
+ - Create both `name.tsx` and `name/` for the same component id