@unchainedshop/api 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.
Files changed (168) hide show
  1. package/README.md +204 -0
  2. package/lib/api-index.js +3 -0
  3. package/lib/chat/generateImageHandler.d.ts +7 -1
  4. package/lib/chat/generateImageHandler.js +4 -5
  5. package/lib/context.js +2 -13
  6. package/lib/errors.d.ts +1 -0
  7. package/lib/errors.js +2 -1
  8. package/lib/events.js +0 -2
  9. package/lib/express/chatHandler.js +4 -4
  10. package/lib/express/createERCMetadataMiddleware.js +1 -1
  11. package/lib/express/index.js +23 -9
  12. package/lib/fastify/chatHandler.js +4 -4
  13. package/lib/fastify/ercMetadataHandler.js +1 -1
  14. package/lib/fastify/index.js +9 -3
  15. package/lib/loaders/assortmentMediaTextLoader.js +1 -1
  16. package/lib/loaders/assortmentMediasLoader.js +1 -1
  17. package/lib/loaders/assortmentTextLoader.js +1 -1
  18. package/lib/loaders/countryLoader.js +1 -1
  19. package/lib/loaders/currencyLoader.js +1 -1
  20. package/lib/loaders/deliveryProviderLoader.js +1 -1
  21. package/lib/loaders/fileLoader.js +1 -1
  22. package/lib/loaders/filterTextLoader.js +1 -1
  23. package/lib/loaders/languageLoader.js +1 -1
  24. package/lib/loaders/orderLoader.js +1 -1
  25. package/lib/loaders/paymentProviderLoader.js +1 -1
  26. package/lib/loaders/productBySKULoader.js +2 -4
  27. package/lib/loaders/productLoader.js +1 -3
  28. package/lib/loaders/productMediaTextLoader.js +1 -1
  29. package/lib/loaders/productMediasLoader.js +1 -1
  30. package/lib/loaders/productProxiesLoader.js +2 -10
  31. package/lib/loaders/productTextLoader.js +1 -1
  32. package/lib/loaders/productVariationByKeyLoader.js +1 -1
  33. package/lib/loaders/productVariationLoader.js +1 -1
  34. package/lib/loaders/productVariationTextLoader.js +1 -1
  35. package/lib/loaders/quotationLoader.js +1 -1
  36. package/lib/loaders/userLoader.js +1 -1
  37. package/lib/loaders/warehousingProviderLoader.js +1 -1
  38. package/lib/mcp/tools/assortment/handlers/addAssortmentFilter.d.ts +0 -1
  39. package/lib/mcp/tools/assortment/handlers/addAssortmentLink.d.ts +0 -1
  40. package/lib/mcp/tools/assortment/handlers/addAssortmentMedia.d.ts +0 -1
  41. package/lib/mcp/tools/assortment/handlers/addAssortmentProduct.d.ts +0 -1
  42. package/lib/mcp/tools/assortment/handlers/createAssortment.d.ts +0 -1
  43. package/lib/mcp/tools/assortment/handlers/getAssortment.d.ts +0 -1
  44. package/lib/mcp/tools/assortment/handlers/getAssortmentChildren.d.ts +0 -2
  45. package/lib/mcp/tools/assortment/handlers/getAssortmentFilters.d.ts +0 -1
  46. package/lib/mcp/tools/assortment/handlers/getAssortmentLinks.d.ts +0 -2
  47. package/lib/mcp/tools/assortment/handlers/getAssortmentMedia.d.ts +0 -1
  48. package/lib/mcp/tools/assortment/handlers/getAssortmentProducts.d.ts +0 -1
  49. package/lib/mcp/tools/assortment/handlers/index.d.ts +0 -2
  50. package/lib/mcp/tools/assortment/handlers/index.js +0 -2
  51. package/lib/mcp/tools/assortment/handlers/listAssortments.d.ts +0 -1
  52. package/lib/mcp/tools/assortment/handlers/reorderAssortmentLinks.d.ts +0 -1
  53. package/lib/mcp/tools/assortment/handlers/searchAssortmentProducts.d.ts +0 -1
  54. package/lib/mcp/tools/assortment/handlers/updateAssortment.d.ts +0 -1
  55. package/lib/mcp/tools/assortment/handlers/updateAssortmentStatus.d.ts +0 -1
  56. package/lib/mcp/tools/assortment/schemas.d.ts +0 -5
  57. package/lib/mcp/tools/assortment/schemas.js +0 -4
  58. package/lib/mcp/tools/order/handlers/confirmOrder.d.ts +1 -1
  59. package/lib/mcp/tools/order/handlers/deliverOrder.d.ts +1 -1
  60. package/lib/mcp/tools/order/handlers/getOrder.d.ts +1 -1
  61. package/lib/mcp/tools/order/handlers/getTopCustomers.d.ts +6 -6
  62. package/lib/mcp/tools/order/handlers/getTopCustomers.js +5 -55
  63. package/lib/mcp/tools/order/handlers/getTopProducts.d.ts +3 -3
  64. package/lib/mcp/tools/order/handlers/getTopProducts.js +4 -43
  65. package/lib/mcp/tools/order/handlers/getUserCart.d.ts +1 -1
  66. package/lib/mcp/tools/order/handlers/listOrders.d.ts +1 -1
  67. package/lib/mcp/tools/order/handlers/payOrder.d.ts +1 -1
  68. package/lib/mcp/tools/order/handlers/rejectOrder.d.ts +1 -1
  69. package/lib/mcp/tools/provider/handlers/listProviders.js +4 -8
  70. package/lib/mcp/tools/quotation/handlers/getQuotation.d.ts +2 -2
  71. package/lib/mcp/tools/quotation/handlers/listQuotations.d.ts +2 -2
  72. package/lib/mcp/tools/quotation/handlers/makeQuotationProposal.d.ts +2 -2
  73. package/lib/mcp/tools/quotation/handlers/rejectQuotation.d.ts +2 -2
  74. package/lib/mcp/tools/quotation/handlers/rejectQuotation.js +1 -1
  75. package/lib/mcp/tools/quotation/handlers/verifyQuotation.d.ts +2 -2
  76. package/lib/mcp/tools/quotation/index.js +1 -1
  77. package/lib/mcp/tools/quotation/schemas.d.ts +5 -5
  78. package/lib/mcp/tools/quotation/schemas.js +3 -3
  79. package/lib/mcp/tools/system/schemas.d.ts +6 -6
  80. package/lib/mcp/tools/system/schemas.js +14 -7
  81. package/lib/mcp/tools/users/handlers/addUserEmail.d.ts +1 -1
  82. package/lib/mcp/tools/users/handlers/createUser.d.ts +1 -1
  83. package/lib/mcp/tools/users/handlers/enrollUser.d.ts +1 -1
  84. package/lib/mcp/tools/users/handlers/getCurrentUser.d.ts +1 -1
  85. package/lib/mcp/tools/users/handlers/getUser.d.ts +1 -1
  86. package/lib/mcp/tools/users/handlers/getUserOrders.d.ts +1 -1
  87. package/lib/mcp/tools/users/handlers/getUserQuotations.d.ts +1 -1
  88. package/lib/mcp/tools/users/handlers/listUsers.d.ts +1 -1
  89. package/lib/mcp/tools/users/handlers/setUserTags.d.ts +1 -1
  90. package/lib/mcp/tools/users/handlers/setUserUsername.d.ts +1 -1
  91. package/lib/mcp/tools/users/handlers/updateUser.d.ts +1 -1
  92. package/lib/mcp/utils/getNormalizedAssortmentDetails.d.ts +0 -1
  93. package/lib/mcp/utils/getNormalizedOrderDetails.d.ts +1 -1
  94. package/lib/mcp/utils/getNormalizedQuotationDetails.d.ts +2 -2
  95. package/lib/mcp/utils/getNormalizedUserDetails.d.ts +1 -1
  96. package/lib/mongo-store.d.ts +9 -5
  97. package/lib/mongo-store.js +31 -25
  98. package/lib/resolvers/mutations/accounts/addWeb3Address.d.ts +2 -2
  99. package/lib/resolvers/mutations/accounts/addWeb3Address.js +1 -14
  100. package/lib/resolvers/mutations/accounts/addWebAuthnCredentials.d.ts +2 -2
  101. package/lib/resolvers/mutations/accounts/addWebAuthnCredentials.js +2 -6
  102. package/lib/resolvers/mutations/accounts/createUser.js +3 -1
  103. package/lib/resolvers/mutations/accounts/createWebAuthnCredentialCreationOptions.d.ts +1 -4
  104. package/lib/resolvers/mutations/accounts/createWebAuthnCredentialRequestOptions.d.ts +1 -4
  105. package/lib/resolvers/mutations/accounts/forgotPassword.js +4 -4
  106. package/lib/resolvers/mutations/accounts/loginAsGuest.js +1 -3
  107. package/lib/resolvers/mutations/accounts/removeWeb3Address.d.ts +1 -1
  108. package/lib/resolvers/mutations/accounts/removeWeb3Address.js +3 -7
  109. package/lib/resolvers/mutations/accounts/removeWebAuthnCredentials.d.ts +1 -1
  110. package/lib/resolvers/mutations/accounts/removeWebAuthnCredentials.js +1 -5
  111. package/lib/resolvers/mutations/accounts/verifyWeb3Address.d.ts +2 -2
  112. package/lib/resolvers/mutations/accounts/verifyWeb3Address.js +8 -89
  113. package/lib/resolvers/mutations/filters/removeFilter.d.ts +2 -2
  114. package/lib/resolvers/mutations/filters/removeFilter.js +3 -5
  115. package/lib/resolvers/mutations/index.d.ts +0 -1
  116. package/lib/resolvers/mutations/index.js +0 -2
  117. package/lib/resolvers/mutations/orders/addMultipleCartProducts.js +23 -31
  118. package/lib/resolvers/mutations/orders/removeCartDiscount.d.ts +2 -2
  119. package/lib/resolvers/mutations/orders/removeCartDiscount.js +9 -14
  120. package/lib/resolvers/mutations/orders/updateCart.js +2 -8
  121. package/lib/resolvers/mutations/quotations/rejectQuotation.js +1 -1
  122. package/lib/resolvers/mutations/users/removeUser.d.ts +1 -1
  123. package/lib/resolvers/mutations/users/removeUser.js +2 -3
  124. package/lib/resolvers/mutations/warehousing/exportToken.js +9 -17
  125. package/lib/resolvers/queries/payment/paymentProvidersCount.d.ts +3 -3
  126. package/lib/resolvers/queries/payment/paymentProvidersCount.js +1 -1
  127. package/lib/resolvers/queries/shopInfo.js +4 -36
  128. package/lib/resolvers/type/delivery-provider-interface.d.ts +1 -7
  129. package/lib/resolvers/type/delivery-provider-interface.js +10 -20
  130. package/lib/resolvers/type/delivery-provider-pickup-types.d.ts +1 -7
  131. package/lib/resolvers/type/delivery-provider-shipping-types.d.ts +1 -7
  132. package/lib/resolvers/type/delivery-provider-types.d.ts +1 -7
  133. package/lib/resolvers/type/index.d.ts +33 -54
  134. package/lib/resolvers/type/media-types.d.ts +1 -1
  135. package/lib/resolvers/type/media-types.js +7 -5
  136. package/lib/resolvers/type/order/order-item-types.d.ts +2 -9
  137. package/lib/resolvers/type/order/order-item-types.js +2 -37
  138. package/lib/resolvers/type/order/order-statistics-types.d.ts +10 -10
  139. package/lib/resolvers/type/order/order-statistics-types.js +10 -64
  140. package/lib/resolvers/type/payment/payment-provider-types.d.ts +1 -7
  141. package/lib/resolvers/type/payment/payment-provider-types.js +7 -17
  142. package/lib/resolvers/type/price-types.d.ts +0 -1
  143. package/lib/resolvers/type/product/product-bundle-types.d.ts +1 -1
  144. package/lib/resolvers/type/product/product-configurable-types.d.ts +1 -1
  145. package/lib/resolvers/type/product/product-configurable-types.js +9 -32
  146. package/lib/resolvers/type/product/product-plan-types.d.ts +1 -1
  147. package/lib/resolvers/type/product/product-simple-types.d.ts +1 -1
  148. package/lib/resolvers/type/product/product-tokenized-types.d.ts +1 -1
  149. package/lib/resolvers/type/product/product-types.d.ts +1 -1
  150. package/lib/resolvers/type/product/product-types.js +7 -17
  151. package/lib/resolvers/type/shop-types.js +2 -5
  152. package/lib/resolvers/type/token-types.d.ts +3 -3
  153. package/lib/resolvers/type/token-types.js +4 -25
  154. package/lib/resolvers/type/user-types.js +1 -4
  155. package/lib/resolvers/type/webauthn-credentials-types.d.ts +10 -1
  156. package/lib/roles/index.d.ts +2 -1
  157. package/lib/roles/index.js +7 -1
  158. package/lib/schema/mutation.js +1 -7
  159. package/lib/schema/types/assortment.js +0 -1
  160. package/lib/schema/types/order/order.js +2 -2
  161. package/lib/schema/types/quotation.js +2 -2
  162. package/lib/utils/getConfiguredTags.d.ts +1 -0
  163. package/lib/utils/getConfiguredTags.js +9 -0
  164. package/package.json +14 -23
  165. package/lib/mcp/tools/assortment/handlers/setAssortmentBase.d.ts +0 -28
  166. package/lib/mcp/tools/assortment/handlers/setAssortmentBase.js +0 -11
  167. package/lib/resolvers/mutations/assortments/setBaseAssortment.d.ts +0 -4
  168. package/lib/resolvers/mutations/assortments/setBaseAssortment.js +0 -11
