@unchainedshop/api 5.0.0-alpha.2 → 5.0.0-alpha.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 +6 -4
- package/lib/adminUiPlugins.d.ts +73 -0
- package/lib/adminUiPlugins.js +164 -0
- package/lib/adminUiTheme.d.ts +25 -0
- package/lib/adminUiTheme.js +34 -0
- package/lib/chat/generateImageHandler.d.ts +273 -7
- package/lib/chat/utils.d.ts +8 -0
- package/lib/chat/utils.js +54 -2
- package/lib/createGraphQLServer.js +6 -0
- package/lib/express/chatHandler.js +52 -61
- package/lib/express/createMCPMiddleware.js +19 -78
- package/lib/express/index.d.ts +8 -2
- package/lib/express/index.js +55 -7
- package/lib/fastify/chatHandler.js +52 -61
- package/lib/fastify/index.d.ts +7 -1
- package/lib/fastify/index.js +58 -11
- package/lib/fastify/mcpHandler.js +24 -75
- package/lib/loaders/cartLoader.d.ts +13 -0
- package/lib/loaders/cartLoader.js +8 -0
- package/lib/loaders/index.d.ts +9 -0
- package/lib/loaders/index.js +2 -0
- package/lib/locale-context.d.ts +2 -4
- package/lib/locale-context.js +2 -1
- package/lib/mcp/handleMcpHttpRequest.d.ts +2 -0
- package/lib/mcp/handleMcpHttpRequest.js +83 -0
- package/lib/mcp/index.d.ts +1 -1
- package/lib/mcp/nodeHttpBridge.d.ts +3 -0
- package/lib/mcp/nodeHttpBridge.js +64 -0
- package/lib/mcp/resources/localization.d.ts +5 -1
- package/lib/mcp/resources/localization.js +93 -69
- package/lib/mcp/tools/assortment/index.d.ts +1 -1
- package/lib/mcp/tools/assortment/index.js +4 -1
- package/lib/mcp/tools/assortment/schemas.d.ts +2 -2
- package/lib/mcp/tools/filter/handlers/createFilter.js +2 -4
- package/lib/mcp/tools/filter/handlers/createFilterOption.js +2 -4
- package/lib/mcp/tools/filter/handlers/removeFilterOption.js +2 -4
- package/lib/mcp/tools/filter/handlers/updateFilter.js +2 -2
- package/lib/mcp/tools/filter/index.d.ts +1 -1
- package/lib/mcp/tools/filter/index.js +4 -1
- package/lib/mcp/tools/filter/schemas.d.ts +2 -2
- package/lib/mcp/tools/localization/index.d.ts +1 -1
- package/lib/mcp/tools/localization/index.js +4 -1
- package/lib/mcp/tools/localization/schemas.d.ts +2 -2
- package/lib/mcp/tools/order/index.d.ts +1 -1
- package/lib/mcp/tools/order/index.js +4 -1
- package/lib/mcp/tools/order/schemas.d.ts +2 -2
- package/lib/mcp/tools/product/index.d.ts +1 -1
- package/lib/mcp/tools/product/index.js +4 -1
- package/lib/mcp/tools/product/schemas.d.ts +7 -7
- package/lib/mcp/tools/product/schemas.js +3 -2
- package/lib/mcp/tools/provider/index.d.ts +1 -1
- package/lib/mcp/tools/provider/index.js +4 -1
- package/lib/mcp/tools/provider/schemas.d.ts +2 -2
- package/lib/mcp/tools/quotation/index.d.ts +1 -1
- package/lib/mcp/tools/quotation/index.js +4 -1
- package/lib/mcp/tools/quotation/schemas.d.ts +2 -2
- package/lib/mcp/tools/system/index.d.ts +1 -1
- package/lib/mcp/tools/system/index.js +4 -1
- package/lib/mcp/tools/users/index.d.ts +1 -1
- package/lib/mcp/tools/users/index.js +4 -1
- package/lib/mcp/tools/users/schemas.d.ts +2 -2
- package/lib/mcp/utils/sharedSchemas.d.ts +1 -0
- package/lib/mcp/utils/sharedSchemas.js +1 -0
- package/lib/resolvers/index.js +2 -1
- package/lib/resolvers/mutations/bookmarks/createBookmark.d.ts +1 -1
- package/lib/resolvers/mutations/bookmarks/createBookmark.js +4 -3
- package/lib/resolvers/mutations/filters/createFilter.js +3 -4
- package/lib/resolvers/mutations/filters/createFilterOption.d.ts +1 -1
- package/lib/resolvers/mutations/filters/createFilterOption.js +3 -4
- package/lib/resolvers/mutations/filters/removeFilterOption.d.ts +1 -1
- package/lib/resolvers/mutations/filters/removeFilterOption.js +2 -8
- package/lib/resolvers/mutations/filters/updateFilter.d.ts +1 -1
- package/lib/resolvers/mutations/filters/updateFilter.js +2 -5
- package/lib/resolvers/mutations/index.js +3 -3
- package/lib/resolvers/mutations/products/updateProductCommerce.js +10 -1
- package/lib/resolvers/scalars/LowerCaseString.d.ts +1 -1
- package/lib/resolvers/scalars/index.d.ts +1 -1
- package/lib/resolvers/type/filter/loaded-filter-types.d.ts +1 -1
- package/lib/resolvers/type/filter/loaded-filter-types.js +1 -1
- package/lib/resolvers/type/index.d.ts +9 -5
- package/lib/resolvers/type/product/product-bundle-types.d.ts +1 -1
- package/lib/resolvers/type/product/product-plan-types.d.ts +1 -1
- package/lib/resolvers/type/product/product-simple-types.d.ts +1 -1
- package/lib/resolvers/type/product/product-tokenized-types.d.ts +1 -1
- package/lib/resolvers/type/quotation-types.d.ts +4 -0
- package/lib/resolvers/type/quotation-types.js +1 -0
- package/lib/resolvers/type/user-types.js +2 -2
- package/lib/roles/index.js +2 -0
- package/lib/roles/loggedIn.js +11 -0
- package/lib/schema/inputTypes.js +3 -3
- package/lib/schema/scalars.js +1 -0
- package/lib/schema/types/filter.js +2 -2
- package/lib/schema/types/product/product.js +1 -1
- package/lib/schema/types/quotation.js +5 -0
- package/lib/utils/optionalPeerError.d.ts +1 -0
- package/lib/utils/optionalPeerError.js +6 -0
- package/package.json +37 -13
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { systemManagement } from "./systemManagement.js";
|
|
2
2
|
import { SystemManagementSchema } from "./schemas.js";
|
|
3
3
|
export const registerSystemTools = (server, context) => {
|
|
4
|
-
server.
|
|
4
|
+
server.registerTool('system_management', {
|
|
5
|
+
description: 'Comprehensive system management with unified system information, worker queue, and event operations. System actions: SHOP_INFO (returns shop configuration including default locale settings). Worker actions: WORKER_ADD (add work items), WORKER_REMOVE (delete work items), WORKER_GET (retrieve work item), WORKER_LIST (search work items), WORKER_COUNT (count work items), WORKER_ALLOCATE (allocate work to workers), WORKER_FINISH_WORK (mark work complete), WORKER_PROCESS_NEXT (get next work item), WORKER_STATISTICS (work queue statistics), WORKER_ACTIVE_WORK_TYPES (get active work types). Event actions: EVENT_GET (retrieve event), EVENT_LIST (search events), EVENT_COUNT (count events), EVENT_STATISTICS (event analytics).',
|
|
6
|
+
inputSchema: SystemManagementSchema,
|
|
7
|
+
}, async (params) => systemManagement(context, params));
|
|
5
8
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { Context } from '../../../context.ts';
|
|
3
3
|
export declare const registerUsersTools: (server: McpServer, context: Context) => void;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { usersManagement, UsersManagementSchema } from "./usersManagement.js";
|
|
2
2
|
export const registerUsersTools = (server, context) => {
|
|
3
|
-
server.
|
|
3
|
+
server.registerTool('users_management', {
|
|
4
|
+
description: 'Comprehensive user management system for Unchained e-commerce platform. Core operations: LIST (paginated user listing with filters for guests, email verification, last login dates), COUNT (user count with same filters), GET (retrieve user by ID), CREATE (new user with optional profile), UPDATE (profile/metadata updates), REMOVE (soft delete with optional review cleanup), ENROLL (create user + send enrollment email). User administration: SET_ROLES (assign admin/editor roles), SET_TAGS (categorization tags), SET_PASSWORD (admin password reset), SET_USERNAME (username changes). Email management: ADD_EMAIL/REMOVE_EMAIL (multi-email support), SEND_ENROLLMENT_EMAIL (trigger enrollment), SEND_VERIFICATION_EMAIL (email verification). Data access: GET_ORDERS (user order history with cart inclusion), GET_ENROLLMENTS (subscription enrollments), GET_QUOTATIONS (price quotes), GET_BOOKMARKS (saved products), GET_CART (active user cart), GET_PAYMENT_CREDENTIALS (stored payment methods), GET_AVATAR (profile image), GET_REVIEWS/GET_REVIEWS_COUNT (product reviews), REMOVE_PRODUCT_REVIEWS (bulk review cleanup), GET_CURRENT_USER (current session logged in user). Supports pagination, sorting, filtering, date ranges, and proper validation for all operations.',
|
|
5
|
+
inputSchema: UsersManagementSchema,
|
|
6
|
+
}, async (params) => usersManagement(context, params));
|
|
4
7
|
};
|
|
@@ -222,11 +222,11 @@ export declare const UsersManagementSchema: {
|
|
|
222
222
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
223
223
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
224
224
|
action: z.ZodEnum<{
|
|
225
|
+
LIST: "LIST";
|
|
225
226
|
GET: "GET";
|
|
226
227
|
CREATE: "CREATE";
|
|
227
228
|
UPDATE: "UPDATE";
|
|
228
229
|
REMOVE: "REMOVE";
|
|
229
|
-
LIST: "LIST";
|
|
230
230
|
COUNT: "COUNT";
|
|
231
231
|
GET_REVIEWS: "GET_REVIEWS";
|
|
232
232
|
ENROLL: "ENROLL";
|
|
@@ -290,11 +290,11 @@ export declare const UsersManagementZodSchema: z.ZodObject<{
|
|
|
290
290
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
291
291
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
292
292
|
action: z.ZodEnum<{
|
|
293
|
+
LIST: "LIST";
|
|
293
294
|
GET: "GET";
|
|
294
295
|
CREATE: "CREATE";
|
|
295
296
|
UPDATE: "UPDATE";
|
|
296
297
|
REMOVE: "REMOVE";
|
|
297
|
-
LIST: "LIST";
|
|
298
298
|
COUNT: "COUNT";
|
|
299
299
|
GET_REVIEWS: "GET_REVIEWS";
|
|
300
300
|
ENROLL: "ENROLL";
|
package/lib/resolvers/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GraphQLJSON, GraphQLTimestamp, GraphQLDateTimeISO, GraphQLDate, GraphQLLocale, } from 'graphql-scalars';
|
|
1
|
+
import { GraphQLJSON, GraphQLTimestamp, GraphQLDateTimeISO, GraphQLDate, GraphQLLocale, GraphQLPhoneNumber, } from 'graphql-scalars';
|
|
2
2
|
import Query from "./queries/index.js";
|
|
3
3
|
import Mutation from "./mutations/index.js";
|
|
4
4
|
import Types from "./type/index.js";
|
|
@@ -13,4 +13,5 @@ export default {
|
|
|
13
13
|
Date: GraphQLDate,
|
|
14
14
|
Timestamp: GraphQLTimestamp,
|
|
15
15
|
Locale: GraphQLLocale,
|
|
16
|
+
PhoneNumber: GraphQLPhoneNumber,
|
|
16
17
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Context } from '../../../context.ts';
|
|
2
2
|
export default function createBookmark(root: never, { productId, userId, meta }: {
|
|
3
3
|
productId: string;
|
|
4
|
-
userId
|
|
4
|
+
userId?: string;
|
|
5
5
|
meta?: any;
|
|
6
6
|
}, { modules, userId: currentUserId }: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-bookmarks").Bookmark> | null>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { log } from '@unchainedshop/logger';
|
|
2
2
|
import { BookmarkAlreadyExistsError, InvalidIdError, ProductNotFoundError } from "../../../errors.js";
|
|
3
3
|
export default async function createBookmark(root, { productId, userId, meta }, { modules, userId: currentUserId }) {
|
|
4
|
-
|
|
4
|
+
const targetUserId = userId || currentUserId;
|
|
5
|
+
log(`mutation createBookmark for ${targetUserId}`, {
|
|
5
6
|
productId,
|
|
6
7
|
userId: currentUserId,
|
|
7
8
|
});
|
|
@@ -11,13 +12,13 @@ export default async function createBookmark(root, { productId, userId, meta },
|
|
|
11
12
|
throw new ProductNotFoundError({ productId });
|
|
12
13
|
const [bookmark] = await modules.bookmarks.findBookmarks({
|
|
13
14
|
productId,
|
|
14
|
-
userId,
|
|
15
|
+
userId: targetUserId,
|
|
15
16
|
meta,
|
|
16
17
|
});
|
|
17
18
|
if (bookmark)
|
|
18
19
|
throw new BookmarkAlreadyExistsError({ bookmarkId: bookmark._id });
|
|
19
20
|
const bookmarkId = await modules.bookmarks.create({
|
|
20
|
-
userId,
|
|
21
|
+
userId: targetUserId,
|
|
21
22
|
productId,
|
|
22
23
|
meta,
|
|
23
24
|
});
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { log } from '@unchainedshop/logger';
|
|
2
|
-
import {
|
|
2
|
+
import {} from '@unchainedshop/core';
|
|
3
3
|
import { DuplicateFilterKeyError } from "../../../errors.js";
|
|
4
4
|
export default async function createFilter(root, { filter, texts }, context) {
|
|
5
|
-
const { modules, userId } = context;
|
|
5
|
+
const { modules, services, userId } = context;
|
|
6
6
|
log('mutation createFilter', { userId });
|
|
7
7
|
try {
|
|
8
|
-
const newFilter = await
|
|
9
|
-
await FilterDirector.invalidateProductIdCache(newFilter, context);
|
|
8
|
+
const newFilter = await services.filters.createFilter(filter);
|
|
10
9
|
if (texts) {
|
|
11
10
|
await modules.filters.texts.updateTexts({ filterId: newFilter._id }, texts);
|
|
12
11
|
}
|
|
@@ -4,4 +4,4 @@ export default function createFilterOption(root: never, params: {
|
|
|
4
4
|
filterId: string;
|
|
5
5
|
option: string;
|
|
6
6
|
texts?: FilterInputText[];
|
|
7
|
-
}, context: Context): Promise<import("
|
|
7
|
+
}, context: Context): Promise<import("@unchainedshop/core-filters").Filter | null>;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { log } from '@unchainedshop/logger';
|
|
2
|
-
import {
|
|
2
|
+
import {} from '@unchainedshop/core';
|
|
3
3
|
import { FilterNotFoundError, InvalidIdError } from "../../../errors.js";
|
|
4
4
|
export default async function createFilterOption(root, params, context) {
|
|
5
|
-
const { modules, userId } = context;
|
|
5
|
+
const { modules, services, userId } = context;
|
|
6
6
|
const { filterId, option, texts } = params;
|
|
7
7
|
log(`mutation createFilterOption ${filterId}`, { userId });
|
|
8
8
|
if (!filterId)
|
|
9
9
|
throw new InvalidIdError({ filterId });
|
|
10
10
|
if (!(await modules.filters.filterExists({ filterId })))
|
|
11
11
|
throw new FilterNotFoundError({ filterId });
|
|
12
|
-
const filter = await
|
|
13
|
-
await FilterDirector.invalidateProductIdCache(filter, context);
|
|
12
|
+
const filter = await services.filters.createFilterOption(filterId, { value: option });
|
|
14
13
|
if (texts) {
|
|
15
14
|
await modules.filters.texts.updateTexts({ filterId, filterOptionValue: option }, texts);
|
|
16
15
|
}
|
|
@@ -2,4 +2,4 @@ import type { Context } from '../../../context.ts';
|
|
|
2
2
|
export default function removeFilterOption(root: never, { filterId, filterOptionValue }: {
|
|
3
3
|
filterId: string;
|
|
4
4
|
filterOptionValue: string;
|
|
5
|
-
}, context: Context): Promise<import("
|
|
5
|
+
}, context: Context): Promise<import("@unchainedshop/core-filters").Filter | null>;
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { log } from '@unchainedshop/logger';
|
|
2
2
|
import { FilterNotFoundError, InvalidIdError } from "../../../errors.js";
|
|
3
|
-
import { FilterDirector } from '@unchainedshop/core';
|
|
4
3
|
export default async function removeFilterOption(root, { filterId, filterOptionValue }, context) {
|
|
5
|
-
const { modules, userId } = context;
|
|
4
|
+
const { modules, services, userId } = context;
|
|
6
5
|
log(`mutation removeFilterOption ${filterId}`, { userId });
|
|
7
6
|
if (!filterId || !filterOptionValue)
|
|
8
7
|
throw new InvalidIdError({ filterId, filterOptionValue });
|
|
9
8
|
if (!(await modules.filters.filterExists({ filterId })))
|
|
10
9
|
throw new FilterNotFoundError({ filterId });
|
|
11
|
-
|
|
12
|
-
filterId,
|
|
13
|
-
filterOptionValue,
|
|
14
|
-
});
|
|
15
|
-
await FilterDirector.invalidateProductIdCache(filter, context);
|
|
16
|
-
return filter;
|
|
10
|
+
return services.filters.removeFilterOption({ filterId, filterOptionValue });
|
|
17
11
|
}
|
|
@@ -3,4 +3,4 @@ import type { Context } from '../../../context.ts';
|
|
|
3
3
|
export default function updateFilter(root: never, { filter, filterId }: {
|
|
4
4
|
filter: Filter;
|
|
5
5
|
filterId: string;
|
|
6
|
-
}, context: Context): Promise<
|
|
6
|
+
}, context: Context): Promise<Filter | null>;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { log } from '@unchainedshop/logger';
|
|
2
2
|
import { FilterNotFoundError, InvalidIdError } from "../../../errors.js";
|
|
3
|
-
import { FilterDirector } from '@unchainedshop/core';
|
|
4
3
|
export default async function updateFilter(root, { filter, filterId }, context) {
|
|
5
|
-
const { modules, userId } = context;
|
|
4
|
+
const { modules, services, userId } = context;
|
|
6
5
|
log(`mutation updateFilter ${filterId}`, { userId });
|
|
7
6
|
if (!filterId)
|
|
8
7
|
throw new InvalidIdError({ filterId });
|
|
9
8
|
if (!(await modules.filters.filterExists({ filterId })))
|
|
10
9
|
throw new FilterNotFoundError({ filterId });
|
|
11
|
-
|
|
12
|
-
await FilterDirector.invalidateProductIdCache(updatedFilter, context);
|
|
13
|
-
return updatedFilter;
|
|
10
|
+
return services.filters.updateFilter(filterId, filter);
|
|
14
11
|
}
|
|
@@ -227,7 +227,7 @@ export default {
|
|
|
227
227
|
addCartProduct: acl(actions.updateCart)(addCartProduct),
|
|
228
228
|
addMultipleCartProducts: acl(actions.updateCart)(addMultipleCartProducts),
|
|
229
229
|
addCartDiscount: acl(actions.updateCart)(addCartDiscount),
|
|
230
|
-
addCartQuotation: acl(actions.
|
|
230
|
+
addCartQuotation: acl(actions.addCartQuotation)(addCartQuotation),
|
|
231
231
|
updateCart: acl(actions.updateCart)(updateCart),
|
|
232
232
|
emptyCart: acl(actions.updateCart)(emptyCart),
|
|
233
233
|
checkoutCart: acl(actions.checkoutCart)(checkoutCart),
|
|
@@ -291,7 +291,7 @@ export default {
|
|
|
291
291
|
verifyQuotation: acl(actions.manageQuotations)(verifyQuotation),
|
|
292
292
|
makeQuotationProposal: acl(actions.manageQuotations)(makeQuotationProposal),
|
|
293
293
|
bookmark: acl(actions.bookmarkProduct)(bookmark),
|
|
294
|
-
createBookmark: acl(actions.
|
|
294
|
+
createBookmark: acl(actions.createBookmark)(createBookmark),
|
|
295
295
|
removeBookmark: acl(actions.manageBookmarks)(removeBookmark),
|
|
296
296
|
addWork: acl(actions.manageWorker)(addWork),
|
|
297
297
|
allocateWork: acl(actions.manageWorker)(allocateWork),
|
|
@@ -299,6 +299,6 @@ export default {
|
|
|
299
299
|
removeWork: acl(actions.manageWorker)(removeWork),
|
|
300
300
|
processNextWork: acl(actions.manageWorker)(processNextWork),
|
|
301
301
|
signPaymentProviderForCredentialRegistration: acl(actions.registerPaymentCredentials)(signPaymentProviderForCredentialRegistration),
|
|
302
|
-
signPaymentProviderForCheckout: acl(actions.
|
|
302
|
+
signPaymentProviderForCheckout: acl(actions.updateOrderPayment)(signPaymentProviderForCheckout),
|
|
303
303
|
removeUserProductReviews: acl(actions.updateUser)(removeUserProductReviews),
|
|
304
304
|
};
|
|
@@ -15,6 +15,15 @@ export default async function updateProductCommerce(root, { commerce, productId
|
|
|
15
15
|
required: { not: ProductType.CONFIGURABLE_PRODUCT },
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
const normalizedCommerce = {
|
|
19
|
+
...commerce,
|
|
20
|
+
pricing: commerce?.pricing?.map((priceLevel) => {
|
|
21
|
+
if (priceLevel.minQuantity != null && priceLevel.minQuantity < 0) {
|
|
22
|
+
throw new Error('minQuantity must be greater than or equal to 0');
|
|
23
|
+
}
|
|
24
|
+
return { ...priceLevel, minQuantity: priceLevel.minQuantity ?? 0 };
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
await modules.products.update(productId, { commerce: normalizedCommerce });
|
|
19
28
|
return modules.products.findProduct({ productId });
|
|
20
29
|
}
|
|
@@ -10,7 +10,7 @@ export interface LoadedFilterData {
|
|
|
10
10
|
}
|
|
11
11
|
export declare const LoadedFilter: {
|
|
12
12
|
definition: ({ filter }: LoadedFilterData) => Filter;
|
|
13
|
-
isSelected: ({ searchQuery, filter }: LoadedFilterData) => boolean
|
|
13
|
+
isSelected: ({ searchQuery, filter }: LoadedFilterData) => boolean;
|
|
14
14
|
filteredProductsCount: ({ filteredByOtherFiltersSet, filteredByThisFilterSet, searchQuery }: LoadedFilterData, _: never, context: Context) => Promise<number>;
|
|
15
15
|
productsCount: ({ examinedProductIdSet, searchQuery }: LoadedFilterData, _: never, context: Context) => Promise<number>;
|
|
16
16
|
options: ({ filter, filteredByOtherFiltersSet, forceLiveCollection, searchQuery }: LoadedFilterData, _: never, context: Context) => Promise<({
|
|
@@ -4,7 +4,7 @@ export const LoadedFilter = {
|
|
|
4
4
|
return filter;
|
|
5
5
|
},
|
|
6
6
|
isSelected: ({ searchQuery, filter }) => {
|
|
7
|
-
return searchQuery?.filterQuery?.some((q) => q.key === filter.key);
|
|
7
|
+
return Boolean(searchQuery?.filterQuery?.some((q) => q.key === filter.key));
|
|
8
8
|
},
|
|
9
9
|
filteredProductsCount: async ({ filteredByOtherFiltersSet, filteredByThisFilterSet, searchQuery }, _, context) => {
|
|
10
10
|
const filterActions = await FilterDirector.actions({ searchQuery }, context);
|
|
@@ -64,7 +64,7 @@ declare const types: {
|
|
|
64
64
|
currencyCode?: string;
|
|
65
65
|
}, requestContext: import("../../context.ts").Context): Promise<{
|
|
66
66
|
minQuantity: number;
|
|
67
|
-
maxQuantity: number;
|
|
67
|
+
maxQuantity: number | null;
|
|
68
68
|
price: import("@unchainedshop/core-products").ProductPrice;
|
|
69
69
|
}[]>;
|
|
70
70
|
salesUnit({ commerce }: import("@unchainedshop/core-products").Product): string | null;
|
|
@@ -279,7 +279,7 @@ declare const types: {
|
|
|
279
279
|
Language: import("./language-types.ts").LanguageHelperTypes;
|
|
280
280
|
LoadedFilter: {
|
|
281
281
|
definition: ({ filter }: import("./filter/loaded-filter-types.ts").LoadedFilterData) => import("@unchainedshop/core-filters").Filter;
|
|
282
|
-
isSelected: ({ searchQuery, filter }: import("./filter/loaded-filter-types.ts").LoadedFilterData) => boolean
|
|
282
|
+
isSelected: ({ searchQuery, filter }: import("./filter/loaded-filter-types.ts").LoadedFilterData) => boolean;
|
|
283
283
|
filteredProductsCount: ({ filteredByOtherFiltersSet, filteredByThisFilterSet, searchQuery }: import("./filter/loaded-filter-types.ts").LoadedFilterData, _: never, context: import("../../context.ts").Context) => Promise<number>;
|
|
284
284
|
productsCount: ({ examinedProductIdSet, searchQuery }: import("./filter/loaded-filter-types.ts").LoadedFilterData, _: never, context: import("../../context.ts").Context) => Promise<number>;
|
|
285
285
|
options: ({ filter, filteredByOtherFiltersSet, forceLiveCollection, searchQuery }: import("./filter/loaded-filter-types.ts").LoadedFilterData, _: never, context: import("../../context.ts").Context) => Promise<({
|
|
@@ -498,7 +498,7 @@ declare const types: {
|
|
|
498
498
|
currencyCode?: string;
|
|
499
499
|
}, requestContext: import("../../context.ts").Context): Promise<{
|
|
500
500
|
minQuantity: number;
|
|
501
|
-
maxQuantity: number;
|
|
501
|
+
maxQuantity: number | null;
|
|
502
502
|
price: import("@unchainedshop/core-products").ProductPrice;
|
|
503
503
|
}[]>;
|
|
504
504
|
salesUnit({ commerce }: import("@unchainedshop/core-products").Product): string | null;
|
|
@@ -622,6 +622,10 @@ declare const types: {
|
|
|
622
622
|
isExpired: (obj: import("@unchainedshop/core-quotations").Quotation, { referenceDate }: {
|
|
623
623
|
referenceDate: Date;
|
|
624
624
|
}, { modules }: import("../../context.ts").Context) => boolean;
|
|
625
|
+
price: (obj: import("@unchainedshop/core-quotations").Quotation) => {
|
|
626
|
+
amount: number;
|
|
627
|
+
currencyCode: string;
|
|
628
|
+
} | null;
|
|
625
629
|
product: (obj: import("@unchainedshop/core-quotations").Quotation, _: never, { loaders }: import("../../context.ts").Context) => Promise<import("@unchainedshop/core-products").Product>;
|
|
626
630
|
status: (obj: import("@unchainedshop/core-quotations").Quotation, _: never, { modules }: import("../../context.ts").Context) => import("@unchainedshop/core-quotations").QuotationStatus;
|
|
627
631
|
user: (obj: import("@unchainedshop/core-quotations").Quotation, _: never, { loaders }: import("../../context.ts").Context) => Promise<import("@unchainedshop/core-users").User>;
|
|
@@ -669,7 +673,7 @@ declare const types: {
|
|
|
669
673
|
currencyCode?: string;
|
|
670
674
|
}, requestContext: import("../../context.ts").Context): Promise<{
|
|
671
675
|
minQuantity: number;
|
|
672
|
-
maxQuantity: number;
|
|
676
|
+
maxQuantity: number | null;
|
|
673
677
|
price: import("@unchainedshop/core-products").ProductPrice;
|
|
674
678
|
}[]>;
|
|
675
679
|
salesUnit({ commerce }: import("@unchainedshop/core-products").Product): string | null;
|
|
@@ -734,7 +738,7 @@ declare const types: {
|
|
|
734
738
|
currencyCode?: string;
|
|
735
739
|
}, requestContext: import("../../context.ts").Context): Promise<{
|
|
736
740
|
minQuantity: number;
|
|
737
|
-
maxQuantity: number;
|
|
741
|
+
maxQuantity: number | null;
|
|
738
742
|
price: import("@unchainedshop/core-products").ProductPrice;
|
|
739
743
|
}[]>;
|
|
740
744
|
salesUnit({ commerce }: import("@unchainedshop/core-products").Product): string | null;
|
|
@@ -15,7 +15,7 @@ export declare const BundleProduct: {
|
|
|
15
15
|
currencyCode?: string;
|
|
16
16
|
}, requestContext: import("../../../context.ts").Context): Promise<{
|
|
17
17
|
minQuantity: number;
|
|
18
|
-
maxQuantity: number;
|
|
18
|
+
maxQuantity: number | null;
|
|
19
19
|
price: import("@unchainedshop/core-products").ProductPrice;
|
|
20
20
|
}[]>;
|
|
21
21
|
salesUnit({ commerce }: import("@unchainedshop/core-products").Product): string | null;
|
|
@@ -15,7 +15,7 @@ export declare const PlanProduct: {
|
|
|
15
15
|
currencyCode?: string;
|
|
16
16
|
}, requestContext: Context): Promise<{
|
|
17
17
|
minQuantity: number;
|
|
18
|
-
maxQuantity: number;
|
|
18
|
+
maxQuantity: number | null;
|
|
19
19
|
price: ProductPrice;
|
|
20
20
|
}[]>;
|
|
21
21
|
salesUnit({ commerce }: ProductType): string | null;
|
|
@@ -45,7 +45,7 @@ export declare const SimpleProduct: {
|
|
|
45
45
|
currencyCode?: string;
|
|
46
46
|
}, requestContext: Context): Promise<{
|
|
47
47
|
minQuantity: number;
|
|
48
|
-
maxQuantity: number;
|
|
48
|
+
maxQuantity: number | null;
|
|
49
49
|
price: import("@unchainedshop/core-products").ProductPrice;
|
|
50
50
|
}[]>;
|
|
51
51
|
salesUnit({ commerce }: Product): string | null;
|
|
@@ -29,7 +29,7 @@ export declare const TokenizedProduct: {
|
|
|
29
29
|
currencyCode?: string;
|
|
30
30
|
}, requestContext: Context): Promise<{
|
|
31
31
|
minQuantity: number;
|
|
32
|
-
maxQuantity: number;
|
|
32
|
+
maxQuantity: number | null;
|
|
33
33
|
price: import("@unchainedshop/core-products").ProductPrice;
|
|
34
34
|
}[]>;
|
|
35
35
|
salesUnit({ commerce }: Product): string | null;
|
|
@@ -6,6 +6,10 @@ export declare const Quotation: {
|
|
|
6
6
|
isExpired: (obj: QuotationType, { referenceDate }: {
|
|
7
7
|
referenceDate: Date;
|
|
8
8
|
}, { modules }: Context) => boolean;
|
|
9
|
+
price: (obj: QuotationType) => {
|
|
10
|
+
amount: number;
|
|
11
|
+
currencyCode: string;
|
|
12
|
+
} | null;
|
|
9
13
|
product: (obj: QuotationType, _: never, { loaders }: Context) => Promise<import("@unchainedshop/core-products").Product>;
|
|
10
14
|
status: (obj: QuotationType, _: never, { modules }: Context) => import("@unchainedshop/core-quotations").QuotationStatus;
|
|
11
15
|
user: (obj: QuotationType, _: never, { loaders }: Context) => Promise<import("@unchainedshop/core-users").User>;
|
|
@@ -2,6 +2,7 @@ export const Quotation = {
|
|
|
2
2
|
country: async (obj, _, { loaders }) => obj.countryCode ? loaders.countryLoader.load({ isoCode: obj.countryCode }) : null,
|
|
3
3
|
currency: async (obj, _, { loaders }) => obj.currencyCode ? loaders.currencyLoader.load({ isoCode: obj.currencyCode }) : null,
|
|
4
4
|
isExpired: (obj, { referenceDate }, { modules }) => modules.quotations.isExpired(obj, { referenceDate }),
|
|
5
|
+
price: (obj) => obj.price != null && obj.currencyCode ? { amount: obj.price, currencyCode: obj.currencyCode } : null,
|
|
5
6
|
product: async (obj, _, { loaders }) => {
|
|
6
7
|
const product = await loaders.productLoader.load({
|
|
7
8
|
productId: obj.productId,
|
|
@@ -49,9 +49,9 @@ export const User = {
|
|
|
49
49
|
return context.modules.bookmarks.findBookmarksByUserId(user._id);
|
|
50
50
|
},
|
|
51
51
|
async cart(user, params, context) {
|
|
52
|
-
const {
|
|
52
|
+
const { loaders, countryCode } = context;
|
|
53
53
|
await checkAction(context, viewUserOrders, [user, params]);
|
|
54
|
-
return
|
|
54
|
+
return loaders.cartLoader.load({
|
|
55
55
|
countryCode,
|
|
56
56
|
orderNumber: params.orderNumber,
|
|
57
57
|
userId: user._id,
|
package/lib/roles/index.js
CHANGED
|
@@ -60,6 +60,7 @@ const actions = [
|
|
|
60
60
|
'createEnrollment',
|
|
61
61
|
'updateEnrollment',
|
|
62
62
|
'updateCart',
|
|
63
|
+
'addCartQuotation',
|
|
63
64
|
'checkoutCart',
|
|
64
65
|
'updateOrder',
|
|
65
66
|
'updateOrderDelivery',
|
|
@@ -84,6 +85,7 @@ const actions = [
|
|
|
84
85
|
'manageQuotations',
|
|
85
86
|
'answerQuotation',
|
|
86
87
|
'bookmarkProduct',
|
|
88
|
+
'createBookmark',
|
|
87
89
|
'manageBookmarks',
|
|
88
90
|
'search',
|
|
89
91
|
'manageWorker',
|
package/lib/roles/loggedIn.js
CHANGED
|
@@ -116,6 +116,14 @@ export const loggedIn = (role, actions) => {
|
|
|
116
116
|
return true;
|
|
117
117
|
return bookmark.userId === userId;
|
|
118
118
|
};
|
|
119
|
+
const isOwnBookmarkUser = (obj, { userId: bookmarkUserId }, { userId }) => {
|
|
120
|
+
return !bookmarkUserId || bookmarkUserId === userId;
|
|
121
|
+
};
|
|
122
|
+
const isOwnedCartAndQuotation = async (obj, params, context) => {
|
|
123
|
+
if (!(await isOwnedOrderOrCart(obj, params, context)))
|
|
124
|
+
return false;
|
|
125
|
+
return isOwnedQuotation(obj, params, context);
|
|
126
|
+
};
|
|
119
127
|
const isOwnedPaymentCredential = async (obj, { paymentCredentialsId }, { modules, userId }) => {
|
|
120
128
|
const credentials = await modules.payment.paymentCredentials.findPaymentCredential({
|
|
121
129
|
paymentCredentialsId,
|
|
@@ -155,6 +163,7 @@ export const loggedIn = (role, actions) => {
|
|
|
155
163
|
role.allow(actions.updateOrderPayment, isOwnedOrderPayment);
|
|
156
164
|
role.allow(actions.checkoutCart, isOwnedOrderOrCart);
|
|
157
165
|
role.allow(actions.updateCart, isOwnedOrderOrCart);
|
|
166
|
+
role.allow(actions.addCartQuotation, isOwnedCartAndQuotation);
|
|
158
167
|
role.allow(actions.createCart, () => true);
|
|
159
168
|
role.allow(actions.viewEnrollment, isOwnedEnrollment);
|
|
160
169
|
role.allow(actions.updateEnrollment, isOwnedEnrollment);
|
|
@@ -163,7 +172,9 @@ export const loggedIn = (role, actions) => {
|
|
|
163
172
|
role.allow(actions.updateProductReview, isOwnedProductReview);
|
|
164
173
|
role.allow(actions.requestQuotation, () => true);
|
|
165
174
|
role.allow(actions.answerQuotation, isOwnedQuotation);
|
|
175
|
+
role.allow(actions.viewQuotation, isOwnedQuotation);
|
|
166
176
|
role.allow(actions.manageBookmarks, isOwnedBookmark);
|
|
177
|
+
role.allow(actions.createBookmark, isOwnBookmarkUser);
|
|
167
178
|
role.allow(actions.bookmarkProduct, () => true);
|
|
168
179
|
role.allow(actions.voteProductReview, () => true);
|
|
169
180
|
role.allow(actions.registerPaymentCredentials, () => true);
|
package/lib/schema/inputTypes.js
CHANGED
|
@@ -8,7 +8,7 @@ export default [
|
|
|
8
8
|
input UserProfileInput {
|
|
9
9
|
displayName: String
|
|
10
10
|
birthday: Timestamp
|
|
11
|
-
phoneMobile:
|
|
11
|
+
phoneMobile: PhoneNumber
|
|
12
12
|
gender: String
|
|
13
13
|
address: AddressInput
|
|
14
14
|
}
|
|
@@ -27,7 +27,7 @@ export default [
|
|
|
27
27
|
|
|
28
28
|
input ContactInput {
|
|
29
29
|
emailAddress: String
|
|
30
|
-
telNumber:
|
|
30
|
+
telNumber: PhoneNumber
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
input CreateLanguageInput {
|
|
@@ -105,7 +105,7 @@ export default [
|
|
|
105
105
|
|
|
106
106
|
input UpdateProductCommercePricingInput {
|
|
107
107
|
amount: Int!
|
|
108
|
-
|
|
108
|
+
minQuantity: Int
|
|
109
109
|
isTaxable: Boolean
|
|
110
110
|
isNetPrice: Boolean
|
|
111
111
|
currencyCode: String!
|
package/lib/schema/scalars.js
CHANGED
|
@@ -49,14 +49,14 @@ export default [
|
|
|
49
49
|
type LoadedFilterOption @cacheControl(maxAge: 180) {
|
|
50
50
|
filteredProductsCount: Int!
|
|
51
51
|
definition: FilterOption!
|
|
52
|
-
isSelected: Boolean
|
|
52
|
+
isSelected: Boolean!
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
type LoadedFilter @cacheControl(maxAge: 180) {
|
|
56
56
|
productsCount: Int!
|
|
57
57
|
filteredProductsCount: Int!
|
|
58
58
|
definition: Filter!
|
|
59
|
-
isSelected: Boolean
|
|
59
|
+
isSelected: Boolean!
|
|
60
60
|
options: [LoadedFilterOption!]
|
|
61
61
|
}
|
|
62
62
|
`,
|
|
@@ -57,6 +57,11 @@ export default [
|
|
|
57
57
|
country: Country
|
|
58
58
|
currency: Currency
|
|
59
59
|
configuration: [ProductConfigurationParameter!]
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
Proposed unit price (minor units of the quotation's currency), set when the quotation reaches PROPOSED
|
|
63
|
+
"""
|
|
64
|
+
price: Price
|
|
60
65
|
}
|
|
61
66
|
`,
|
|
62
67
|
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isPeerNotInstalledError(packageName: string, error: unknown): boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function isPeerNotInstalledError(packageName, error) {
|
|
2
|
+
if (error?.code !== 'ERR_MODULE_NOT_FOUND')
|
|
3
|
+
return false;
|
|
4
|
+
const match = String(error?.message || '').match(/^Cannot find (?:package|module) '([^']+)'/);
|
|
5
|
+
return !!match && (match[1] === packageName || match[1].startsWith(`${packageName}/`));
|
|
6
|
+
}
|