@unchainedshop/core 4.8.19 → 4.8.21

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.
@@ -10,7 +10,11 @@ export declare const ProductCreateSpecificationSchema: z.ZodMiniObject<{
10
10
  readonly TOKENIZED_PRODUCT: "TOKENIZED_PRODUCT";
11
11
  }>;
12
12
  sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
13
- status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
13
+ status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
14
+ readonly DRAFT: "DRAFT";
15
+ readonly ACTIVE: "ACTIVE";
16
+ readonly DELETED: "DELETED";
17
+ }>>>;
14
18
  published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
15
19
  tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
16
20
  commerce: z.ZodMiniOptional<z.ZodMiniObject<{
@@ -67,7 +71,11 @@ export declare const ProductCreatePayloadSchema: z.ZodMiniObject<{
67
71
  readonly TOKENIZED_PRODUCT: "TOKENIZED_PRODUCT";
68
72
  }>;
69
73
  sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
70
- status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
74
+ status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
75
+ readonly DRAFT: "DRAFT";
76
+ readonly ACTIVE: "ACTIVE";
77
+ readonly DELETED: "DELETED";
78
+ }>>>;
71
79
  published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
72
80
  tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
73
81
  commerce: z.ZodMiniOptional<z.ZodMiniObject<{
@@ -170,7 +178,11 @@ declare namespace createProduct {
170
178
  readonly TOKENIZED_PRODUCT: "TOKENIZED_PRODUCT";
171
179
  }>;
172
180
  sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
173
- status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
181
+ status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
182
+ readonly DRAFT: "DRAFT";
183
+ readonly ACTIVE: "ACTIVE";
184
+ readonly DELETED: "DELETED";
185
+ }>>>;
174
186
  published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
175
187
  tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
