@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.
Files changed (97) hide show
  1. package/README.md +6 -4
  2. package/lib/adminUiPlugins.d.ts +73 -0
  3. package/lib/adminUiPlugins.js +164 -0
  4. package/lib/adminUiTheme.d.ts +25 -0
  5. package/lib/adminUiTheme.js +34 -0
  6. package/lib/chat/generateImageHandler.d.ts +273 -7
  7. package/lib/chat/utils.d.ts +8 -0
  8. package/lib/chat/utils.js +54 -2
  9. package/lib/createGraphQLServer.js +6 -0
  10. package/lib/express/chatHandler.js +52 -61
  11. package/lib/express/createMCPMiddleware.js +19 -78
  12. package/lib/express/index.d.ts +8 -2
  13. package/lib/express/index.js +55 -7
  14. package/lib/fastify/chatHandler.js +52 -61
  15. package/lib/fastify/index.d.ts +7 -1
  16. package/lib/fastify/index.js +58 -11
  17. package/lib/fastify/mcpHandler.js +24 -75
  18. package/lib/loaders/cartLoader.d.ts +13 -0
  19. package/lib/loaders/cartLoader.js +8 -0
  20. package/lib/loaders/index.d.ts +9 -0
  21. package/lib/loaders/index.js +2 -0
  22. package/lib/locale-context.d.ts +2 -4
  23. package/lib/locale-context.js +2 -1
  24. package/lib/mcp/handleMcpHttpRequest.d.ts +2 -0
  25. package/lib/mcp/handleMcpHttpRequest.js +83 -0
  26. package/lib/mcp/index.d.ts +1 -1
  27. package/lib/mcp/nodeHttpBridge.d.ts +3 -0
  28. package/lib/mcp/nodeHttpBridge.js +64 -0
  29. package/lib/mcp/resources/localization.d.ts +5 -1
  30. package/lib/mcp/resources/localization.js +93 -69
  31. package/lib/mcp/tools/assortment/index.d.ts +1 -1
  32. package/lib/mcp/tools/assortment/index.js +4 -1
  33. package/lib/mcp/tools/assortment/schemas.d.ts +2 -2
  34. package/lib/mcp/tools/filter/handlers/createFilter.js +2 -4
  35. package/lib/mcp/tools/filter/handlers/createFilterOption.js +2 -4
  36. package/lib/mcp/tools/filter/handlers/removeFilterOption.js +2 -4
  37. package/lib/mcp/tools/filter/handlers/updateFilter.js +2 -2
  38. package/lib/mcp/tools/filter/index.d.ts +1 -1
  39. package/lib/mcp/tools/filter/index.js +4 -1
  40. package/lib/mcp/tools/filter/schemas.d.ts +2 -2
  41. package/lib/mcp/tools/localization/index.d.ts +1 -1
  42. package/lib/mcp/tools/localization/index.js +4 -1
  43. package/lib/mcp/tools/localization/schemas.d.ts +2 -2
  44. package/lib/mcp/tools/order/index.d.ts +1 -1
  45. package/lib/mcp/tools/order/index.js +4 -1
  46. package/lib/mcp/tools/order/schemas.d.ts +2 -2
  47. package/lib/mcp/tools/product/index.d.ts +1 -1
  48. package/lib/mcp/tools/product/index.js +4 -1
  49. package/lib/mcp/tools/product/schemas.d.ts +7 -7
  50. package/lib/mcp/tools/product/schemas.js +3 -2
  51. package/lib/mcp/tools/provider/index.d.ts +1 -1
  52. package/lib/mcp/tools/provider/index.js +4 -1
  53. package/lib/mcp/tools/provider/schemas.d.ts +2 -2
  54. package/lib/mcp/tools/quotation/index.d.ts +1 -1
  55. package/lib/mcp/tools/quotation/index.js +4 -1
  56. package/lib/mcp/tools/quotation/schemas.d.ts +2 -2
  57. package/lib/mcp/tools/system/index.d.ts +1 -1
  58. package/lib/mcp/tools/system/index.js +4 -1
  59. package/lib/mcp/tools/users/index.d.ts +1 -1
  60. package/lib/mcp/tools/users/index.js +4 -1
  61. package/lib/mcp/tools/users/schemas.d.ts +2 -2
  62. package/lib/mcp/utils/sharedSchemas.d.ts +1 -0
  63. package/lib/mcp/utils/sharedSchemas.js +1 -0
  64. package/lib/resolvers/index.js +2 -1
  65. package/lib/resolvers/mutations/bookmarks/createBookmark.d.ts +1 -1
  66. package/lib/resolvers/mutations/bookmarks/createBookmark.js +4 -3
  67. package/lib/resolvers/mutations/filters/createFilter.js +3 -4
  68. package/lib/resolvers/mutations/filters/createFilterOption.d.ts +1 -1
  69. package/lib/resolvers/mutations/filters/createFilterOption.js +3 -4
  70. package/lib/resolvers/mutations/filters/removeFilterOption.d.ts +1 -1
  71. package/lib/resolvers/mutations/filters/removeFilterOption.js +2 -8
  72. package/lib/resolvers/mutations/filters/updateFilter.d.ts +1 -1
  73. package/lib/resolvers/mutations/filters/updateFilter.js +2 -5
  74. package/lib/resolvers/mutations/index.js +3 -3
  75. package/lib/resolvers/mutations/products/updateProductCommerce.js +10 -1
  76. package/lib/resolvers/scalars/LowerCaseString.d.ts +1 -1
  77. package/lib/resolvers/scalars/index.d.ts +1 -1
  78. package/lib/resolvers/type/filter/loaded-filter-types.d.ts +1 -1
  79. package/lib/resolvers/type/filter/loaded-filter-types.js +1 -1
  80. package/lib/resolvers/type/index.d.ts +9 -5
  81. package/lib/resolvers/type/product/product-bundle-types.d.ts +1 -1
  82. package/lib/resolvers/type/product/product-plan-types.d.ts +1 -1
  83. package/lib/resolvers/type/product/product-simple-types.d.ts +1 -1
  84. package/lib/resolvers/type/product/product-tokenized-types.d.ts +1 -1
  85. package/lib/resolvers/type/quotation-types.d.ts +4 -0
  86. package/lib/resolvers/type/quotation-types.js +1 -0
  87. package/lib/resolvers/type/user-types.js +2 -2
  88. package/lib/roles/index.js +2 -0
  89. package/lib/roles/loggedIn.js +11 -0
  90. package/lib/schema/inputTypes.js +3 -3
  91. package/lib/schema/scalars.js +1 -0
  92. package/lib/schema/types/filter.js +2 -2
  93. package/lib/schema/types/product/product.js +1 -1
  94. package/lib/schema/types/quotation.js +5 -0
  95. package/lib/utils/optionalPeerError.d.ts +1 -0
  96. package/lib/utils/optionalPeerError.js +6 -0
  97. 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.tool('system_management', '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).', SystemManagementSchema, async (params) => systemManagement(context, params));
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/sdk/server/mcp.js';
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.tool('users_management', '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.', UsersManagementSchema, async (params) => usersManagement(context, params));
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";
@@ -63,6 +63,7 @@ export declare function createMcpResponse(response: any): {
63
63
  }[];