@@ -2,7 +2,4 @@ import type { Context } from '../../../context.ts';
2
2
  export default function createWebAuthnCredentialCreationOptions(root: never, { extensionOptions, username }: {
3
3
  username: string;
4
4
  extensionOptions: any;
5
- }, { modules, userId, getHeader }: Context): Promise<(Omit<import("fido2-lib").PublicKeyCredentialCreationOptions, "challenge" | "requestId"> & {
6
- challenge: string;
7
- requestId: number;
8
- }) | null>;
5
+ }, { modules, userId, getHeader }: Context): Promise<import("@unchainedshop/core-users").WebAuthnCredentialCreationOptions>;
@@ -2,7 +2,4 @@ import type { Context } from '../../../context.ts';
2
2
  export default function createWebAuthnCredentialRequestOptions(root: never, { extensionOptions, username }: {
3
3
  username: string;
4
4
  extensionOptions: any;
5
- }, { modules, userId, getHeader }: Context): Promise<(Omit<import("fido2-lib").PublicKeyCredentialRequestOptions, "challenge" | "requestId"> & {
6
- challenge: string;
7
- requestId: number;
8
- }) | null>;
5
+ }, { modules, userId, getHeader }: Context): Promise<import("@unchainedshop/core-users").WebAuthnCredentialRequestOptions>;
@@ -1,10 +1,10 @@
1
1
  import { log } from '@unchainedshop/logger';
