@commerce-blocks/sdk 1.3.0 → 2.0.0-alpha.1
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 +103 -64
- package/dist/index.d.ts +176 -109
- package/dist/index.js +1300 -1146
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @commerce-blocks/sdk
|
|
2
2
|
|
|
3
|
-
ES module SDK
|
|
3
|
+
ES module SDK powered by Layers API with optional Shopify Storefront enrichment.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ const result = createSdk({
|
|
|
22
22
|
],
|
|
23
23
|
facets: ['options.color', 'options.size', 'vendor'],
|
|
24
24
|
|
|
25
|
-
// Opt in to
|
|
25
|
+
// Opt in to Storefront API for additional product data
|
|
26
26
|
// enableStorefront: true,
|
|
27
27
|
// shop: 'your-store.myshopify.com',
|
|
28
28
|
// storefrontPublicToken: 'your-storefront-token',
|
|
@@ -38,18 +38,6 @@ if (result.error) {
|
|
|
38
38
|
|
|
39
39
|
## Configuration
|
|
40
40
|
|
|
41
|
-
### Shopify (optional)
|
|
42
|
-
|
|
43
|
-
Storefront API is opt-in. Enable it for richer product data (metafields, full variant info, collection/page metadata).
|
|
44
|
-
|
|
45
|
-
| Option | Type | Required | Description |
|
|
46
|
-
| ----------------------- | ------------- | ----------------------------- | ---------------------------------------------------- |
|
|
47
|
-
| `enableStorefront` | `boolean` | No | Enable Storefront API hydration (default: `false`) |
|
|
48
|
-
| `shop` | `string` | When `enableStorefront: true` | Store domain |
|
|
49
|
-
| `storefrontPublicToken` | `string` | When `enableStorefront: true` | Storefront API public access token |
|
|
50
|
-
| `storefrontApiVersion` | `string` | No | API version (default: `2025-01`) |
|
|
51
|
-
| `fetch` | `CustomFetch` | No | Custom fetch implementation (SSR, testing, proxying) |
|
|
52
|
-
|
|
53
41
|
### Layers
|
|
54
42
|
|
|
55
43
|
| Option | Type | Required | Description |
|
|
@@ -61,6 +49,18 @@ Storefront API is opt-in. Enable it for richer product data (metafields, full va
|
|
|
61
49
|
| `layersBaseUrl` | `string` | No | Custom API URL |
|
|
62
50
|
| `fetch` | `CustomFetch` | No | Custom fetch implementation (SSR, testing, proxying) |
|
|
63
51
|
|
|
52
|
+
### Storefront (optional)
|
|
53
|
+
|
|
54
|
+
Storefront API is opt-in. Enable it for collection/page metadata and Shopify-specific fields (metafields, variant detail).
|
|
55
|
+
|
|
56
|
+
| Option | Type | Required | Description |
|
|
57
|
+
| ----------------------- | ------------- | ----------------------------- | ---------------------------------------------------- |
|
|
58
|
+
| `enableStorefront` | `boolean` | No | Enable Storefront API hydration (default: `false`) |
|
|
59
|
+
| `shop` | `string` | When `enableStorefront: true` | Store domain |
|
|
60
|
+
| `storefrontPublicToken` | `string` | When `enableStorefront: true` | Storefront API public access token |
|
|
61
|
+
| `storefrontApiVersion` | `string` | No | API version (default: `2025-01`) |
|
|
62
|
+
| `fetch` | `CustomFetch` | No | Custom fetch implementation (SSR, testing, proxying) |
|
|
63
|
+
|
|
64
64
|
Layers API supports identity tracking for personalization. Pass identity fields via request context:
|
|
65
65
|
|
|
66
66
|
```typescript
|
|
@@ -87,14 +87,14 @@ interface LayersIdentity {
|
|
|
87
87
|
|
|
88
88
|
### Extensibility
|
|
89
89
|
|
|
90
|
-
| Option | Type
|
|
91
|
-
| ------------------ |
|
|
92
|
-
| `extendProduct` | `({ base, raw,
|
|
93
|
-
| `extendCollection` | `(result, raw) => result`
|
|
94
|
-
| `extendSearch` | `(result, raw) => result`
|
|
95
|
-
| `extendBlock` | `(result, raw) => result`
|
|
96
|
-
| `transformFilters` | `(filters) => FilterGroup`
|
|
97
|
-
| `filterMap` | `FilterMap`
|
|
90
|
+
| Option | Type | Description |
|
|
91
|
+
| ------------------ | ---------------------------------- | ---------------------------------- |
|
|
92
|
+
| `extendProduct` | `({ base, raw, storefront }) => P` | Transform products after hydration |
|
|
93
|
+
| `extendCollection` | `(result, raw) => result` | Transform collection results |
|
|
94
|
+
| `extendSearch` | `(result, raw) => result` | Transform search results |
|
|
95
|
+
| `extendBlock` | `(result, raw) => result` | Transform blocks results |
|
|
96
|
+
| `transformFilters` | `(filters) => FilterGroup` | Custom filter transformation |
|
|
97
|
+
| `filterMap` | `FilterMap` | URL-friendly filter key mapping |
|
|
98
98
|
|
|
99
99
|
Once configured, extenders and transformers are applied automatically. You pass simple inputs and receive transformed outputs—no manual transformation needed on each call.
|
|
100
100
|
|
|
@@ -102,7 +102,7 @@ Once configured, extenders and transformers are applied automatically. You pass
|
|
|
102
102
|
// Configure once at initialization
|
|
103
103
|
const sdk = createSdk({
|
|
104
104
|
// ... base config
|
|
105
|
-
extendProduct: ({ base, raw,
|
|
105
|
+
extendProduct: ({ base, raw, storefront }) => ({
|
|
106
106
|
...base,
|
|
107
107
|
isNew: raw.tags?.includes('new') ?? false,
|
|
108
108
|
rating: raw.calculated?.average_rating,
|
|
@@ -457,7 +457,7 @@ effect(() => {
|
|
|
457
457
|
|
|
458
458
|
| Parameter | Type | Required | Description |
|
|
459
459
|
| --------------------- | ------------- | -------- | ---------------------------------------- |
|
|
460
|
-
| `ids` | `string[]` | Yes |
|
|
460
|
+
| `ids` | `string[]` | Yes | Product GIDs |
|
|
461
461
|
| `meta.collection` | `string` | No | Collection handle to fetch metadata |
|
|
462
462
|
| `meta.page` | `string` | No | Page handle to fetch metadata |
|
|
463
463
|
| `meta.includeFilters` | `boolean` | No | Include available filters for collection |
|
|
@@ -502,8 +502,9 @@ interface CollectionResult {
|
|
|
502
502
|
resultsPerPage?: number
|
|
503
503
|
facets: Record<string, Record<string, number>>
|
|
504
504
|
facetRanges?: Record<string, { min: number; max: number }>
|
|
505
|
+
priceRange?: PriceRange // Formatted min/max prices from result set
|
|
505
506
|
attributionToken: string
|
|
506
|
-
collection?:
|
|
507
|
+
collection?: StorefrontCollection
|
|
507
508
|
}
|
|
508
509
|
|
|
509
510
|
interface SearchResult {
|
|
@@ -514,6 +515,7 @@ interface SearchResult {
|
|
|
514
515
|
resultsPerPage?: number
|
|
515
516
|
facets: Record<string, Record<string, number>>
|
|
516
517
|
facetRanges?: Record<string, { min: number; max: number }>
|
|
518
|
+
priceRange?: PriceRange // Formatted min/max prices from result set
|
|
517
519
|
attributionToken: string
|
|
518
520
|
}
|
|
519
521
|
|
|
@@ -525,14 +527,26 @@ interface BlocksResult {
|
|
|
525
527
|
resultsPerPage?: number
|
|
526
528
|
facets: Record<string, Record<string, number>>
|
|
527
529
|
facetRanges?: Record<string, { min: number; max: number }>
|
|
530
|
+
priceRange?: PriceRange // Formatted min/max prices from result set
|
|
528
531
|
attributionToken: string
|
|
529
532
|
block?: BlocksInfo // { id, title, anchor_type, strategy_type, strategy_key }
|
|
530
533
|
}
|
|
531
534
|
|
|
535
|
+
interface PriceRange {
|
|
536
|
+
min: Price
|
|
537
|
+
max: Price
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
interface Price {
|
|
541
|
+
amount: number
|
|
542
|
+
currencyCode: string
|
|
543
|
+
formatted: string
|
|
544
|
+
}
|
|
545
|
+
|
|
532
546
|
interface StorefrontResult {
|
|
533
547
|
products: Product[]
|
|
534
|
-
collection?:
|
|
535
|
-
page?:
|
|
548
|
+
collection?: StorefrontCollection
|
|
549
|
+
page?: StorefrontPage
|
|
536
550
|
}
|
|
537
551
|
```
|
|
538
552
|
|
|
@@ -551,7 +565,7 @@ if (result.error) {
|
|
|
551
565
|
break
|
|
552
566
|
case 'ApiError':
|
|
553
567
|
// Server errors, rate limits
|
|
554
|
-
console.log(result.error.source) // 'layers' | '
|
|
568
|
+
console.log(result.error.source) // 'layers' | 'storefront'
|
|
555
569
|
console.log(result.error.status) // HTTP status code
|
|
556
570
|
break
|
|
557
571
|
case 'ValidationError':
|
|
@@ -585,7 +599,7 @@ if (result.error) {
|
|
|
585
599
|
| Field | Type | Description |
|
|
586
600
|
| -------------- | -------------- | -------------------------------------------------- |
|
|
587
601
|
| `code` | `ApiErrorCode` | `NOT_FOUND`, `RATE_LIMITED`, `GRAPHQL_ERROR`, etc. |
|
|
588
|
-
| `source` | `ApiSource` | `'layers'` or `'
|
|
602
|
+
| `source` | `ApiSource` | `'layers'` or `'storefront'` |
|
|
589
603
|
| `status` | `number?` | HTTP status code |
|
|
590
604
|
| `retryable` | `boolean` | Whether the request can be retried |
|
|
591
605
|
| `retryAfterMs` | `number?` | Suggested retry delay |
|
|
@@ -606,6 +620,8 @@ if (result.error) {
|
|
|
606
620
|
|
|
607
621
|
### Error Helpers
|
|
608
622
|
|
|
623
|
+
Always check `isRetryable()` before calling `getRetryDelay()`. `getRetryDelay()` returns `undefined` for non-retryable errors — it's not meant to be used standalone.
|
|
624
|
+
|
|
609
625
|
```typescript
|
|
610
626
|
import { isRetryable, getRetryDelay } from '@commerce-blocks/sdk'
|
|
611
627
|
|
|
@@ -636,7 +652,7 @@ const priceFilter = filter(and(gte('price', 50), lte('price', 200)))
|
|
|
636
652
|
|
|
637
653
|
// Use in query
|
|
638
654
|
await collection.execute({
|
|
639
|
-
filters: multiFilter
|
|
655
|
+
filters: multiFilter,
|
|
640
656
|
})
|
|
641
657
|
```
|
|
642
658
|
|
|
@@ -675,57 +691,80 @@ await collection.execute({
|
|
|
675
691
|
})
|
|
676
692
|
```
|
|
677
693
|
|
|
678
|
-
##
|
|
694
|
+
## Product Card
|
|
679
695
|
|
|
680
|
-
### `
|
|
696
|
+
### `createProductCard()` - Reactive Product Card Controller
|
|
681
697
|
|
|
682
|
-
|
|
698
|
+
Creates a reactive controller for product cards with variant selection and availability logic. All derived values are computed signals that auto-update when inputs change.
|
|
683
699
|
|
|
684
700
|
```typescript
|
|
685
|
-
import {
|
|
701
|
+
import { createProductCard, effect } from '@commerce-blocks/sdk'
|
|
686
702
|
|
|
687
|
-
const card =
|
|
703
|
+
const card = createProductCard({
|
|
688
704
|
product,
|
|
689
|
-
selectedOptions: [{ name: 'Size', value: '
|
|
690
|
-
|
|
705
|
+
selectedOptions: [{ name: 'Size', value: '7' }],
|
|
706
|
+
breakoutOptions: [{ name: 'Stone', value: 'Ruby' }],
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
// Subscribe to reactive state
|
|
710
|
+
effect(() => {
|
|
711
|
+
console.log('Selected variant:', card.selectedVariant.value)
|
|
712
|
+
console.log('Available options:', card.options.value)
|
|
691
713
|
})
|
|
692
714
|
|
|
693
|
-
// Access
|
|
694
|
-
card.variants // Variants filtered by
|
|
695
|
-
card.selectedVariant // Currently selected variant
|
|
696
|
-
card.options // Available options (excludes
|
|
697
|
-
card.images // Variant image or product images
|
|
698
|
-
card.carouselIndex // Image index for carousel
|
|
715
|
+
// Access reactive signals
|
|
716
|
+
card.variants.value // Variants filtered by breakoutOptions
|
|
717
|
+
card.selectedVariant.value // Currently selected variant
|
|
718
|
+
card.options.value // Available options (excludes breakout option names)
|
|
719
|
+
card.images.value // Variant image or product images
|
|
720
|
+
card.carouselIndex.value // Image index for carousel
|
|
699
721
|
|
|
700
|
-
//
|
|
722
|
+
// Mutate state via actions
|
|
723
|
+
card.selectOption('Size', 'L') // Select a single option
|
|
724
|
+
card.setSelectedOptions([{ name: 'Size', value: 'L' }]) // Merge options by name
|
|
725
|
+
card.setBreakoutOptions([{ name: 'Stone', value: 'Emerald' }]) // Change breakout filter
|
|
726
|
+
|
|
727
|
+
// Query methods (pure)
|
|
701
728
|
card.getOptionValues('Size') // ['S', 'M', 'L']
|
|
702
729
|
card.getSwatches('Color') // Swatch definitions
|
|
703
730
|
card.isOptionAvailable('Size', 'L') // Check if selecting 'L' results in available variant
|
|
704
731
|
card.getVariantByOptions([{ name: 'Size', value: 'L' }])
|
|
732
|
+
|
|
733
|
+
// Cleanup
|
|
734
|
+
card.dispose()
|
|
705
735
|
```
|
|
706
736
|
|
|
707
737
|
**Parameters:**
|
|
708
738
|
|
|
709
|
-
| Parameter
|
|
710
|
-
|
|
|
711
|
-
| `product`
|
|
712
|
-
| `selectedOptions`
|
|
713
|
-
| `
|
|
714
|
-
|
|
715
|
-
**
|
|
716
|
-
|
|
717
|
-
| Property | Type
|
|
718
|
-
| ----------------- |
|
|
719
|
-
| `product` | `Product`
|
|
720
|
-
| `variants` | `ProductVariant[]
|
|
721
|
-
| `selectedVariant` | `ProductVariant \| null
|
|
722
|
-
| `selectedOptions` | `ProductOption[]
|
|
723
|
-
| `options` | `RichProductOption[]
|
|
724
|
-
| `optionNames` | `string[]
|
|
725
|
-
| `images` | `Image[]
|
|
726
|
-
| `carouselIndex` | `number
|
|
727
|
-
|
|
728
|
-
**
|
|
739
|
+
| Parameter | Type | Required | Description |
|
|
740
|
+
| ----------------- | ----------------- | -------- | -------------------------------------------------------- |
|
|
741
|
+
| `product` | `Product` | Yes | Product to display |
|
|
742
|
+
| `selectedOptions` | `ProductOption[]` | No | Initially selected options |
|
|
743
|
+
| `breakoutOptions` | `ProductOption[]` | No | Options to filter variants (auto-set from variant tiles) |
|
|
744
|
+
|
|
745
|
+
**Reactive State (ReadonlySignal):**
|
|
746
|
+
|
|
747
|
+
| Property | Type | Description |
|
|
748
|
+
| ----------------- | ---------------------------------------- | --------------------------------------- |
|
|
749
|
+
| `product` | `Product` | Original product (static) |
|
|
750
|
+
| `variants` | `ReadonlySignal<ProductVariant[]>` | Variants matching breakoutOptions |
|
|
751
|
+
| `selectedVariant` | `ReadonlySignal<ProductVariant \| null>` | Variant matching all selected options |
|
|
752
|
+
| `selectedOptions` | `ReadonlySignal<ProductOption[]>` | Combined breakout + selected options |
|
|
753
|
+
| `options` | `ReadonlySignal<RichProductOption[]>` | Available options from visible variants |
|
|
754
|
+
| `optionNames` | `ReadonlySignal<string[]>` | Option names (excludes breakout) |
|
|
755
|
+
| `images` | `ReadonlySignal<Image[]>` | Variant image or product images |
|
|
756
|
+
| `carouselIndex` | `ReadonlySignal<number>` | Index of selected variant's image |
|
|
757
|
+
|
|
758
|
+
**Actions:**
|
|
759
|
+
|
|
760
|
+
| Method | Description |
|
|
761
|
+
| ----------------------------- | ------------------------------- |
|
|
762
|
+
| `selectOption(name, value)` | Select a single option by name |
|
|
763
|
+
| `setSelectedOptions(options)` | Merge options by name |
|
|
764
|
+
| `setBreakoutOptions(options)` | Replace breakout filter options |
|
|
765
|
+
| `dispose()` | Cleanup controller |
|
|
766
|
+
|
|
767
|
+
**Query Methods:**
|
|
729
768
|
|
|
730
769
|
| Method | Returns | Description |
|
|
731
770
|
| -------------------------------- | ------------------------ | ------------------------------------------------------ |
|