@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/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
+ }
@@ -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