64
64
  };
65
65
  export declare function createMcpErrorResponse(action: string, error: Error): {
66
+ isError: boolean;
66
67
  content: {
67
68
  type: "text";
68
69
  text: string;
@@ -69,6 +69,7 @@ export function createMcpResponse(response) {
69
69
  }
70
70
  export function createMcpErrorResponse(action, error) {
71
71
  return {
72
+ isError: true,
72
73
  content: [
73
74
  {
74
75
  type: 'text',
@@ -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: string;
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
- log(`mutation createBookmark for ${userId}`, {
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 { FilterDirector } from '@unchainedshop/core';
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 modules.filters.create(filter);
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("mongodb").WithId<import("@unchainedshop/core-filters").Filter> | null>;
7
+ }, context: Context): Promise<import("@unchainedshop/core-filters").Filter | null>;
@@ -1,16 +1,15 @@
1
1
  import { log } from '@unchainedshop/logger';
2
- import { FilterDirector } from '@unchainedshop/core';
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 modules.filters.createFilterOption(filterId, { value: option });
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("mongodb").WithId<import("@unchainedshop/core-filters").Filter> | null>;
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
- const filter = await modules.filters.removeFilterOption({
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<import("mongodb").WithId<Filter> | null>;
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
- const updatedFilter = await modules.filters.update(filterId, filter);
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.updateCart)(addCartQuotation),
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.manageBookmarks)(createBookmark),
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.registerPaymentCredentials)(signPaymentProviderForCheckout),
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
- await modules.products.update(productId, { commerce });
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
  }
@@ -1,3 +1,3 @@
1
1
  import { GraphQLScalarType } from 'graphql';
2
- declare const LowerCaseString: GraphQLScalarType<string | null, any>;
2
+ declare const LowerCaseString: GraphQLScalarType<string, any>;
3
3
  export default LowerCaseString;
@@ -1,4 +1,4 @@
1
1
  declare const _default: {
2
- LowerCaseString: import("graphql").GraphQLScalarType<string | null, any>;
2
+ LowerCaseString: import("graphql").GraphQLScalarType<string, any>;
3
3
  };
4
4
  export default _default;
@@ -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 | undefined;
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 | undefined;
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 { modules, countryCode } = context;
52
+ const { loaders, countryCode } = context;
53
53
  await checkAction(context, viewUserOrders, [user, params]);
54
- return modules.orders.cart({
54
+ return loaders.cartLoader.load({
55
55
  countryCode,
56
56
  orderNumber: params.orderNumber,
57
57
  userId: user._id,
@@ -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',
@@ -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);
@@ -8,7 +8,7 @@ export default [
8
8
  input UserProfileInput {
9
9
  displayName: String
10
10
  birthday: Timestamp
11
- phoneMobile: String
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: String
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
- maxQuantity: Int
108
+ minQuantity: Int
109
109
  isTaxable: Boolean
110
110
  isNetPrice: Boolean
111
111
  currencyCode: String!
@@ -6,5 +6,6 @@ export default [
6
6
  scalar Timestamp
7
7
  scalar LowerCaseString
8
8
  scalar Locale
9
+ scalar PhoneNumber
9
10
  `,
10
11
  ];
@@ -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
  `,
@@ -139,7 +139,7 @@ export default [
139
139
  country: Country!
140
140
  currency: Currency!
141
141
  amount: Int!
142
- maxQuantity: Int
142
+ minQuantity: Int
143
143
  }
144
144
 
145
145
  union ConfigurableOrBundleProduct = BundleProduct | ConfigurableProduct
@@ -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
+ }