medusa-product-helper 0.0.12 → 0.0.16
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/.medusa/server/src/api/store/product-helper/products/route.js +76 -0
- package/.medusa/server/src/api/store/product-helper/products/validators.js +2 -1
- package/.medusa/server/src/config/product-helper-options.js +15 -1
- package/.medusa/server/src/helpers/wishlist.js +6 -13
- package/.medusa/server/src/index.js +101 -0
- package/.medusa/server/src/providers/filter-providers/availability-provider.js +96 -0
- package/.medusa/server/src/providers/filter-providers/base-filter-provider.js +32 -0
- package/.medusa/server/src/providers/filter-providers/base-product-provider.js +122 -0
- package/.medusa/server/src/providers/filter-providers/category-provider.js +55 -0
- package/.medusa/server/src/providers/filter-providers/collection-provider.js +53 -0
- package/.medusa/server/src/providers/filter-providers/index.js +94 -0
- package/.medusa/server/src/providers/filter-providers/metadata-provider.js +88 -0
- package/.medusa/server/src/providers/filter-providers/price-range-provider.js +108 -0
- package/.medusa/server/src/providers/filter-providers/promotion-provider.js +197 -0
- package/.medusa/server/src/providers/filter-providers/promotion-window-provider.js +125 -0
- package/.medusa/server/src/providers/filter-providers/rating-provider.js +92 -0
- package/.medusa/server/src/services/dynamic-filter-service.js +814 -0
- package/.medusa/server/src/services/filter-provider-loader.js +155 -0
- package/.medusa/server/src/services/filter-provider-registry.js +142 -0
- package/.medusa/server/src/services/product-filter-service.js +230 -0
- package/.medusa/server/src/utils/query-parser.js +103 -0
- package/README.md +142 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -147,6 +147,17 @@ const plugins = [
|
|
|
147
147
|
// Require products to have at least one review
|
|
148
148
|
require_reviews: false,
|
|
149
149
|
},
|
|
150
|
+
// Custom filter providers (optional)
|
|
151
|
+
filterProviders: [
|
|
152
|
+
// File path (relative to project root)
|
|
153
|
+
"./src/providers/margin-provider.ts",
|
|
154
|
+
// Or module reference
|
|
155
|
+
"@my-org/custom-filters/brand-provider",
|
|
156
|
+
],
|
|
157
|
+
// Disable specific built-in providers (optional)
|
|
158
|
+
disableBuiltInProviders: [
|
|
159
|
+
// "rating", // Uncomment to disable rating filter provider
|
|
160
|
+
],
|
|
150
161
|
},
|
|
151
162
|
},
|
|
152
163
|
]
|
|
@@ -230,6 +241,84 @@ Configure rating-based filtering:
|
|
|
230
241
|
- `max`: Maximum rating (0-5)
|
|
231
242
|
- `require_reviews`: Require at least one review
|
|
232
243
|
|
|
244
|
+
#### Filter Providers
|
|
245
|
+
|
|
246
|
+
Configure custom filter providers:
|
|
247
|
+
- `filterProviders`: Array of file paths or module references to custom filter providers
|
|
248
|
+
- `disableBuiltInProviders`: Array of provider identifiers to disable (e.g., `["rating"]`)
|
|
249
|
+
|
|
250
|
+
See the [Provider Development Guide](./PROVIDER_DEVELOPMENT_GUIDE.md) for details on creating custom filter providers.
|
|
251
|
+
|
|
252
|
+
## Dynamic Filter Provider System
|
|
253
|
+
|
|
254
|
+
The plugin includes a provider-based dynamic filter system that allows you to extend product filtering capabilities without modifying the plugin code. All built-in filters (category, collection, metadata, price range, etc.) are implemented as filter providers, and you can add your own custom providers.
|
|
255
|
+
|
|
256
|
+
### Built-in Filter Providers
|
|
257
|
+
|
|
258
|
+
The plugin includes the following built-in filter providers:
|
|
259
|
+
|
|
260
|
+
- **Category Filter** (`category_id`): Filter products by category IDs
|
|
261
|
+
- **Collection Filter** (`collection_id`): Filter products by collection IDs
|
|
262
|
+
- **Metadata Filter** (`metadata`): Filter products by metadata with allowlist validation
|
|
263
|
+
- **Price Range Filter** (`price_range`): Filter products by price range (min/max)
|
|
264
|
+
- **Promotion Window Filter** (`promotion_window`): Filter products by promotion date windows
|
|
265
|
+
- **Availability Filter** (`availability`): Filter products by availability status
|
|
266
|
+
- **Rating Filter** (`rating`): Filter products by rating (min/max)
|
|
267
|
+
- **Base Product Filters** (`base_product`): Filter by ID, handle, tags, sales channel
|
|
268
|
+
|
|
269
|
+
### Using Filters
|
|
270
|
+
|
|
271
|
+
All filters are available through the `/store/product-helper/products` endpoint:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# Filter by category
|
|
275
|
+
GET /store/product-helper/products?category_id=cat_123,cat_456
|
|
276
|
+
|
|
277
|
+
# Filter by price range
|
|
278
|
+
GET /store/product-helper/products?price_min=10&price_max=100
|
|
279
|
+
|
|
280
|
+
# Filter by metadata (if filterable)
|
|
281
|
+
GET /store/product-helper/products?metadata[brand]=nike&metadata[color]=red
|
|
282
|
+
|
|
283
|
+
# Multiple filters
|
|
284
|
+
GET /store/product-helper/products?category_id=cat_123&price_min=10&rating_min=4
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Custom Filter Providers
|
|
288
|
+
|
|
289
|
+
You can create custom filter providers to add new filtering capabilities. See the [Provider Development Guide](./PROVIDER_DEVELOPMENT_GUIDE.md) for complete documentation.
|
|
290
|
+
|
|
291
|
+
**Quick Example:**
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// src/providers/margin-provider.ts
|
|
295
|
+
import { BaseFilterProvider } from "medusa-product-helper/providers/filter-providers"
|
|
296
|
+
|
|
297
|
+
export class MarginFilterProvider extends BaseFilterProvider {
|
|
298
|
+
static readonly identifier = "margin"
|
|
299
|
+
static readonly displayName = "Margin Filter"
|
|
300
|
+
|
|
301
|
+
apply(filters: Record<string, unknown>, value: unknown): Record<string, unknown> {
|
|
302
|
+
if (!value || typeof value !== "object") return filters
|
|
303
|
+
|
|
304
|
+
const { min, max } = value as { min?: number; max?: number }
|
|
305
|
+
// Apply margin filter logic...
|
|
306
|
+
return filters
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Then register it in `medusa-config.ts`:
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
{
|
|
315
|
+
resolve: "medusa-product-helper",
|
|
316
|
+
options: {
|
|
317
|
+
filterProviders: ["./src/providers/margin-provider.ts"],
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
233
322
|
## Wishlist Feature
|
|
234
323
|
|
|
235
324
|
The plugin includes a comprehensive wishlist feature that allows customers to save products they're interested in and admins to view wishlist statistics.
|
|
@@ -448,11 +537,12 @@ import {
|
|
|
448
537
|
#### Example Usage
|
|
449
538
|
|
|
450
539
|
```typescript
|
|
540
|
+
// Recommended: Using Bearer token for authentication
|
|
451
541
|
const options: HelperTransportOptions = {
|
|
452
542
|
baseUrl: "https://store.example.com",
|
|
453
543
|
publishableApiKey: "pk_your_publishable_api_key",
|
|
454
544
|
headers: {
|
|
455
|
-
|
|
545
|
+
Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", // Customer JWT token
|
|
456
546
|
},
|
|
457
547
|
}
|
|
458
548
|
|
|
@@ -466,23 +556,44 @@ const { wishlist } = await getWishlist({ includeDetails: true }, options)
|
|
|
466
556
|
await removeFromWishlist({ product_id: "prod_123" }, options)
|
|
467
557
|
```
|
|
468
558
|
|
|
559
|
+
**Alternative: Using session cookie**
|
|
560
|
+
```typescript
|
|
561
|
+
const options: HelperTransportOptions = {
|
|
562
|
+
baseUrl: "https://store.example.com",
|
|
563
|
+
publishableApiKey: "pk_your_publishable_api_key",
|
|
564
|
+
headers: {
|
|
565
|
+
Cookie: "connect.sid=...", // Session cookie (browser-based)
|
|
566
|
+
},
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
469
570
|
#### Configuration Options
|
|
470
571
|
|
|
471
572
|
All helper calls accept the following options:
|
|
472
573
|
|
|
473
574
|
- `publishableApiKey`: Required for public storefront calls when not passing a Medusa JS client. Add it from **Settings → API Keys** in the Medusa dashboard.
|
|
474
|
-
- `client`: Medusa JS/SDK client instance. When provided, network requests are delegated to `client.request` and the client
|
|
575
|
+
- `client`: Medusa JS/SDK client instance. When provided, network requests are delegated to `client.request` and the client's publishable key is reused.
|
|
475
576
|
- `baseUrl`: Base URL for the Store API (e.g., `https://store.example.com`). Required when a client is not provided.
|
|
476
577
|
- `fetchImpl`: Custom `fetch` implementation for SSR or React Native environments. Defaults to `globalThis.fetch`.
|
|
477
|
-
- `headers`: Additional headers appended to every request
|
|
578
|
+
- `headers`: Additional headers appended to every request. **Required for authenticated endpoints** - include `Authorization: Bearer <token>` for customer authentication:
|
|
579
|
+
```ts
|
|
580
|
+
headers: {
|
|
581
|
+
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**Note:** All wishlist endpoints require customer authentication. Pass the Bearer token via the `headers` option.
|
|
478
586
|
|
|
479
587
|
You can also generate pre-configured helpers:
|
|
480
588
|
|
|
481
589
|
```typescript
|
|
590
|
+
// Recommended: Using Bearer token
|
|
482
591
|
const wishlist = createWishlistHelpers({
|
|
483
592
|
baseUrl: "https://store.example.com",
|
|
484
593
|
publishableApiKey: "pk_your_publishable_api_key",
|
|
485
|
-
headers: {
|
|
594
|
+
headers: {
|
|
595
|
+
Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
596
|
+
},
|
|
486
597
|
})
|
|
487
598
|
|
|
488
599
|
await wishlist.addToWishlist({ product_id: "prod_123" })
|
|
@@ -490,6 +601,33 @@ const { wishlist: items } = await wishlist.getWishlist({ includeDetails: true })
|
|
|
490
601
|
await wishlist.removeFromWishlist({ product_id: "prod_123" })
|
|
491
602
|
```
|
|
492
603
|
|
|
604
|
+
**Getting the Bearer Token:**
|
|
605
|
+
```typescript
|
|
606
|
+
// Login to get JWT token
|
|
607
|
+
const loginResponse = await fetch("https://store.example.com/store/auth/customer/emailpass", {
|
|
608
|
+
method: "POST",
|
|
609
|
+
headers: {
|
|
610
|
+
"Content-Type": "application/json",
|
|
611
|
+
"x-publishable-api-key": "pk_your_publishable_api_key",
|
|
612
|
+
},
|
|
613
|
+
body: JSON.stringify({
|
|
614
|
+
email: "customer@example.com",
|
|
615
|
+
password: "password123",
|
|
616
|
+
}),
|
|
617
|
+
})
|
|
618
|
+
|
|
619
|
+
const { token } = await loginResponse.json()
|
|
620
|
+
|
|
621
|
+
// Use token in wishlist helpers
|
|
622
|
+
const wishlist = createWishlistHelpers({
|
|
623
|
+
baseUrl: "https://store.example.com",
|
|
624
|
+
publishableApiKey: "pk_your_publishable_api_key",
|
|
625
|
+
headers: {
|
|
626
|
+
Authorization: `Bearer ${token}`,
|
|
627
|
+
},
|
|
628
|
+
})
|
|
629
|
+
```
|
|
630
|
+
|
|
493
631
|
### Using Workflows Directly
|
|
494
632
|
|
|
495
633
|
You can also use the workflows directly in your custom code:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "medusa-product-helper",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "A starter for Medusa plugins.",
|
|
5
5
|
"author": "Medusa (https://medusajs.com)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"@medusajs/admin-sdk": "2.11.2",
|
|
38
38
|
"@medusajs/cli": "2.11.2",
|
|
39
39
|
"@medusajs/framework": "2.11.2",
|
|
40
|
+
"@medusajs/icons": "2.11.2",
|
|
40
41
|
"@medusajs/medusa": "2.11.2",
|
|
41
42
|
"@medusajs/test-utils": "2.11.2",
|
|
42
43
|
"@medusajs/ui": "4.0.25",
|
|
43
|
-
"@medusajs/icons": "2.11.2",
|
|
44
44
|
"@swc/core": "1.5.7",
|
|
45
45
|
"@types/node": "^20.0.0",
|
|
46
46
|
"@types/react": "^18.3.2",
|
|
@@ -68,4 +68,4 @@
|
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": ">=20"
|
|
70
70
|
}
|
|
71
|
-
}
|
|
71
|
+
}
|