@reactionary/meilisearch 0.6.3

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 ADDED
@@ -0,0 +1,11 @@
1
+ # meilisearch
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build meilisearch` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test meilisearch` to execute the unit tests via [Vitest](https://vitest.dev/).
@@ -0,0 +1,3 @@
1
+ export * from "./product-search.capability.js";
2
+ export * from "./product-recommendations.capability.js";
3
+ export * from "./order-search.capability.js";
@@ -0,0 +1,165 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ OrderSearchQueryByTermSchema,
14
+ OrderSearchResultSchema,
15
+ OrderSearchCapability,
16
+ Reactionary,
17
+ success,
18
+ AddressIdentifierSchema
19
+ } from "@reactionary/core";
20
+ import { MeiliSearch } from "meilisearch";
21
+ class MeilisearchOrderSearchCapability extends OrderSearchCapability {
22
+ config;
23
+ factory;
24
+ constructor(config, cache, context, factory) {
25
+ super(cache, context);
26
+ this.config = config;
27
+ this.factory = factory;
28
+ }
29
+ queryByTermPayload(payload) {
30
+ const filters = [];
31
+ if (payload.search.orderStatus && payload.search.orderStatus.length > 0) {
32
+ const statusFilters = payload.search.orderStatus.map((status) => `orderStatus = "${this.mapOrderStatus(status)}"`).join(" OR ");
33
+ filters.push(`(${statusFilters})`);
34
+ }
35
+ if (payload.search.user) {
36
+ filters.push(`userIdentifier = "${payload.search.user.userId}"`);
37
+ }
38
+ if (payload.search.startDate) {
39
+ filters.push(`orderDateTimestamp >= ${new Date(payload.search.startDate).getTime()}`);
40
+ }
41
+ if (payload.search.endDate) {
42
+ filters.push(`orderDateTimestamp <= ${new Date(payload.search.endDate).getTime()}`);
43
+ }
44
+ if (payload.search.partNumber && payload.search.partNumber.length > 0) {
45
+ const partNumberFilters = payload.search.partNumber.map((partNumber) => `items.sku = "${partNumber}"`).join(" OR ");
46
+ filters.push(`(${partNumberFilters})`);
47
+ }
48
+ const searchOptions = {
49
+ offset: (payload.search.paginationOptions.pageNumber - 1) * payload.search.paginationOptions.pageSize,
50
+ limit: payload.search.paginationOptions.pageSize,
51
+ filter: filters.length > 0 ? filters.join(" AND ") : void 0,
52
+ sort: ["orderDateTimestamp:desc"]
53
+ };
54
+ return searchOptions;
55
+ }
56
+ async queryByTerm(payload) {
57
+ const client = new MeiliSearch({
58
+ host: this.config.apiUrl,
59
+ apiKey: this.config.apiKey
60
+ });
61
+ const index = client.index(this.config.orderIndexName);
62
+ const remote = await index.search(
63
+ payload.search.term || "",
64
+ this.queryByTermPayload(payload)
65
+ );
66
+ const result = this.parsePaginatedResult(remote, payload);
67
+ return success(this.factory.parseOrderSearchResult(this.context, result, payload));
68
+ }
69
+ mapOrderStatus(status) {
70
+ const statusMap = {
71
+ AwaitingPayment: "awaiting_payment",
72
+ ReleasedToFulfillment: "released_to_fulfillment",
73
+ Shipped: "shipped",
74
+ Cancelled: "cancelled"
75
+ };
76
+ return statusMap[status] || status;
77
+ }
78
+ mapFromNativeOrderStatus(nativeStatus) {
79
+ const statusMap = {
80
+ awaiting_payment: "AwaitingPayment",
81
+ released_to_fulfillment: "ReleasedToFulfillment",
82
+ shipped: "Shipped",
83
+ cancelled: "Cancelled"
84
+ };
85
+ return statusMap[nativeStatus] || "AwaitingPayment";
86
+ }
87
+ mapFromNativeInventoryStatus(nativeStatus) {
88
+ const statusMap = {
89
+ not_allocated: "NotAllocated",
90
+ allocated: "Allocated",
91
+ preordered: "Preordered",
92
+ backordered: "Backordered"
93
+ };
94
+ return statusMap[nativeStatus] || "NotAllocated";
95
+ }
96
+ composeAddressFromNativeAddress(nativeAddress) {
97
+ return {
98
+ identifier: AddressIdentifierSchema.parse({
99
+ nickName: "shipping"
100
+ }),
101
+ firstName: "",
102
+ lastName: "",
103
+ streetAddress: nativeAddress.address1,
104
+ streetNumber: nativeAddress.address2,
105
+ city: nativeAddress.city,
106
+ postalCode: nativeAddress.postalCode,
107
+ countryCode: nativeAddress.country,
108
+ region: ""
109
+ };
110
+ }
111
+ parseSingle(body) {
112
+ const identifier = { key: body.orderIdentifier };
113
+ const userId = {
114
+ userId: body.userIdentifier
115
+ };
116
+ const customerName = body.customerName;
117
+ const shippingAddress = this.composeAddressFromNativeAddress(body.shippingAddress);
118
+ const orderDate = body.orderDate;
119
+ const orderStatus = this.mapFromNativeOrderStatus(body.orderStatus);
120
+ const inventoryStatus = this.mapFromNativeInventoryStatus(body.inventoryStatus);
121
+ const totalAmount = {
122
+ currency: body.currency || this.context.languageContext.currencyCode,
123
+ value: body.totalAmount
124
+ };
125
+ const order = {
126
+ identifier,
127
+ userId,
128
+ customerName,
129
+ shippingAddress,
130
+ orderDate,
131
+ orderStatus,
132
+ inventoryStatus,
133
+ totalAmount
134
+ };
135
+ return order;
136
+ }
137
+ parsePaginatedResult(body, query) {
138
+ const identifier = {
139
+ ...query.search
140
+ };
141
+ const orders = body.hits.map((hit) => {
142
+ return this.parseSingle(hit);
143
+ });
144
+ const totalCount = body.estimatedTotalHits || body.hits.length;
145
+ const totalPages = Math.ceil(totalCount / (body.limit || 1));
146
+ const result = {
147
+ identifier,
148
+ pageNumber: Math.floor((body.offset || 0) / (body.limit || 1)) + 1,
149
+ pageSize: body.limit || orders.length,
150
+ totalCount,
151
+ totalPages,
152
+ items: orders
153
+ };
154
+ return result;
155
+ }
156
+ }
157
+ __decorateClass([
158
+ Reactionary({
159
+ inputSchema: OrderSearchQueryByTermSchema,
160
+ outputSchema: OrderSearchResultSchema
161
+ })
162
+ ], MeilisearchOrderSearchCapability.prototype, "queryByTerm", 1);
163
+ export {
164
+ MeilisearchOrderSearchCapability
165
+ };
@@ -0,0 +1,79 @@
1
+ import {
2
+ ProductRecommendationsCapability,
3
+ ImageSchema,
4
+ ProductSearchResultItemVariantSchema
5
+ } from "@reactionary/core";
6
+ import { MeiliSearch } from "meilisearch";
7
+ class MeilisearchProductRecommendationsCapability extends ProductRecommendationsCapability {
8
+ config;
9
+ constructor(config, cache, context) {
10
+ super(cache, context);
11
+ this.config = config;
12
+ }
13
+ getSimilarProductsRecommendationsPayload(query) {
14
+ return {
15
+ id: query.sourceProduct.key,
16
+ limit: query.numberOfRecommendations,
17
+ embedder: this.config.useAIEmbedding
18
+ };
19
+ }
20
+ /**
21
+ * Get similar product recommendations
22
+ * Uses semantic search to find visually or data-wise similar products
23
+ */
24
+ async getSimilarProductsRecommendations(query) {
25
+ const client = new MeiliSearch({
26
+ host: this.config.apiUrl,
27
+ apiKey: this.config.apiKey
28
+ });
29
+ const index = client.index(this.config.indexName);
30
+ if (!this.config.useAIEmbedding) {
31
+ console.warn("AI embedding is not enabled in configuration. Similar product recommendations will be based on keyword matching, which may not provide optimal results.");
32
+ return [];
33
+ }
34
+ try {
35
+ const response = await index.searchSimilarDocuments(this.getSimilarProductsRecommendationsPayload(query));
36
+ return this.parseRecommendations(response, "similar");
37
+ } catch (error) {
38
+ console.error("Error fetching similar product recommendations:", error);
39
+ return [];
40
+ }
41
+ }
42
+ /**
43
+ * Maps Meilisearch search results to ProductRecommendation format
44
+ */
45
+ parseRecommendations(recommendation, algorithm) {
46
+ return recommendation.hits.map((hit) => ({
47
+ recommendationIdentifier: {
48
+ key: hit.objectID,
49
+ algorithm
50
+ },
51
+ recommendationReturnType: "productSearchResultItem",
52
+ product: this.parseSearchResultItem(hit)
53
+ }));
54
+ }
55
+ parseSearchResultItem(body) {
56
+ const product = {
57
+ identifier: { key: body.objectID },
58
+ name: body.name || body.objectID,
59
+ slug: body.slug || body.objectID,
60
+ variants: [...body.variants || []].map((variant) => this.parseVariant(variant, body))
61
+ };
62
+ return product;
63
+ }
64
+ parseVariant(variant, product) {
65
+ const result = ProductSearchResultItemVariantSchema.parse({
66
+ variant: {
67
+ sku: variant.sku
68
+ },
69
+ image: ImageSchema.parse({
70
+ sourceUrl: variant.image,
71
+ altText: product.name || ""
72
+ })
73
+ });
74
+ return result;
75
+ }
76
+ }
77
+ export {
78
+ MeilisearchProductRecommendationsCapability
79
+ };
@@ -0,0 +1,203 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ FacetIdentifierSchema,
14
+ FacetValueIdentifierSchema,
15
+ ImageSchema,
16
+ ProductSearchCapability,
17
+ ProductSearchQueryByTermSchema,
18
+ ProductSearchResultFacetSchema,
19
+ ProductSearchResultFacetValueSchema,
20
+ ProductSearchResultItemVariantSchema,
21
+ ProductSearchResultSchema,
22
+ Reactionary,
23
+ success
24
+ } from "@reactionary/core";
25
+ import { MeiliSearch } from "meilisearch";
26
+ class MeilisearchProductSearchCapability extends ProductSearchCapability {
27
+ config;
28
+ factory;
29
+ constructor(config, cache, context, factory) {
30
+ super(cache, context);
31
+ this.config = config;
32
+ this.factory = factory;
33
+ }
34
+ queryByTermPayload(payload) {
35
+ const facetsThatAreNotCategory = payload.search.facets.filter((x) => x.facet.key !== "categories");
36
+ const categoryFacet = payload.search.facets.find((x) => x.facet.key === "categories") || payload.search.categoryFilter;
37
+ const finalFilters = [...payload.search.filters || []];
38
+ const finalFacetFilters = [
39
+ ...facetsThatAreNotCategory.map(
40
+ (x) => `${x.facet.key}="${x.key}"`
41
+ )
42
+ ];
43
+ if (categoryFacet) {
44
+ finalFilters.push(`categories = "${categoryFacet.key}"`);
45
+ }
46
+ let filterString;
47
+ if (finalFilters.length > 0 || finalFacetFilters.length > 0) {
48
+ const allFilters = [...finalFilters, ...finalFacetFilters];
49
+ filterString = allFilters.join(" AND ");
50
+ }
51
+ const searchOptions = {
52
+ offset: (payload.search.paginationOptions.pageNumber - 1) * payload.search.paginationOptions.pageSize,
53
+ limit: payload.search.paginationOptions.pageSize,
54
+ facets: ["*"],
55
+ filter: filterString
56
+ };
57
+ if (this.config.useAIEmbedding) {
58
+ searchOptions.hybrid = {
59
+ embedder: this.config.useAIEmbedding
60
+ };
61
+ }
62
+ return searchOptions;
63
+ }
64
+ async queryByTerm(payload) {
65
+ const client = new MeiliSearch({
66
+ host: this.config.apiUrl,
67
+ apiKey: this.config.apiKey
68
+ });
69
+ const index = client.index(this.config.indexName);
70
+ const remote = await index.search(payload.search.term, this.queryByTermPayload(payload));
71
+ const result = this.parsePaginatedResult(remote, payload);
72
+ for (const selectedFacet of payload.search.facets) {
73
+ const facet = result.facets.find((f) => f.identifier.key === selectedFacet.facet.key);
74
+ if (facet) {
75
+ const value = facet.values.find((v) => v.identifier.key === selectedFacet.key);
76
+ if (value) {
77
+ value.active = true;
78
+ }
79
+ }
80
+ }
81
+ return success(this.factory.parseSearchResult(this.context, result, payload));
82
+ }
83
+ async createCategoryNavigationFilter(payload) {
84
+ const facetIdentifier = FacetIdentifierSchema.parse({
85
+ key: "categories"
86
+ });
87
+ const facetValueIdentifier = FacetValueIdentifierSchema.parse({
88
+ facet: facetIdentifier,
89
+ key: payload.categoryPath.map((c) => c.name).join(" > ")
90
+ });
91
+ return success(facetValueIdentifier);
92
+ }
93
+ parseSingle(body) {
94
+ const product = {
95
+ identifier: { key: body.objectID },
96
+ name: body.name || body.objectID,
97
+ slug: body.slug || body.objectID,
98
+ variants: [...body.variants || []].map((variant) => this.parseVariant(variant, body))
99
+ };
100
+ return product;
101
+ }
102
+ parseVariant(variant, product) {
103
+ const result = ProductSearchResultItemVariantSchema.parse({
104
+ variant: {
105
+ sku: variant.sku
106
+ },
107
+ image: ImageSchema.parse({
108
+ sourceUrl: variant.image,
109
+ altText: product.name || ""
110
+ })
111
+ });
112
+ return result;
113
+ }
114
+ parsePaginatedResult(body, query) {
115
+ const items = body.hits.map((hit) => this.parseSingle(hit));
116
+ let facets = [];
117
+ if (body.facetDistribution) {
118
+ for (const id in body.facetDistribution) {
119
+ const f = body.facetDistribution[id];
120
+ const facetId = FacetIdentifierSchema.parse({
121
+ key: id
122
+ });
123
+ const facet = this.parseFacet(facetId, f);
124
+ if (facet.values.length > 0) {
125
+ facets.push(facet);
126
+ }
127
+ }
128
+ }
129
+ const selectedCategoryFacet = query.search.facets.find((x) => x.facet.key === "categories") || query.search.categoryFilter;
130
+ let subCategoryFacet;
131
+ if (selectedCategoryFacet) {
132
+ const valueDepth = selectedCategoryFacet.key.split(" > ").length;
133
+ subCategoryFacet = facets.find((f) => f.identifier.key === `hierarchy.lvl${valueDepth}`);
134
+ } else {
135
+ subCategoryFacet = facets.find((f) => f.identifier.key === "hierarchy.lvl0");
136
+ }
137
+ if (subCategoryFacet) {
138
+ subCategoryFacet.identifier = FacetIdentifierSchema.parse({
139
+ key: "categories"
140
+ });
141
+ subCategoryFacet.name = "Categories";
142
+ for (const v of subCategoryFacet.values) {
143
+ const pathParts = v.identifier.key.split(" > ");
144
+ v.identifier.facet = subCategoryFacet.identifier;
145
+ v.name = pathParts[pathParts.length - 1];
146
+ }
147
+ }
148
+ facets = facets.filter((f) => !f.identifier.key.startsWith("hierarchy.lvl"));
149
+ const totalPages = Math.ceil((body.estimatedTotalHits || 0) / query.search.paginationOptions.pageSize);
150
+ const result = {
151
+ identifier: {
152
+ term: query.search.term,
153
+ facets: query.search.facets,
154
+ filters: query.search.filters,
155
+ paginationOptions: query.search.paginationOptions
156
+ },
157
+ pageNumber: query.search.paginationOptions.pageNumber,
158
+ pageSize: query.search.paginationOptions.pageSize,
159
+ totalCount: body.estimatedTotalHits || 0,
160
+ totalPages,
161
+ items,
162
+ facets
163
+ };
164
+ return result;
165
+ }
166
+ parseFacet(facetIdentifier, facetValues) {
167
+ const result = ProductSearchResultFacetSchema.parse({
168
+ identifier: facetIdentifier,
169
+ name: facetIdentifier.key.replace(/_/g, " "),
170
+ values: []
171
+ });
172
+ for (const vid in facetValues) {
173
+ const fv = facetValues[vid];
174
+ const facetValueIdentifier = FacetValueIdentifierSchema.parse({
175
+ facet: facetIdentifier,
176
+ key: vid
177
+ });
178
+ result.values.push(this.parseFacetValue(facetValueIdentifier, vid, fv));
179
+ }
180
+ return result;
181
+ }
182
+ parseFacetValue(facetValueIdentifier, label, count) {
183
+ return ProductSearchResultFacetValueSchema.parse({
184
+ identifier: facetValueIdentifier,
185
+ name: label,
186
+ count,
187
+ active: false
188
+ });
189
+ }
190
+ }
191
+ __decorateClass([
192
+ Reactionary({
193
+ inputSchema: ProductSearchQueryByTermSchema,
194
+ outputSchema: ProductSearchResultSchema,
195
+ cache: true,
196
+ cacheTimeToLiveInSeconds: 300,
197
+ currencyDependentCaching: false,
198
+ localeDependentCaching: true
199
+ })
200
+ ], MeilisearchProductSearchCapability.prototype, "queryByTerm", 1);
201
+ export {
202
+ MeilisearchProductSearchCapability
203
+ };
@@ -0,0 +1,78 @@
1
+ import { OrderSearchResultSchema, ProductSearchResultSchema } from "@reactionary/core";
2
+ import { MeilisearchProductSearchCapability } from "../capabilities/product-search.capability.js";
3
+ import { MeilisearchProductRecommendationsCapability } from "../capabilities/product-recommendations.capability.js";
4
+ import { MeilisearchOrderSearchCapability } from "../capabilities/order-search.capability.js";
5
+ import {
6
+ MeilisearchCapabilitiesSchema
7
+ } from "../schema/capabilities.schema.js";
8
+ import { MeilisearchOrderSearchFactory } from "../factories/order-search/order-search.factory.js";
9
+ import { MeilisearchProductSearchFactory } from "../factories/product-search/product-search.factory.js";
10
+ import {
11
+ resolveCapabilityWithFactory,
12
+ resolveDirectCapability
13
+ } from "./initialize.types.js";
14
+ function withMeilisearchCapabilities(configuration, capabilities) {
15
+ return (cache, context) => {
16
+ const client = {};
17
+ const caps = MeilisearchCapabilitiesSchema.parse(capabilities);
18
+ if (caps.productSearch?.enabled) {
19
+ client.productSearch = resolveCapabilityWithFactory(
20
+ capabilities.productSearch,
21
+ {
22
+ factory: new MeilisearchProductSearchFactory(ProductSearchResultSchema),
23
+ capability: (args) => new MeilisearchProductSearchCapability(
24
+ args.config,
25
+ args.cache,
26
+ args.context,
27
+ args.factory
28
+ )
29
+ },
30
+ (factory) => ({
31
+ cache,
32
+ context,
33
+ config: configuration,
34
+ factory
35
+ })
36
+ );
37
+ }
38
+ if (caps.orderSearch?.enabled) {
39
+ client.orderSearch = resolveCapabilityWithFactory(
40
+ capabilities.orderSearch,
41
+ {
42
+ factory: new MeilisearchOrderSearchFactory(OrderSearchResultSchema),
43
+ capability: (args) => new MeilisearchOrderSearchCapability(
44
+ args.config,
45
+ args.cache,
46
+ args.context,
47
+ args.factory
48
+ )
49
+ },
50
+ (factory) => ({
51
+ cache,
52
+ context,
53
+ config: configuration,
54
+ factory
55
+ })
56
+ );
57
+ }
58
+ if (caps.productRecommendations?.enabled) {
59
+ client.productRecommendations = resolveDirectCapability(
60
+ capabilities.productRecommendations,
61
+ (args) => new MeilisearchProductRecommendationsCapability(
62
+ args.config,
63
+ args.cache,
64
+ args.context
65
+ ),
66
+ {
67
+ cache,
68
+ context,
69
+ config: configuration
70
+ }
71
+ );
72
+ }
73
+ return client;
74
+ };
75
+ }
76
+ export {
77
+ withMeilisearchCapabilities
78
+ };
@@ -0,0 +1,13 @@
1
+ function resolveCapabilityWithFactory(capability, defaults, buildCapabilityArgs) {
2
+ const factory = capability?.factory ?? defaults.factory;
3
+ const capabilityFactory = capability?.capability ?? defaults.capability;
4
+ return capabilityFactory(buildCapabilityArgs(factory));
5
+ }
6
+ function resolveDirectCapability(capability, defaultCapability, args) {
7
+ const capabilityFactory = capability?.capability ?? defaultCapability;
8
+ return capabilityFactory(args);
9
+ }
10
+ export {
11
+ resolveCapabilityWithFactory,
12
+ resolveDirectCapability
13
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./order-search/order-search.factory.js";
2
+ export * from "./product-search/product-search.factory.js";
@@ -0,0 +1,12 @@
1
+ class MeilisearchOrderSearchFactory {
2
+ orderSearchResultSchema;
3
+ constructor(orderSearchResultSchema) {
4
+ this.orderSearchResultSchema = orderSearchResultSchema;
5
+ }
6
+ parseOrderSearchResult(_context, data, _query) {
7
+ return this.orderSearchResultSchema.parse(data);
8
+ }
9
+ }
10
+ export {
11
+ MeilisearchOrderSearchFactory
12
+ };
@@ -0,0 +1,12 @@
1
+ class MeilisearchProductSearchFactory {
2
+ productSearchResultSchema;
3
+ constructor(productSearchResultSchema) {
4
+ this.productSearchResultSchema = productSearchResultSchema;
5
+ }
6
+ parseSearchResult(_context, data, _query) {
7
+ return this.productSearchResultSchema.parse(data);
8
+ }
9
+ }
10
+ export {
11
+ MeilisearchProductSearchFactory
12
+ };
package/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./core/initialize.js";
2
+ export * from "./core/initialize.types.js";
3
+ export * from "./factories/index.js";
4
+ export * from "./capabilities/product-search.capability.js";
5
+ export * from "./capabilities/product-recommendations.capability.js";
6
+ export * from "./capabilities/order-search.capability.js";
7
+ export * from "./schema/configuration.schema.js";
8
+ export * from "./schema/capabilities.schema.js";
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@reactionary/meilisearch",
3
+ "version": "0.6.3",
4
+ "type": "module",
5
+ "main": "./index.js",
6
+ "types": "./src/index.d.ts",
7
+ "dependencies": {
8
+ "vitest": "^4.0.9",
9
+ "@nx/vite": "22.4.5",
10
+ "@reactionary/core": "0.6.3",
11
+ "zod": "4.1.9",
12
+ "meilisearch": "^0.55.0"
13
+ },
14
+ "sideEffects": false
15
+ }
@@ -0,0 +1,23 @@
1
+ import { CapabilitiesSchema } from "@reactionary/core";
2
+ import * as z from "zod";
3
+ const SearchCapabilitySchema = z.looseObject({
4
+ enabled: z.boolean(),
5
+ factory: z.unknown().optional(),
6
+ capability: z.unknown().optional()
7
+ });
8
+ const DirectCapabilitySchema = z.looseObject({
9
+ enabled: z.boolean(),
10
+ capability: z.unknown().optional()
11
+ });
12
+ const MeilisearchCapabilitiesSchema = CapabilitiesSchema.pick({
13
+ productSearch: true,
14
+ productRecommendations: true,
15
+ orderSearch: true
16
+ }).extend({
17
+ productSearch: SearchCapabilitySchema.optional(),
18
+ orderSearch: SearchCapabilitySchema.optional(),
19
+ productRecommendations: DirectCapabilitySchema.optional()
20
+ }).partial();
21
+ export {
22
+ MeilisearchCapabilitiesSchema
23
+ };
@@ -0,0 +1,11 @@
1
+ import * as z from "zod";
2
+ const MeilisearchConfigurationSchema = z.looseObject({
3
+ apiUrl: z.string(),
4
+ apiKey: z.string(),
5
+ indexName: z.string(),
6
+ orderIndexName: z.string(),
7
+ useAIEmbedding: z.string().optional()
8
+ });
9
+ export {
10
+ MeilisearchConfigurationSchema
11
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./configuration.schema.js";
2
+ export * from "./capabilities.schema.js";
3
+ export * from "./search.schema.js";
@@ -0,0 +1,13 @@
1
+ import { ProductSearchIdentifierSchema, ProductSearchResultSchema } from "@reactionary/core";
2
+ import * as z from "zod";
3
+ const MeilisearchProductSearchIdentifierSchema = ProductSearchIdentifierSchema.extend({
4
+ key: z.string(),
5
+ index: z.string()
6
+ });
7
+ const MeilisearchProductSearchResultSchema = ProductSearchResultSchema.extend({
8
+ identifier: MeilisearchProductSearchIdentifierSchema.default(() => MeilisearchProductSearchIdentifierSchema.parse({}))
9
+ });
10
+ export {
11
+ MeilisearchProductSearchIdentifierSchema,
12
+ MeilisearchProductSearchResultSchema
13
+ };
@@ -0,0 +1,3 @@
1
+ export * from './product-search.capability.js';
2
+ export * from './product-recommendations.capability.js';
3
+ export * from './order-search.capability.js';
@@ -0,0 +1,37 @@
1
+ import { type Cache, type OrderSearchQueryByTerm, type OrderSearchResult, type OrderSearchResultItem, OrderSearchCapability, type RequestContext, type Result, type OrderStatus, type Address, type OrderInventoryStatus, type OrderSearchFactory, type OrderSearchFactoryOutput, type OrderSearchFactoryWithOutput } from '@reactionary/core';
2
+ import { type SearchParams, type SearchResponse } from 'meilisearch';
3
+ import type { MeilisearchConfiguration } from '../schema/configuration.schema.js';
4
+ import type { MeilisearchOrderSearchFactory } from '../factories/order-search/order-search.factory.js';
5
+ interface MeilisearchNativeOrderAddress {
6
+ address1: string;
7
+ address2: string;
8
+ city: string;
9
+ postalCode: string;
10
+ country: string;
11
+ }
12
+ interface MeilisearchNativeOrderRecord {
13
+ orderIdentifier: string;
14
+ userIdentifier: string;
15
+ customerName: string;
16
+ shippingAddress: MeilisearchNativeOrderAddress;
17
+ orderDate: string;
18
+ orderDateTimestamp: number;
19
+ orderStatus: string;
20
+ inventoryStatus: string;
21
+ totalAmount: number;
22
+ currency: string;
23
+ }
24
+ export declare class MeilisearchOrderSearchCapability<TFactory extends OrderSearchFactory = MeilisearchOrderSearchFactory> extends OrderSearchCapability<OrderSearchFactoryOutput<TFactory>> {
25
+ protected config: MeilisearchConfiguration;
26
+ protected factory: OrderSearchFactoryWithOutput<TFactory>;
27
+ constructor(config: MeilisearchConfiguration, cache: Cache, context: RequestContext, factory: OrderSearchFactoryWithOutput<TFactory>);
28
+ protected queryByTermPayload(payload: OrderSearchQueryByTerm): SearchParams;
29
+ queryByTerm(payload: OrderSearchQueryByTerm): Promise<Result<OrderSearchFactoryOutput<TFactory>>>;
30
+ protected mapOrderStatus(status: OrderStatus): string;
31
+ protected mapFromNativeOrderStatus(nativeStatus: string): OrderStatus;
32
+ protected mapFromNativeInventoryStatus(nativeStatus: string): OrderInventoryStatus;
33
+ protected composeAddressFromNativeAddress(nativeAddress: MeilisearchNativeOrderAddress): Address;
34
+ protected parseSingle(body: MeilisearchNativeOrderRecord): OrderSearchResultItem;
35
+ protected parsePaginatedResult(body: SearchResponse<MeilisearchNativeOrderRecord>, query: OrderSearchQueryByTerm): OrderSearchResult;
36
+ }
37
+ export {};
@@ -0,0 +1,37 @@
1
+ import { type Cache, ProductRecommendationsCapability, type ProductRecommendation, type ProductRecommendationAlgorithmSimilarProductsQuery, type RequestContext, type ProductSearchResultItemVariant } from '@reactionary/core';
2
+ import { type SearchResponse, type SearchSimilarDocumentsParams } from 'meilisearch';
3
+ import type { MeilisearchConfiguration } from '../schema/configuration.schema.js';
4
+ import type { MeilisearchNativeRecord, MeilisearchNativeVariant } from '../schema/index.js';
5
+ /**
6
+ * MeilisearchProductRecommendationsCapability
7
+ *
8
+ * Provides product recommendations using Meilisearch's hybrid search and filtering capabilities.
9
+ * Supports frequentlyBoughtTogether, similar, related, and trendingInCategory algorithms.
10
+ *
11
+ * Note: This implementation uses semantic search (if AI embedding is enabled) and facet-based filtering.
12
+ * For production use, consider implementing more sophisticated recommendation logic or integrating
13
+ * with a dedicated recommendation engine.
14
+ */
15
+ export declare class MeilisearchProductRecommendationsCapability extends ProductRecommendationsCapability {
16
+ protected config: MeilisearchConfiguration;
17
+ constructor(config: MeilisearchConfiguration, cache: Cache, context: RequestContext);
18
+ protected getSimilarProductsRecommendationsPayload(query: ProductRecommendationAlgorithmSimilarProductsQuery): SearchSimilarDocumentsParams;
19
+ /**
20
+ * Get similar product recommendations
21
+ * Uses semantic search to find visually or data-wise similar products
22
+ */
23
+ protected getSimilarProductsRecommendations(query: ProductRecommendationAlgorithmSimilarProductsQuery): Promise<ProductRecommendation[]>;
24
+ /**
25
+ * Maps Meilisearch search results to ProductRecommendation format
26
+ */
27
+ protected parseRecommendations(recommendation: SearchResponse<MeilisearchNativeRecord>, algorithm: string): ProductRecommendation[];
28
+ protected parseSearchResultItem(body: MeilisearchNativeRecord): {
29
+ identifier: {
30
+ key: string;
31
+ };
32
+ name: string;
33
+ slug: string;
34
+ variants: ProductSearchResultItemVariant[];
35
+ };
36
+ protected parseVariant(variant: MeilisearchNativeVariant, product: MeilisearchNativeRecord): ProductSearchResultItemVariant;
37
+ }
@@ -0,0 +1,53 @@
1
+ import { type Cache, type FacetIdentifier, type FacetValueIdentifier, ProductSearchCapability, type ProductSearchFactory, type ProductSearchFactoryOutput, type ProductSearchFactoryWithOutput, type ProductSearchQueryByTerm, type ProductSearchQueryCreateNavigationFilter, type ProductSearchResultFacet, type ProductSearchResultFacetValue, type ProductSearchResultItemVariant, type RequestContext, type Result } from '@reactionary/core';
2
+ import { type SearchParams, type SearchResponse } from 'meilisearch';
3
+ import type { MeilisearchConfiguration } from '../schema/configuration.schema.js';
4
+ import type { MeilisearchNativeRecord, MeilisearchNativeVariant } from '../schema/search.schema.js';
5
+ import type { MeilisearchProductSearchFactory } from '../factories/product-search/product-search.factory.js';
6
+ export declare class MeilisearchProductSearchCapability<TFactory extends ProductSearchFactory = MeilisearchProductSearchFactory> extends ProductSearchCapability<ProductSearchFactoryOutput<TFactory>> {
7
+ protected config: MeilisearchConfiguration;
8
+ protected factory: ProductSearchFactoryWithOutput<TFactory>;
9
+ constructor(config: MeilisearchConfiguration, cache: Cache, context: RequestContext, factory: ProductSearchFactoryWithOutput<TFactory>);
10
+ protected queryByTermPayload(payload: ProductSearchQueryByTerm): SearchParams;
11
+ queryByTerm(payload: ProductSearchQueryByTerm): Promise<Result<ProductSearchFactoryOutput<TFactory>>>;
12
+ createCategoryNavigationFilter(payload: ProductSearchQueryCreateNavigationFilter): Promise<Result<FacetValueIdentifier>>;
13
+ protected parseSingle(body: MeilisearchNativeRecord): {
14
+ identifier: {
15
+ key: string;
16
+ };
17
+ name: string;
18
+ slug: string;
19
+ variants: ProductSearchResultItemVariant[];
20
+ };
21
+ protected parseVariant(variant: MeilisearchNativeVariant, product: MeilisearchNativeRecord): ProductSearchResultItemVariant;
22
+ protected parsePaginatedResult(body: SearchResponse<MeilisearchNativeRecord>, query: ProductSearchQueryByTerm): {
23
+ identifier: {
24
+ term: string;
25
+ facets: {
26
+ facet: {
27
+ key: string;
28
+ };
29
+ key: string;
30
+ }[];
31
+ filters: string[];
32
+ paginationOptions: {
33
+ pageNumber: number;
34
+ pageSize: number;
35
+ };
36
+ };
37
+ pageNumber: number;
38
+ pageSize: number;
39
+ totalCount: number;
40
+ totalPages: number;
41
+ items: {
42
+ identifier: {
43
+ key: string;
44
+ };
45
+ name: string;
46
+ slug: string;
47
+ variants: ProductSearchResultItemVariant[];
48
+ }[];
49
+ facets: ProductSearchResultFacet[];
50
+ };
51
+ protected parseFacet(facetIdentifier: FacetIdentifier, facetValues: Record<string, number>): ProductSearchResultFacet;
52
+ protected parseFacetValue(facetValueIdentifier: FacetValueIdentifier, label: string, count: number): ProductSearchResultFacetValue;
53
+ }
@@ -0,0 +1,5 @@
1
+ import type { Cache, RequestContext } from '@reactionary/core';
2
+ import { type MeilisearchCapabilities } from '../schema/capabilities.schema.js';
3
+ import type { MeilisearchConfiguration } from '../schema/configuration.schema.js';
4
+ import { type MeilisearchClientFromCapabilities } from './initialize.types.js';
5
+ export declare function withMeilisearchCapabilities<T extends MeilisearchCapabilities>(configuration: MeilisearchConfiguration, capabilities: T): (cache: Cache, context: RequestContext) => MeilisearchClientFromCapabilities<T>;
@@ -0,0 +1,45 @@
1
+ import type { ClientFromCapabilities, OrderSearchFactory, ProductSearchFactory } from '@reactionary/core';
2
+ import type { MeilisearchCapabilities } from '../schema/capabilities.schema.js';
3
+ import type { MeilisearchOrderSearchFactory } from '../factories/order-search/order-search.factory.js';
4
+ import type { MeilisearchProductSearchFactory } from '../factories/product-search/product-search.factory.js';
5
+ import type { MeilisearchOrderSearchCapability } from '../capabilities/order-search.capability.js';
6
+ import type { MeilisearchProductRecommendationsCapability } from '../capabilities/product-recommendations.capability.js';
7
+ import type { MeilisearchProductSearchCapability } from '../capabilities/product-search.capability.js';
8
+ type EnabledCapability<TCapability> = TCapability extends {
9
+ enabled: true;
10
+ } ? true : false;
11
+ type NormalizeConfiguredCapabilities<T extends MeilisearchCapabilities> = Omit<T, 'productSearch' | 'orderSearch' | 'productRecommendations'> & {
12
+ productSearch?: EnabledCapability<T['productSearch']>;
13
+ orderSearch?: EnabledCapability<T['orderSearch']>;
14
+ productRecommendations?: EnabledCapability<T['productRecommendations']>;
15
+ };
16
+ type ExtractCapabilityFactory<TCapability, TContract, TDefaultFactory> = TCapability extends {
17
+ enabled: true;
18
+ factory?: infer TFactory;
19
+ } ? TFactory extends TContract ? TFactory : TDefaultFactory : TDefaultFactory;
20
+ type ExtractCapabilityImplementation<TCapability, TDefaultCapability> = TCapability extends {
21
+ enabled: true;
22
+ capability?: infer TCapabilityFactory;
23
+ } ? TCapabilityFactory extends (...args: unknown[]) => infer TResolvedCapability ? TResolvedCapability : TDefaultCapability : TDefaultCapability;
24
+ type CapabilityOverride<TCapability, TKey extends string, TResolvedCapability> = TCapability extends {
25
+ enabled: true;
26
+ } ? {
27
+ [K in TKey]: TResolvedCapability;
28
+ } : Record<never, never>;
29
+ type ProductSearchFactoryFor<T extends MeilisearchCapabilities> = ExtractCapabilityFactory<T['productSearch'], ProductSearchFactory, MeilisearchProductSearchFactory>;
30
+ type OrderSearchFactoryFor<T extends MeilisearchCapabilities> = ExtractCapabilityFactory<T['orderSearch'], OrderSearchFactory, MeilisearchOrderSearchFactory>;
31
+ type ProductSearchCapabilityFor<T extends MeilisearchCapabilities> = ExtractCapabilityImplementation<T['productSearch'], MeilisearchProductSearchCapability<ProductSearchFactoryFor<T>>>;
32
+ type OrderSearchCapabilityFor<T extends MeilisearchCapabilities> = ExtractCapabilityImplementation<T['orderSearch'], MeilisearchOrderSearchCapability<OrderSearchFactoryFor<T>>>;
33
+ type ProductRecommendationsCapabilityFor<T extends MeilisearchCapabilities> = ExtractCapabilityImplementation<T['productRecommendations'], MeilisearchProductRecommendationsCapability>;
34
+ export type MeilisearchClientFromCapabilities<T extends MeilisearchCapabilities> = Omit<ClientFromCapabilities<NormalizeConfiguredCapabilities<T>>, 'productSearch' | 'orderSearch' | 'productRecommendations'> & CapabilityOverride<T['productSearch'], 'productSearch', ProductSearchCapabilityFor<T>> & CapabilityOverride<T['orderSearch'], 'orderSearch', OrderSearchCapabilityFor<T>> & CapabilityOverride<T['productRecommendations'], 'productRecommendations', ProductRecommendationsCapabilityFor<T>>;
35
+ export declare function resolveCapabilityWithFactory<TFactory, TResolvedCapability, TCapabilityArgs>(capability: {
36
+ factory?: TFactory;
37
+ capability?: (args: TCapabilityArgs) => TResolvedCapability;
38
+ } | undefined, defaults: {
39
+ factory: TFactory;
40
+ capability: (args: TCapabilityArgs) => TResolvedCapability;
41
+ }, buildCapabilityArgs: (factory: TFactory) => TCapabilityArgs): TResolvedCapability;
42
+ export declare function resolveDirectCapability<TResolvedCapability, TCapabilityArgs>(capability: {
43
+ capability?: (args: TCapabilityArgs) => TResolvedCapability;
44
+ } | undefined, defaultCapability: (args: TCapabilityArgs) => TResolvedCapability, args: TCapabilityArgs): TResolvedCapability;
45
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './order-search/order-search.factory.js';
2
+ export * from './product-search/product-search.factory.js';
@@ -0,0 +1,7 @@
1
+ import type { AnyOrderSearchResultSchema, OrderSearchFactory, OrderSearchQueryByTerm, OrderSearchResultSchema, RequestContext } from '@reactionary/core';
2
+ import type * as z from 'zod';
3
+ export declare class MeilisearchOrderSearchFactory<TOrderSearchResultSchema extends AnyOrderSearchResultSchema = typeof OrderSearchResultSchema> implements OrderSearchFactory<TOrderSearchResultSchema> {
4
+ readonly orderSearchResultSchema: TOrderSearchResultSchema;
5
+ constructor(orderSearchResultSchema: TOrderSearchResultSchema);
6
+ parseOrderSearchResult(_context: RequestContext, data: unknown, _query: OrderSearchQueryByTerm): z.output<TOrderSearchResultSchema>;
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { AnyProductSearchResultSchema, ProductSearchFactory, ProductSearchQueryByTerm, ProductSearchResultSchema, RequestContext } from '@reactionary/core';
2
+ import type * as z from 'zod';
3
+ export declare class MeilisearchProductSearchFactory<TProductSearchResultSchema extends AnyProductSearchResultSchema = typeof ProductSearchResultSchema> implements ProductSearchFactory<TProductSearchResultSchema> {
4
+ readonly productSearchResultSchema: TProductSearchResultSchema;
5
+ constructor(productSearchResultSchema: TProductSearchResultSchema);
6
+ parseSearchResult(_context: RequestContext, data: unknown, _query: ProductSearchQueryByTerm): z.output<TProductSearchResultSchema>;
7
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export * from './core/initialize.js';
2
+ export * from './core/initialize.types.js';
3
+ export * from './factories/index.js';
4
+ export * from './capabilities/product-search.capability.js';
5
+ export * from './capabilities/product-recommendations.capability.js';
6
+ export * from './capabilities/order-search.capability.js';
7
+ export * from './schema/configuration.schema.js';
8
+ export * from './schema/capabilities.schema.js';
@@ -0,0 +1,49 @@
1
+ import type { Cache, OrderSearchFactory, OrderSearchFactoryWithOutput, OrderSearchCapability, ProductRecommendationsCapability, ProductSearchFactory, ProductSearchFactoryWithOutput, ProductSearchCapability, RequestContext } from '@reactionary/core';
2
+ import type { MeilisearchConfiguration } from './configuration.schema.js';
3
+ import * as z from 'zod';
4
+ export declare const MeilisearchCapabilitiesSchema: z.ZodObject<{
5
+ productSearch: z.ZodOptional<z.ZodOptional<z.ZodObject<{
6
+ enabled: z.ZodBoolean;
7
+ factory: z.ZodOptional<z.ZodUnknown>;
8
+ capability: z.ZodOptional<z.ZodUnknown>;
9
+ }, z.core.$loose>>>;
10
+ orderSearch: z.ZodOptional<z.ZodOptional<z.ZodObject<{
11
+ enabled: z.ZodBoolean;
12
+ factory: z.ZodOptional<z.ZodUnknown>;
13
+ capability: z.ZodOptional<z.ZodUnknown>;
14
+ }, z.core.$loose>>>;
15
+ productRecommendations: z.ZodOptional<z.ZodOptional<z.ZodObject<{
16
+ enabled: z.ZodBoolean;
17
+ capability: z.ZodOptional<z.ZodUnknown>;
18
+ }, z.core.$loose>>>;
19
+ }, z.core.$loose>;
20
+ export interface MeilisearchCapabilityFactoryArgs {
21
+ cache: Cache;
22
+ context: RequestContext;
23
+ config: MeilisearchConfiguration;
24
+ }
25
+ export interface MeilisearchProductSearchCapabilityFactoryArgs<TFactory extends ProductSearchFactory = ProductSearchFactory> extends MeilisearchCapabilityFactoryArgs {
26
+ factory: ProductSearchFactoryWithOutput<TFactory>;
27
+ }
28
+ export interface MeilisearchOrderSearchCapabilityFactoryArgs<TFactory extends OrderSearchFactory = OrderSearchFactory> extends MeilisearchCapabilityFactoryArgs {
29
+ factory: OrderSearchFactoryWithOutput<TFactory>;
30
+ }
31
+ export interface MeilisearchProductSearchCapabilityConfig<TFactory extends ProductSearchFactory = ProductSearchFactory, TCapability extends ProductSearchCapability = ProductSearchCapability> {
32
+ enabled: boolean;
33
+ factory?: ProductSearchFactoryWithOutput<TFactory>;
34
+ capability?: (args: MeilisearchProductSearchCapabilityFactoryArgs<TFactory>) => TCapability;
35
+ }
36
+ export interface MeilisearchOrderSearchCapabilityConfig<TFactory extends OrderSearchFactory = OrderSearchFactory, TCapability extends OrderSearchCapability = OrderSearchCapability> {
37
+ enabled: boolean;
38
+ factory?: OrderSearchFactoryWithOutput<TFactory>;
39
+ capability?: (args: MeilisearchOrderSearchCapabilityFactoryArgs<TFactory>) => TCapability;
40
+ }
41
+ export interface MeilisearchProductRecommendationsCapabilityConfig<TCapability extends ProductRecommendationsCapability = ProductRecommendationsCapability> {
42
+ enabled: boolean;
43
+ capability?: (args: MeilisearchCapabilityFactoryArgs) => TCapability;
44
+ }
45
+ export type MeilisearchCapabilities<TProductSearchFactory extends ProductSearchFactory = ProductSearchFactory, TProductSearchCapability extends ProductSearchCapability = ProductSearchCapability, TOrderSearchFactory extends OrderSearchFactory = OrderSearchFactory, TOrderSearchCapability extends OrderSearchCapability = OrderSearchCapability, TProductRecommendationsCapability extends ProductRecommendationsCapability = ProductRecommendationsCapability> = {
46
+ productSearch?: MeilisearchProductSearchCapabilityConfig<TProductSearchFactory, TProductSearchCapability>;
47
+ orderSearch?: MeilisearchOrderSearchCapabilityConfig<TOrderSearchFactory, TOrderSearchCapability>;
48
+ productRecommendations?: MeilisearchProductRecommendationsCapabilityConfig<TProductRecommendationsCapability>;
49
+ };
@@ -0,0 +1,9 @@
1
+ import * as z from 'zod';
2
+ export declare const MeilisearchConfigurationSchema: z.ZodObject<{
3
+ apiUrl: z.ZodString;
4
+ apiKey: z.ZodString;
5
+ indexName: z.ZodString;
6
+ orderIndexName: z.ZodString;
7
+ useAIEmbedding: z.ZodOptional<z.ZodString>;
8
+ }, z.core.$loose>;
9
+ export type MeilisearchConfiguration = z.infer<typeof MeilisearchConfigurationSchema>;
@@ -0,0 +1,3 @@
1
+ export * from './configuration.schema.js';
2
+ export * from './capabilities.schema.js';
3
+ export * from './search.schema.js';
@@ -0,0 +1,113 @@
1
+ import * as z from 'zod';
2
+ export declare const MeilisearchProductSearchIdentifierSchema: z.ZodObject<{
3
+ term: z.ZodString;
4
+ facets: z.ZodArray<z.ZodObject<{
5
+ facet: z.ZodObject<{
6
+ key: z.ZodString;
7
+ }, z.core.$loose>;
8
+ key: z.ZodString;
9
+ }, z.core.$strip>>;
10
+ filters: z.ZodArray<z.ZodString>;
11
+ paginationOptions: z.ZodObject<{
12
+ pageNumber: z.ZodDefault<z.ZodNumber>;
13
+ pageSize: z.ZodDefault<z.ZodNumber>;
14
+ }, z.core.$loose>;
15
+ categoryFilter: z.ZodOptional<z.ZodObject<{
16
+ facet: z.ZodObject<{
17
+ key: z.ZodString;
18
+ }, z.core.$loose>;
19
+ key: z.ZodString;
20
+ }, z.core.$strip>>;
21
+ key: z.ZodString;
22
+ index: z.ZodString;
23
+ }, z.core.$loose>;
24
+ export declare const MeilisearchProductSearchResultSchema: z.ZodObject<{
25
+ pageNumber: z.ZodNumber;
26
+ pageSize: z.ZodNumber;
27
+ totalCount: z.ZodNumber;
28
+ totalPages: z.ZodNumber;
29
+ items: z.ZodArray<z.ZodObject<{
30
+ identifier: z.ZodObject<{
31
+ key: z.ZodString;
32
+ }, z.core.$loose>;
33
+ name: z.ZodString;
34
+ slug: z.ZodString;
35
+ variants: z.ZodArray<z.ZodObject<{
36
+ variant: z.ZodObject<{
37
+ sku: z.ZodString;
38
+ }, z.core.$loose>;
39
+ image: z.ZodObject<{
40
+ sourceUrl: z.ZodDefault<z.ZodString>;
41
+ altText: z.ZodDefault<z.ZodString>;
42
+ width: z.ZodOptional<z.ZodNumber>;
43
+ height: z.ZodOptional<z.ZodNumber>;
44
+ }, z.core.$loose>;
45
+ options: z.ZodOptional<z.ZodObject<{
46
+ identifier: z.ZodObject<{
47
+ key: z.ZodString;
48
+ }, z.core.$loose>;
49
+ name: z.ZodString;
50
+ value: z.ZodObject<{
51
+ identifier: z.ZodObject<{
52
+ option: z.ZodObject<{
53
+ key: z.ZodString;
54
+ }, z.core.$loose>;
55
+ key: z.ZodString;
56
+ }, z.core.$loose>;
57
+ label: z.ZodString;
58
+ }, z.core.$loose>;
59
+ }, z.core.$loose>>;
60
+ }, z.core.$loose>>;
61
+ }, z.core.$loose>>;
62
+ facets: z.ZodArray<z.ZodObject<{
63
+ identifier: z.ZodObject<{
64
+ key: z.ZodString;
65
+ }, z.core.$loose>;
66
+ name: z.ZodString;
67
+ values: z.ZodArray<z.ZodObject<{
68
+ identifier: z.ZodObject<{
69
+ facet: z.ZodObject<{
70
+ key: z.ZodString;
71
+ }, z.core.$loose>;
72
+ key: z.ZodString;
73
+ }, z.core.$strip>;
74
+ name: z.ZodString;
75
+ count: z.ZodNumber;
76
+ active: z.ZodBoolean;
77
+ }, z.core.$loose>>;
78
+ }, z.core.$loose>>;
79
+ identifier: z.ZodDefault<z.ZodObject<{
80
+ term: z.ZodString;
81
+ facets: z.ZodArray<z.ZodObject<{
82
+ facet: z.ZodObject<{
83
+ key: z.ZodString;
84
+ }, z.core.$loose>;
85
+ key: z.ZodString;
86
+ }, z.core.$strip>>;
87
+ filters: z.ZodArray<z.ZodString>;
88
+ paginationOptions: z.ZodObject<{
89
+ pageNumber: z.ZodDefault<z.ZodNumber>;
90
+ pageSize: z.ZodDefault<z.ZodNumber>;
91
+ }, z.core.$loose>;
92
+ categoryFilter: z.ZodOptional<z.ZodObject<{
93
+ facet: z.ZodObject<{
94
+ key: z.ZodString;
95
+ }, z.core.$loose>;
96
+ key: z.ZodString;
97
+ }, z.core.$strip>>;
98
+ key: z.ZodString;
99
+ index: z.ZodString;
100
+ }, z.core.$loose>>;
101
+ }, z.core.$strip>;
102
+ export type MeilisearchProductSearchResult = z.infer<typeof MeilisearchProductSearchResultSchema>;
103
+ export type MeilisearchProductSearchIdentifier = z.infer<typeof MeilisearchProductSearchIdentifierSchema>;
104
+ export interface MeilisearchNativeVariant {
105
+ sku: string;
106
+ image: string;
107
+ }
108
+ export interface MeilisearchNativeRecord {
109
+ objectID: string;
110
+ slug?: string;
111
+ name?: string;
112
+ variants: Array<MeilisearchNativeVariant>;
113
+ }