@thorprovider/types 2.0.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/.turbo/turbo-build.log +18 -0
- package/.turbo/turbo-type-check.log +0 -0
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +52 -0
- package/README.md +222 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.mts +3341 -0
- package/dist/index.d.ts +3341 -0
- package/dist/index.js +144 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +113 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +34 -0
- package/publish.log +60 -0
- package/src/admin/AdminUser.ts +32 -0
- package/src/admin/AuditLog.ts +43 -0
- package/src/admin/DashboardConfig.ts +82 -0
- package/src/admin/DashboardMetrics.ts +81 -0
- package/src/admin/SiteConfigMetadata.ts +46 -0
- package/src/admin/index.ts +13 -0
- package/src/auth.ts +267 -0
- package/src/cart.ts +130 -0
- package/src/category.ts +88 -0
- package/src/collection.ts +39 -0
- package/src/commerce-provider.ts +1139 -0
- package/src/common.ts +95 -0
- package/src/customer.ts +122 -0
- package/src/designer-config.ts +106 -0
- package/src/header-config.README.md +321 -0
- package/src/header-config.ts +197 -0
- package/src/index.ts +249 -0
- package/src/order.ts +188 -0
- package/src/payment.ts +259 -0
- package/src/product.ts +364 -0
- package/src/provider.ts +174 -0
- package/src/region.ts +43 -0
- package/src/site-config-labels.ts +87 -0
- package/src/site-config.ts +148 -0
- package/src/stock-location.ts +65 -0
- package/src/storefront-config.ts +65 -0
- package/src/storefront.ts +126 -0
- package/tsconfig.json +14 -0
- package/tsup.config.ts +13 -0
package/src/common.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @thorprovider/types v3.0
|
|
3
|
+
* Common types shared across all commerce providers
|
|
4
|
+
* Universal interfaces compatible with: Shopify, Medusa.js, WooCommerce, Magento, BigCommerce
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Monetary value with currency
|
|
9
|
+
*
|
|
10
|
+
* Using string for amount prevents float precision errors.
|
|
11
|
+
* Compatible with:
|
|
12
|
+
* - Shopify: MoneyV2 (amount: Decimal, currencyCode: CurrencyCode)
|
|
13
|
+
* - Medusa: numbers (converted to string)
|
|
14
|
+
* - WooCommerce: strings ("21.99")
|
|
15
|
+
* - Magento: Float (converted to string)
|
|
16
|
+
*/
|
|
17
|
+
export interface Money {
|
|
18
|
+
amount: string; // Decimal as string (e.g., "45.00")
|
|
19
|
+
currencyCode: string; // ISO 4217 code (e.g., "USD", "EUR")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Image with metadata
|
|
24
|
+
*
|
|
25
|
+
* Universal format for product/variant images.
|
|
26
|
+
* Compatible with all platforms (URLs are normalized in adapters).
|
|
27
|
+
*/
|
|
28
|
+
export interface Image {
|
|
29
|
+
id?: string; // Optional platform-specific ID
|
|
30
|
+
url: string;
|
|
31
|
+
altText: string;
|
|
32
|
+
width?: number; // Optional for platforms without dimensions
|
|
33
|
+
height?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* SEO metadata
|
|
38
|
+
*/
|
|
39
|
+
export interface SEO {
|
|
40
|
+
title: string;
|
|
41
|
+
description: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generic connection type for paginated data
|
|
46
|
+
*/
|
|
47
|
+
export interface Connection<T> {
|
|
48
|
+
edges: Array<Edge<T>>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface Edge<T> {
|
|
52
|
+
node: T;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Pagination options
|
|
57
|
+
*/
|
|
58
|
+
export interface PaginationOptions {
|
|
59
|
+
first?: number;
|
|
60
|
+
after?: string;
|
|
61
|
+
last?: number;
|
|
62
|
+
before?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Sort options
|
|
67
|
+
*/
|
|
68
|
+
export interface SortOptions {
|
|
69
|
+
sortKey?: string;
|
|
70
|
+
reverse?: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Country information
|
|
75
|
+
*
|
|
76
|
+
* Represents a country available in a region.
|
|
77
|
+
* Used for shipping address validation and checkout forms.
|
|
78
|
+
* Compatible with:
|
|
79
|
+
* - Medusa: Country entity with iso_2, name, display_name
|
|
80
|
+
* - Shopify: CountryCode enum
|
|
81
|
+
* - WooCommerce: WC_Countries
|
|
82
|
+
*/
|
|
83
|
+
export interface Country {
|
|
84
|
+
/** ISO 3166-1 alpha-2 country code (e.g., "US", "ES", "DE") */
|
|
85
|
+
code: string;
|
|
86
|
+
|
|
87
|
+
/** Human-readable country name (e.g., "United States", "Spain") */
|
|
88
|
+
name: string;
|
|
89
|
+
|
|
90
|
+
/** ISO 3166-1 alpha-3 country code (optional, e.g., "USA", "ESP") */
|
|
91
|
+
iso3?: string;
|
|
92
|
+
|
|
93
|
+
/** ISO 3166-1 numeric code (optional, e.g., "840", "724") */
|
|
94
|
+
numCode?: string;
|
|
95
|
+
}
|
package/src/customer.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @thorprovider/types v3.0
|
|
3
|
+
* Customer types - unified interface for all commerce providers
|
|
4
|
+
* Universal interfaces compatible with: Shopify, Medusa.js, WooCommerce, Magento, BigCommerce
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Customer address
|
|
9
|
+
*
|
|
10
|
+
* Universal format using camelCase (JavaScript convention).
|
|
11
|
+
*
|
|
12
|
+
* Platform mapping:
|
|
13
|
+
* - Shopify: MailingAddress (firstName, address1, zip, province, countryCodeV2)
|
|
14
|
+
* - Medusa: Address (first_name, address_1, postal_code, province, country_code)
|
|
15
|
+
* - WooCommerce: Address (first_name, address_1, postcode, state, country)
|
|
16
|
+
* - Magento: Address (firstname, street, postcode, region, country_id)
|
|
17
|
+
*
|
|
18
|
+
* Adapters transform platform-specific snake_case to universal camelCase.
|
|
19
|
+
*/
|
|
20
|
+
export interface Address {
|
|
21
|
+
id?: string;
|
|
22
|
+
firstName: string; // Shopify: firstName, Medusa: first_name, WooCommerce: first_name
|
|
23
|
+
lastName: string; // Shopify: lastName, Medusa: last_name, WooCommerce: last_name
|
|
24
|
+
company?: string;
|
|
25
|
+
address1: string; // Shopify: address1, Medusa: address_1, WooCommerce: address_1
|
|
26
|
+
address2?: string; // Optional second address line
|
|
27
|
+
city: string;
|
|
28
|
+
province?: string; // State/province (Shopify: province, WooCommerce: state, Magento: region)
|
|
29
|
+
postalCode: string; // Shopify: zip, Medusa: postal_code, WooCommerce: postcode
|
|
30
|
+
countryCode: string; // ISO 3166-1 alpha-2 code (e.g., "US", "CA", "GB")
|
|
31
|
+
phone?: string;
|
|
32
|
+
isDefault?: boolean; // Whether this is the default/primary address for the customer
|
|
33
|
+
metadata?: Record<string, unknown>; // Flexible storage for platform-specific extras (label, etc.)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Customer
|
|
38
|
+
*
|
|
39
|
+
* Universal customer format using camelCase.
|
|
40
|
+
* Adapters transform platform-specific naming to this format.
|
|
41
|
+
*/
|
|
42
|
+
export interface Customer {
|
|
43
|
+
id: string;
|
|
44
|
+
email: string;
|
|
45
|
+
firstName: string | null; // Platform adapters transform first_name → firstName
|
|
46
|
+
lastName: string | null; // Platform adapters transform last_name → lastName
|
|
47
|
+
phone?: string | null;
|
|
48
|
+
hasAccount?: boolean; // Whether customer has a registered account
|
|
49
|
+
createdAt?: string; // ISO 8601 timestamp
|
|
50
|
+
updatedAt?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Flexible metadata storage.
|
|
53
|
+
*
|
|
54
|
+
* Multi-tenant convention: when `metadata.sales_channel_id` is present the
|
|
55
|
+
* customer is scoped to that channel. See `@thorprovider/adapters/metadata` helpers.
|
|
56
|
+
*/
|
|
57
|
+
metadata?: Record<string, unknown>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Custom fetcher callback for advanced customer queries.
|
|
62
|
+
*
|
|
63
|
+
* When provided, this callback replaces the default SDK logic entirely.
|
|
64
|
+
* Useful for: custom API endpoints, backend-specific filters, Module Link queries.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* // Custom endpoint that filters by channel server-side
|
|
69
|
+
* const customFetcher = async (options: GetCustomersOptions) => {
|
|
70
|
+
* const response = await fetch(`/api/admin/sales-channels/${options.salesChannelId}/customers`);
|
|
71
|
+
* return response.json();
|
|
72
|
+
* };
|
|
73
|
+
*
|
|
74
|
+
* const customers = await provider.getCustomers({
|
|
75
|
+
* salesChannelId: 'sc_123',
|
|
76
|
+
* customFetcher,
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export type GetCustomersCallback = (options: GetCustomersOptions) => Promise<Customer[]>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Options for querying a list of customers.
|
|
84
|
+
*
|
|
85
|
+
* Used by CommerceProvider.getCustomers() and admin list endpoints.
|
|
86
|
+
*/
|
|
87
|
+
export interface GetCustomersOptions {
|
|
88
|
+
/** Full-text search by name or email */
|
|
89
|
+
search?: string;
|
|
90
|
+
/** Maximum number of results */
|
|
91
|
+
limit?: number;
|
|
92
|
+
/** Zero-based offset for pagination */
|
|
93
|
+
offset?: number;
|
|
94
|
+
/** Field to sort results by */
|
|
95
|
+
sortBy?: 'createdAt' | 'email' | 'firstName';
|
|
96
|
+
/**
|
|
97
|
+
* Filter customers to a specific sales channel.
|
|
98
|
+
*
|
|
99
|
+
* When set, only customers whose `metadata.sales_channel_id` matches
|
|
100
|
+
* this value are returned. Enables multi-tenant isolation for
|
|
101
|
+
* dropshippers who should only see their own customers.
|
|
102
|
+
*
|
|
103
|
+
* If omitted, all customers are returned (admin/super-admin view).
|
|
104
|
+
*/
|
|
105
|
+
salesChannelId?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Custom fetcher callback (optional).
|
|
108
|
+
*
|
|
109
|
+
* When provided, this callback is invoked instead of the default SDK logic.
|
|
110
|
+
* Allows backends to implement custom filters, Module Link queries, or
|
|
111
|
+
* call alternative endpoints (e.g., `/api/admin/sales-channels/{id}/customers`).
|
|
112
|
+
*
|
|
113
|
+
* This option enables:
|
|
114
|
+
* - **Medusa Module Link**: Query customers via custom module API
|
|
115
|
+
* - **Custom endpoints**: Call `/api/admin/sales-channels/{id}/customers` for server-side filtering
|
|
116
|
+
* - **Backend-specific optimizations**: Shopify/WooCommerce adapters can implement their own logic
|
|
117
|
+
*
|
|
118
|
+
* @default undefined (uses default SDK + in-memory filter)
|
|
119
|
+
* @see {@link GetCustomersCallback} for callback signature
|
|
120
|
+
*/
|
|
121
|
+
customFetcher?: GetCustomersCallback;
|
|
122
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @thorprovider/types — Site Designer Configuration
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the Site Designer feature.
|
|
5
|
+
* Describes the visual theme, navigation, and identity configuration
|
|
6
|
+
* managed through the admin Site Designer and served to storefronts
|
|
7
|
+
* via `GET /store/thor/site-config`.
|
|
8
|
+
*
|
|
9
|
+
* These types are the source of truth (L1) so that both L2 adapters
|
|
10
|
+
* and L3 components can depend on them without circular imports.
|
|
11
|
+
*
|
|
12
|
+
* @module designer-config
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Available theme presets for the Site Designer.
|
|
17
|
+
*/
|
|
18
|
+
export type DesignerThemePreset =
|
|
19
|
+
| 'electro'
|
|
20
|
+
| 'midnight'
|
|
21
|
+
| 'sunset'
|
|
22
|
+
| 'forest'
|
|
23
|
+
| 'custom';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Theme configuration managed by the Site Designer.
|
|
27
|
+
*/
|
|
28
|
+
export interface DesignerThemeConfig {
|
|
29
|
+
/** Active theme preset */
|
|
30
|
+
preset: DesignerThemePreset;
|
|
31
|
+
|
|
32
|
+
/** Accent color name (e.g., "indigo", "blue", "crimson") */
|
|
33
|
+
accentColor: string;
|
|
34
|
+
|
|
35
|
+
/** Gray scale family */
|
|
36
|
+
grayColor: 'auto' | 'gray' | 'mauve' | 'slate' | 'sage' | 'olive' | 'sand';
|
|
37
|
+
|
|
38
|
+
/** Border radius scale */
|
|
39
|
+
radius: 'none' | 'small' | 'medium' | 'large' | 'full';
|
|
40
|
+
|
|
41
|
+
/** Color scheme */
|
|
42
|
+
appearance: 'light' | 'dark';
|
|
43
|
+
|
|
44
|
+
/** UI scaling factor */
|
|
45
|
+
scaling: '90%' | '95%' | '100%' | '105%' | '110%';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A single navigation item in the Site Designer menu.
|
|
50
|
+
*/
|
|
51
|
+
export interface DesignerNavItem {
|
|
52
|
+
/** Unique identifier for this nav entry */
|
|
53
|
+
id: string;
|
|
54
|
+
|
|
55
|
+
/** Display label */
|
|
56
|
+
label: string;
|
|
57
|
+
|
|
58
|
+
/** Target URL or path */
|
|
59
|
+
href: string;
|
|
60
|
+
|
|
61
|
+
/** Whether this item is visible to storefront visitors */
|
|
62
|
+
visible: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A version history entry for the Site Designer config.
|
|
67
|
+
*/
|
|
68
|
+
export interface DesignerHistoryEntry {
|
|
69
|
+
/** Version identifier (typically ISO 8601 timestamp) */
|
|
70
|
+
version: string;
|
|
71
|
+
|
|
72
|
+
/** ISO 8601 timestamp of when this version was created */
|
|
73
|
+
createdAt: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Complete Site Designer configuration.
|
|
78
|
+
*
|
|
79
|
+
* Persisted per sales channel in the backend and served to the
|
|
80
|
+
* storefront via `GET /store/thor/site-config`.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const result = await commerce.getDesignerConfig();
|
|
85
|
+
* if (result) {
|
|
86
|
+
* const { config } = result;
|
|
87
|
+
* console.log(config.theme.preset, config.siteName);
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export interface DesignerConfig {
|
|
92
|
+
/** Theme visual settings */
|
|
93
|
+
theme: DesignerThemeConfig;
|
|
94
|
+
|
|
95
|
+
/** Navigation menu items */
|
|
96
|
+
navigation: DesignerNavItem[];
|
|
97
|
+
|
|
98
|
+
/** Storefront display name */
|
|
99
|
+
siteName: string;
|
|
100
|
+
|
|
101
|
+
/** Storefront description */
|
|
102
|
+
siteDescription: string;
|
|
103
|
+
|
|
104
|
+
/** Logo URL (optional, overrides StorefrontConfig.logoUrl) */
|
|
105
|
+
logo?: string;
|
|
106
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Header Configuration Types
|
|
2
|
+
Type definitions for configurable header navigation in Thor Commerce.
|
|
3
|
+
|
|
4
|
+
## Overview
|
|
5
|
+
|
|
6
|
+
This module provides a complete type system for defining header navigation structure via configuration instead of hardcoded JSX. Enables CMS-like customization of site headers without modifying components.
|
|
7
|
+
|
|
8
|
+
## Core Types
|
|
9
|
+
|
|
10
|
+
### `HeaderNavigationConfig`
|
|
11
|
+
|
|
12
|
+
Root configuration interface for the entire header structure.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
interface HeaderNavigationConfig {
|
|
16
|
+
logo: {
|
|
17
|
+
src: string
|
|
18
|
+
alt: string
|
|
19
|
+
width: number
|
|
20
|
+
height: number
|
|
21
|
+
href: string
|
|
22
|
+
}
|
|
23
|
+
leftLinks?: HeaderLinkItem[]
|
|
24
|
+
rightLinks?: HeaderLinkItem[]
|
|
25
|
+
search?: {
|
|
26
|
+
enabled: boolean
|
|
27
|
+
width: number
|
|
28
|
+
placeholder?: string
|
|
29
|
+
}
|
|
30
|
+
account?: {
|
|
31
|
+
items: AccountMenuItem[]
|
|
32
|
+
}
|
|
33
|
+
cart?: {
|
|
34
|
+
label?: string
|
|
35
|
+
variant?: 'mini' | 'drawer'
|
|
36
|
+
composition?: 'compact' | 'detailed'
|
|
37
|
+
showBadge?: boolean
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### `HeaderLinkItem`
|
|
43
|
+
|
|
44
|
+
Discriminated union for different link types in the navigation.
|
|
45
|
+
|
|
46
|
+
**Types:**
|
|
47
|
+
1. **Direct Link** - Simple href navigation
|
|
48
|
+
2. **Dropdown Menu** - Multi-item dropdown with optional dynamic data
|
|
49
|
+
3. **Preset Component** - Pre-built components (cart, account)
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
type HeaderLinkItem =
|
|
53
|
+
| { type: 'link'; label: string; href: string; icon?: IconConfig }
|
|
54
|
+
| {
|
|
55
|
+
type: 'dropdown'
|
|
56
|
+
trigger: { label: string; icon?: IconConfig }
|
|
57
|
+
items: NavigationMenuItem[]
|
|
58
|
+
dynamicSource?: DynamicSource
|
|
59
|
+
}
|
|
60
|
+
| { type: 'preset'; preset: PresetType }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Discriminated Union Benefits:**
|
|
64
|
+
- TypeScript enforces valid combinations at compile-time
|
|
65
|
+
- IntelliSense provides accurate property suggestions based on `type`
|
|
66
|
+
- Impossible to create invalid states (e.g., a link with dropdown items)
|
|
67
|
+
|
|
68
|
+
### `AccountMenuItem`
|
|
69
|
+
|
|
70
|
+
Discriminated union for account dropdown menu items.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
type AccountMenuItem =
|
|
74
|
+
| {
|
|
75
|
+
type: 'item'
|
|
76
|
+
label: string
|
|
77
|
+
href?: string
|
|
78
|
+
action?: string
|
|
79
|
+
icon?: IconConfig
|
|
80
|
+
destructive?: boolean
|
|
81
|
+
// Discriminator ensures divider can't have these
|
|
82
|
+
divider?: never
|
|
83
|
+
}
|
|
84
|
+
| {
|
|
85
|
+
type: 'divider'
|
|
86
|
+
// Discriminator ensures divider can't have item properties
|
|
87
|
+
label?: never
|
|
88
|
+
href?: never
|
|
89
|
+
action?: never
|
|
90
|
+
icon?: never
|
|
91
|
+
destructive?: never
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Usage:**
|
|
96
|
+
```typescript
|
|
97
|
+
const accountItems: AccountMenuItem[] = [
|
|
98
|
+
{ type: 'item', label: 'Profile', href: '/profile' },
|
|
99
|
+
{ type: 'divider' },
|
|
100
|
+
{ type: 'item', label: 'Logout', action: 'logout', destructive: true }
|
|
101
|
+
]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### `IconConfig`
|
|
105
|
+
|
|
106
|
+
Hybrid type supporting both Lucide icon names and custom React nodes.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
type IconConfig = string | React.ReactNode
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Examples:**
|
|
113
|
+
```typescript
|
|
114
|
+
// Lucide icon name (resolved at runtime)
|
|
115
|
+
icon: 'ShoppingBag'
|
|
116
|
+
|
|
117
|
+
// Custom React component
|
|
118
|
+
icon: <CustomIcon className="w-4 h-4" />
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `DynamicSource`
|
|
122
|
+
|
|
123
|
+
Backend data sources for dynamic content injection.
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
type DynamicSource = 'categories' | 'collections'
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Use Case:**
|
|
130
|
+
```typescript
|
|
131
|
+
{
|
|
132
|
+
type: 'dropdown',
|
|
133
|
+
trigger: { label: 'Categories' },
|
|
134
|
+
dynamicSource: 'categories', // Fetch from Medusa backend
|
|
135
|
+
items: [] // Will be populated at runtime
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `PresetType`
|
|
140
|
+
|
|
141
|
+
Type-safe identifiers for pre-built components.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
type PresetType = 'cart' | 'account'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Rendering:**
|
|
148
|
+
- `'cart'` → Renders `CartModule` (mini cart with badge)
|
|
149
|
+
- `'account'` → Renders `AccountMenu` (dropdown with user actions)
|
|
150
|
+
|
|
151
|
+
## Design Patterns
|
|
152
|
+
|
|
153
|
+
### Discriminated Unions
|
|
154
|
+
|
|
155
|
+
Used extensively to prevent invalid states at compile-time:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// ✅ Valid
|
|
159
|
+
const link: HeaderLinkItem = {
|
|
160
|
+
type: 'link',
|
|
161
|
+
label: 'Products',
|
|
162
|
+
href: '/products'
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ❌ TypeScript Error: 'items' not allowed on 'link' type
|
|
166
|
+
const invalid: HeaderLinkItem = {
|
|
167
|
+
type: 'link',
|
|
168
|
+
label: 'Products',
|
|
169
|
+
href: '/products',
|
|
170
|
+
items: [] // Error!
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Never Constraints
|
|
175
|
+
|
|
176
|
+
Ensure mutually exclusive properties in discriminated unions:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// Divider can't have label (enforced by `label?: never`)
|
|
180
|
+
const divider: AccountMenuItem = {
|
|
181
|
+
type: 'divider',
|
|
182
|
+
label: 'Invalid' // TypeScript Error!
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Type Guards
|
|
187
|
+
|
|
188
|
+
Helper functions to narrow types at runtime:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
function isLinkItem(item: HeaderLinkItem): item is { type: 'link' } {
|
|
192
|
+
return item.type === 'link'
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function isDropdownItem(item: HeaderLinkItem): item is { type: 'dropdown' } {
|
|
196
|
+
return item.type === 'dropdown'
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Usage Example
|
|
201
|
+
|
|
202
|
+
Complete header configuration in `site.config.ts`:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import type { HeaderNavigationConfig } from '@thorprovider/types'
|
|
206
|
+
|
|
207
|
+
export const siteConfig = {
|
|
208
|
+
header: {
|
|
209
|
+
logo: {
|
|
210
|
+
src: '/logo.svg',
|
|
211
|
+
alt: 'My Store',
|
|
212
|
+
width: 120,
|
|
213
|
+
height: 40,
|
|
214
|
+
href: '/'
|
|
215
|
+
},
|
|
216
|
+
leftLinks: [
|
|
217
|
+
{
|
|
218
|
+
type: 'link',
|
|
219
|
+
label: 'Products',
|
|
220
|
+
href: '/products',
|
|
221
|
+
icon: 'ShoppingBag'
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
type: 'dropdown',
|
|
225
|
+
trigger: { label: 'Categories' },
|
|
226
|
+
dynamicSource: 'categories', // Fetches from backend
|
|
227
|
+
items: []
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
rightLinks: [
|
|
231
|
+
{ type: 'preset', preset: 'account' },
|
|
232
|
+
{ type: 'preset', preset: 'cart' }
|
|
233
|
+
],
|
|
234
|
+
search: {
|
|
235
|
+
enabled: true,
|
|
236
|
+
width: 400
|
|
237
|
+
},
|
|
238
|
+
account: {
|
|
239
|
+
items: [
|
|
240
|
+
{ type: 'item', label: 'Profile', href: '/profile', icon: 'User' },
|
|
241
|
+
{ type: 'item', label: 'Orders', href: '/orders', icon: 'Package' },
|
|
242
|
+
{ type: 'divider' },
|
|
243
|
+
{
|
|
244
|
+
type: 'item',
|
|
245
|
+
label: 'Logout',
|
|
246
|
+
action: 'logout',
|
|
247
|
+
destructive: true,
|
|
248
|
+
icon: 'LogOut'
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
} satisfies HeaderNavigationConfig
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Related Types
|
|
257
|
+
|
|
258
|
+
This module imports navigation types from `@thorprovider/components`:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import type { NavigationMenuItem } from '@thorprovider/components'
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Used for dropdown item structure consistency across the application.
|
|
265
|
+
|
|
266
|
+
## Type Safety Benefits
|
|
267
|
+
|
|
268
|
+
1. **Compile-time validation**: Invalid configurations fail at build time
|
|
269
|
+
2. **IntelliSense support**: Full autocomplete in IDEs
|
|
270
|
+
3. **Refactoring safety**: Type changes propagate through the codebase
|
|
271
|
+
4. **Self-documenting**: Types serve as inline documentation
|
|
272
|
+
5. **Prevents runtime errors**: Impossible states caught before deployment
|
|
273
|
+
|
|
274
|
+
## Migration Path
|
|
275
|
+
|
|
276
|
+
**Before (untyped configuration):**
|
|
277
|
+
```typescript
|
|
278
|
+
const header = {
|
|
279
|
+
links: [
|
|
280
|
+
{ label: 'Products', href: '/products', items: [] } // Ambiguous!
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**After (type-safe):**
|
|
286
|
+
```typescript
|
|
287
|
+
const header = {
|
|
288
|
+
leftLinks: [
|
|
289
|
+
{ type: 'link', label: 'Products', href: '/products' }
|
|
290
|
+
]
|
|
291
|
+
} satisfies HeaderNavigationConfig
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
TypeScript now enforces `HeaderLinkItem` shape, preventing mixed concerns.
|
|
295
|
+
|
|
296
|
+
## Future Extensions
|
|
297
|
+
|
|
298
|
+
Extend types to support new features:
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
// Add new preset types
|
|
302
|
+
type PresetType = 'cart' | 'account' | 'notifications' | 'search'
|
|
303
|
+
|
|
304
|
+
// Add new dynamic sources
|
|
305
|
+
type DynamicSource = 'categories' | 'collections' | 'pages' | 'blog-posts'
|
|
306
|
+
|
|
307
|
+
// Add link badges
|
|
308
|
+
interface HeaderLinkItem {
|
|
309
|
+
// ... existing properties
|
|
310
|
+
badge?: {
|
|
311
|
+
value: number | string
|
|
312
|
+
variant: 'solid' | 'soft' | 'outline'
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## See Also
|
|
318
|
+
|
|
319
|
+
- **@thorprovider/components**: `NavigationMenu`, `AccountMenu`, `OverflowMenu` components
|
|
320
|
+
- **@thorprovider/core**: `HeaderLayout` orchestrator consuming these types
|
|
321
|
+
- **V0 Starter Layout README**: Implementation details and usage patterns
|