@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.
- package/lib/db/ProductsCollection.js +1 -0
- package/lib/module/configureProductMediaModule.d.ts +8 -3
- package/lib/module/configureProductMediaModule.js +17 -4
- package/lib/module/configureProductPrices.d.ts +1 -0
- package/lib/module/configureProductReviewsModule.d.ts +2 -0
- package/lib/module/configureProductReviewsModule.js +8 -0
- package/lib/module/configureProductTextsModule.d.ts +6 -1
- package/lib/module/configureProductTextsModule.js +11 -1
- package/lib/module/configureProductVariationsModule.d.ts +10 -3
- package/lib/module/configureProductVariationsModule.js +19 -3
- package/lib/module/configureProductsModule.d.ts +27 -8
- package/lib/module/configureProductsModule.js +24 -7
- package/package.json +6 -4
|
@@ -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?:
|
|
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: (
|
|
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 =
|
|
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 (
|
|
126
|
-
|
|
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);
|
|
@@ -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:
|
|
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
|
|
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:
|
|
13
|
-
productId?: 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:
|
|
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
|
|
57
|
-
const selector = {
|
|
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
|
-
|
|
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,
|
|
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?:
|
|
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: (
|
|
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:
|
|
209
|
-
productId?: 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:
|
|
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:
|
|
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,
|
|
27
|
-
const selector = productSelector ? { ...productSelector
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
"
|
|
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.
|
|
37
|
-
"@unchainedshop/file-upload": "^4.
|
|
38
|
-
"@unchainedshop/utils": "^4.
|
|
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",
|