2
- import { UserNotFoundError } from "../../../errors.js";
3
2
  export default async function forgotPassword(root, { email }, { modules, userId }) {
4
- log('mutation forgotPassword', { email, userId });
3
+ log('mutation forgotPassword', { userId });
5
4
  const user = await modules.users.findUserByEmail(email);
6
- if (!user)
7
- throw new UserNotFoundError({ email });
5
+ if (!user) {
6
+ return { success: true };
7
+ }
8
8
  try {
9
9
  await modules.users.sendResetPasswordEmail(user._id, email);
10
10
  return {
@@ -1,9 +1,7 @@
1
1
  import { log } from '@unchainedshop/logger';
2
- import moniker from 'moniker';
3
- import { generateDbObjectId } from '@unchainedshop/mongodb';
4
2
  export default async function loginAsGuest(root, _, context) {
5
3
  log('mutation loginAsGuest');
6
- const guestname = `${moniker.choose()}-${generateDbObjectId(5)}`;
4
+ const guestname = `guest-${crypto.randomUUID()}`;
7
5
  const guestUserId = await context.modules.users.createUser({
8
6
  email: `${guestname}@unchained.local`,
9
7
  guest: true,
@@ -1,4 +1,4 @@
1
1
  import type { Context } from '../../../context.ts';
2
2
  export default function removeWeb3Address(root: never, { address }: {
3
3
  address: string;
4
- }, { modules, userId, user }: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-users").User> | null>;
4
+ }, { modules, userId, user }: Context): Promise<import("@unchainedshop/core-users").User>;
@@ -4,13 +4,9 @@ export default async function removeWeb3Address(root, { address }, { modules, us
4
4
  log(`mutation removeWeb3Address ${address} ${user?.username}`, {
5
5
  userId,
6
6
  });
7
- const foundCredentials = user?.services?.web3?.find((service) => service.address.toLowerCase() === address.toLowerCase());
8
- if (!foundCredentials) {
7
+ const updatedUser = await modules.users.removeWeb3Address(userId, address);
8
+ if (!updatedUser) {
9
9
  throw new UserWeb3AddressNotFoundError({ userId, address });
10
10
  }
11
- return modules.users.updateUser({ _id: userId }, {
12
- $pull: {
13
- 'services.web3': { address: foundCredentials.address },
14
- },
15
- }, {});
11
+ return updatedUser;
16
12
  }
@@ -1,4 +1,4 @@
1
1
  import type { Context } from '../../../context.ts';
2
2
  export default function removeWebAuthnCredentials(root: never, { credentialsId }: {
3
3
  credentialsId: string;
4
- }, { modules, userId, user }: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-users").User> | null>;
4
+ }, { modules, userId, user }: Context): Promise<import("@unchainedshop/core-users").User | null>;
@@ -8,9 +8,5 @@ export default async function removeWebAuthnCredentials(root, { credentialsId },
8
8
  if (!foundCredentials) {
9
9
  throw new UserWebAuthnCredentialsNotFoundError({ userId, credentialsId });
10
10
  }
11
- return modules.users.updateUser({ _id: userId }, {
12
- $pull: {
13
- 'services.webAuthn': { id: credentialsId },
14
- },
15
- }, {});
11
+ return modules.users.removeWebAuthnCredential(userId, credentialsId);
16
12
  }
@@ -1,5 +1,5 @@
1
1
  import type { Context } from '../../../context.ts';
2
- export default function verifyWeb3Address(root: never, { address, hash }: {
2
+ export default function verifyWeb3Address(_root: never, { address, hash }: {
3
3
  address: string;
4
4
  hash: `0x${string}`;
5
- }, { modules, userId, user }: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-users").User> | null>;
5
+ }, { modules, userId, user }: Context): Promise<import("@unchainedshop/core-users").User>;
@@ -1,100 +1,19 @@
1
1
  import { log } from '@unchainedshop/logger';
2
2
  import { UserWeb3AddressNotFoundError, UserWeb3AddressSignatureError } from "../../../errors.js";
3
- let secp256k1;
4
- let keccak_256;
5
- let bytesToHex;
6
- let hexToBytes;
7
- async function loadNoblePackages() {
8
- try {
9
- const curves = await import('@noble/curves/secp256k1.js');
10
- const hashes = await import('@noble/hashes/sha3.js');
11
- const utils = await import('@noble/hashes/utils.js');
12
- if (!curves || !hashes || !utils) {
13
- throw new Error('Missing required @noble packages for Web3 signature verification');
14
- }
15
- secp256k1 = curves.secp256k1;
16
- keccak_256 = hashes.keccak_256;
17
- bytesToHex = utils.bytesToHex;
18
- hexToBytes = utils.hexToBytes;
19
- return true;
20
- }
21
- catch (error) {
22
- log('Failed to load @noble packages for Web3 verification', { error: error.message });
23
- return false;
24
- }
25
- }
26
- function fromRPCSig(sig) {
27
- const bytes = hexToBytes(sig.startsWith('0x') ? sig.slice(2) : sig);
28
- if (bytes.length !== 65)
29
- throw new Error('Invalid signature length');
30
- const r = bytes.slice(0, 32);
31
- const s = bytes.slice(32, 64);
32
- let v = BigInt(bytes[64]);
33
- if (v >= 35n) {
34
- v = v - 35n - 2n * 1n;
35
- }
36
- else if (v >= 27n) {
37
- v = v - 27n;
38
- }
39
- return { v, r, s };
40
- }
41
- function hashPersonalMessage(message) {
42
- const prefix = new TextEncoder().encode('\x19Ethereum Signed Message:\n');
43
- const lengthBytes = new TextEncoder().encode(message.length.toString());
44
- const combined = new Uint8Array(prefix.length + lengthBytes.length + message.length);
45
- combined.set(prefix, 0);
46
- combined.set(lengthBytes, prefix.length);
47
- combined.set(message, prefix.length + lengthBytes.length);
48
- return keccak_256(combined);
49
- }
50
- function ecrecover(msgHash, v, r, s) {
51
- const recovery = Number(v);
52
- const signature = new Uint8Array(64);
53
- signature.set(r, 0);
54
- signature.set(s, 32);
55
- const publicKey = secp256k1.Signature.fromBytes(signature)
56
- .addRecoveryBit(recovery)
57
- .recoverPublicKey(msgHash);
58
- return publicKey.toBytes(false).slice(1);
59
- }
60
- function publicToAddress(publicKey) {
61
- const hash = keccak_256(publicKey);
62
- return hash.slice(-20);
63
- }
64
- export default async function verifyWeb3Address(root, { address, hash }, { modules, userId, user }) {
3
+ export default async function verifyWeb3Address(_root, { address, hash }, { modules, userId, user }) {
65
4
  log(`mutation verifyWeb3Address ${address} ${user?.username}`, {
66
5
  userId,
67
6
  });
68
- const packagesLoaded = await loadNoblePackages();
69
- if (!packagesLoaded) {
70
- throw new Error('Web3 signature verification is not available. Please install the required @noble packages: @noble/curves, @noble/hashes');
71
- }
72
- const foundCredentials = user?.services?.web3?.find((service) => service.address.toLowerCase() === address.toLowerCase());
7
+ const foundCredentials = modules.users.findWeb3Address(user, address);
73
8
  if (!foundCredentials) {
74
9
  throw new UserWeb3AddressNotFoundError({ userId, address });
75
10
  }
76
- const messageHash = hashPersonalMessage(hexToBytes(Buffer.from(foundCredentials.nonce, 'utf8').toString('hex')));
77
- const sigParams = fromRPCSig(hash);
78
- const publicKey = ecrecover(messageHash, sigParams.v, sigParams.r, sigParams.s);
79
- const sender = publicToAddress(publicKey);
80
- const recoveredAddr = `0x${bytesToHex(sender)}`;
81
- const isSignatureCorrectForAddress = recoveredAddr.toLowerCase() === foundCredentials.address.toLowerCase();
82
- if (!isSignatureCorrectForAddress) {
11
+ if (!foundCredentials.nonce) {
83
12
  throw new UserWeb3AddressSignatureError({ userId, address: foundCredentials.address });
84
13
  }
85
- const web3Services = user?.services?.web3.map((service) => {
86
- if (foundCredentials.address === service.address) {
87
- return {
88
- ...service,
89
- nonce: undefined,
90
- verified: true,
91
- };
92
- }
93
- return service;
94
- });
95
- return modules.users.updateUser({ _id: userId }, {
96
- $set: {
97
- 'services.web3': web3Services,
98
- },
99
- }, {});
14
+ const updatedUser = await modules.users.verifyWeb3SignatureAndUpdate(user, { address: foundCredentials.address, nonce: foundCredentials.nonce }, hash);
15
+ if (!updatedUser) {
16
+ throw new UserWeb3AddressSignatureError({ userId, address: foundCredentials.address });
17
+ }
18
+ return updatedUser;
100
19
  }
@@ -1,4 +1,4 @@
1
1
  import type { Context } from '../../../context.ts';
2
- export default function removeFilter(root: never, { filterId }: {
2
+ export default function removeFilter(_root: never, { filterId }: {
3
3
  filterId: string;
4
- }, context: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-filters").Filter>>;
4
+ }, context: Context): Promise<import("@unchainedshop/core-filters").Filter | null>;
@@ -1,14 +1,12 @@
1
1
  import { log } from '@unchainedshop/logger';
2
2
  import { FilterNotFoundError, InvalidIdError } from "../../../errors.js";
3
- export default async function removeFilter(root, { filterId }, context) {
4
- const { modules, userId } = context;
3
+ export default async function removeFilter(_root, { filterId }, context) {
4
+ const { modules, services, userId } = context;
5
5
  log(`mutation removeFilter ${filterId}`, { userId });
6
6
  if (!filterId)
7
7
  throw new InvalidIdError({ filterId });
8
8
  const filter = await modules.filters.findFilter({ filterId });
9
9
  if (!filter)
10
10
  throw new FilterNotFoundError({ filterId });
11
- await modules.assortments.filters.deleteMany({ filterId });
12
- await modules.filters.delete(filterId);
13
- return filter;
11
+ return services.filters.removeFilter({ filter });
14
12
  }
@@ -120,7 +120,6 @@ declare const _default: {
120
120
  createAssortment: (root: any, params: any, context: any, ...other: any[]) => Promise<any>;
121
121
  prepareAssortmentMediaUpload: (root: any, params: any, context: any, ...other: any[]) => Promise<any>;
122
122
  updateAssortment: (root: any, params: any, context: any, ...other: any[]) => Promise<any>;
123
- setBaseAssortment: (root: any, params: any, context: any, ...other: any[]) => Promise<any>;
124
123
  removeAssortment: (root: any, params: any, context: any, ...other: any[]) => Promise<any>;
125
124
  reorderAssortmentMedia: (root: any, params: any, context: any, ...other: any[]) => Promise<any>;
126
125
  removeAssortmentMedia: (root: any, params: any, context: any, ...other: any[]) => Promise<any>;
@@ -98,7 +98,6 @@ import updateFilterTexts from "./filters/updateFilterTexts.js";
98
98
  import removeFilterOption from "./filters/removeFilterOption.js";
99
99
  import createAssortment from "./assortments/createAssortment.js";
100
100
  import updateAssortment from "./assortments/updateAssortment.js";
101
- import setBaseAssortment from "./assortments/setBaseAssortment.js";
102
101
  import removeAssortment from "./assortments/removeAssortment.js";
103
102
  import updateAssortmentTexts from "./assortments/updateAssortmentTexts.js";
104
103
  import addAssortmentProduct from "./assortments/addAssortmentProduct.js";
@@ -278,7 +277,6 @@ export default {
278
277
  createAssortment: acl(actions.manageAssortments)(createAssortment),
279
278
  prepareAssortmentMediaUpload: acl(actions.manageAssortments)(prepareAssortmentMediaUpload),
280
279
  updateAssortment: acl(actions.manageAssortments)(updateAssortment),
281
- setBaseAssortment: acl(actions.manageAssortments)(setBaseAssortment),
282
280
  removeAssortment: acl(actions.manageAssortments)(removeAssortment),
283
281
  reorderAssortmentMedia: acl(actions.manageAssortments)(reorderAssortmentMedia),
284
282
  removeAssortmentMedia: acl(actions.manageAssortments)(removeAssortmentMedia),
@@ -1,53 +1,45 @@
1
1
  import { log } from '@unchainedshop/logger';
2
2
  import { ProductNotFoundError, OrderQuantityTooLowError, OrderWrongStatusError, OrderNotFoundError, } from "../../../errors.js";
3
- import { ordersSettings } from '@unchainedshop/core-orders';
4
3
  export default async function addMultipleCartProducts(root, params, context) {
5
- const { modules, services, userId, user } = context;
4
+ const { modules, services, userId, user, locale, countryCode } = context;
6
5
  const { orderId, items } = params;
7
6
  log(`mutation addMultipleCartProducts ${JSON.stringify(items)}`, {
8
7
  userId,
9
8
  orderId,
10
9
  });
11
- const itemsWithProducts = await Promise.all(items.map(async ({ productId, ...item }) => {
12
- const originalProduct = await modules.products.findProduct({ productId });
13
- if (!originalProduct)
10
+ for (const { productId, quantity } of items) {
11
+ const product = await modules.products.findProduct({ productId });
12
+ if (!product)
14
13
  throw new ProductNotFoundError({ productId });
15
- return {
16
- ...item,
17
- originalProduct,
18
- };
19
- }));
14
+ if (quantity < 1)
15
+ throw new OrderQuantityTooLowError({ quantity, productId });
16
+ }
20
17
  const order = await services.orders.findOrInitCart({
21
18
  orderId,
22
19
  user: user,
23
- countryCode: context.countryCode,
20
+ countryCode,
24
21
  });
25
22
  if (!order)
26
23
  throw new OrderNotFoundError({ orderId });
27
24
  if (!modules.orders.isCart(order))
28
25
  throw new OrderWrongStatusError({ status: order.status });
29
- for (const { originalProduct, quantity, configuration } of itemsWithProducts) {
30
- if (quantity < 1)
31
- throw new OrderQuantityTooLowError({
32
- quantity,
33
- productId: originalProduct._id,
34
- });
35
- const product = await modules.products.resolveOrderableProduct(originalProduct, {
36
- configuration,
37
- });
38
- await ordersSettings.validateOrderPosition({
39
- order,
40
- product,
41
- configuration,
42
- quantityDiff: quantity,
43
- }, context);
44
- await modules.orders.positions.addProductItem({
45
- quantity,
46
- configuration,
47
- originalProductId: originalProduct._id,
48
- productId: product._id,
26
+ try {
27
+ await services.orders.addMultipleCartProducts({
49
28
  orderId: order._id,
29
+ items,
30
+ context: { localeContext: locale, userId, countryCode },
50
31
  });
51
32
  }
33
+ catch (error) {
34
+ if (error.message?.startsWith('Product not found:')) {
35
+ const productId = error.message.split(': ')[1];
36
+ throw new ProductNotFoundError({ productId });
37
+ }
38
+ if (error.message?.startsWith('Invalid quantity')) {
39
+ const productId = error.message.split(': ')[1];
40
+ throw new OrderQuantityTooLowError({ quantity: 0, productId });
41
+ }
42
+ throw error;
43
+ }
52
44
  return services.orders.updateCalculation(order._id);
53
45
  }
@@ -1,4 +1,4 @@
1
1
  import type { Context } from '../../../context.ts';
2
- export default function removeCartDiscount(root: never, { discountId }: {
2
+ export default function removeCartDiscount(_root: never, { discountId }: {
3
3
  discountId: string;
4
- }, requestContext: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-orders").OrderDiscount> | null>;
4
+ }, requestContext: Context): Promise<import("@unchainedshop/core-orders").OrderDiscount>;
@@ -1,9 +1,7 @@
1
1
  import { log } from '@unchainedshop/logger';
2
2
  import { OrderDiscountNotFoundError, OrderWrongStatusError, InvalidIdError, OrderNotFoundError, } from "../../../errors.js";
3
- import { OrderDiscountTrigger } from '@unchainedshop/core-orders';
4
- import { OrderDiscountDirector } from '@unchainedshop/core';
5
- export default async function removeCartDiscount(root, { discountId }, requestContext) {
6
- const { modules, services, userId } = requestContext;
3
+ export default async function removeCartDiscount(_root, { discountId }, requestContext) {
4
+ const { modules, services, userId, locale } = requestContext;
7
5
  log(`mutation removeCartDiscount ${discountId}`, { userId });
8
6
  if (!discountId)
9
7
  throw new InvalidIdError({ discountId });
@@ -20,16 +18,13 @@ export default async function removeCartDiscount(root, { discountId }, requestCo
20
18
  if (!modules.orders.isCart(order)) {
21
19
  throw new OrderWrongStatusError({ status: order.status });
22
20
  }
23
- if (orderDiscount.trigger === OrderDiscountTrigger.USER) {
24
- const Adapter = OrderDiscountDirector.getAdapter(orderDiscount.discountKey);
25
- if (Adapter) {
26
- const adapter = await Adapter.actions({
27
- context: { order, orderDiscount, code: orderDiscount.code, ...requestContext },
28
- });
29
- await adapter.release();
30
- }
31
- }
32
- const deletedDiscount = await modules.orders.discounts.delete(discountId);
21
+ const deletedDiscount = await services.orders.removeCartDiscount({
22
+ order,
23
+ orderDiscount,
24
+ requestContext: { localeContext: locale, userId },
25
+ });
26
+ if (!deletedDiscount)
27
+ throw new OrderDiscountNotFoundError({ orderDiscount });
33
28
  await services.orders.updateCalculation(order._id);
34
29
  return deletedDiscount;
35
30
  }
@@ -13,14 +13,8 @@ export default async function updateCart(root, params, context) {
13
13
  throw new OrderNotFoundError({ orderId });
14
14
  if (!modules.orders.isCart(order))
15
15
  throw new OrderWrongStatusError({ status: order.status });
16
- if (meta) {
17
- await modules.orders.updateContext(order._id, meta);
18
- }
19
- if (billingAddress) {
20
- await modules.orders.updateBillingAddress(order._id, billingAddress);
21
- }
22
- if (contact) {
23
- await modules.orders.updateContact(order._id, contact);
16
+ if (meta || billingAddress || contact) {
17
+ await modules.orders.updateCartFields(order._id, { meta, billingAddress, contact });
24
18
  }
25
19
  if (paymentProviderId) {
26
20
  await modules.orders.setPaymentProvider(order._id, paymentProviderId);
@@ -10,7 +10,7 @@ export default async function rejectQuotation(root, params, context) {
10
10
  const quotation = await modules.quotations.findQuotation({ quotationId });
11
11
  if (!quotation)
12
12
  throw new QuotationNotFoundError({ quotationId });
13
- if (quotation.status === QuotationStatus.FULLFILLED) {
13
+ if (quotation.status === QuotationStatus.FULFILLED) {
14
14
  throw new QuotationWrongStatusError({ status: quotation.status });
15
15
  }
16
16
  return services.quotations.rejectQuotation(quotation, transactionContext);
@@ -2,4 +2,4 @@ import type { Context } from '../../../context.ts';
2
2
  export default function removeUser(root: never, params: {
3
3
  userId: string;
4
4
  removeUserReviews?: boolean;
5
- }, unchainedAPI: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-users").User> | null>;
5
+ }, { modules, services, userId: currentUserId }: Context): Promise<import("mongodb").WithId<import("@unchainedshop/core-users").User> | null>;
@@ -1,14 +1,13 @@
1
1
  import { log } from '@unchainedshop/logger';
2
2
  import { UserNotFoundError } from "../../../errors.js";
3
- export default async function removeUser(root, params, unchainedAPI) {
4
- const { modules, services, userId: currentUserId } = unchainedAPI;
3
+ export default async function removeUser(root, params, { modules, services, userId: currentUserId }) {
5
4
  const { userId: paramUserId, removeUserReviews = false } = params;
6
5
  const normalizedUserId = paramUserId || currentUserId;
7
6
  log(`mutation removeUser ${normalizedUserId}`, { userId: currentUserId });
8
7
  if (!(await modules.users.userExists({ userId: normalizedUserId })))
9
8
  throw new UserNotFoundError({ userId: normalizedUserId });
10
9
  if (removeUserReviews) {
11
- await modules.products.reviews.deleteMany({ authorId: normalizedUserId });
10
+ await modules.products.reviews.deleteByAuthorId(normalizedUserId);
12
11
  }
13
12
  return services.users.deleteUser({ userId: normalizedUserId });
14
13
  }
@@ -1,5 +1,4 @@
1
1
  import { log } from '@unchainedshop/logger';
2
- import { WorkStatus } from '@unchainedshop/core-worker';
3
2
  import { InvalidIdError, TokenNotFoundError, TokenWrongStatusError } from "../../../errors.js";
4
3
  export default async function exportToken(root, { tokenId, quantity, recipientWalletAddress, }, { modules, userId }) {
5
4
  log(`mutation exportToken ${tokenId}`, {
@@ -13,21 +12,14 @@ export default async function exportToken(root, { tokenId, quantity, recipientWa
13
12
  if (token.walletAddress && !token.userId) {
14
13
  throw new TokenWrongStatusError({ tokenId });
15
14
  }
16
- const workItems = await modules.worker.findWorkQueue({
17
- types: ['EXPORT_TOKEN'],
18
- status: [WorkStatus.NEW, WorkStatus.ALLOCATED],
19
- });
20
- const existingWork = workItems.find((item) => item.input?.token?._id === token._id);
21
- if (!existingWork) {
22
- await modules.worker.addWork({
23
- type: 'EXPORT_TOKEN',
24
- retries: 5,
25
- input: {
26
- token,
27
- quantity,
28
- recipientWalletAddress,
29
- },
30
- });
31
- }
15
+ await modules.worker.addWorkIfNotExists({
16
+ type: 'EXPORT_TOKEN',
17
+ retries: 5,
18
+ input: {
19
+ token,
20
+ quantity,
21
+ recipientWalletAddress,
22
+ },
23
+ }, (item) => item.input?.token?._id === token._id);
32
24
  return modules.warehousing.findToken({ tokenId });
33
25
  }
@@ -1,5 +1,5 @@
1
1
  import type { Context } from '../../../context.ts';
2
- import type { PaymentProvider } from '@unchainedshop/core-payment';
3
- export default function paymentProvidersCount(root: never, params: {
4
- type?: PaymentProvider | null;
2
+ import type { PaymentProviderType } from '@unchainedshop/core-payment';
3
+ export default function paymentProvidersCount(_root: never, params: {
4
+ type?: PaymentProviderType | null;
5
5
  }, { modules, userId }: Context): Promise<number>;
@@ -1,5 +1,5 @@
1
1
  import { log } from '@unchainedshop/logger';
2
- export default async function paymentProvidersCount(root, params, { modules, userId }) {
2
+ export default async function paymentProvidersCount(_root, params, { modules, userId }) {
3
3
  log(`query paymentProvidersCount ${params.type}`, { userId });
4
4
  return modules.payment.paymentProviders.count(params.type
5
5
  ? {
@@ -1,5 +1,6 @@
1
1
  import { readFile } from 'fs/promises';
2
2
  import { log } from '@unchainedshop/logger';
3
+ import { getConfiguredTags } from "../../utils/getConfiguredTags.js";
3
4
  export default function shopInfo(root, _, context) {
4
5
  const { adminUiConfig, modules } = context;
5
6
  log('query shopInfo', { userId: context.userId });
@@ -30,42 +31,9 @@ export default function shopInfo(root, _, context) {
30
31
  return [];
31
32
  }
32
33
  },
33
- productTags: async () => {
34
- const existingProductTags = await modules.products.existingTags();
35
- const envTags = (process.env.UNCHAINED_ADMIN_UI_DEFAULT_PRODUCT_TAGS || '')
36
- .split(',')
37
- .map((t) => t.trim())
38
- .filter(Boolean);
39
- const normalizedDefaultTags = envTags?.length
40
- ? envTags
41
- : (adminUiConfig?.defaultProductTags || []).filter(Boolean);
42
- const normalizedTags = Array.from(new Set(normalizedDefaultTags.concat(existingProductTags)));
43
- return normalizedTags;
44
- },
45
- assortmentTags: async () => {
46
- const existingAssortmentTags = await modules.assortments.existingTags();
47
- const envTags = (process.env.UNCHAINED_ADMIN_UI_DEFAULT_ASSORTMENT_TAGS || '')
48
- .split(',')
49
- .map((t) => t.trim())
50
- .filter(Boolean);
51
- const normalizedDefaultTags = envTags?.length
52
- ? envTags
53
- : (adminUiConfig?.defaultAssortmentTags || []).filter(Boolean);
54
- const normalizedTags = Array.from(new Set(normalizedDefaultTags.concat(existingAssortmentTags)));
55
- return normalizedTags;
56
- },
57
- userTags: async () => {
58
- const existingUserTags = await modules.users.existingTags();
59
- const envTags = (process.env.UNCHAINED_ADMIN_UI_DEFAULT_USER_TAGS || '')
60
- .split(',')
61
- .map((t) => t.trim())
62
- .filter(Boolean);
63
- const normalizedDefaultTags = envTags?.length
64
- ? envTags
65
- : (adminUiConfig?.defaultUserTags || []).filter(Boolean);
66
- const normalizedTags = Array.from(new Set(normalizedDefaultTags.concat(existingUserTags)));
67
- return normalizedTags;
68
- },
34
+ productTags: () => getConfiguredTags(() => modules.products.existingTags(), 'UNCHAINED_ADMIN_UI_DEFAULT_PRODUCT_TAGS', adminUiConfig?.defaultProductTags),
35
+ assortmentTags: () => getConfiguredTags(() => modules.assortments.existingTags(), 'UNCHAINED_ADMIN_UI_DEFAULT_ASSORTMENT_TAGS', adminUiConfig?.defaultAssortmentTags),
36
+ userTags: () => getConfiguredTags(() => modules.users.existingTags(), 'UNCHAINED_ADMIN_UI_DEFAULT_USER_TAGS', adminUiConfig?.defaultUserTags),
69
37
  },
70
38
  vapidPublicKey: process.env?.PUSH_NOTIFICATION_PUBLIC_KEY,
71
39
  };
@@ -7,11 +7,5 @@ export declare const DeliveryProviderInterface: {
7
7
  label: string;
8
8
  version: string;
9
9
  } | null;
10
- simulatedPrice(deliveryProvider: any, args: any, context: Context): Promise<{
11
- amount: number;
12
- currencyCode: string;
13
- countryCode: string;
14
- isTaxable: boolean;
15
- isNetPrice: any;
16
- } | null>;
10
+ simulatedPrice(deliveryProvider: any, args: any, requestContext: Context): Promise<import("@unchainedshop/core/lib/services/simulateDeliveryPricing.js").SimulatedDeliveryPrice | null>;
17
11
  };
@@ -1,4 +1,4 @@
1
- import { DeliveryDirector, DeliveryPricingDirector } from '@unchainedshop/core';
1
+ import { DeliveryDirector } from '@unchainedshop/core';
2
2
  export const DeliveryProviderInterface = {
3
3
  async isActive(deliveryProvider, _, context) {
4
4
  const director = await DeliveryDirector.actions(deliveryProvider, {}, context);
@@ -18,30 +18,20 @@ export const DeliveryProviderInterface = {
18
18
  version: Adapter.version,
19
19
  };
20
20
  },
21
- async simulatedPrice(deliveryProvider, args, context) {
22
- const { loaders, countryCode, user } = context;
21
+ async simulatedPrice(deliveryProvider, args, requestContext) {
22
+ const { loaders, services, countryCode, user } = requestContext;
23
23
  const { currencyCode: forcedCurrencyCode, orderId, useNetPrice, context: providerContext } = args;
24
- const order = await loaders.orderLoader.load({ orderId });
25
- const currencyCode = forcedCurrencyCode || order?.currencyCode || context.currencyCode;
26
- const pricingContext = {
24
+ if (!user)
25
+ return null;
26
+ const order = orderId ? await loaders.orderLoader.load({ orderId }) : undefined;
27
+ const currencyCode = forcedCurrencyCode || order?.currencyCode || requestContext.currencyCode;
28
+ return services.delivery.simulateDeliveryPricing({
27
29
  countryCode,
28
30
  currencyCode,
29
31
  provider: deliveryProvider,
30
32
  order,
31
33
  providerContext,
32
- user: user,
33
- };
34
- const calculated = await DeliveryPricingDirector.rebuildCalculation(pricingContext, context);
35
- if (!calculated?.length)
36
- return null;
37
- const pricing = DeliveryPricingDirector.calculationSheet(pricingContext, calculated);
38
- const orderPrice = pricing.total({ useNetPrice });
39
- return {
40
- amount: orderPrice.amount,
41
- currencyCode: orderPrice.currencyCode,
42
- countryCode,
43
- isTaxable: pricing.taxSum() > 0,
44
- isNetPrice: useNetPrice,
45
- };
34
+ user,
35
+ }, { useNetPrice });
46
36
  },
47
37
  };
@@ -9,11 +9,5 @@ export declare const DeliveryProviderPickUp: {
9
9
  label: string;
10
10
  version: string;
11
11
  } | null;
12
- simulatedPrice(deliveryProvider: any, args: any, context: Context): Promise<{
13
- amount: number;
14
- currencyCode: string;
15
- countryCode: string;
16
- isTaxable: boolean;
17
- isNetPrice: any;
18
- } | null>;
12
+ simulatedPrice(deliveryProvider: any, args: any, requestContext: Context): Promise<import("@unchainedshop/core/lib/services/simulateDeliveryPricing.js").SimulatedDeliveryPrice | null>;
19
13
  };