@unchainedshop/core-products 4.4.0 → 4.6.0

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.
@@ -43,6 +43,7 @@ export const ProductsCollection = async (db) => {
43
43
  ]);
44
44
  }
45
45
  await buildDbIndexes(Products, [
46
+ { index: { deleted: 1 } },
46
47
  { index: { sequence: 1 } },
47
48
  { index: { slugs: 1 } },
48
49
  { index: { status: 1 } },
@@ -5,8 +5,9 @@ export declare const configureProductMediaModule: ({ db }: ModuleInput<Record<st
5
5
  findProductMedia: ({ productMediaId }: {
6
6
  productMediaId: string;
7
7
  }) => Promise<mongodb.WithId<ProductMedia> | null>;
8
- findProductMedias: ({ productId, tags, offset, limit, }: {
9
- productId?: mongodb.Filter<ProductMedia>["assortmentId"];
8
+ findProductMedias: ({ productId, productIds, tags, offset, limit, }: {
9
+ productId?: string;
10
+ productIds?: string[];
10
11
  limit?: number;
11
12
  offset?: number;
12
13
  tags?: string[];
@@ -26,7 +27,10 @@ export declare const configureProductMediaModule: ({ db }: ModuleInput<Record<st
26
27
  }[];
27
28
  }) => Promise<ProductMedia[]>;
28
29
  texts: {
29
- findMediaTexts: ({ productMediaId }: mongodb.Filter<ProductMediaText>, options?: mongodb.FindOptions) => Promise<ProductMediaText[]>;
30
+ findMediaTexts: (query: {
31
+ productMediaId?: string;
32
+ productMediaIds?: string[];
33
+ }, options?: mongodb.FindOptions) => Promise<ProductMediaText[]>;
30
34
  findLocalizedMediaText: ({ productMediaId, locale, }: {
31
35
  productMediaId: string;
32
36
  locale: Intl.Locale;
@@ -36,3 +40,4 @@ export declare const configureProductMediaModule: ({ db }: ModuleInput<Record<st
36
40
  } & Omit<Partial<ProductMediaText>, "productMediaId" | "locale">)[]) => Promise<ProductMediaText[]>;
37
41
  };
38
42
  }>;
43
+ export type ProductMediaModule = Awaited<ReturnType<typeof configureProductMediaModule>>;
@@ -40,8 +40,14 @@ export const configureProductMediaModule = async ({ db }) => {
40
40
  findProductMedia: async ({ productMediaId }) => {
41
41
  return ProductMedias.findOne(generateDbFilterById(productMediaId), {});
42
42
  },
43
- findProductMedias: async ({ productId, tags, offset, limit, }, options) => {
44
- const selector = productId ? { productId } : {};
43
+ findProductMedias: async ({ productId, productIds, tags, offset, limit, }, options) => {
44
+ const selector = {};
45
+ if (productId) {
46
+ selector.productId = productId;
47
+ }
48
+ if (productIds) {
49
+ selector.productId = { $in: productIds };
50
+ }
45
51
  if (tags?.length && tags?.length > 0) {
46
52
  selector.tags = { $all: tags };
47
53
  }
@@ -122,8 +128,15 @@ export const configureProductMediaModule = async ({ db }) => {
122
128
  return productMedias;
123
129
  },
124
130
  texts: {
125
- findMediaTexts: async ({ productMediaId }, options) => {
126
- return ProductMediaTexts.find({ productMediaId }, options).toArray();
131
+ findMediaTexts: async (query, options) => {
132
+ const selector = {};
133
+ if (query.productMediaId) {
134
+ selector.productMediaId = query.productMediaId;
135
+ }
136
+ if (query.productMediaIds) {
137
+ selector.productMediaId = { $in: query.productMediaIds };
138
+ }
139
+ return ProductMediaTexts.find(selector, options).toArray();
127
140
  },
128
141
  findLocalizedMediaText: async ({ productMediaId, locale, }) => {
129
142
  const text = await findLocalizedText(ProductMediaTexts, { productMediaId }, locale);
@@ -63,3 +63,4 @@ export declare const configureProductPricesModule: ({ proxyProducts, db, }: {
63
63
  updateRates: (rates: ProductPriceRate[]) => Promise<boolean>;
64
64
  };
65
65
  };
66
+ export type ProductPricesModule = ReturnType<typeof configureProductPricesModule>;
@@ -31,6 +31,7 @@ export declare const configureProductReviewsModule: ({ db }: ModuleInput<Record<
31
31
  create: (doc: Omit<ProductReview, "_id" | "created" | "votes"> & Pick<Partial<ProductReview>, "created" | "_id">) => Promise<ProductReview>;
32
32
  delete: (productReviewId: string) => Promise<number>;
33
33
  deleteMany: (selector: mongodb.Filter<ProductReview>) => Promise<number>;
34
+ deleteByAuthorId: (authorId: string) => Promise<number>;
34
35
  update: (productReviewId: string, doc: Partial<ProductReview>) => Promise<mongodb.WithId<ProductReview> | null>;
35
36
  votes: {
36
37
  userIdsThatVoted: (productReview: ProductReview, { type }: {
@@ -47,3 +48,4 @@ export declare const configureProductReviewsModule: ({ db }: ModuleInput<Record<
47
48
  removeVote: (productReviewId: string, { userId, type }: ProductVote) => Promise<mongodb.WithId<ProductReview> | null>;
48
49
  };
49
50
  }>;
51
+ export type ProductReviewsModule = Awaited<ReturnType<typeof configureProductReviewsModule>>;
@@ -99,6 +99,14 @@ export const configureProductReviewsModule = async ({ db }) => {
99
99
  })));
100
100
  return deletionResult.deletedCount;
101
101
  },
102
+ deleteByAuthorId: async (authorId) => {
103
+ const productReviews = await ProductReviews.find({ authorId }, { projection: { _id: 1 } }).toArray();
104
+ const deletionResult = await ProductReviews.deleteMany({ authorId });
105
+ await Promise.all(productReviews.map(async (review) => emit('PRODUCT_REMOVE_REVIEW', {
106
+ productReviewId: review._id,
107
+ })));
108
+ return deletionResult.deletedCount;
109
+ },
102
110
  update: async (productReviewId, doc) => {
103
111
  const productReview = await ProductReviews.findOneAndUpdate(generateDbFilterById(productReviewId), {
104
112
  $set: {
@@ -4,7 +4,11 @@ export declare const configureProductTextsModule: ({ Products, ProductTexts, }:
4
4
  Products: mongodb.Collection<Product>;
5
5
  ProductTexts: mongodb.Collection<ProductText>;
6
6
  }) => {
7
- findTexts: (query: mongodb.Filter<ProductText>, options?: mongodb.FindOptions) => Promise<ProductText[]>;
7
+ findTexts: (query: {
8
+ productId?: string;
9
+ productIds?: string[];
10
+ queryString?: string;
11
+ }, options?: mongodb.FindOptions) => Promise<ProductText[]>;
8
12
  findLocalizedText: ({ productId, locale, }: {
9
13
  productId: string;
10
14
  locale: Intl.Locale;
@@ -22,3 +26,4 @@ export declare const configureProductTextsModule: ({ Products, ProductTexts, }:
22
26
  excludedProductIds?: string[];
23
27
  }) => Promise<number>;
24
28
  };
29
+ export type ProductTextsModule = ReturnType<typeof configureProductTextsModule>;
@@ -75,7 +75,17 @@ export const configureProductTextsModule = ({ Products, ProductTexts, }) => {
75
75
  };
76
76
  return {
77
77
  findTexts: async (query, options) => {
78
- const texts = ProductTexts.find(query, options);
78
+ const selector = {};
79
+ if (query.productId) {
80
+ selector.productId = query.productId;
81
+ }
82
+ if (query.productIds) {
83
+ selector.productId = { $in: query.productIds };
84
+ }
85
+ if (query.queryString) {
86
+ selector.$text = { $search: query.queryString };
87
+ }
88
+ const texts = ProductTexts.find(selector, options);
79
89
  return texts.toArray();
80
90
  },
81
91
  findLocalizedText: async ({ productId, locale, }) => {
@@ -9,8 +9,10 @@ export declare const configureProductVariationsModule: ({ db }: ModuleInput<Reco
9
9
  findProductVariation: ({ productVariationId }: {
10
10
  productVariationId: string;
11
11
  }) => Promise<mongodb.WithId<ProductVariation> | null>;
12
- findProductVariations: (query: mongodb.Filter<ProductVariation> & {
13
- productId?: string | mongodb.Filter<string>;
12
+ findProductVariations: (query: {
13
+ productId?: string;
14
+ productIds?: string[];
15
+ productVariationIds?: string[];
14
16
  tags?: string[];
15
17
  limit?: number;
16
18
  offset?: number;
@@ -30,7 +32,11 @@ export declare const configureProductVariationsModule: ({ db }: ModuleInput<Reco
30
32
  }) => Promise<mongodb.WithId<ProductVariation> | null>;
31
33
  removeVariationOption: (productVariationId: string, productVariationOptionValue: string) => Promise<void>;
32
34
  texts: {
33
- findVariationTexts: (query: mongodb.Filter<ProductVariationText>, options?: mongodb.FindOptions) => Promise<ProductVariationText[]>;
35
+ findVariationTexts: (query: {
36
+ productVariationId?: string;
37
+ productVariationIds?: string[];
38
+ productVariationOptionValue?: string | null;
39
+ }, options?: mongodb.FindOptions) => Promise<ProductVariationText[]>;
34
40
  findLocalizedVariationText: ({ productVariationId, productVariationOptionValue, locale, }: {
35
41
  locale: Intl.Locale;
36
42
  productVariationId: string;
@@ -41,3 +47,4 @@ export declare const configureProductVariationsModule: ({ db }: ModuleInput<Reco
41
47
  } & Omit<Partial<ProductVariationText>, "locale" | "productVariationId" | "productVariationOptionValue">)[], productVariationOptionValue?: string) => Promise<ProductVariationText[]>;
42
48
  };
43
49
  }>;
50
+ export type ProductVariationsModule = Awaited<ReturnType<typeof configureProductVariationsModule>>;
@@ -53,11 +53,17 @@ export const configureProductVariationsModule = async ({ db }) => {
53
53
  return ProductVariations.findOne(generateDbFilterById(productVariationId), {});
54
54
  },
55
55
  findProductVariations: async (query, options) => {
56
- const { productId, tags, offset, limit, ...rest } = query;
57
- const selector = { ...rest };
56
+ const { productId, productIds, productVariationIds, tags, offset, limit } = query;
57
+ const selector = {};
58
58
  if (productId) {
59
59
  selector.productId = productId;
60
60
  }
61
+ if (productIds) {
62
+ selector.productId = { $in: productIds };
63
+ }
64
+ if (productVariationIds) {
65
+ selector._id = { $in: productVariationIds };
66
+ }
61
67
  if (tags && tags.length > 0) {
62
68
  selector.tags = { $all: tags };
63
69
  }
@@ -142,7 +148,17 @@ export const configureProductVariationsModule = async ({ db }) => {
142
148
  },
143
149
  texts: {
144
150
  findVariationTexts: async (query, options) => {
145
- return ProductVariationTexts.find(query, options).toArray();
151
+ const selector = {};
152
+ if (query.productVariationId) {
153
+ selector.productVariationId = query.productVariationId;
154
+ }
155
+ if (query.productVariationIds) {
156
+ selector.productVariationId = { $in: query.productVariationIds };
157
+ }
158
+ if (query.productVariationOptionValue !== undefined) {
159
+ selector.productVariationOptionValue = query.productVariationOptionValue || { $eq: null };
160
+ }
161
+ return ProductVariationTexts.find(selector, options).toArray();
146
162
  },
147
163
  findLocalizedVariationText: async ({ productVariationId, productVariationOptionValue, locale, }) => {
148
164
  const selector = { productVariationId };
@@ -5,10 +5,14 @@ import { type ProductsSettingsOptions } from '../products-settings.ts';
5
5
  export interface ProductQuery {
6
6
  queryString?: string;
7
7
  includeDrafts?: boolean;
8
+ includeDeleted?: boolean;
8
9
  productIds?: string[];
9
10
  productSelector?: mongodb.Filter<Product>;
10
11
  slugs?: string[];
11
12
  tags?: string[];
13
+ skus?: string[];
14
+ bundleItemProductIds?: string[];
15
+ proxyAssignmentProductIds?: string[];
12
16
  }
13
17
  export interface ProductDiscount {
14
18
  _id: string;
@@ -18,7 +22,7 @@ export interface ProductDiscount {
18
22
  discountKey: string;
19
23
  context?: any;
20
24
  }
21
- export declare const buildFindSelector: ({ slugs, tags, includeDrafts, productIds, productSelector, queryString, ...query }: ProductQuery) => mongodb.Filter<Product>;
25
+ export declare const buildFindSelector: ({ slugs, tags, includeDrafts, includeDeleted, productIds, productSelector, queryString, skus, bundleItemProductIds, proxyAssignmentProductIds, }: ProductQuery) => mongodb.Filter<Product>;
22
26
  export declare const configureProductsModule: (moduleInput: ModuleInput<ProductsSettingsOptions>) => Promise<{
23
27
  findProduct: (params: {
24
28
  productId: string;
@@ -134,8 +138,9 @@ export declare const configureProductsModule: (moduleInput: ModuleInput<Products
134
138
  findProductMedia: ({ productMediaId }: {
135
139
  productMediaId: string;
136
140
  }) => Promise<mongodb.WithId<import("../products-index.ts").ProductMedia> | null>;
137
- findProductMedias: ({ productId, tags, offset, limit, }: {
138
- productId?: mongodb.Filter<import("../products-index.ts").ProductMedia>["assortmentId"];
141
+ findProductMedias: ({ productId, productIds, tags, offset, limit, }: {
142
+ productId?: string;
143
+ productIds?: string[];
139
144
  limit?: number;
140
145
  offset?: number;
141
146
  tags?: string[];
@@ -155,7 +160,10 @@ export declare const configureProductsModule: (moduleInput: ModuleInput<Products
155
160
  }[];
156
161
  }) => Promise<import("../products-index.ts").ProductMedia[]>;
157
162
  texts: {
158
- findMediaTexts: ({ productMediaId }: mongodb.Filter<import("../products-index.ts").ProductMediaText>, options?: mongodb.FindOptions) => Promise<import("../products-index.ts").ProductMediaText[]>;
163
+ findMediaTexts: (query: {
164
+ productMediaId?: string;
165
+ productMediaIds?: string[];
166
+ }, options?: mongodb.FindOptions) => Promise<import("../products-index.ts").ProductMediaText[]>;
159
167
  findLocalizedMediaText: ({ productMediaId, locale, }: {
160
168
  productMediaId: string;
161
169
  locale: Intl.Locale;
@@ -181,6 +189,7 @@ export declare const configureProductsModule: (moduleInput: ModuleInput<Products
181
189
  create: (doc: Omit<import("../products-index.ts").ProductReview, "_id" | "created" | "votes"> & Pick<Partial<import("../products-index.ts").ProductReview>, "created" | "_id">) => Promise<import("../products-index.ts").ProductReview>;
182
190
  delete: (productReviewId: string) => Promise<number>;
183
191
  deleteMany: (selector: mongodb.Filter<import("../products-index.ts").ProductReview>) => Promise<number>;
192
+ deleteByAuthorId: (authorId: string) => Promise<number>;
184
193
  update: (productReviewId: string, doc: Partial<import("../products-index.ts").ProductReview>) => Promise<mongodb.WithId<import("../products-index.ts").ProductReview> | null>;
185
194
  votes: {
186
195
  userIdsThatVoted: (productReview: import("../products-index.ts").ProductReview, { type }: {
@@ -205,8 +214,10 @@ export declare const configureProductsModule: (moduleInput: ModuleInput<Products
205
214
  findProductVariation: ({ productVariationId }: {
206
215
  productVariationId: string;
207
216
  }) => Promise<mongodb.WithId<import("../products-index.ts").ProductVariation> | null>;
208
- findProductVariations: (query: mongodb.Filter<import("../products-index.ts").ProductVariation> & {
209
- productId?: string | mongodb.Filter<string>;
217
+ findProductVariations: (query: {
218
+ productId?: string;
219
+ productIds?: string[];
220
+ productVariationIds?: string[];
210
221
  tags?: string[];
211
222
  limit?: number;
212
223
  offset?: number;
@@ -226,7 +237,11 @@ export declare const configureProductsModule: (moduleInput: ModuleInput<Products
226
237
  }) => Promise<mongodb.WithId<import("../products-index.ts").ProductVariation> | null>;
227
238
  removeVariationOption: (productVariationId: string, productVariationOptionValue: string) => Promise<void>;
228
239
  texts: {
229
- findVariationTexts: (query: mongodb.Filter<import("../products-index.ts").ProductVariationText>, options?: mongodb.FindOptions) => Promise<import("../products-index.ts").ProductVariationText[]>;
240
+ findVariationTexts: (query: {
241
+ productVariationId?: string;
242
+ productVariationIds?: string[];
243
+ productVariationOptionValue?: string | null;
244
+ }, options?: mongodb.FindOptions) => Promise<import("../products-index.ts").ProductVariationText[]>;
230
245
  findLocalizedVariationText: ({ productVariationId, productVariationOptionValue, locale, }: {
231
246
  locale: Intl.Locale;
232
247
  productVariationId: string;
@@ -253,7 +268,11 @@ export declare const configureProductsModule: (moduleInput: ModuleInput<Products
253
268
  }) => Promise<Product[]>;
254
269
  };
255
270
  texts: {
256
- findTexts: (query: mongodb.Filter<import("../db/ProductsCollection.ts").ProductText>, options?: mongodb.FindOptions) => Promise<import("../db/ProductsCollection.ts").ProductText[]>;
271
+ findTexts: (query: {
272
+ productId?: string;
273
+ productIds?: string[];
274
+ queryString?: string;
275
+ }, options?: mongodb.FindOptions) => Promise<import("../db/ProductsCollection.ts").ProductText[]>;
257
276
  findLocalizedText: ({ productId, locale, }: {
258
277
  productId: string;
259
278
  locale: Intl.Locale;
@@ -23,8 +23,8 @@ const PRODUCT_EVENTS = [
23
23
  const InternalProductStatus = {
24
24
  DRAFT: null,
25
25
  };
26
- export const buildFindSelector = ({ slugs, tags, includeDrafts = false, productIds, productSelector, queryString, ...query }) => {
27
- const selector = productSelector ? { ...productSelector, ...query } : query;
26
+ export const buildFindSelector = ({ slugs, tags, includeDrafts = false, includeDeleted = false, productIds, productSelector, queryString, skus, bundleItemProductIds, proxyAssignmentProductIds, }) => {
27
+ const selector = productSelector ? { ...productSelector } : {};
28
28
  if (productIds && !selector._id) {
29
29
  selector._id = { $in: productIds };
30
30
  }
@@ -39,16 +39,33 @@ export const buildFindSelector = ({ slugs, tags, includeDrafts = false, productI
39
39
  selector.tags = tags;
40
40
  }
41
41
  }
42
+ if (skus) {
43
+ selector['warehousing.sku'] = { $in: skus };
44
+ }
45
+ if (bundleItemProductIds || proxyAssignmentProductIds) {
46
+ const orConditions = [];
47
+ if (bundleItemProductIds) {
48
+ orConditions.push({ 'bundleItems.productId': { $in: bundleItemProductIds } });
49
+ }
50
+ if (proxyAssignmentProductIds) {
51
+ orConditions.push({ 'proxy.assignments.productId': { $in: proxyAssignmentProductIds } });
52
+ }
53
+ selector.$or = orConditions;
54
+ }
42
55
  if (queryString && !selector.$text) {
43
56
  assertDocumentDBCompatMode();
44
57
  selector.$text = { $search: queryString };
45
58
  }
46
59
  if (!selector.status) {
47
- selector.status = !includeDrafts
48
- ? { $eq: ProductStatus.ACTIVE }
49
- : {
50
- $in: [ProductStatus.ACTIVE, InternalProductStatus.DRAFT],
51
- };
60
+ if (includeDeleted) {
61
+ selector.status = { $exists: true };
62
+ }
63
+ else if (includeDrafts) {
64
+ selector.status = { $in: [ProductStatus.ACTIVE, InternalProductStatus.DRAFT] };
65
+ }
66
+ else {
67
+ selector.status = { $eq: ProductStatus.ACTIVE };
68
+ }
52
69
  }
53
70
  return selector;
54
71
  };
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@unchainedshop/core-products",
3
- "version": "4.4.0",
3
+ "description": "Product catalog management module for the Unchained Engine",
4
+ "version": "4.6.0",
4
5
  "main": "lib/products-index.js",
5
6
  "types": "lib/products-index.d.ts",
6
7
  "type": "module",
8
+ "sideEffects": false,
7
9
  "scripts": {
8
10
  "clean": "tsc -b --clean",
9
11
  "build": "tsc -b",
@@ -33,9 +35,9 @@
33
35
  },
34
36
  "homepage": "https://github.com/unchainedshop/unchained#readme",
35
37
  "dependencies": {
36
- "@unchainedshop/events": "^4.4.0",
37
- "@unchainedshop/file-upload": "^4.4.0",
38
- "@unchainedshop/utils": "^4.4.0"
38
+ "@unchainedshop/events": "^4.6.0",
39
+ "@unchainedshop/file-upload": "^4.6.0",
40
+ "@unchainedshop/utils": "^4.6.0"
39
41
  },
40
42
  "devDependencies": {
41
43
  "@types/node": "^25.0.0",