@unchainedshop/api 5.0.0-alpha.2 → 5.0.0-alpha.4
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 +8 -6
- package/lib/adminUiPlugins.d.ts +97 -0
- package/lib/adminUiPlugins.js +164 -0
- package/lib/auth.d.ts +0 -8
- package/lib/auth.js +0 -20
- 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 +63 -61
- package/lib/express/createMCPMiddleware.js +19 -78
- package/lib/express/index.d.ts +6 -2
- package/lib/express/index.js +67 -7
- package/lib/fastify/chatHandler.js +61 -61
- package/lib/fastify/index.d.ts +5 -1
- package/lib/fastify/index.js +70 -11
- package/lib/fastify/mcpHandler.js +24 -75
- package/lib/loaders/assortmentLinksLoader.js +24 -22
- package/lib/loaders/assortmentMediaTextLoader.js +1 -0
- package/lib/loaders/assortmentProductLoader.js +7 -4
- package/lib/loaders/assortmentTextLoader.js +1 -0
- package/lib/loaders/cartLoader.d.ts +13 -0
- package/lib/loaders/cartLoader.js +8 -0
- package/lib/loaders/filterTextLoader.js +1 -0
- package/lib/loaders/index.d.ts +9 -0
- package/lib/loaders/index.js +2 -0
- package/lib/loaders/productMediaTextLoader.js +1 -0
- package/lib/loaders/productTextLoader.js +1 -0
- package/lib/loaders/productVariationTextLoader.js +1 -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/handlers/getAssortmentFilters.js +1 -1
- package/lib/mcp/tools/assortment/handlers/getAssortmentProducts.js +1 -1
- 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/handlers/getUserPaymentCredentials.js +1 -0
- 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/getNormalizedAssortmentDetails.js +2 -2
- package/lib/mcp/utils/getNormalizedUserDetails.js +1 -0
- package/lib/mcp/utils/sharedSchemas.d.ts +1 -0
- package/lib/mcp/utils/sharedSchemas.js +1 -0
- package/lib/middleware/createAuthMiddleware.js +2 -39
- 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/orders/checkoutCart.js +1 -1
- 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/assortment/assortment-types.js +2 -2
- 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 +3 -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 +44 -15
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { productManagement, ProductManagementSchema } from "./productManagement.js";
|
|
2
2
|
export const registerProductTools = (server, context) => {
|
|
3
|
-
server.
|
|
3
|
+
server.registerTool('product_management', {
|
|
4
|
+
description: 'Unified product management system with comprehensive action-based operations: CREATE/UPDATE/REMOVE/GET/LIST/COUNT products, UPDATE_STATUS (publish/unpublish), ADD_MEDIA/REMOVE_MEDIA/REORDER_MEDIA/GET_MEDIA/UPDATE_MEDIA_TEXTS, CREATE_VARIATION/REMOVE_VARIATION/ADD_VARIATION_OPTION/REMOVE_VARIATION_OPTION/UPDATE_VARIATION_TEXTS, ADD_ASSIGNMENT/REMOVE_ASSIGNMENT/GET_ASSIGNMENTS/GET_VARIATION_PRODUCTS, ADD_BUNDLE_ITEM/REMOVE_BUNDLE_ITEM/GET_BUNDLE_ITEMS, SIMULATE_PRICE/SIMULATE_PRICE_RANGE/GET_CATALOG_PRICE, GET_PRODUCT_TEXTS/GET_MEDIA_TEXTS/GET_VARIATION_TEXTS, GET_REVIEWS/COUNT_REVIEWS, GET_SIBLINGS. Supports all product types (SIMPLE, CONFIGURABLE, BUNDLE, PLAN, TOKENIZED) with type-specific validations and comprehensive error handling.',
|
|
5
|
+
inputSchema: ProductManagementSchema,
|
|
6
|
+
}, async (params) => productManagement(context, params));
|
|
4
7
|
};
|
|
@@ -108,7 +108,7 @@ export declare const ProductSchema: z.ZodObject<{
|
|
|
108
108
|
commerce: z.ZodOptional<z.ZodObject<{
|
|
109
109
|
pricing: z.ZodArray<z.ZodObject<{
|
|
110
110
|
amount: z.ZodNumber;
|
|
111
|
-
|
|
111
|
+
minQuantity: z.ZodOptional<z.ZodNumber>;
|
|
112
112
|
isTaxable: z.ZodOptional<z.ZodBoolean>;
|
|
113
113
|
isNetPrice: z.ZodOptional<z.ZodBoolean>;
|
|
114
114
|
currencyCode: z.ZodString;
|
|
@@ -164,7 +164,7 @@ export declare const actionValidators: {
|
|
|
164
164
|
commerce: z.ZodOptional<z.ZodObject<{
|
|
165
165
|
pricing: z.ZodArray<z.ZodObject<{
|
|
166
166
|
amount: z.ZodNumber;
|
|
167
|
-
|
|
167
|
+
minQuantity: z.ZodOptional<z.ZodNumber>;
|
|
168
168
|
isTaxable: z.ZodOptional<z.ZodBoolean>;
|
|
169
169
|
isNetPrice: z.ZodOptional<z.ZodBoolean>;
|
|
170
170
|
currencyCode: z.ZodString;
|
|
@@ -237,7 +237,7 @@ export declare const actionValidators: {
|
|
|
237
237
|
commerce: z.ZodOptional<z.ZodObject<{
|
|
238
238
|
pricing: z.ZodArray<z.ZodObject<{
|
|
239
239
|
amount: z.ZodNumber;
|
|
240
|
-
|
|
240
|
+
minQuantity: z.ZodOptional<z.ZodNumber>;
|
|
241
241
|
isTaxable: z.ZodOptional<z.ZodBoolean>;
|
|
242
242
|
isNetPrice: z.ZodOptional<z.ZodBoolean>;
|
|
243
243
|
currencyCode: z.ZodString;
|
|
@@ -476,11 +476,11 @@ export declare const ProductManagementSchema: {
|
|
|
476
476
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
477
477
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
478
478
|
action: z.ZodEnum<{
|
|
479
|
+
LIST: "LIST";
|
|
479
480
|
GET: "GET";
|
|
480
481
|
CREATE: "CREATE";
|
|
481
482
|
UPDATE: "UPDATE";
|
|
482
483
|
REMOVE: "REMOVE";
|
|
483
|
-
LIST: "LIST";
|
|
484
484
|
COUNT: "COUNT";
|
|
485
485
|
UPDATE_STATUS: "UPDATE_STATUS";
|
|
486
486
|
ADD_MEDIA: "ADD_MEDIA";
|
|
@@ -565,7 +565,7 @@ export declare const ProductManagementSchema: {
|
|
|
565
565
|
commerce: z.ZodOptional<z.ZodObject<{
|
|
566
566
|
pricing: z.ZodArray<z.ZodObject<{
|
|
567
567
|
amount: z.ZodNumber;
|
|
568
|
-
|
|
568
|
+
minQuantity: z.ZodOptional<z.ZodNumber>;
|
|
569
569
|
isTaxable: z.ZodOptional<z.ZodBoolean>;
|
|
570
570
|
isNetPrice: z.ZodOptional<z.ZodBoolean>;
|
|
571
571
|
currencyCode: z.ZodString;
|
|
@@ -640,11 +640,11 @@ export declare const ProductManagementZodSchema: z.ZodObject<{
|
|
|
640
640
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
641
641
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
642
642
|
action: z.ZodEnum<{
|
|
643
|
+
LIST: "LIST";
|
|
643
644
|
GET: "GET";
|
|
644
645
|
CREATE: "CREATE";
|
|
645
646
|
UPDATE: "UPDATE";
|
|
646
647
|
REMOVE: "REMOVE";
|
|
647
|
-
LIST: "LIST";
|
|
648
648
|
COUNT: "COUNT";
|
|
649
649
|
UPDATE_STATUS: "UPDATE_STATUS";
|
|
650
650
|
ADD_MEDIA: "ADD_MEDIA";
|
|
@@ -729,7 +729,7 @@ export declare const ProductManagementZodSchema: z.ZodObject<{
|
|
|
729
729
|
commerce: z.ZodOptional<z.ZodObject<{
|
|
730
730
|
pricing: z.ZodArray<z.ZodObject<{
|
|
731
731
|
amount: z.ZodNumber;
|
|
732
|
-
|
|
732
|
+
minQuantity: z.ZodOptional<z.ZodNumber>;
|
|
733
733
|
isTaxable: z.ZodOptional<z.ZodBoolean>;
|
|
734
734
|
isNetPrice: z.ZodOptional<z.ZodBoolean>;
|
|
735
735
|
currencyCode: z.ZodString;
|
|
@@ -73,11 +73,12 @@ export const ProductSchema = z.object({
|
|
|
73
73
|
pricing: z
|
|
74
74
|
.array(z.object({
|
|
75
75
|
amount: z.number().int().describe('Price amount in smallest currency unit.'),
|
|
76
|
-
|
|
76
|
+
minQuantity: z
|
|
77
77
|
.number()
|
|
78
78
|
.int()
|
|
79
|
+
.min(0)
|
|
79
80
|
.optional()
|
|
80
|
-
.describe('Optional
|
|
81
|
+
.describe('Optional inclusive minimum quantity (tier floor) this price applies to; defaults to the base tier (0).'),
|
|
81
82
|
isTaxable: z.boolean().optional().describe('Whether tax applies to this price'),
|
|
82
83
|
isNetPrice: z.boolean().optional().describe('Whether this is a net price (without tax)'),
|
|
83
84
|
currencyCode: z
|
|
@@ -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 registerProviderTools: (server: McpServer, context: Context) => void;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { providerManagement, ProviderManagementSchema } from "./providerManagement.js";
|
|
2
2
|
export const registerProviderTools = (server, context) => {
|
|
3
|
-
server.
|
|
3
|
+
server.registerTool('provider_management', {
|
|
4
|
+
description: 'Unified provider management tool for all provider operations (CREATE, UPDATE, REMOVE, GET, LIST, INTERFACES) across payment processing (Stripe, PayPal), delivery services (FedEx, UPS), and warehousing systems. Use action parameter to specify operation type.',
|
|
5
|
+
inputSchema: ProviderManagementSchema,
|
|
6
|
+
}, async (params) => providerManagement(context, params));
|
|
4
7
|
};
|
|
@@ -133,11 +133,11 @@ export declare const ProviderManagementSchema: {
|
|
|
133
133
|
queryString: z.ZodOptional<z.ZodString>;
|
|
134
134
|
includeInactive: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
135
135
|
action: z.ZodEnum<{
|
|
136
|
+
LIST: "LIST";
|
|
136
137
|
GET: "GET";
|
|
137
138
|
CREATE: "CREATE";
|
|
138
139
|
UPDATE: "UPDATE";
|
|
139
140
|
REMOVE: "REMOVE";
|
|
140
|
-
LIST: "LIST";
|
|
141
141
|
INTERFACES: "INTERFACES";
|
|
142
142
|
}>;
|
|
143
143
|
providerType: z.ZodEnum<{
|
|
@@ -182,11 +182,11 @@ export declare const ProviderManagementZodSchema: z.ZodObject<{
|
|
|
182
182
|
queryString: z.ZodOptional<z.ZodString>;
|
|
183
183
|
includeInactive: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
184
184
|
action: z.ZodEnum<{
|
|
185
|
+
LIST: "LIST";
|
|
185
186
|
GET: "GET";
|
|
186
187
|
CREATE: "CREATE";
|
|
187
188
|
UPDATE: "UPDATE";
|
|
188
189
|
REMOVE: "REMOVE";
|
|
189
|
-
LIST: "LIST";
|
|
190
190
|
INTERFACES: "INTERFACES";
|
|
191
191
|
}>;
|
|
192
192
|
providerType: z.ZodEnum<{
|
|
@@ -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 registerQuotationTools: (server: McpServer, context: Context) => void;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { quotationManagement, QuotationManagementSchema } from "./quotationManagement.js";
|
|
2
2
|
export const registerQuotationTools = (server, context) => {
|
|
3
|
-
server.
|
|
3
|
+
server.registerTool('quotation_management', {
|
|
4
|
+
description: 'Unified quotation management system. Supports: LIST (get quotations with filters and pagination), GET (single quotation by ID), COUNT (count quotations), VERIFY (verify a REQUESTED quotation), MAKE_PROPOSAL (create proposal for PROCESSING quotation), REJECT (reject any quotation except FULFILLED). Quotations go through lifecycle: REQUESTED → PROCESSING → PROPOSED → FULFILLED/REJECTED.',
|
|
5
|
+
inputSchema: QuotationManagementSchema,
|
|
6
|
+
}, async (params) => quotationManagement(context, params));
|
|
4
7
|
};
|
|
@@ -94,8 +94,8 @@ export declare const QuotationManagementSchema: {
|
|
|
94
94
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
95
95
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
96
96
|
action: z.ZodEnum<{
|
|
97
|
-
GET: "GET";
|
|
98
97
|
LIST: "LIST";
|
|
98
|
+
GET: "GET";
|
|
99
99
|
COUNT: "COUNT";
|
|
100
100
|
VERIFY: "VERIFY";
|
|
101
101
|
MAKE_PROPOSAL: "MAKE_PROPOSAL";
|
|
@@ -131,8 +131,8 @@ export declare const QuotationManagementZodSchema: z.ZodObject<{
|
|
|
131
131
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
132
132
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
133
133
|
action: z.ZodEnum<{
|
|
134
|
-
GET: "GET";
|
|
135
134
|
LIST: "LIST";
|
|
135
|
+
GET: "GET";
|
|
136
136
|
COUNT: "COUNT";
|
|
137
137
|
VERIFY: "VERIFY";
|
|
138
138
|
MAKE_PROPOSAL: "MAKE_PROPOSAL";
|
|
@@ -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 registerSystemTools: (server: McpServer, context: Context) => void;
|
|
@@ -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";
|
|
@@ -9,7 +9,7 @@ export async function getNormalizedAssortmentDetails({ assortmentId, slug }, con
|
|
|
9
9
|
assortmentId: normalizedAssortmentId,
|
|
10
10
|
locale,
|
|
11
11
|
});
|
|
12
|
-
const filters = await modules.assortments.filters.findFilters({ assortmentId: assortment._id }, { sort: { sortKey: 1 } });
|
|
12
|
+
const filters = await modules.assortments.filters.findFilters({ assortmentId: assortment._id }, { sort: { sortKey: 1, _id: 1 } });
|
|
13
13
|
const assortmentMedias = await modules.assortments.media.findAssortmentMedias({
|
|
14
14
|
assortmentId: normalizedAssortmentId,
|
|
15
15
|
});
|
|
@@ -19,7 +19,7 @@ export async function getNormalizedAssortmentDetails({ assortmentId, slug }, con
|
|
|
19
19
|
const links = (await loaders.assortmentLinksLoader.load({
|
|
20
20
|
assortmentId: assortment._id,
|
|
21
21
|
})) || [];
|
|
22
|
-
const products = await modules.assortments.products.findAssortmentProducts({ assortmentId: assortment._id }, { sort: { sortKey: 1 } });
|
|
22
|
+
const products = await modules.assortments.products.findAssortmentProducts({ assortmentId: assortment._id }, { sort: { sortKey: 1, _id: 1 } });
|
|
23
23
|
const assortmentIds = assortmentChildLinks.map(({ childAssortmentId }) => childAssortmentId);
|
|
24
24
|
const childrenCount = await modules.assortments.count({
|
|
25
25
|
assortmentIds,
|
|
@@ -38,6 +38,7 @@ export async function getNormalizedUserDetails(userId, context) {
|
|
|
38
38
|
const paymentCredentials = await modules.payment.paymentCredentials.findPaymentCredentials({ userId: user._id }, {
|
|
39
39
|
sort: {
|
|
40
40
|
created: -1,
|
|
41
|
+
_id: -1,
|
|
41
42
|
},
|
|
42
43
|
});
|
|
43
44
|
const quotations = await modules.quotations.findQuotations({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { emit } from '@unchainedshop/events';
|
|
2
|
-
import { signAccessToken, createAuthHandler
|
|
2
|
+
import { signAccessToken, createAuthHandler } from "../auth.js";
|
|
3
3
|
import { API_EVENTS } from "../events.js";
|
|
4
4
|
import { createLogger } from '@unchainedshop/logger';
|
|
5
5
|
const logger = createLogger('unchained:api:auth-middleware');
|
|
6
|
-
const { UNCHAINED_COOKIE_NAME = 'unchained_token', UNCHAINED_COOKIE_PATH = '/', UNCHAINED_COOKIE_DOMAIN, UNCHAINED_COOKIE_SAMESITE = 'lax', UNCHAINED_COOKIE_INSECURE,
|
|
6
|
+
const { UNCHAINED_COOKIE_NAME = 'unchained_token', UNCHAINED_COOKIE_PATH = '/', UNCHAINED_COOKIE_DOMAIN, UNCHAINED_COOKIE_SAMESITE = 'lax', UNCHAINED_COOKIE_INSECURE, UNCHAINED_TOKEN_EXPIRY_SECONDS = '3600', } = process.env;
|
|
7
7
|
function getTokenCookieOptions(expires) {
|
|
8
8
|
const secure = !UNCHAINED_COOKIE_INSECURE;
|
|
9
9
|
const sameSite = {
|
|
@@ -30,19 +30,6 @@ function getTokenCookieOptions(expires) {
|
|
|
30
30
|
expires,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
function getFingerprintCookieOptions(expires) {
|
|
34
|
-
const secure = !UNCHAINED_COOKIE_INSECURE;
|
|
35
|
-
const expirySeconds = parseInt(UNCHAINED_TOKEN_EXPIRY_SECONDS, 10);
|
|
36
|
-
return {
|
|
37
|
-
domain: UNCHAINED_COOKIE_DOMAIN,
|
|
38
|
-
path: UNCHAINED_COOKIE_PATH,
|
|
39
|
-
secure,
|
|
40
|
-
httpOnly: true,
|
|
41
|
-
sameSite: 'strict',
|
|
42
|
-
maxAge: expires ? undefined : expirySeconds * 1000,
|
|
43
|
-
expires,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
33
|
function extractBearerToken(authHeader) {
|
|
47
34
|
if (!authHeader)
|
|
48
35
|
return undefined;
|
|
@@ -62,38 +49,15 @@ export async function createAuthContext(params, authConfig) {
|
|
|
62
49
|
const headerToken = extractBearerToken(authHeader);
|
|
63
50
|
const cookieToken = getCookie(UNCHAINED_COOKIE_NAME);
|
|
64
51
|
const token = headerToken || cookieToken;
|
|
65
|
-
const fingerprintCookie = getCookie(UNCHAINED_FINGERPRINT_COOKIE_NAME);
|
|
66
52
|
const verifyToken = createAuthHandler(authConfig);
|
|
67
53
|
const authResult = token ? await verifyToken(token) : {};
|
|
68
|
-
if (authResult.fingerprintHash && fingerprintCookie) {
|
|
69
|
-
const fingerprintValid = verifyFingerprint(fingerprintCookie, authResult.fingerprintHash);
|
|
70
|
-
if (!fingerprintValid) {
|
|
71
|
-
logger.warn('Token sidejacking detected: fingerprint mismatch', {
|
|
72
|
-
userId: authResult.userId,
|
|
73
|
-
});
|
|
74
|
-
authResult.userId = undefined;
|
|
75
|
-
authResult.tokenVersion = undefined;
|
|
76
|
-
authResult.impersonatorId = undefined;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
else if (authResult.fingerprintHash && !fingerprintCookie) {
|
|
80
|
-
logger.warn('Token sidejacking detected: fingerprint cookie missing', {
|
|
81
|
-
userId: authResult.userId,
|
|
82
|
-
});
|
|
83
|
-
authResult.userId = undefined;
|
|
84
|
-
authResult.tokenVersion = undefined;
|
|
85
|
-
authResult.impersonatorId = undefined;
|
|
86
|
-
}
|
|
87
54
|
const login = async (user, options = {}) => {
|
|
88
55
|
const { impersonator } = options;
|
|
89
56
|
const tokenVersion = user.tokenVersion ?? 1;
|
|
90
|
-
const { raw: fingerprintRaw, hash: fingerprintHash } = generateFingerprint();
|
|
91
57
|
const { token: newToken, expires } = await signAccessToken(user._id, tokenVersion, {
|
|
92
58
|
impersonatorId: impersonator?._id,
|
|
93
|
-
fingerprintHash,
|
|
94
59
|
});
|
|
95
60
|
setCookie(UNCHAINED_COOKIE_NAME, newToken, getTokenCookieOptions(expires));
|
|
96
|
-
setCookie(UNCHAINED_FINGERPRINT_COOKIE_NAME, fingerprintRaw, getFingerprintCookieOptions(expires));
|
|
97
61
|
const tokenObject = {
|
|
98
62
|
_id: crypto.randomUUID(),
|
|
99
63
|
userId: user._id,
|
|
@@ -105,7 +69,6 @@ export async function createAuthContext(params, authConfig) {
|
|
|
105
69
|
};
|
|
106
70
|
const logout = async () => {
|
|
107
71
|
clearCookie(UNCHAINED_COOKIE_NAME, getTokenCookieOptions());
|
|
108
|
-
clearCookie(UNCHAINED_FINGERPRINT_COOKIE_NAME, getFingerprintCookieOptions());
|
|
109
72
|
if (authResult.userId) {
|
|
110
73
|
const tokenObject = {
|
|
111
74
|
_id: crypto.randomUUID(),
|
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
|
};
|
|
@@ -22,7 +22,7 @@ export default async function checkoutCart(root, params, context) {
|
|
|
22
22
|
userId,
|
|
23
23
|
orderId: order._id,
|
|
24
24
|
...transactionContext,
|
|
25
|
-
detailCode: error.name || error.code,
|
|
25
|
+
detailCode: error.extensions?.code || error.name || error.code,
|
|
26
26
|
detailMessage: error.message,
|
|
27
27
|
});
|
|
28
28
|
}
|
|
@@ -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
|
}
|
|
@@ -32,7 +32,7 @@ export const AssortmentTypes = {
|
|
|
32
32
|
return modules.assortments.filters.findFilters({
|
|
33
33
|
assortmentId: obj._id,
|
|
34
34
|
}, {
|
|
35
|
-
sort: { sortKey: 1 },
|
|
35
|
+
sort: { sortKey: 1, _id: 1 },
|
|
36
36
|
});
|
|
37
37
|
},
|
|
38
38
|
async linkedAssortments(assortment, _, { loaders }) {
|
|
@@ -53,7 +53,7 @@ export const AssortmentTypes = {
|
|
|
53
53
|
return modules.assortments.products.findAssortmentProducts({
|
|
54
54
|
assortmentId: obj._id,
|
|
55
55
|
}, {
|
|
56
|
-
sort: { sortKey: 1 },
|
|
56
|
+
sort: { sortKey: 1, _id: 1 },
|
|
57
57
|
});
|
|
58
58
|
},
|
|
59
59
|
async texts(obj, { forceLocale }, requestContext) {
|
|
@@ -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<({
|