@reactionary/core 0.0.59 → 0.0.60

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.
Files changed (48) hide show
  1. package/initialization.js +1 -1
  2. package/package.json +1 -1
  3. package/providers/index.js +1 -1
  4. package/providers/price.provider.js +1 -1
  5. package/providers/{search.provider.js → product-search.provider.js} +2 -2
  6. package/providers/product.provider.js +8 -0
  7. package/schemas/capabilities.schema.js +1 -1
  8. package/schemas/models/base.model.js +2 -2
  9. package/schemas/models/cart.model.js +2 -2
  10. package/schemas/models/checkout.model.js +2 -2
  11. package/schemas/models/identifiers.model.js +29 -11
  12. package/schemas/models/index.js +1 -1
  13. package/schemas/models/order.model.js +2 -2
  14. package/schemas/models/product-search.model.js +37 -0
  15. package/schemas/models/product.model.js +51 -19
  16. package/schemas/mutations/analytics.mutation.js +3 -3
  17. package/schemas/mutations/cart.mutation.js +2 -2
  18. package/schemas/queries/index.js +1 -1
  19. package/schemas/queries/inventory.query.js +2 -2
  20. package/schemas/queries/price.query.js +2 -2
  21. package/schemas/queries/product-search.query.js +8 -0
  22. package/schemas/queries/product.query.js +8 -3
  23. package/src/client/client.d.ts +2 -2
  24. package/src/providers/index.d.ts +1 -1
  25. package/src/providers/product-search.provider.d.ts +35 -0
  26. package/src/providers/product.provider.d.ts +34 -1
  27. package/src/schemas/capabilities.schema.d.ts +1 -1
  28. package/src/schemas/models/cart.model.d.ts +4 -4
  29. package/src/schemas/models/checkout.model.d.ts +4 -4
  30. package/src/schemas/models/identifiers.model.d.ts +35 -12
  31. package/src/schemas/models/index.d.ts +1 -1
  32. package/src/schemas/models/inventory.model.d.ts +2 -2
  33. package/src/schemas/models/order.model.d.ts +4 -4
  34. package/src/schemas/models/price.model.d.ts +2 -2
  35. package/src/schemas/models/product-search.model.d.ts +184 -0
  36. package/src/schemas/models/product.model.d.ts +154 -14
  37. package/src/schemas/mutations/analytics.mutation.d.ts +24 -12
  38. package/src/schemas/mutations/cart.mutation.d.ts +2 -2
  39. package/src/schemas/queries/index.d.ts +1 -1
  40. package/src/schemas/queries/inventory.query.d.ts +3 -3
  41. package/src/schemas/queries/price.query.d.ts +2 -2
  42. package/src/schemas/queries/product-search.query.d.ts +18 -0
  43. package/src/schemas/queries/product.query.d.ts +12 -2
  44. package/schemas/models/search.model.js +0 -32
  45. package/schemas/queries/search.query.js +0 -8
  46. package/src/providers/search.provider.d.ts +0 -8
  47. package/src/schemas/models/search.model.d.ts +0 -87
  48. package/src/schemas/queries/search.query.d.ts +0 -15
package/initialization.js CHANGED
@@ -7,7 +7,7 @@ function createInitialRequestContext() {
7
7
  cache: { hit: false, key: "" },
8
8
  placeholder: false
9
9
  },
10
- id: { userId: "anonymous" },
10
+ id: { userId: "anonymous-" + crypto.randomUUID().toString() },
11
11
  token: void 0,
12
12
  issued: /* @__PURE__ */ new Date(),
13
13
  expiry: new Date((/* @__PURE__ */ new Date()).getTime() + 3600 * 1e3),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactionary/core",
3
- "version": "0.0.59",
3
+ "version": "0.0.60",
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
@@ -8,6 +8,6 @@ export * from "./inventory.provider.js";
8
8
  export * from "./price.provider.js";
9
9
  export * from "./product.provider.js";
10
10
  export * from "./profile.provider.js";
11
- export * from "./search.provider.js";
11
+ export * from "./product-search.provider.js";
12
12
  export * from "./store.provider.js";
13
13
  export * from "./order.provider.js";
