@thorprovider/storefront 0.3.1 → 0.4.0-mvp.2
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/README.md +321 -152
- package/VENDOR.md +69 -0
- package/assets/openspec/config.yaml +38 -0
- package/assets/templates/AGENTS.md +76 -0
- package/assets/templates/app/app/[[...slug]]/page.tsx +54 -2
- package/assets/templates/app/app/[[...slug]]/renderer.tsx +13 -2
- package/assets/templates/app/app/globals.css +5 -8
- package/assets/templates/app/app/layout.tsx +17 -7
- package/assets/templates/app/app/robots.ts +19 -0
- package/assets/templates/app/app/sitemap.ts +71 -0
- package/assets/templates/app/lib/__STOREFRONT__/actions.ts +612 -0
- package/assets/templates/app/lib/__STOREFRONT__/cart-state.ts +66 -0
- package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +50 -57
- package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +679 -0
- package/assets/templates/app/lib/__STOREFRONT__/composition.ts +26 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +197 -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 +264 -51
- package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +6 -3
- package/assets/templates/app/lib/__STOREFRONT__/schema.ts +136 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-observation.ts +182 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-sources.ts +130 -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 +120 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +38 -0
- package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +129 -10
- package/assets/templates/app/lib/__STOREFRONT__/spec/page-root.ts +5 -1
- package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +191 -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 +161 -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 +18 -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/products.client.tsx +100 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.tsx +19 -0
- 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/schema.products.ts +39 -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 +159 -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 +45 -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 +439 -0
- package/assets/templates/views/account/schema.ts +53 -0
- package/assets/templates/views/cart/content.ts +11 -0
- package/assets/templates/views/cart/data.ts +23 -0
- package/assets/templates/views/cart/index.tsx +53 -0
- package/assets/templates/views/cart/props.ts +12 -0
- package/assets/templates/views/cart/registry.tsx +81 -0
- package/assets/templates/views/cart/schema.ts +52 -0
- package/assets/templates/views/category/assembly/assembly.json +29 -0
- package/assets/templates/views/category/assembly/index.skeleton.tsx +251 -0
- package/assets/templates/views/category/assembly/registry.skeleton.tsx +34 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/binding.json +5 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/catalog.part +4 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/element.part +7 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/registry.part +18 -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 +299 -0
- package/assets/templates/views/category/props.ts +23 -0
- package/assets/templates/views/category/registry.tsx +122 -0
- package/assets/templates/views/category/schema.ts +91 -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 +33 -0
- package/assets/templates/views/home/assembly/index.skeleton.tsx +90 -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 +24 -0
- package/assets/templates/views/home/index.tsx +57 -85
- 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 +50 -0
- package/assets/templates/views/product/index.tsx +148 -0
- package/assets/templates/views/product/props.ts +27 -0
- package/assets/templates/views/product/registry.tsx +103 -0
- package/assets/templates/views/product/schema.ts +121 -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/bin/storefront.js +2424 -148
- package/examples/merchandising/category-led.json +37 -0
- package/examples/merchandising/collection-led.json +37 -0
- package/package.json +15 -9
- package/recipes/archetypes.json +28 -14
- package/recipes/catalog.json +400 -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 +162 -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 +76 -19
- package/recipes/sections.json +34 -5
- package/recipes/validate.mjs +838 -32
- package/scripts/candidate.mjs +236 -0
- package/scripts/composers.mjs +160 -0
- package/scripts/env-file.mjs +86 -0
- package/scripts/file-classes.mjs +121 -0
- package/scripts/logical-controls.mjs +61 -0
- package/scripts/manifest.mjs +298 -0
- package/scripts/migrate-english-routes.mjs +276 -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 +573 -0
- package/scripts/plan-apply.mjs +987 -0
- package/scripts/preflight.mjs +51 -0
- package/scripts/reconcile.mjs +549 -0
- package/scripts/render-templates.mjs +338 -68
- package/scripts/schema-validate.mjs +132 -0
- package/scripts/section-compat.mjs +300 -0
- package/scripts/section-config.mjs +253 -0
- package/scripts/section-operations.mjs +508 -0
- package/scripts/starter.mjs +17 -0
- package/scripts/sync-assets.mjs +22 -15
- package/scripts/theme/color.mjs +185 -0
- package/scripts/theme/css-theme.mjs +233 -0
- package/scripts/theme/fonts.mjs +123 -0
- package/scripts/theme/import-export.mjs +125 -0
- package/scripts/theme/preset.mjs +93 -0
- package/scripts/theme/theme-plan.mjs +292 -0
- package/scripts/theme/tokens.mjs +137 -0
- package/scripts/view-assembly.mjs +337 -0
- package/scripts/view-selection.mjs +211 -0
- package/skills/sf-feature/SKILL.md +80 -0
- package/skills/sf-setup/SKILL.md +79 -0
- package/skills/sf-theme-gen/SKILL.md +100 -30
- package/skills/sf-theme-gen/references/shadcn-theming.md +87 -0
- package/skills/{shadcn-theming/references/templates → sf-theme-gen/references}/theme-setup.md +15 -19
- package/skills/{shadcn-theming → sf-theme-gen}/references/theming-guide.md +6 -11
- package/skills/sf-view-gen/SKILL.md +146 -93
- package/skills/sf-view-gen/assets/recipes/archetypes.json +28 -14
- package/skills/sf-view-gen/assets/recipes/catalog.json +400 -0
- package/skills/sf-view-gen/assets/recipes/catalog.schema.json +64 -0
- package/skills/sf-view-gen/assets/recipes/features.json +162 -0
- package/skills/sf-view-gen/assets/recipes/recipes.json +76 -19
- package/skills/sf-view-gen/assets/recipes/sections.json +34 -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/products.client.tsx +100 -0
- package/skills/sf-view-gen/assets/templates/views/sections/products.tsx +19 -0
- 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.products.ts +39 -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/{json-render-core/SKILL.md → sf-view-gen/references/json-render-core.md} +4 -27
- package/skills/{json-render-next/SKILL.md → sf-view-gen/references/json-render-next.md} +5 -8
- package/skills/{json-render-react/SKILL.md → sf-view-gen/references/json-render-react.md} +3 -5
- package/skills/{json-render-shadcn/SKILL.md → sf-view-gen/references/json-render-shadcn.md} +3 -5
- package/skills/sf-view-gen/references/views.md +58 -33
- 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 +838 -32
- package/skills/storefront-workflow/SKILL.md +179 -0
- package/skills/{storefront-best-practices/reference/design.md → storefront-workflow/references/design-consistency.md} +13 -29
- package/CHANGELOG.md +0 -61
- package/commands/sf-add-view.md +0 -26
- package/commands/sf-theme.md +0 -20
- package/commands/sf-view.md +0 -25
- package/skills/building-storefronts/SKILL.md +0 -178
- package/skills/building-storefronts/references/frontend-integration.md +0 -229
- package/skills/json-render-remotion/SKILL.md +0 -111
- package/skills/json-render-solid/SKILL.md +0 -204
- package/skills/nextjs-shadcn/SKILL.md +0 -367
- package/skills/nextjs-shadcn/references/architecture.md +0 -499
- package/skills/nextjs-shadcn/references/project-setup.md +0 -162
- package/skills/nextjs-shadcn/references/shadcn-platform.md +0 -261
- package/skills/nextjs-shadcn/references/sidebar.md +0 -274
- package/skills/nextjs-shadcn/references/styling.md +0 -555
- 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
- package/skills/sf-view-gen/assets/templates/views/user-panel/index.tsx +0 -168
- package/skills/sf-view-gen/assets/templates/views/user-panel/registry.tsx +0 -49
- package/skills/shadcn-component-discovery/SKILL.md +0 -273
- package/skills/shadcn-component-discovery/references/registries.md +0 -226
- package/skills/shadcn-theming/SKILL.md +0 -104
- package/skills/storefront-best-practices/SKILL.md +0 -421
- package/skills/storefront-best-practices/reference/components/breadcrumbs.md +0 -123
- package/skills/storefront-best-practices/reference/components/cart-popup.md +0 -189
- package/skills/storefront-best-practices/reference/components/country-selector.md +0 -298
- package/skills/storefront-best-practices/reference/components/footer.md +0 -112
- package/skills/storefront-best-practices/reference/components/hero.md +0 -241
- package/skills/storefront-best-practices/reference/components/megamenu.md +0 -239
- package/skills/storefront-best-practices/reference/components/navbar.md +0 -397
- package/skills/storefront-best-practices/reference/components/popups.md +0 -221
- package/skills/storefront-best-practices/reference/components/product-card.md +0 -125
- package/skills/storefront-best-practices/reference/components/product-reviews.md +0 -217
- package/skills/storefront-best-practices/reference/components/product-slider.md +0 -174
- package/skills/storefront-best-practices/reference/components/search.md +0 -101
- package/skills/storefront-best-practices/reference/connecting-to-backend.md +0 -391
- package/skills/storefront-best-practices/reference/features/promotions.md +0 -307
- package/skills/storefront-best-practices/reference/features/wishlist.md +0 -230
- package/skills/storefront-best-practices/reference/layouts/account.md +0 -380
- package/skills/storefront-best-practices/reference/layouts/cart.md +0 -316
- package/skills/storefront-best-practices/reference/layouts/checkout.md +0 -486
- package/skills/storefront-best-practices/reference/layouts/home-page.md +0 -264
- package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +0 -231
- package/skills/storefront-best-practices/reference/layouts/product-details.md +0 -527
- package/skills/storefront-best-practices/reference/layouts/product-listing.md +0 -520
- package/skills/storefront-best-practices/reference/layouts/static-pages.md +0 -356
- package/skills/storefront-best-practices/reference/medusa.md +0 -307
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/mobile-responsiveness.md +0 -0
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/seo.md +0 -0
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
# Frontend SDK Integration
|
|
2
|
-
|
|
3
|
-
## Contents
|
|
4
|
-
- [Frontend SDK Pattern](#frontend-sdk-pattern)
|
|
5
|
-
- [Locating the SDK](#locating-the-sdk)
|
|
6
|
-
- [Using sdk.client.fetch()](#using-sdkclientfetch)
|
|
7
|
-
- [React Query Pattern](#react-query-pattern)
|
|
8
|
-
- [Query Key Best Practices](#query-key-best-practices)
|
|
9
|
-
- [Error Handling](#error-handling)
|
|
10
|
-
- [Optimistic Updates](#optimistic-updates)
|
|
11
|
-
|
|
12
|
-
This guide covers how to integrate Medusa custom API routes with frontend applications using the Medusa SDK and React Query.
|
|
13
|
-
|
|
14
|
-
**Note:** API routes are also referred to as "endpoints" - these terms are interchangeable.
|
|
15
|
-
|
|
16
|
-
## Frontend SDK Pattern
|
|
17
|
-
|
|
18
|
-
### Locating the SDK
|
|
19
|
-
|
|
20
|
-
**IMPORTANT:** Never hardcode SDK import paths. Always locate where the SDK is instantiated in the project first.
|
|
21
|
-
|
|
22
|
-
Look for `@medusajs/js-sdk`
|
|
23
|
-
|
|
24
|
-
The SDK instance is typically exported as `sdk`:
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
import { sdk } from "[LOCATE IN PROJECT]"
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Using sdk.client.fetch()
|
|
31
|
-
|
|
32
|
-
**⚠️ CRITICAL: ALWAYS use the Medusa JS SDK for ALL API requests - NEVER use regular fetch()**
|
|
33
|
-
|
|
34
|
-
**Why this is critical:**
|
|
35
|
-
- **Store API routes** require the publishable API key in headers
|
|
36
|
-
- **Admin API routes** require authentication headers
|
|
37
|
-
- **Regular fetch()** without these headers will cause errors
|
|
38
|
-
- The SDK automatically handles all required headers for you
|
|
39
|
-
|
|
40
|
-
**When to use what:**
|
|
41
|
-
- **Existing endpoints** (built-in Medusa routes): Use existing SDK methods like `sdk.store.product.list()`, `sdk.admin.order.retrieve()`
|
|
42
|
-
- **Custom endpoints** (your custom API routes): Use `sdk.client.fetch()` for custom routes
|
|
43
|
-
|
|
44
|
-
**⚠️ CRITICAL: The SDK handles JSON serialization automatically. NEVER use JSON.stringify() on the body.**
|
|
45
|
-
|
|
46
|
-
Call custom API routes using the SDK:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { sdk } from "[LOCATE SDK INSTANCE IN PROJECT]"
|
|
50
|
-
|
|
51
|
-
// ✅ CORRECT - Pass object directly
|
|
52
|
-
const result = await sdk.client.fetch("/store/my-route", {
|
|
53
|
-
method: "POST",
|
|
54
|
-
body: {
|
|
55
|
-
email: "user@example.com",
|
|
56
|
-
name: "John Doe",
|
|
57
|
-
},
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
// ❌ WRONG - Don't use JSON.stringify
|
|
61
|
-
const result = await sdk.client.fetch("/store/my-route", {
|
|
62
|
-
method: "POST",
|
|
63
|
-
body: JSON.stringify({ // ❌ DON'T DO THIS!
|
|
64
|
-
email: "user@example.com",
|
|
65
|
-
}),
|
|
66
|
-
})
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**Key points:**
|
|
70
|
-
|
|
71
|
-
- **The SDK handles JSON serialization automatically** - just pass plain objects
|
|
72
|
-
- **NEVER use JSON.stringify()** - this will break the request
|
|
73
|
-
- No need to set Content-Type headers - SDK adds them
|
|
74
|
-
- Session/JWT authentication is handled automatically
|
|
75
|
-
- Publishable API key is automatically added
|
|
76
|
-
|
|
77
|
-
### Built-in Endpoints vs Custom Endpoints
|
|
78
|
-
|
|
79
|
-
**⚠️ CRITICAL: Use the appropriate SDK method based on endpoint type**
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
import { sdk } from "[LOCATE SDK INSTANCE IN PROJECT]"
|
|
83
|
-
|
|
84
|
-
// ✅ CORRECT - Built-in endpoint: Use existing SDK method
|
|
85
|
-
const products = await sdk.store.product.list({
|
|
86
|
-
limit: 10,
|
|
87
|
-
offset: 0
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
// ✅ CORRECT - Custom endpoint: Use sdk.client.fetch()
|
|
91
|
-
const reviews = await sdk.client.fetch("/store/products/prod_123/reviews")
|
|
92
|
-
|
|
93
|
-
// ❌ WRONG - Using regular fetch for ANY endpoint
|
|
94
|
-
const products = await fetch("http://localhost:9000/store/products")
|
|
95
|
-
// ❌ Error: Missing publishable API key header!
|
|
96
|
-
|
|
97
|
-
// ❌ WRONG - Using regular fetch for custom endpoint
|
|
98
|
-
const reviews = await fetch("http://localhost:9000/store/products/prod_123/reviews")
|
|
99
|
-
// ❌ Error: Missing publishable API key header!
|
|
100
|
-
|
|
101
|
-
// ❌ WRONG - Using sdk.client.fetch() for built-in endpoint when SDK method exists
|
|
102
|
-
const products = await sdk.client.fetch("/store/products")
|
|
103
|
-
// ❌ Less type-safe than using sdk.store.product.list()
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
**Why this matters:**
|
|
107
|
-
- **Store routes** require `x-publishable-api-key` header - SDK adds it automatically
|
|
108
|
-
- **Admin routes** require `Authorization` and session cookie headers - SDK adds them automatically
|
|
109
|
-
- **Regular fetch()** doesn't include these headers → API returns authentication/authorization errors
|
|
110
|
-
- Using existing SDK methods provides **better type safety** and autocomplete
|
|
111
|
-
|
|
112
|
-
## React Query Pattern
|
|
113
|
-
|
|
114
|
-
Use `useQuery` for GET requests and `useMutation` for POST/DELETE:
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
import { sdk } from "[LOCATE SDK INSTANCE IN PROJECT]"
|
|
118
|
-
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
|
119
|
-
|
|
120
|
-
function MyComponent({ userId }: { userId: string }) {
|
|
121
|
-
const queryClient = useQueryClient()
|
|
122
|
-
|
|
123
|
-
// GET request - fetching data
|
|
124
|
-
const { data, isLoading } = useQuery({
|
|
125
|
-
queryKey: ["my-data", userId],
|
|
126
|
-
queryFn: () => sdk.client.fetch(`/store/my-route?userId=${userId}`),
|
|
127
|
-
enabled: !!userId,
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
// POST request - mutation with cache invalidation
|
|
131
|
-
const mutation = useMutation({
|
|
132
|
-
mutationFn: (input: { email: string }) =>
|
|
133
|
-
sdk.client.fetch("/store/my-route", { method: "POST", body: input }),
|
|
134
|
-
onSuccess: () => {
|
|
135
|
-
// Invalidate and refetch related queries
|
|
136
|
-
queryClient.invalidateQueries({ queryKey: ["my-data"] })
|
|
137
|
-
},
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
if (isLoading) return <p>Loading...</p>
|
|
141
|
-
|
|
142
|
-
return (
|
|
143
|
-
<div>
|
|
144
|
-
<p>{data?.title}</p>
|
|
145
|
-
<button
|
|
146
|
-
onClick={() => mutation.mutate({ email: "test@example.com" })}
|
|
147
|
-
disabled={mutation.isPending}
|
|
148
|
-
>
|
|
149
|
-
{mutation.isPending ? "Loading..." : "Submit"}
|
|
150
|
-
</button>
|
|
151
|
-
{mutation.isError && <p>Error occurred</p>}
|
|
152
|
-
</div>
|
|
153
|
-
)
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
**Key states:** `isLoading`, `isPending`, `isSuccess`, `isError`, `error`
|
|
158
|
-
|
|
159
|
-
## Query Key Best Practices
|
|
160
|
-
|
|
161
|
-
Structure query keys for effective cache management:
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
// Good: Hierarchical structure
|
|
165
|
-
queryKey: ["products", productId]
|
|
166
|
-
queryKey: ["products", "list", { page, filters }]
|
|
167
|
-
|
|
168
|
-
// Invalidate all product queries
|
|
169
|
-
queryClient.invalidateQueries({ queryKey: ["products"] })
|
|
170
|
-
|
|
171
|
-
// Invalidate specific product
|
|
172
|
-
queryClient.invalidateQueries({ queryKey: ["products", productId] })
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## Error Handling
|
|
176
|
-
|
|
177
|
-
Handle API errors gracefully:
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
const mutation = useMutation({
|
|
181
|
-
mutationFn: (input) => sdk.client.fetch("/store/my-route", {
|
|
182
|
-
method: "POST",
|
|
183
|
-
body: input
|
|
184
|
-
}),
|
|
185
|
-
onError: (error) => {
|
|
186
|
-
console.error("Mutation failed:", error)
|
|
187
|
-
// Show error message to user
|
|
188
|
-
},
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
// In component
|
|
192
|
-
{mutation.isError && (
|
|
193
|
-
<p className="error">
|
|
194
|
-
{mutation.error?.message || "An error occurred"}
|
|
195
|
-
</p>
|
|
196
|
-
)}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## Optimistic Updates
|
|
200
|
-
|
|
201
|
-
Update UI immediately before server confirms:
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
const mutation = useMutation({
|
|
205
|
-
mutationFn: (newItem) =>
|
|
206
|
-
sdk.client.fetch("/store/items", { method: "POST", body: newItem }),
|
|
207
|
-
onMutate: async (newItem) => {
|
|
208
|
-
// Cancel outgoing refetches
|
|
209
|
-
await queryClient.cancelQueries({ queryKey: ["items"] })
|
|
210
|
-
|
|
211
|
-
// Snapshot previous value
|
|
212
|
-
const previousItems = queryClient.getQueryData(["items"])
|
|
213
|
-
|
|
214
|
-
// Optimistically update
|
|
215
|
-
queryClient.setQueryData(["items"], (old) => [...old, newItem])
|
|
216
|
-
|
|
217
|
-
// Return context with snapshot
|
|
218
|
-
return { previousItems }
|
|
219
|
-
},
|
|
220
|
-
onError: (err, newItem, context) => {
|
|
221
|
-
// Rollback on error
|
|
222
|
-
queryClient.setQueryData(["items"], context.previousItems)
|
|
223
|
-
},
|
|
224
|
-
onSettled: () => {
|
|
225
|
-
// Refetch after mutation
|
|
226
|
-
queryClient.invalidateQueries({ queryKey: ["items"] })
|
|
227
|
-
},
|
|
228
|
-
})
|
|
229
|
-
```
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: remotion
|
|
3
|
-
description: Remotion renderer for json-render that turns JSON timeline specs into videos. Use when working with @json-render/remotion, building video compositions from JSON, creating video catalogs, or rendering AI-generated video timelines.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# @json-render/remotion
|
|
7
|
-
|
|
8
|
-
Remotion renderer that converts JSON timeline specs into video compositions.
|
|
9
|
-
|
|
10
|
-
## Quick Start
|
|
11
|
-
|
|
12
|
-
```typescript
|
|
13
|
-
import { Player } from "@remotion/player";
|
|
14
|
-
import { Renderer, type TimelineSpec } from "@json-render/remotion";
|
|
15
|
-
|
|
16
|
-
function VideoPlayer({ spec }: { spec: TimelineSpec }) {
|
|
17
|
-
return (
|
|
18
|
-
<Player
|
|
19
|
-
component={Renderer}
|
|
20
|
-
inputProps={{ spec }}
|
|
21
|
-
durationInFrames={spec.composition.durationInFrames}
|
|
22
|
-
fps={spec.composition.fps}
|
|
23
|
-
compositionWidth={spec.composition.width}
|
|
24
|
-
compositionHeight={spec.composition.height}
|
|
25
|
-
controls
|
|
26
|
-
/>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Using Standard Components
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
import { defineCatalog } from "@json-render/core";
|
|
35
|
-
import {
|
|
36
|
-
schema,
|
|
37
|
-
standardComponentDefinitions,
|
|
38
|
-
standardTransitionDefinitions,
|
|
39
|
-
standardEffectDefinitions,
|
|
40
|
-
} from "@json-render/remotion";
|
|
41
|
-
|
|
42
|
-
export const videoCatalog = defineCatalog(schema, {
|
|
43
|
-
components: standardComponentDefinitions,
|
|
44
|
-
transitions: standardTransitionDefinitions,
|
|
45
|
-
effects: standardEffectDefinitions,
|
|
46
|
-
});
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Adding Custom Components
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
import { z } from "zod";
|
|
53
|
-
|
|
54
|
-
const catalog = defineCatalog(schema, {
|
|
55
|
-
components: {
|
|
56
|
-
...standardComponentDefinitions,
|
|
57
|
-
MyCustomClip: {
|
|
58
|
-
props: z.object({ text: z.string() }),
|
|
59
|
-
type: "scene",
|
|
60
|
-
defaultDuration: 90,
|
|
61
|
-
description: "My custom video clip",
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Pass custom component to Renderer
|
|
67
|
-
<Player
|
|
68
|
-
component={Renderer}
|
|
69
|
-
inputProps={{
|
|
70
|
-
spec,
|
|
71
|
-
components: { MyCustomClip: MyCustomComponent },
|
|
72
|
-
}}
|
|
73
|
-
/>
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Timeline Spec Structure
|
|
77
|
-
|
|
78
|
-
```json
|
|
79
|
-
{
|
|
80
|
-
"composition": { "id": "video", "fps": 30, "width": 1920, "height": 1080, "durationInFrames": 300 },
|
|
81
|
-
"tracks": [{ "id": "main", "name": "Main", "type": "video", "enabled": true }],
|
|
82
|
-
"clips": [
|
|
83
|
-
{ "id": "clip-1", "trackId": "main", "component": "TitleCard", "props": { "title": "Hello" }, "from": 0, "durationInFrames": 90 }
|
|
84
|
-
],
|
|
85
|
-
"audio": { "tracks": [] }
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Standard Components
|
|
90
|
-
|
|
91
|
-
| Component | Type | Description |
|
|
92
|
-
|-----------|------|-------------|
|
|
93
|
-
| `TitleCard` | scene | Full-screen title with subtitle |
|
|
94
|
-
| `TypingText` | scene | Terminal-style typing animation |
|
|
95
|
-
| `ImageSlide` | image | Full-screen image display |
|
|
96
|
-
| `SplitScreen` | scene | Two-panel comparison |
|
|
97
|
-
| `QuoteCard` | scene | Quote with attribution |
|
|
98
|
-
| `StatCard` | scene | Animated statistic display |
|
|
99
|
-
| `TextOverlay` | overlay | Text overlay |
|
|
100
|
-
| `LowerThird` | overlay | Name/title overlay |
|
|
101
|
-
|
|
102
|
-
## Key Exports
|
|
103
|
-
|
|
104
|
-
| Export | Purpose |
|
|
105
|
-
|--------|---------|
|
|
106
|
-
| `Renderer` | Render spec to Remotion composition |
|
|
107
|
-
| `schema` | Timeline schema |
|
|
108
|
-
| `standardComponents` | Pre-built component registry |
|
|
109
|
-
| `standardComponentDefinitions` | Catalog definitions |
|
|
110
|
-
| `useTransition` | Transition animation hook |
|
|
111
|
-
| `ClipWrapper` | Wrap clips with transitions |
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: solid
|
|
3
|
-
description: SolidJS renderer for json-render. Use when building @json-render/solid catalogs/registries, wiring Renderer providers, implementing bindings/actions, or troubleshooting Solid-specific reactivity patterns.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# @json-render/solid
|
|
7
|
-
|
|
8
|
-
`@json-render/solid` renders json-render specs into Solid component trees with fine-grained reactivity.
|
|
9
|
-
|
|
10
|
-
## Quick Start
|
|
11
|
-
|
|
12
|
-
```tsx
|
|
13
|
-
import { Renderer, JSONUIProvider } from "@json-render/solid";
|
|
14
|
-
import type { Spec } from "@json-render/solid";
|
|
15
|
-
import { registry } from "./registry";
|
|
16
|
-
|
|
17
|
-
export function App(props: { spec: Spec | null }) {
|
|
18
|
-
return (
|
|
19
|
-
<JSONUIProvider registry={registry} initialState={{}}>
|
|
20
|
-
<Renderer spec={props.spec} registry={registry} />
|
|
21
|
-
</JSONUIProvider>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Create a Catalog
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import { defineCatalog } from "@json-render/core";
|
|
30
|
-
import { schema } from "@json-render/solid/schema";
|
|
31
|
-
import { z } from "zod";
|
|
32
|
-
|
|
33
|
-
export const catalog = defineCatalog(schema, {
|
|
34
|
-
components: {
|
|
35
|
-
Button: {
|
|
36
|
-
props: z.object({
|
|
37
|
-
label: z.string(),
|
|
38
|
-
variant: z.enum(["primary", "secondary"]).nullable(),
|
|
39
|
-
}),
|
|
40
|
-
description: "Clickable button",
|
|
41
|
-
},
|
|
42
|
-
Card: {
|
|
43
|
-
props: z.object({ title: z.string() }),
|
|
44
|
-
description: "Card container",
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
actions: {
|
|
48
|
-
submit: { description: "Submit data" },
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Define Components
|
|
54
|
-
|
|
55
|
-
Components receive `ComponentRenderProps` from the renderer:
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
interface ComponentRenderProps<P = Record<string, unknown>> {
|
|
59
|
-
element: UIElement<string, P>;
|
|
60
|
-
children?: JSX.Element;
|
|
61
|
-
emit: (event: string) => void;
|
|
62
|
-
on: (event: string) => EventHandle;
|
|
63
|
-
bindings?: Record<string, string>;
|
|
64
|
-
loading?: boolean;
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Example:
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
import type { BaseComponentProps } from "@json-render/solid";
|
|
72
|
-
|
|
73
|
-
export function Button(props: BaseComponentProps<{ label: string }>) {
|
|
74
|
-
return (
|
|
75
|
-
<button onClick={() => props.emit("press")}>{props.props.label}</button>
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Create a Registry
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
import { defineRegistry } from "@json-render/solid";
|
|
84
|
-
import { catalog } from "./catalog";
|
|
85
|
-
import { Card } from "./Card";
|
|
86
|
-
import { Button } from "./Button";
|
|
87
|
-
|
|
88
|
-
const { registry, handlers, executeAction } = defineRegistry(catalog, {
|
|
89
|
-
components: {
|
|
90
|
-
Card,
|
|
91
|
-
Button,
|
|
92
|
-
},
|
|
93
|
-
actions: {
|
|
94
|
-
submit: async (params, setState, state) => {
|
|
95
|
-
// custom action logic
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Spec Structure
|
|
102
|
-
|
|
103
|
-
```json
|
|
104
|
-
{
|
|
105
|
-
"root": "card1",
|
|
106
|
-
"elements": {
|
|
107
|
-
"card1": {
|
|
108
|
-
"type": "Card",
|
|
109
|
-
"props": { "title": "Hello" },
|
|
110
|
-
"children": ["btn1"]
|
|
111
|
-
},
|
|
112
|
-
"btn1": {
|
|
113
|
-
"type": "Button",
|
|
114
|
-
"props": { "label": "Click me" },
|
|
115
|
-
"on": {
|
|
116
|
-
"press": { "action": "submit" }
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## Providers
|
|
124
|
-
|
|
125
|
-
- `StateProvider`: state model read/write and controlled mode via `store`
|
|
126
|
-
- `VisibilityProvider`: evaluates `visible` conditions
|
|
127
|
-
- `ValidationProvider`: field validation + `validateForm` integration
|
|
128
|
-
- `ActionProvider`: runs built-in and custom actions
|
|
129
|
-
- `JSONUIProvider`: combined provider wrapper
|
|
130
|
-
|
|
131
|
-
## Hooks
|
|
132
|
-
|
|
133
|
-
- `useStateStore`, `useStateValue`, `useStateBinding`
|
|
134
|
-
- `useVisibility`, `useIsVisible`
|
|
135
|
-
- `useActions`, `useAction`
|
|
136
|
-
- `useValidation`, `useOptionalValidation`, `useFieldValidation`
|
|
137
|
-
- `useBoundProp`
|
|
138
|
-
- `useUIStream`, `useChatUI`
|
|
139
|
-
|
|
140
|
-
## Built-in Actions
|
|
141
|
-
|
|
142
|
-
Handled automatically by `ActionProvider`:
|
|
143
|
-
|
|
144
|
-
- `setState`
|
|
145
|
-
- `pushState`
|
|
146
|
-
- `removeState`
|
|
147
|
-
- `validateForm`
|
|
148
|
-
|
|
149
|
-
## Dynamic Props and Bindings
|
|
150
|
-
|
|
151
|
-
Nested lists can set `repeat.statePath` to `{ "$item": "field" }` inside an enclosing repeat.
|
|
152
|
-
|
|
153
|
-
Supported expression forms include:
|
|
154
|
-
|
|
155
|
-
- `{"$state": "/path"}`
|
|
156
|
-
- `{"$bindState": "/path"}`
|
|
157
|
-
- `{"$bindItem": "field"}`
|
|
158
|
-
- `{"$template": "Hi ${/user/name}"}`
|
|
159
|
-
- `{"$computed": "fn", "args": {...}}`
|
|
160
|
-
- `{"$cond": <condition>, "$then": <value>, "$else": <value>}`
|
|
161
|
-
|
|
162
|
-
Use `useBoundProp` in components for writable bound values:
|
|
163
|
-
|
|
164
|
-
```tsx
|
|
165
|
-
import { useBoundProp } from "@json-render/solid";
|
|
166
|
-
|
|
167
|
-
function Input(props: BaseComponentProps<{ value?: string }>) {
|
|
168
|
-
const [value, setValue] = useBoundProp(
|
|
169
|
-
props.props.value,
|
|
170
|
-
props.bindings?.value,
|
|
171
|
-
);
|
|
172
|
-
return (
|
|
173
|
-
<input
|
|
174
|
-
value={String(value() ?? "")}
|
|
175
|
-
onInput={(e) => setValue(e.currentTarget.value)}
|
|
176
|
-
/>
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
`useStateValue`, `useStateBinding`, and the `state` / `errors` / `isValid` fields from `useFieldValidation` are reactive accessors in Solid. Call them as functions inside JSX, `createMemo`, or `createEffect`.
|
|
182
|
-
|
|
183
|
-
## Solid Reactivity Rules
|
|
184
|
-
|
|
185
|
-
- Do not destructure component props in function signatures when values need to stay reactive.
|
|
186
|
-
- Keep changing reads inside JSX expressions, `createMemo`, or `createEffect`.
|
|
187
|
-
- Context values are exposed through getter-based objects so consumers always observe live signals.
|
|
188
|
-
|
|
189
|
-
## Streaming UI
|
|
190
|
-
|
|
191
|
-
```tsx
|
|
192
|
-
import { useUIStream, Renderer } from "@json-render/solid";
|
|
193
|
-
|
|
194
|
-
const stream = useUIStream({ api: "/api/generate-ui" });
|
|
195
|
-
await stream.send("Create a support dashboard");
|
|
196
|
-
|
|
197
|
-
<Renderer
|
|
198
|
-
spec={stream.spec}
|
|
199
|
-
registry={registry}
|
|
200
|
-
loading={stream.isStreaming}
|
|
201
|
-
/>;
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Use `useChatUI` for chat + UI generation flows.
|