176
188
  commerce: z.ZodMiniOptional<z.ZodMiniObject<{
@@ -3,11 +3,11 @@ import upsertVariations, { ProductVariationSchema } from "./upsertVariations.js"
3
3
  import upsertMedia from "./upsertMedia.js";
4
4
  import { MediaSchema } from "../assortment/upsertMedia.js";
5
5
  import convertTagsToLowerCase from "../utils/convertTagsToLowerCase.js";
6
- import { ProductType } from '@unchainedshop/core-products';
6
+ import { ProductStatus, ProductType } from '@unchainedshop/core-products';
7
7
  export const ProductCreateSpecificationSchema = z.object({
8
8
  type: z.enum(ProductType),
9
9
  sequence: z.optional(z.number()),
10
- status: z.nullish(z.string()),
10
+ status: z.nullish(z.enum(ProductStatus)),
11
11
  published: z.nullish(z.iso.datetime()),
12
12
  tags: z.optional(z.array(z.string())),
13
13
  commerce: z.optional(z.object({
@@ -59,6 +59,7 @@ export const ProductCreatePayloadSchema = z.object({
59
59
  media: z.optional(z.array(MediaSchema)),
60
60
  variations: z.optional(z.array(ProductVariationSchema)),
61
61
  });
62
+ const normalizeStatus = (status) => (status === ProductStatus.DRAFT ? null : status);
62
63
  const transformSpecification = (specification) => {
63
64
  const { variationResolvers: assignments, content, supply, warehousing, sequence, ...productData } = specification;
64
65
  const tags = productData?.tags ? convertTagsToLowerCase(productData.tags) : [];
@@ -66,6 +67,7 @@ const transformSpecification = (specification) => {
66
67
  return {
67
68
  ...productData,
68
69
  published: productData.published ? new Date(productData.published) : undefined,
70
+ ...(productData.status !== undefined && { status: normalizeStatus(productData.status) }),
69
71
  tags,
70
72
  warehousing,
71
73
  supply,
@@ -4,7 +4,11 @@ import type { Services } from '../../../services/index.ts';
4
4
  export declare const ProductUpdateSpecificationSchema: z.ZodMiniObject<{
5
5
  type: z.ZodMiniOptional<z.ZodMiniString<string>>;
6
6
  sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
7
- status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
7
+ status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
8
+ readonly DRAFT: "DRAFT";
9
+ readonly ACTIVE: "ACTIVE";
10
+ readonly DELETED: "DELETED";
11
+ }>>>;
8
12
  published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
9
13
  tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
10
14
  commerce: z.ZodMiniOptional<z.ZodMiniObject<{
@@ -55,7 +59,11 @@ export declare const ProductUpdatePayloadSchema: z.ZodMiniObject<{
55
59
  specification: z.ZodMiniOptional<z.ZodMiniObject<{
56
60
  type: z.ZodMiniOptional<z.ZodMiniString<string>>;
57
61
  sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
58
- status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
62
+ status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
63
+ readonly DRAFT: "DRAFT";
64
+ readonly ACTIVE: "ACTIVE";
65
+ readonly DELETED: "DELETED";
66
+ }>>>;
59
67
  published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
60
68
  tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
61
69
  commerce: z.ZodMiniOptional<z.ZodMiniObject<{
@@ -152,7 +160,11 @@ declare namespace updateProduct {
152
160
  specification: z.ZodMiniOptional<z.ZodMiniObject<{
153
161
  type: z.ZodMiniOptional<z.ZodMiniString<string>>;
154
162
  sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
155
- status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniString<string>>>;
163
+ status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
164
+ readonly DRAFT: "DRAFT";
165
+ readonly ACTIVE: "ACTIVE";
166
+ readonly DELETED: "DELETED";
167
+ }>>>;
156
168
  published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
157
169
  tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
158
170
  commerce: z.ZodMiniOptional<z.ZodMiniObject<{
@@ -3,10 +3,11 @@ import upsertVariations, { ProductVariationSchema } from "./upsertVariations.js"
3
3
  import upsertMedia, { MediaSchema } from "./upsertMedia.js";
4
4
  import createProduct, { ProductCreatePayloadSchema } from "./create.js";
5
5
  import convertTagsToLowerCase from "../utils/convertTagsToLowerCase.js";
6
+ import { ProductStatus } from '@unchainedshop/core-products';
6
7
  export const ProductUpdateSpecificationSchema = z.object({
7
8
  type: z.optional(z.string()),
8
9
  sequence: z.optional(z.number()),
9
- status: z.nullish(z.string()),
10
+ status: z.nullish(z.enum(ProductStatus)),
10
11
  published: z.nullish(z.iso.datetime()),
11
12
  tags: z.optional(z.array(z.string())),
12
13
  commerce: z.optional(z.object({
@@ -58,6 +59,7 @@ export const ProductUpdatePayloadSchema = z.object({
58
59
  media: z.optional(z.array(MediaSchema)),
59
60
  variations: z.optional(z.array(ProductVariationSchema)),
60
61
  });
62
+ const normalizeStatus = (status) => (status === ProductStatus.DRAFT ? null : status);
61
63
  const transformSpecification = (specification) => {
62
64
  const { variationResolvers: assignments, content, supply, warehousing, ...productData } = specification;
63
65
  const tags = productData?.tags ? convertTagsToLowerCase(productData.tags) : [];
@@ -65,6 +67,7 @@ const transformSpecification = (specification) => {
65
67
  return {
66
68
  ...productData,
67
69
  published: productData.published ? new Date(productData.published) : undefined,
70
+ ...(productData.status !== undefined && { status: normalizeStatus(productData.status) }),
68
71
  tags,
69
72
  warehousing,
70
73
  supply,
@@ -1,6 +1,6 @@
1
1
  import { mongodb } from '@unchainedshop/mongodb';
2
2
  import { BaseDirector } from '@unchainedshop/utils';
3
- import { filtersSettings, FilterType, } from '@unchainedshop/core-filters';
3
+ import { filterCacheGeneration, filtersSettings, FilterType, } from '@unchainedshop/core-filters';
4
4
  export const parseQueryArray = (query) => (query || []).reduce((accumulator, { key, value }) => ({
5
5
  ...accumulator,
6
6
  [key]: accumulator[key] ? accumulator[key].concat(value) : [value],
@@ -70,18 +70,19 @@ export const FilterDirector = {
70
70
  },
71
71
  async buildProductIdMap(filter, unchainedAPI) {
72
72
  const allProductIds = await this.findProductIds(filter, {}, unchainedAPI);
73
- const productIdsMap = filter.type === FilterType.SWITCH
74
- ? {
75
- true: await this.findProductIds(filter, { value: true }, unchainedAPI),
76
- false: await this.findProductIds(filter, { value: { $in: [null, false] } }, unchainedAPI),
77
- }
78
- : await (filter.options || []).reduce(async (accumulatorPromise, option) => {
79
- const accumulator = await accumulatorPromise;
80
- return {
81
- ...accumulator,
82
- [option]: await this.findProductIds(filter, { value: option }, unchainedAPI),
83
- };
84
- }, Promise.resolve({}));
73
+ if (filter.type === FilterType.SWITCH) {
74
+ return [
75
+ allProductIds,
76
+ {
77
+ true: await this.findProductIds(filter, { value: true }, unchainedAPI),
78
+ false: await this.findProductIds(filter, { value: { $in: [null, false] } }, unchainedAPI),
79
+ },
80
+ ];
81
+ }
82
+ const productIdsMap = Object.create(null);
83
+ for (const option of filter.options || []) {
84
+ productIdsMap[option] = await this.findProductIds(filter, { value: option }, unchainedAPI);
85
+ }
85
86
  return [allProductIds, productIdsMap];
86
87
  },
87
88
  async filterProductIds(filter, { values, forceLiveCollection }, unchainedAPI) {
@@ -92,11 +93,13 @@ export const FilterDirector = {
92
93
  return new Set(allProductIds);
93
94
  const result = new Set();
94
95
  for (const key of filteredKeys) {
96
+ if (!Object.hasOwn(keyToProductIdMap, key))
97
+ continue;
95
98
  const additionalValues = keyToProductIdMap[key];
96
- if (additionalValues) {
97
- for (const val of additionalValues)
98
- result.add(val);
99
- }
99
+ if (!additionalValues)
100
+ continue;
101
+ for (const val of additionalValues)
102
+ result.add(val);
100
103
  }
101
104
  return result;
102
105
  },
@@ -165,6 +168,8 @@ export const FilterDirector = {
165
168
  if (!filter)
166
169
  return;
167
170
  const [productIds, productIdMap] = await this.buildProductIdMap(filter, unchainedAPI);
168
- await filtersSettings.setCachedProductIds(filter._id, productIds, productIdMap);
171
+ if (!(await unchainedAPI.modules.filters.filterExists({ filterId: filter._id })))
172
+ return;
173
+ await filtersSettings.setCachedProductIds(filter._id, productIds, productIdMap, filterCacheGeneration(filter));
169
174
  },
170
175
  };
@@ -54,7 +54,7 @@ export const WorkerDirector = {
54
54
  logger.warn(`WorkerDirector: No registered adapter for type: ${type}`);
55
55
  }
56
56
  try {
57
- const output = await adapter.doWork(input, unchainedAPI, workId);
57
+ const output = await adapter.doWork(input ?? {}, unchainedAPI, workId);
58
58
  return output;
59
59
  }
60
60
  catch (error) {
@@ -0,0 +1,3 @@
1
+ import type { Filter } from '@unchainedshop/core-filters';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function createFilterService(this: Modules, filter: Parameters<Modules['filters']['create']>[0]): Promise<Filter>;
@@ -0,0 +1,6 @@
1
+ import { FilterDirector } from "../core-index.js";
2
+ export async function createFilterService(filter) {
3
+ const newFilter = await this.filters.create(filter);
4
+ await FilterDirector.invalidateProductIdCache(newFilter, { modules: this });
5
+ return newFilter;
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { Filter } from '@unchainedshop/core-filters';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function createFilterOptionService(this: Modules, filterId: string, { value }: {
4
+ value: string;
5
+ }): Promise<Filter | null>;
@@ -0,0 +1,8 @@
1
+ import { FilterDirector } from "../core-index.js";
2
+ export async function createFilterOptionService(filterId, { value }) {
3
+ const filter = await this.filters.createFilterOption(filterId, { value });
4
+ if (filter) {
5
+ await FilterDirector.invalidateProductIdCache(filter, { modules: this });
6
+ }
7
+ return filter;
8
+ }
@@ -41,6 +41,10 @@ import { verifyQuotationService } from './verifyQuotation.ts';
41
41
  import { loadFiltersService } from './loadFilters.ts';
42
42
  import { loadFilterOptionsService } from './loadFilterOptions.ts';
43
43
  import { removeFilterService } from './removeFilter.ts';
44
+ import { createFilterService } from './createFilter.ts';
45
+ import { updateFilterService } from './updateFilter.ts';
46
+ import { createFilterOptionService } from './createFilterOption.ts';
47
+ import { removeFilterOptionService } from './removeFilterOption.ts';
44
48
  import { removeCartDiscountService } from './removeCartDiscount.ts';
45
49
  import { addMultipleCartProductsService } from './addMultipleCartProducts.ts';
46
50
  import { ercMetadataService } from './ercMetadata.ts';
@@ -131,6 +135,10 @@ export default function initServices(modules: Modules, customServices?: CustomSe
131
135
  loadFilters: Bound<typeof loadFiltersService>;
132
136
  loadFilterOptions: Bound<typeof loadFilterOptionsService>;
133
137
  removeFilter: Bound<typeof removeFilterService>;
138
+ createFilter: Bound<typeof createFilterService>;
139
+ updateFilter: Bound<typeof updateFilterService>;
140
+ createFilterOption: Bound<typeof createFilterOptionService>;
141
+ removeFilterOption: Bound<typeof removeFilterOptionService>;
134
142
  };
135
143
  warehousing: {
136
144
  ercMetadata: Bound<typeof ercMetadataService>;
@@ -40,6 +40,10 @@ import { verifyQuotationService } from "./verifyQuotation.js";
40
40
  import { loadFiltersService } from "./loadFilters.js";
41
41
  import { loadFilterOptionsService } from "./loadFilterOptions.js";
42
42
  import { removeFilterService } from "./removeFilter.js";
43
+ import { createFilterService } from "./createFilter.js";
44
+ import { updateFilterService } from "./updateFilter.js";
45
+ import { createFilterOptionService } from "./createFilterOption.js";
46
+ import { removeFilterOptionService } from "./removeFilterOption.js";
43
47
  import { removeCartDiscountService } from "./removeCartDiscount.js";
44
48
  import { addMultipleCartProductsService } from "./addMultipleCartProducts.js";
45
49
  import { ercMetadataService } from "./ercMetadata.js";
@@ -142,6 +146,10 @@ export default function initServices(modules, customServices = {}) {
142
146
  loadFilters: loadFiltersService,
143
147
  loadFilterOptions: loadFilterOptionsService,
144
148
  removeFilter: removeFilterService,
149
+ createFilter: createFilterService,
150
+ updateFilter: updateFilterService,
151
+ createFilterOption: createFilterOptionService,
152
+ removeFilterOption: removeFilterOptionService,
145
153
  },
146
154
  warehousing: {
147
155
  ercMetadata: ercMetadataService,
@@ -1,10 +1,10 @@
1
- import { FilterType } from '@unchainedshop/core-filters';
1
+ import { filterOptionValues } from '@unchainedshop/core-filters';
2
2
  import { FilterDirector, parseQueryArray } from "../directors/FilterDirector.js";
3
3
  export async function loadFilterOptionsService(filter, params) {
4
4
  const { forceLiveCollection, productIdSet, searchQuery } = params;
5
5
  const filterQueryParsed = parseQueryArray(searchQuery?.filterQuery);
6
6
  const values = filterQueryParsed[filter.key];
7
- const allOptions = (filter.type === FilterType.SWITCH && ['true', 'false']) || filter.options || [];
7
+ const allOptions = filterOptionValues(filter);
8
8
  const mappedOptions = await Promise.all(allOptions.map(async (value) => {
9
9
  const filterOptionProductIds = await FilterDirector.filterProductIds(filter, {
10
10
  values: [value],
@@ -0,0 +1,6 @@
1
+ import type { Filter } from '@unchainedshop/core-filters';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function removeFilterOptionService(this: Modules, { filterId, filterOptionValue }: {
4
+ filterId: string;
5
+ filterOptionValue: string;
6
+ }): Promise<Filter | null>;
@@ -0,0 +1,8 @@
1
+ import { FilterDirector } from "../core-index.js";
2
+ export async function removeFilterOptionService({ filterId, filterOptionValue }) {
3
+ const filter = await this.filters.removeFilterOption({ filterId, filterOptionValue });
4
+ if (filter) {
5
+ await FilterDirector.invalidateProductIdCache(filter, { modules: this });
6
+ }
7
+ return filter;
8
+ }
@@ -0,0 +1,3 @@
1
+ import type { Filter } from '@unchainedshop/core-filters';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function updateFilterService(this: Modules, filterId: string, doc: Partial<Filter>): Promise<Filter | null>;
@@ -0,0 +1,8 @@
1
+ import { FilterDirector } from "../core-index.js";
2
+ export async function updateFilterService(filterId, doc) {
3
+ const updatedFilter = await this.filters.update(filterId, doc);
4
+ if (updatedFilter) {
5
+ await FilterDirector.invalidateProductIdCache(updatedFilter, { modules: this });
6
+ }
7
+ return updatedFilter;
8
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unchainedshop/core",
3
3
  "description": "Core orchestration package for the Unchained Engine with business services and directors",
4
- "version": "4.8.19",
4
+ "version": "4.8.21",
5
5
  "main": "lib/core-index.js",
6
6
  "types": "lib/core-index.d.ts",
7
7
  "type": "module",