@@ -11,7 +11,7 @@ class PriceProvider extends BaseProvider {
11
11
  createEmptyPriceResult(sku, currency) {
12
12
  const base = this.newModel();
13
13
  base.identifier = {
14
- sku: { key: sku }
14
+ variant: { sku }
15
15
  };
16
16
  base.unitPrice = {
17
17
  value: -1,
@@ -1,9 +1,9 @@
1
1
  import { BaseProvider } from "./base.provider.js";
2
- class SearchProvider extends BaseProvider {
2
+ class ProductSearchProvider extends BaseProvider {
3
3
  getResourceName() {
4
4
  return "product-search";
5
5
  }
6
6
  }
7
7
  export {
8
- SearchProvider
8
+ ProductSearchProvider
9
9
  };
@@ -1,5 +1,13 @@
1
1
  import { BaseProvider } from "./base.provider.js";
2
2
  class ProductProvider extends BaseProvider {
3
+ /**
4
+ * Returns a set of Products for each variant. Is a paged response, to ensure we do not build in overfetching from the start.
5
+ *
6
+ * Usecase: You are rendering a variant-list on a b2b PDP page maybe, and it contains 500 variants. You do not want to fetch all 500 variants in one go.
7
+ * @param payload
8
+ * @param reqCtx
9
+ */
10
+ // public abstract getVariantList(payload: ProductQueryVariants, reqCtx: RequestContext): Promise<typeof this.parsePaginatedResult>;
3
11
  createEmptyProduct(id) {
4
12
  const product = this.newModel();
5
13
  product.identifier = { key: id };
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  const CapabilitiesSchema = z.looseObject({
3
3
  product: z.boolean(),
4
- search: z.boolean(),
4
+ productSearch: z.boolean(),
5
5
  analytics: z.boolean(),
6
6
  identity: z.boolean(),
7
7
  cart: z.boolean(),
@@ -12,13 +12,13 @@ const BaseModelSchema = z.looseObject({
12
12
  });
13
13
  const PaginationOptionsSchema = z.looseObject({
14
14
  pageNumber: z.number().default(1).describe("Current page number, starting from 1"),
15
- pageSize: z.number().default(20).describe("Number of items per page")
15
+ pageSize: z.number().min(1).max(50).default(20).describe("Number of items per page")
16
16
  });
17
17
  function createPaginatedResponseSchema(itemSchema) {
18
18
  return z.object({
19
19
  meta: MetaSchema.default(() => MetaSchema.parse({})),
20
20
  pageNumber: z.number().min(1).describe("Current page number, starting from 1"),
21
- pageSize: z.number().min(1).max(50).describe("Number of items per page"),
21
+ pageSize: z.number().min(1).describe("Number of items per page"),
22
22
  totalCount: z.number().min(0).describe("Total number of items available"),
23
23
  totalPages: z.number().min(0).describe("Total number of pages available"),
24
24
  items: z.array(itemSchema)
@@ -1,11 +1,11 @@
1
1
  import { z } from "zod";
2
- import { CartIdentifierSchema, CartItemIdentifierSchema, IdentityIdentifierSchema, ProductIdentifierSchema, SKUIdentifierSchema } from "../models/identifiers.model.js";
2
+ import { CartIdentifierSchema, CartItemIdentifierSchema, IdentityIdentifierSchema, ProductIdentifierSchema, ProductVariantIdentifierSchema } from "../models/identifiers.model.js";
3
3
  import { CostBreakDownSchema, ItemCostBreakdownSchema } from "./cost.model.js";
4
4
  import { BaseModelSchema } from "./base.model.js";
5
5
  const CartItemSchema = z.looseObject({
6
6
  identifier: CartItemIdentifierSchema.default(() => CartItemIdentifierSchema.parse({})),
7
7
  product: ProductIdentifierSchema.default(() => ProductIdentifierSchema.parse({})),
8
- sku: SKUIdentifierSchema.default(() => SKUIdentifierSchema.parse({})),
8
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({})),
9
9
  quantity: z.number().default(0),
10
10
  price: ItemCostBreakdownSchema.default(() => ItemCostBreakdownSchema.parse({}))
11
11
  });
@@ -1,13 +1,13 @@
1
1
  import { z } from "zod";
2
2
  import { BaseModelSchema } from "./base.model.js";
3
- import { CartIdentifierSchema, CheckoutIdentifierSchema, CheckoutItemIdentifierSchema, OrderIdentifierSchema, SKUIdentifierSchema } from "./identifiers.model.js";
3
+ import { CartIdentifierSchema, CheckoutIdentifierSchema, CheckoutItemIdentifierSchema, OrderIdentifierSchema, ProductVariantIdentifierSchema } from "./identifiers.model.js";
4
4
  import { CostBreakDownSchema, ItemCostBreakdownSchema } from "./cost.model.js";
5
5
  import { AddressSchema } from "./profile.model.js";
6
6
  import { ShippingInstructionSchema } from "./shipping-method.model.js";
7
7
  import { PaymentInstructionSchema } from "./payment.model.js";
8
8
  const CheckoutItemSchema = z.looseObject({
9
9
  identifier: CheckoutItemIdentifierSchema.default(() => CheckoutItemIdentifierSchema.parse({})),
10
- sku: SKUIdentifierSchema.default(() => SKUIdentifierSchema.parse({})),
10
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({})),
11
11
  quantity: z.number().default(0),
12
12
  price: ItemCostBreakdownSchema.default(() => ItemCostBreakdownSchema.parse({}))
13
13
  });
@@ -1,22 +1,36 @@
1
1
  import { z } from "zod";
2
+ import { PaginationOptionsSchema } from "./base.model.js";
2
3
  const FacetIdentifierSchema = z.looseObject({
3
4
  key: z.string().default("").nonoptional()
4
5
  });
5
- const FacetValueIdentifierSchema = z.looseObject({
6
+ const FacetValueIdentifierSchema = z.object({
6
7
  facet: FacetIdentifierSchema.default(() => FacetIdentifierSchema.parse({})),
7
8
  key: z.string().default("")
8
9
  });
9
- const SKUIdentifierSchema = z.looseObject({
10
- key: z.string().default("").nonoptional()
10
+ const ProductVariantIdentifierSchema = z.looseObject({
11
+ sku: z.string().default("").nonoptional()
12
+ });
13
+ const ProductAttributeIdentifierSchema = z.looseObject({
14
+ key: z.string().default("").describe("The unique identifier for the product attribute.")
15
+ });
16
+ const ProductAttributeValueIdentifierSchema = z.looseObject({
17
+ key: z.string().default("").describe("The unique identifier for the product attribute value.")
18
+ });
19
+ const ProductOptionIdentifierSchema = z.looseObject({
20
+ key: z.string().default("").describe("The unique identifier for the product option.")
21
+ });
22
+ const ProductOptionValueIdentifierSchema = z.looseObject({
23
+ option: ProductOptionIdentifierSchema.default(() => ProductOptionIdentifierSchema.parse({})),
24
+ key: z.string().default("").describe('The value of the product option, e.g., "Red" or "Large".')
11
25
  });
12
26
  const ProductIdentifierSchema = z.looseObject({
13
27
  key: z.string().default("")
14
28
  });
15
- const SearchIdentifierSchema = z.looseObject({
29
+ const ProductSearchIdentifierSchema = z.looseObject({
16
30
  term: z.string().default(""),
17
- page: z.number().default(0),
18
- pageSize: z.number().default(20),
19
- facets: z.array(FacetValueIdentifierSchema.required()).default(() => [])
31
+ facets: z.array(FacetValueIdentifierSchema.required()).default(() => []),
32
+ filters: z.array(z.string()).default(() => []),
33
+ paginationOptions: PaginationOptionsSchema.default(() => PaginationOptionsSchema.parse({}))
20
34
  });
21
35
  const CartIdentifierSchema = z.looseObject({
22
36
  key: z.string().default("")
@@ -25,7 +39,7 @@ const CartItemIdentifierSchema = z.looseObject({
25
39
  key: z.string().default("")
26
40
  });
27
41
  const PriceIdentifierSchema = z.looseObject({
28
- sku: SKUIdentifierSchema.default(() => SKUIdentifierSchema.parse({}))
42
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({}))
29
43
  });
30
44
  const CategoryIdentifierSchema = z.looseObject({
31
45
  key: z.string().default("").nonoptional()
@@ -52,7 +66,7 @@ const FulfillmentCenterIdentifierSchema = z.looseObject({
52
66
  key: z.string().default("").nonoptional()
53
67
  });
54
68
  const InventoryIdentifierSchema = z.looseObject({
55
- sku: SKUIdentifierSchema.default(() => SKUIdentifierSchema.parse({})),
69
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({})),
56
70
  fulfillmentCenter: FulfillmentCenterIdentifierSchema.default(
57
71
  () => FulfillmentCenterIdentifierSchema.parse({})
58
72
  )
@@ -95,9 +109,13 @@ export {
95
109
  PaymentMethodIdentifierSchema,
96
110
  PickupPointIdentifierSchema,
97
111
  PriceIdentifierSchema,
112
+ ProductAttributeIdentifierSchema,
113
+ ProductAttributeValueIdentifierSchema,
98
114
  ProductIdentifierSchema,
99
- SKUIdentifierSchema,
100
- SearchIdentifierSchema,
115
+ ProductOptionIdentifierSchema,
116
+ ProductOptionValueIdentifierSchema,
117
+ ProductSearchIdentifierSchema,
118
+ ProductVariantIdentifierSchema,
101
119
  ShippingMethodIdentifierSchema,
102
120
  StoreIdentifierSchema,
103
121
  WebStoreIdentifierSchema
@@ -9,8 +9,8 @@ export * from "./inventory.model.js";
9
9
  export * from "./payment.model.js";
10
10
  export * from "./price.model.js";
11
11
  export * from "./product.model.js";
12
+ export * from "./product-search.model.js";
12
13
  export * from "./profile.model.js";
13
- export * from "./search.model.js";
14
14
  export * from "./shipping-method.model.js";
15
15
  export * from "./store.model.js";
16
16
  export * from "./order.model.js";
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { CartIdentifierSchema, CartItemIdentifierSchema, IdentityIdentifierSchema, SKUIdentifierSchema } from "../models/identifiers.model.js";
2
+ import { CartIdentifierSchema, CartItemIdentifierSchema, IdentityIdentifierSchema, ProductVariantIdentifierSchema } from "../models/identifiers.model.js";
3
3
  import { BaseModelSchema } from "./base.model.js";
4
4
  import { AddressSchema } from "./profile.model.js";
5
5
  import { ShippingMethodSchema } from "./shipping-method.model.js";
@@ -9,7 +9,7 @@ const OrderStatusSchema = z.enum(["AwaitingPayment", "ReleasedToFulfillment", "S
9
9
  const OrderInventoryStatusSchema = z.enum(["NotAllocated", "Allocated", "Backordered", "Preordered"]).default("Allocated").describe("The inventory release status of the order.");
10
10
  const OrderItemSchema = z.looseObject({
11
11
  identifier: CartItemIdentifierSchema.default(() => CartItemIdentifierSchema.parse({})),
12
- sku: SKUIdentifierSchema.default(() => SKUIdentifierSchema.parse({})),
12
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({})),
13
13
  quantity: z.number().default(0),
14
14
  price: ItemCostBreakdownSchema.default(() => ItemCostBreakdownSchema.parse({})),
15
15
  inventoryStatus: OrderInventoryStatusSchema.default("Allocated").describe("The inventory release status of the order item.")
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import { ProductIdentifierSchema, FacetValueIdentifierSchema, FacetIdentifierSchema, ProductSearchIdentifierSchema, ProductVariantIdentifierSchema } from "./identifiers.model.js";
3
+ import { BaseModelSchema, createPaginatedResponseSchema, ImageSchema } from "./base.model.js";
4
+ import { ProductVariantOptionSchema } from "./product.model.js";
5
+ const ProductSearchResultItemVariantSchema = z.looseObject({
6
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({})).describe("The specific variant of the product"),
7
+ image: ImageSchema.default(() => ImageSchema.parse({})).describe("The image representing this variant in the search results"),
8
+ options: ProductVariantOptionSchema.optional().describe("The subset of options that can reasonably be applied on a PLP")
9
+ });
10
+ const ProductSearchResultItemSchema = BaseModelSchema.extend({
11
+ identifier: ProductIdentifierSchema.default(ProductIdentifierSchema.parse({})),
12
+ name: z.string().default(""),
13
+ slug: z.string().default(""),
14
+ variants: z.array(ProductSearchResultItemVariantSchema).default(() => []).describe("A list of variants associated with the product in the search results. If exactly one is present, you can use add-to-cart directly from PLP. If none are present, you must direct to PDP. If mulitple are present, and no options are set, you must direct to PDP. If multiple are present, and they have options, you can render swatches on PLP and allow customer to flip between variants.")
15
+ });
16
+ const ProductSearchResultFacetValueSchema = z.looseObject({
17
+ identifier: FacetValueIdentifierSchema.default(() => FacetValueIdentifierSchema.parse({})),
18
+ name: z.string().default(""),
19
+ count: z.number().default(0),
20
+ active: z.boolean().default(false)
21
+ });
22
+ const ProductSearchResultFacetSchema = z.looseObject({
23
+ identifier: FacetIdentifierSchema.default(() => FacetIdentifierSchema.parse({})),
24
+ name: z.string().default(""),
25
+ values: z.array(ProductSearchResultFacetValueSchema).default(() => [])
26
+ });
27
+ const ProductSearchResultSchema = createPaginatedResponseSchema(ProductSearchResultItemSchema).extend({
28
+ identifier: ProductSearchIdentifierSchema.default(() => ProductSearchIdentifierSchema.parse({})),
29
+ facets: z.array(ProductSearchResultFacetSchema).default(() => [])
30
+ });
31
+ export {
32
+ ProductSearchResultFacetSchema,
33
+ ProductSearchResultFacetValueSchema,
34
+ ProductSearchResultItemSchema,
35
+ ProductSearchResultItemVariantSchema,
36
+ ProductSearchResultSchema
37
+ };
@@ -1,29 +1,61 @@
1
1
  import { z } from "zod";
2
- import { ProductIdentifierSchema, SKUIdentifierSchema } from "./identifiers.model.js";
3
- import { BaseModelSchema } from "./base.model.js";
4
- const SKUSchema = z.looseObject({
5
- identifier: SKUIdentifierSchema.default(() => SKUIdentifierSchema.parse({}))
6
- /* name: z.string().default(''),
7
- slug: z.string().default(''),
8
- image: ImageSchema.default(() => ImageSchema.parse({})), */
2
+ import { CategoryIdentifierSchema, ProductAttributeIdentifierSchema, ProductAttributeValueIdentifierSchema, ProductIdentifierSchema, ProductOptionIdentifierSchema, ProductOptionValueIdentifierSchema, ProductVariantIdentifierSchema } from "./identifiers.model.js";
3
+ import { BaseModelSchema, ImageSchema } from "./base.model.js";
4
+ const ProductOptionValueSchema = z.looseObject({
5
+ identifier: ProductOptionValueIdentifierSchema.default(() => ProductOptionValueIdentifierSchema.parse({})).describe("The unique identifier for the product option value."),
6
+ label: z.string().describe("The human-friendly label for the product option value.")
7
+ });
8
+ const ProductOptionSchema = z.looseObject({
9
+ identifier: ProductOptionIdentifierSchema.default(() => ProductOptionIdentifierSchema.parse({})).describe("The unique identifier for the option."),
10
+ name: z.string().describe("The name of the option, e.g., Size or Color."),
11
+ values: z.array(ProductOptionValueSchema).default(() => []).describe("A list of possible values for the option.")
12
+ });
13
+ const ProductVariantOptionSchema = z.looseObject({
14
+ identifier: ProductOptionIdentifierSchema.default(() => ProductOptionIdentifierSchema.parse({})).describe("The unique identifier for the option."),
15
+ name: z.string().describe("The name of the option, e.g., Size or Color."),
16
+ value: ProductOptionValueSchema.default(() => ProductOptionValueSchema.parse({})).describe("The unique identifier for the option value.")
17
+ });
18
+ const ProductVariantSchema = z.looseObject({
19
+ identifier: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({})).describe("The unique identifier for the variant. Often its SKU"),
20
+ name: z.string().default(""),
21
+ images: z.array(ImageSchema).default(() => []).describe("A list of images associated with the product variant"),
22
+ ean: z.string().default("").describe("The European Article Number identifier for the product variant"),
23
+ gtin: z.string().default("").describe("The Global Trade Item Number identifier for the product variant"),
24
+ upc: z.string().default("").describe("The Universal Product Code identifier for the product variant"),
25
+ barcode: z.string().default("").describe("The barcode identifier for the product variant"),
26
+ options: z.array(ProductVariantOptionSchema).default(() => []).describe("A list of option identifiers that define this variant")
27
+ });
28
+ const ProductAttributeValueSchema = z.looseObject({
29
+ identifier: ProductAttributeValueIdentifierSchema.default(() => ProductAttributeValueIdentifierSchema.parse({})).describe("The unique identifier for the attribute value."),
30
+ value: z.string().default("").describe("The value of the attribute. Typically a language independent string"),
31
+ label: z.string().default("").describe("The human friendly label for the attribute value. Typically a language dependent string")
9
32
  });
10
33
  const ProductAttributeSchema = z.looseObject({
11
- id: z.string(),
12
- name: z.string(),
13
- value: z.string()
34
+ identifier: ProductAttributeIdentifierSchema.default(() => ProductAttributeIdentifierSchema.parse({})).describe("The unique identifier for the attribute, also typically used as the facet key if the attribute is filterable."),
35
+ group: z.string().default(""),
36
+ name: z.string().default(""),
37
+ values: z.array(ProductAttributeValueSchema).default(() => [])
14
38
  });
15
39
  const ProductSchema = BaseModelSchema.extend({
16
40
  identifier: ProductIdentifierSchema.default(() => ProductIdentifierSchema.parse({})),
17
- name: z.string().default(""),
18
- slug: z.string().default(""),
19
- description: z.string().default(""),
20
- image: z.string().url().default("https://placehold.co/400"),
21
- images: z.string().url().array().default(() => []),
22
- attributes: z.array(ProductAttributeSchema).default(() => []),
23
- skus: z.array(SKUSchema).default(() => [])
24
- });
41
+ name: z.string().default("").describe("The name of the product"),
42
+ slug: z.string().default("").describe("The URL-friendly identifier for the product"),
43
+ description: z.string().default("").describe("A brief description of the product"),
44
+ longDescription: z.string().default("").describe("A detailed description of the product"),
45
+ brand: z.string().default("").describe("The brand associated with the product"),
46
+ manufacturer: z.string().default("").describe("The manufacturer of the product"),
47
+ parentCategories: z.array(CategoryIdentifierSchema).default(() => []).describe("A list of parent categories the product belongs to"),
48
+ published: z.boolean().default(false).describe("Indicates whether the product is published and visible to customers"),
49
+ sharedAttributes: z.array(ProductAttributeSchema).default(() => []).describe("A list of technical attributes associated with the product"),
50
+ options: z.array(ProductOptionSchema).default(() => []).describe("A list of options available for the product, such as size or color. Can be empty if product is single-sku"),
51
+ mainVariant: ProductVariantSchema.default(() => ProductVariantSchema.parse({})).describe("The primary SKU for the product")
52
+ }).describe("A product is a wrapper around sellable items. It contains all the shared information for a set of SKUs. All products have at least one SKU, but can potentially have hundreds.");
25
53
  export {
26
54
  ProductAttributeSchema,
55
+ ProductAttributeValueSchema,
56
+ ProductOptionSchema,
57
+ ProductOptionValueSchema,
27
58
  ProductSchema,
28
- SKUSchema
59
+ ProductVariantOptionSchema,
60
+ ProductVariantSchema
29
61
  };
@@ -1,14 +1,14 @@
1
1
  import { z } from "zod";
2
2
  import { BaseMutationSchema } from "./base.mutation.js";
3
- import { ProductIdentifierSchema, SearchIdentifierSchema } from "../models/identifiers.model.js";
3
+ import { ProductIdentifierSchema, ProductSearchIdentifierSchema } from "../models/identifiers.model.js";
4
4
  const AnalyticsMutationSearchEventSchema = BaseMutationSchema.extend({
5
5
  mutation: z.literal("search"),
6
- search: SearchIdentifierSchema.required(),
6
+ search: ProductSearchIdentifierSchema.required(),
7
7
  products: z.array(ProductIdentifierSchema)
8
8
  });
9
9
  const AnalyticsMutationSearchProductClickEventSchema = BaseMutationSchema.extend({
10
10
  mutation: z.literal("product-search-click"),
11
- search: SearchIdentifierSchema.required(),
11
+ search: ProductSearchIdentifierSchema.required(),
12
12
  product: ProductIdentifierSchema.required(),
13
13
  position: z.number().min(0)
14
14
  });
@@ -1,12 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import { BaseMutationSchema } from "./base.mutation.js";
3
- import { CartIdentifierSchema, CartItemIdentifierSchema, PaymentMethodIdentifierSchema, ShippingMethodIdentifierSchema, SKUIdentifierSchema } from "../models/identifiers.model.js";
3
+ import { CartIdentifierSchema, CartItemIdentifierSchema, PaymentMethodIdentifierSchema, ShippingMethodIdentifierSchema, ProductVariantIdentifierSchema } from "../models/identifiers.model.js";
4
4
  import { AddressSchema } from "../models/profile.model.js";
5
5
  import { CurrencySchema } from "../models/currency.model.js";
6
6
  import { MonetaryAmountSchema } from "../models/price.model.js";
7
7
  const CartMutationItemAddSchema = BaseMutationSchema.extend({
8
8
  cart: CartIdentifierSchema.nonoptional(),
9
- sku: SKUIdentifierSchema.nonoptional(),
9
+ variant: ProductVariantIdentifierSchema.nonoptional(),
10
10
  quantity: z.number()
11
11
  });
12
12
  const CartMutationItemRemoveSchema = BaseMutationSchema.extend({
@@ -7,7 +7,7 @@ export * from "./inventory.query.js";
7
7
  export * from "./price.query.js";
8
8
  export * from "./product.query.js";
9
9
  export * from "./profile.query.js";
10
- export * from "./search.query.js";
10
+ export * from "./product-search.query.js";
11
11
  export * from "./store.query.js";
12
12
  export * from "./order.query.js";
13
13
  export * from "./checkout.query.js";
@@ -1,7 +1,7 @@
1
1
  import { BaseQuerySchema } from "./base.query.js";
2
- import { FulfillmentCenterIdentifierSchema, ProductIdentifierSchema } from "../models/identifiers.model.js";
2
+ import { FulfillmentCenterIdentifierSchema, ProductIdentifierSchema, ProductVariantIdentifierSchema } from "../models/identifiers.model.js";
3
3
  const InventoryQueryBySKUSchema = BaseQuerySchema.extend({
4
- sku: ProductIdentifierSchema.default(() => ProductIdentifierSchema.parse({})).nonoptional(),
4
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({})).describe("The unique identifier for the product variant (SKU)."),
5
5
  fulfilmentCenter: FulfillmentCenterIdentifierSchema.default(() => FulfillmentCenterIdentifierSchema.parse({})).nonoptional()
6
6
  });
7
7
  export {
@@ -1,7 +1,7 @@
1
1
  import { BaseQuerySchema } from "./base.query.js";
2
- import { SKUIdentifierSchema } from "../models/identifiers.model.js";
2
+ import { ProductVariantIdentifierSchema } from "../models/identifiers.model.js";
3
3
  const PriceQueryBySkuSchema = BaseQuerySchema.extend({
4
- sku: SKUIdentifierSchema.required()
4
+ variant: ProductVariantIdentifierSchema.required()
5
5
  });
6
6
  export {
7
7
  PriceQueryBySkuSchema
@@ -0,0 +1,8 @@
1
+ import { BaseQuerySchema } from "./base.query.js";
2
+ import { ProductSearchIdentifierSchema } from "../models/identifiers.model.js";
3
+ const ProductSearchQueryByTermSchema = BaseQuerySchema.extend({
4
+ search: ProductSearchIdentifierSchema.required()
5
+ });
6
+ export {
7
+ ProductSearchQueryByTermSchema
8
+ };
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { BaseQuerySchema } from "./base.query.js";
3
- import { SKUIdentifierSchema } from "../models/index.js";
3
+ import { PaginationOptionsSchema, ProductIdentifierSchema, ProductVariantIdentifierSchema } from "../models/index.js";
4
4
  const ProductQueryBySlugSchema = BaseQuerySchema.extend({
5
5
  slug: z.string()
6
6
  });
@@ -8,10 +8,15 @@ const ProductQueryByIdSchema = BaseQuerySchema.extend({
8
8
  id: z.string()
9
9
  });
10
10
  const ProductQueryBySKUSchema = BaseQuerySchema.extend({
11
- sku: SKUIdentifierSchema.default(() => SKUIdentifierSchema.parse({}))
11
+ variant: ProductVariantIdentifierSchema.default(() => ProductVariantIdentifierSchema.parse({}))
12
+ });
13
+ const ProductQueryVariantsSchema = BaseQuerySchema.extend({
14
+ parentId: ProductIdentifierSchema.default(() => ProductIdentifierSchema.parse({})),
15
+ paginationOptions: PaginationOptionsSchema.default(() => PaginationOptionsSchema.parse({}))
12
16
  });
13
17
  export {
14
18
  ProductQueryByIdSchema,
15
19
  ProductQueryBySKUSchema,
16
- ProductQueryBySlugSchema
20
+ ProductQueryBySlugSchema,
21
+ ProductQueryVariantsSchema
17
22
  };
@@ -1,6 +1,6 @@
1
1
  import type { AnalyticsProvider } from "../providers/analytics.provider.js";
2
2
  import type { ProductProvider } from "../providers/product.provider.js";
3
- import type { SearchProvider } from "../providers/search.provider.js";
3
+ import type { ProductSearchProvider } from "../providers/product-search.provider.js";
4
4
  import type { IdentityProvider } from '../providers/identity.provider.js';
5
5
  import type { CartProvider } from "../providers/cart.provider.js";
6
6
  import type { PriceProvider } from "../providers/price.provider.js";
@@ -10,7 +10,7 @@ import type { CategoryProvider } from "../providers/category.provider.js";
10
10
  import type { CheckoutProvider } from "../providers/index.js";
11
11
  export interface Client {
12
12
  product: ProductProvider;
13
- search: SearchProvider;
13
+ productSearch: ProductSearchProvider;
14
14
  identity: IdentityProvider;
15
15
  cache: Cache;
16
16
  cart: CartProvider;
@@ -8,6 +8,6 @@ export * from './inventory.provider.js';
8
8
  export * from './price.provider.js';
9
9
  export * from './product.provider.js';
10
10
  export * from './profile.provider.js';
11
- export * from './search.provider.js';
11
+ export * from './product-search.provider.js';
12
12
  export * from './store.provider.js';
13
13
  export * from './order.provider.js';
@@ -0,0 +1,35 @@
1
+ import type { FacetIdentifier, FacetValueIdentifier } from '../index.js';
2
+ import type { ProductSearchResult, ProductSearchResultFacet, ProductSearchResultFacetValue, ProductSearchResultItem, ProductSearchResultItemVariant } from '../schemas/models/product-search.model.js';
3
+ import type { ProductSearchQueryByTerm } from '../schemas/queries/product-search.query.js';
4
+ import type { RequestContext } from '../schemas/session.schema.js';
5
+ import { BaseProvider } from './base.provider.js';
6
+ export declare abstract class ProductSearchProvider<T extends ProductSearchResultItem = ProductSearchResultItem> extends BaseProvider<T> {
7
+ abstract queryByTerm(payload: ProductSearchQueryByTerm, reqCtx: RequestContext): Promise<ProductSearchResult>;
8
+ protected getResourceName(): string;
9
+ /**
10
+ * Parses a facet value from the search response.
11
+ * @param facetValueIdentifier The identifier for the facet value.
12
+ * @param label The label for the facet value.
13
+ * @param count The count for the facet value.
14
+ * @param reqCtx The request context.
15
+ */
16
+ protected abstract parseFacetValue(facetValueIdentifier: FacetValueIdentifier, label: string, count: number, reqCtx: RequestContext): ProductSearchResultFacetValue;
17
+ /**
18
+ * Parses a facet from the search response.
19
+ * @param facetIdentifier The identifier for the facet.
20
+ * @param facetValue The value for the facet.
21
+ * @param reqCtx The request context.
22
+ *
23
+ * Usecase: Override this to customize the parsing of facets.
24
+ */
25
+ protected abstract parseFacet(facetIdentifier: FacetIdentifier, facetValue: unknown, reqCtx: RequestContext): ProductSearchResultFacet;
26
+ /**
27
+ * Parses a product variant from the search response.
28
+ * @param variant The variant data from the search response.
29
+ * @param product The product data from the search response.
30
+ * @param reqCtx The request context.
31
+ *
32
+ * Usecase: Override this to customize the parsing of product variants.
33
+ */
34
+ protected abstract parseVariant(variant: unknown, product: unknown, reqCtx: RequestContext): ProductSearchResultItemVariant;
35
+ }
@@ -3,9 +3,42 @@ import { BaseProvider } from './base.provider.js';
3
3
  import type { RequestContext } from '../schemas/session.schema.js';
4
4
  import type { ProductQueryById, ProductQueryBySKU, ProductQueryBySlug } from '../schemas/queries/product.query.js';
5
5
  export declare abstract class ProductProvider<T extends Product = Product> extends BaseProvider<T> {
6
+ /**
7
+ * Get a product by its ID.
8
+ * @param payload The query payload containing the product ID.
9
+ * @param reqCtx The request context.
10
+ *
11
+ * Usecase: Not clear. Maybe if you get a reference from marketing? But that would most likely be a partnumber.
12
+ * But what if the marketing system recommends products instead of variants? A product does not have a partnumber, or gtin.
13
+ * Marketing will TYPICALLY recommend products, and in some cases maybe HeroVariants of a product.
14
+ * In that case, you would need to resolve the product to its hero variant first, and then get the SKU from there.
15
+ */
6
16
  abstract getById(payload: ProductQueryById, reqCtx: RequestContext): Promise<T>;
17
+ /**
18
+ * Get a product by its slug.
19
+ * @param payload The query payload containing the product slug.
20
+ * @param reqCtx The request context.
21
+ *
22
+ * Usecase: You are rendering a product detail page, and you need to fetch the product by its slug.
23
+ */
7
24
  abstract getBySlug(payload: ProductQueryBySlug, reqCtx: RequestContext): Promise<T | null>;
8
- abstract getBySKU(payload: ProductQueryBySKU | ProductQueryBySKU[], reqCtx: RequestContext): Promise<T>;
25
+ /**
26
+ * Get a product by its SKU
27
+ * @param payload
28
+ * @param reqCtx
29
+ *
30
+ * Usecase: you want to look up product details for a cart item. Or you have a SKU from an external system (e.g. ERP, PIM, Marketing, OMS/Order History),
31
+ * and you need to fetch the product details for that SKU. You will get the a Product back, with the variant matching the SKU set as heroSku.
32
+ * It might also be used on a quick-order page, or product recommendations from external system.
33
+ */
34
+ abstract getBySKU(payload: ProductQueryBySKU, reqCtx: RequestContext): Promise<T>;
35
+ /**
36
+ * Returns a set of Products for each variant. Is a paged response, to ensure we do not build in overfetching from the start.
37
+ *
38
+ * Usecase: You are rendering a variant-list on a b2b PDP page maybe, and it contains 500 variants. You do not want to fetch all 500 variants in one go.
39
+ * @param payload
40
+ * @param reqCtx
41
+ */
9
42
  protected createEmptyProduct(id: string): T;
10
43
  /**
11
44
  * The resource name, used for caching and logging.
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  export declare const CapabilitiesSchema: z.ZodObject<{
3
3
  product: z.ZodBoolean;
4
- search: z.ZodBoolean;
4
+ productSearch: z.ZodBoolean;
5
5
  analytics: z.ZodBoolean;
6
6
  identity: z.ZodBoolean;
7
7
  cart: z.ZodBoolean;
@@ -6,8 +6,8 @@ export declare const CartItemSchema: z.ZodObject<{
6
6
  product: z.ZodDefault<z.ZodObject<{
7
7
  key: z.ZodDefault<z.ZodString>;
8
8
  }, z.core.$loose>>;
9
- sku: z.ZodDefault<z.ZodObject<{
10
- key: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
9
+ variant: z.ZodDefault<z.ZodObject<{
10
+ sku: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
11
11
  }, z.core.$loose>>;
12
12
  quantity: z.ZodDefault<z.ZodNumber>;
13
13
  price: z.ZodDefault<z.ZodObject<{
@@ -778,8 +778,8 @@ export declare const CartSchema: z.ZodObject<{
778
778
  product: z.ZodDefault<z.ZodObject<{
779
779
  key: z.ZodDefault<z.ZodString>;
780
780
  }, z.core.$loose>>;
781
- sku: z.ZodDefault<z.ZodObject<{
782
- key: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
781
+ variant: z.ZodDefault<z.ZodObject<{
782
+ sku: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
783
783
  }, z.core.$loose>>;
784
784
  quantity: z.ZodDefault<z.ZodNumber>;
785
785
  price: z.ZodDefault<z.ZodObject<{
@@ -3,8 +3,8 @@ export declare const CheckoutItemSchema: z.ZodObject<{
3
3
  identifier: z.ZodDefault<z.ZodObject<{
4
4
  key: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
5
5
  }, z.core.$loose>>;
6
- sku: z.ZodDefault<z.ZodObject<{
7
- key: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
6
+ variant: z.ZodDefault<z.ZodObject<{
7
+ sku: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
8
8
  }, z.core.$loose>>;
9
9
  quantity: z.ZodDefault<z.ZodNumber>;
10
10
  price: z.ZodDefault<z.ZodObject<{
@@ -782,8 +782,8 @@ export declare const CheckoutSchema: z.ZodObject<{
782
782
  identifier: z.ZodDefault<z.ZodObject<{
783
783
  key: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
784
784
  }, z.core.$loose>>;
785
- sku: z.ZodDefault<z.ZodObject<{
786
- key: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
785
+ variant: z.ZodDefault<z.ZodObject<{
786
+ sku: z.ZodNonOptional<z.ZodDefault<z.ZodString>>;
787
787
  }, z.core.$loose>>;
788
788
  quantity: z.ZodDefault<z.ZodNumber>;
789
789
  price: z.ZodDefault<z.ZodObject<{