@unchainedshop/api 4.5.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 (82) hide show
  1. package/README.md +204 -0
  2. package/lib/chat/generateImageHandler.d.ts +7 -1
  3. package/lib/chat/generateImageHandler.js +4 -5
  4. package/lib/express/chatHandler.js +4 -4
  5. package/lib/express/createERCMetadataMiddleware.js +1 -1
  6. package/lib/express/index.js +23 -9
  7. package/lib/fastify/chatHandler.js +4 -4
  8. package/lib/fastify/ercMetadataHandler.js +1 -1
  9. package/lib/mcp/tools/assortment/handlers/addAssortmentFilter.d.ts +0 -1
  10. package/lib/mcp/tools/assortment/handlers/addAssortmentLink.d.ts +0 -1
  11. package/lib/mcp/tools/assortment/handlers/addAssortmentMedia.d.ts +0 -1
  12. package/lib/mcp/tools/assortment/handlers/addAssortmentProduct.d.ts +0 -1
  13. package/lib/mcp/tools/assortment/handlers/createAssortment.d.ts +0 -1
  14. package/lib/mcp/tools/assortment/handlers/getAssortment.d.ts +0 -1
  15. package/lib/mcp/tools/assortment/handlers/getAssortmentChildren.d.ts +0 -2
  16. package/lib/mcp/tools/assortment/handlers/getAssortmentFilters.d.ts +0 -1
  17. package/lib/mcp/tools/assortment/handlers/getAssortmentLinks.d.ts +0 -2
  18. package/lib/mcp/tools/assortment/handlers/getAssortmentMedia.d.ts +0 -1
  19. package/lib/mcp/tools/assortment/handlers/getAssortmentProducts.d.ts +0 -1
  20. package/lib/mcp/tools/assortment/handlers/index.d.ts +0 -2
  21. package/lib/mcp/tools/assortment/handlers/index.js +0 -2
  22. package/lib/mcp/tools/assortment/handlers/listAssortments.d.ts +0 -1
  23. package/lib/mcp/tools/assortment/handlers/reorderAssortmentLinks.d.ts +0 -1
  24. package/lib/mcp/tools/assortment/handlers/searchAssortmentProducts.d.ts +0 -1
  25. package/lib/mcp/tools/assortment/handlers/updateAssortment.d.ts +0 -1
  26. package/lib/mcp/tools/assortment/handlers/updateAssortmentStatus.d.ts +0 -1
  27. package/lib/mcp/tools/assortment/schemas.d.ts +0 -5
  28. package/lib/mcp/tools/assortment/schemas.js +0 -4
  29. package/lib/mcp/tools/order/handlers/confirmOrder.d.ts +1 -1
  30. package/lib/mcp/tools/order/handlers/deliverOrder.d.ts +1 -1
  31. package/lib/mcp/tools/order/handlers/getOrder.d.ts +1 -1
  32. package/lib/mcp/tools/order/handlers/getTopCustomers.d.ts +1 -1
  33. package/lib/mcp/tools/order/handlers/getTopCustomers.js +1 -1
  34. package/lib/mcp/tools/order/handlers/getTopProducts.js +1 -1
  35. package/lib/mcp/tools/order/handlers/getUserCart.d.ts +1 -1
  36. package/lib/mcp/tools/order/handlers/listOrders.d.ts +1 -1
  37. package/lib/mcp/tools/order/handlers/payOrder.d.ts +1 -1
  38. package/lib/mcp/tools/order/handlers/rejectOrder.d.ts +1 -1
  39. package/lib/mcp/tools/quotation/handlers/getQuotation.d.ts +2 -2
  40. package/lib/mcp/tools/quotation/handlers/listQuotations.d.ts +2 -2
  41. package/lib/mcp/tools/quotation/handlers/makeQuotationProposal.d.ts +2 -2
  42. package/lib/mcp/tools/quotation/handlers/rejectQuotation.d.ts +2 -2
  43. package/lib/mcp/tools/quotation/handlers/rejectQuotation.js +1 -1
  44. package/lib/mcp/tools/quotation/handlers/verifyQuotation.d.ts +2 -2
  45. package/lib/mcp/tools/quotation/index.js +1 -1
  46. package/lib/mcp/tools/quotation/schemas.d.ts +5 -5
  47. package/lib/mcp/tools/quotation/schemas.js +3 -3
  48. package/lib/mcp/tools/system/schemas.d.ts +6 -6
  49. package/lib/mcp/tools/system/schemas.js +14 -7
  50. package/lib/mcp/tools/users/handlers/addUserEmail.d.ts +1 -1
  51. package/lib/mcp/tools/users/handlers/createUser.d.ts +1 -1
  52. package/lib/mcp/tools/users/handlers/enrollUser.d.ts +1 -1
  53. package/lib/mcp/tools/users/handlers/getCurrentUser.d.ts +1 -1
  54. package/lib/mcp/tools/users/handlers/getUser.d.ts +1 -1
  55. package/lib/mcp/tools/users/handlers/getUserOrders.d.ts +1 -1
  56. package/lib/mcp/tools/users/handlers/getUserQuotations.d.ts +1 -1
  57. package/lib/mcp/tools/users/handlers/listUsers.d.ts +1 -1
  58. package/lib/mcp/tools/users/handlers/setUserTags.d.ts +1 -1
  59. package/lib/mcp/tools/users/handlers/setUserUsername.d.ts +1 -1
  60. package/lib/mcp/tools/users/handlers/updateUser.d.ts +1 -1
  61. package/lib/mcp/utils/getNormalizedAssortmentDetails.d.ts +0 -1
  62. package/lib/mcp/utils/getNormalizedOrderDetails.d.ts +1 -1
  63. package/lib/mcp/utils/getNormalizedQuotationDetails.d.ts +2 -2
  64. package/lib/mcp/utils/getNormalizedUserDetails.d.ts +1 -1
  65. package/lib/mongo-store.d.ts +9 -5
  66. package/lib/mongo-store.js +31 -25
  67. package/lib/resolvers/mutations/accounts/forgotPassword.js +4 -4
  68. package/lib/resolvers/mutations/index.d.ts +0 -1
  69. package/lib/resolvers/mutations/index.js +0 -2
  70. package/lib/resolvers/mutations/quotations/rejectQuotation.js +1 -1
  71. package/lib/resolvers/mutations/users/removeUser.d.ts +1 -1
  72. package/lib/resolvers/mutations/users/removeUser.js +1 -2
  73. package/lib/resolvers/type/order/order-statistics-types.js +2 -2
  74. package/lib/schema/mutation.js +1 -7
  75. package/lib/schema/types/assortment.js +0 -1
  76. package/lib/schema/types/order/order.js +2 -2
  77. package/lib/schema/types/quotation.js +2 -2
  78. package/package.json +13 -12
  79. package/lib/mcp/tools/assortment/handlers/setAssortmentBase.d.ts +0 -28
  80. package/lib/mcp/tools/assortment/handlers/setAssortmentBase.js +0 -11
  81. package/lib/resolvers/mutations/assortments/setBaseAssortment.d.ts +0 -4
  82. package/lib/resolvers/mutations/assortments/setBaseAssortment.js +0 -11
package/README.md CHANGED
@@ -149,6 +149,210 @@ import { createMCPServer } from '@unchainedshop/api/mcp';
149
149
  const mcpServer = createMCPServer(unchainedCore);
150
150
  ```
151
151
 
152
+ ## Security
153
+
154
+ The API layer implements comprehensive security controls.
155
+
156
+ ### Access Control
157
+
158
+ - **128+ permission actions** covering all API operations
159
+ - **Role-Based Access Control (RBAC)** with built-in and custom roles
160
+ - **ACL enforcement** on all GraphQL mutations
161
+ - **Ownership validation** ensuring users can only access their resources
162
+
163
+ ### Session Security
164
+
165
+ | Variable | Purpose | Default |
166
+ |----------|---------|---------|
167
+ | `UNCHAINED_TOKEN_SECRET` | Session encryption (min 32 chars) | Required |
168
+ | `UNCHAINED_COOKIE_NAME` | Cookie name | `unchained_token` |
169
+ | `UNCHAINED_COOKIE_SAMESITE` | SameSite attribute | `none` |
170
+ | `UNCHAINED_COOKIE_INSECURE` | Disable secure flag | `false` |
171
+
172
+ Cookies are `httpOnly` and `secure` by default.
173
+
174
+ ### Error Handling
175
+
176
+ Errors are designed to prevent information leakage:
177
+ - Generic authentication error messages
178
+ - No distinction between "invalid" vs "expired" tokens
179
+ - Permission errors don't reveal action details
180
+
181
+ ### CORS Configuration
182
+
183
+ CORS behavior depends on `NODE_ENV`:
184
+
185
+ | Environment | Default Behavior |
186
+ |-------------|------------------|
187
+ | `development` | Permissive CORS (reflects any origin) + trust proxy headers |
188
+ | `production` | No CORS headers (reverse proxy should handle it) |
189
+
190
+ #### Environment Variable
191
+
192
+ | Variable | Purpose | Default |
193
+ |----------|---------|---------|
194
+ | `UNCHAINED_CORS_ORIGINS` | Allowed CORS origins | Auto (see above) |
195
+
196
+ #### Programmatic Configuration
197
+
198
+ ```typescript
199
+ // Auto behavior (recommended) - permissive in dev, none in prod
200
+ connect(app, { graphqlHandler, db, unchainedAPI });
201
+
202
+ // Explicit whitelist (production)
203
+ connect(app, { graphqlHandler, db, unchainedAPI }, {
204
+ corsOrigins: "https://shop.example.com,https://admin.example.com",
205
+ });
206
+
207
+ // Force permissive (not recommended in production)
208
+ connect(app, { graphqlHandler, db, unchainedAPI }, {
209
+ corsOrigins: true,
210
+ });
211
+
212
+ // Disable CORS entirely
213
+ connect(app, { graphqlHandler, db, unchainedAPI }, {
214
+ corsOrigins: false,
215
+ });
216
+ ```
217
+
218
+ ### Deployment Scenarios
219
+
220
+ #### Scenario 1: Direct TLS (No Reverse Proxy)
221
+
222
+ For simple deployments where the Node.js server handles TLS directly:
223
+
224
+ ```typescript
225
+ import express from 'express';
226
+ import https from 'https';
227
+ import fs from 'fs';
228
+ import { connect } from '@unchainedshop/api/express';
229
+
230
+ const app = express();
231
+
232
+ // Configure CORS for your frontend origins
233
+ connect(app, { graphqlHandler, db, unchainedAPI }, {
234
+ corsOrigins: "https://shop.example.com,https://admin.example.com",
235
+ });
236
+
237
+ // Create HTTPS server with your certificates
238
+ https.createServer({
239
+ key: fs.readFileSync('/path/to/privkey.pem'),
240
+ cert: fs.readFileSync('/path/to/fullchain.pem'),
241
+ }, app).listen(443);
242
+ ```
243
+
244
+ Environment:
245
+ ```bash
246
+ NODE_ENV=production
247
+ UNCHAINED_CORS_ORIGINS=https://shop.example.com,https://admin.example.com
248
+ UNCHAINED_TOKEN_SECRET=your-32-char-secret-here
249
+ ```
250
+
251
+ #### Scenario 2: Behind Reverse Proxy (Recommended)
252
+
253
+ For production deployments behind nginx, Caddy, or a cloud load balancer:
254
+
255
+ ```typescript
256
+ import express from 'express';
257
+ import { connect } from '@unchainedshop/api/express';
258
+
259
+ const app = express();
260
+
261
+ // Trust the reverse proxy for client IP headers
262
+ app.set('trust proxy', 1);
263
+
264
+ // Let the proxy handle CORS, or configure here
265
+ connect(app, { graphqlHandler, db, unchainedAPI }, {
266
+ corsOrigins: "https://shop.example.com,https://admin.example.com",
267
+ });
268
+
269
+ app.listen(4010); // Internal port, not exposed
270
+ ```
271
+
272
+ **Nginx configuration:**
273
+ ```nginx
274
+ server {
275
+ listen 443 ssl http2;
276
+ server_name api.example.com;
277
+
278
+ ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
279
+ ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
280
+
281
+ location / {
282
+ # Pass client IP to the app
283
+ proxy_set_header X-Real-IP $remote_addr;
284
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
285
+ proxy_set_header X-Forwarded-Proto $scheme;
286
+ proxy_set_header Host $host;
287
+
288
+ proxy_pass http://localhost:4010;
289
+ }
290
+ }
291
+ ```
292
+
293
+ **Caddy configuration:**
294
+ ```caddyfile
295
+ api.example.com {
296
+ reverse_proxy localhost:4010
297
+ }
298
+ ```
299
+
300
+ #### Scenario 3: Proxy Handles CORS
301
+
302
+ For complex multi-origin setups, let the reverse proxy manage CORS:
303
+
304
+ ```typescript
305
+ // Don't set corsOrigins - let proxy handle it
306
+ app.set('trust proxy', 1);
307
+ connect(app, { graphqlHandler, db, unchainedAPI });
308
+ ```
309
+
310
+ **Nginx with CORS:**
311
+ ```nginx
312
+ location / {
313
+ proxy_set_header X-Real-IP $remote_addr;
314
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
315
+ proxy_set_header X-Forwarded-Proto $scheme;
316
+
317
+ # CORS whitelist
318
+ set $cors "";
319
+ if ($http_origin ~* "^https://(shop|admin)\.example\.com$") {
320
+ set $cors $http_origin;
321
+ }
322
+ add_header 'Access-Control-Allow-Origin' $cors always;
323
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
324
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
325
+ add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;
326
+
327
+ if ($request_method = 'OPTIONS') { return 204; }
328
+
329
+ proxy_pass http://localhost:4010;
330
+ }
331
+ ```
332
+
333
+ ### Trust Proxy
334
+
335
+ In development mode (`NODE_ENV=development`), trust proxy is automatically enabled.
336
+
337
+ In production, configure it on your Express/Fastify app before calling `connect()`:
338
+
339
+ ```typescript
340
+ // Express
341
+ app.set('trust proxy', 1); // Trust first hop
342
+ app.set('trust proxy', 'loopback'); // Trust loopback addresses
343
+ app.set('trust proxy', '10.0.0.0/8'); // Trust specific CIDR
344
+
345
+ // Fastify
346
+ const fastify = Fastify({ trustProxy: true });
347
+ ```
348
+
349
+ **SECURITY**: Only enable trust proxy if your reverse proxy:
350
+ 1. Strips incoming `X-Real-IP` and `X-Forwarded-For` headers from clients
351
+ 2. Sets `X-Real-IP` to the actual client IP
352
+ 3. Is the only way to reach your API server
353
+
354
+ See [SECURITY.md](../../SECURITY.md) for complete security documentation including FIPS 140-3 mode.
355
+
152
356
  ## License
153
357
 
154
358
  EUPL-1.2
@@ -2,5 +2,11 @@ import type * as aiTypes from 'ai';
2
2
  declare const generateImageHandler: (req: any) => ({ model, uploadUrl, }: {
3
3
  model: aiTypes.ImageModel;
4
4
  uploadUrl?: string;
5
- }) => aiTypes.Tool<never, any>;
5
+ }) => aiTypes.Tool<{
6
+ prompt: string;
7
+ size?: "512x512" | "768x768" | "1024x1024" | "512x896" | "640x1120" | "768x1344" | "1024x1792" | "896x512" | "1120x640" | "1344x768" | "1792x1024" | undefined;
8
+ }, string | {
9
+ imageUrl: any;
10
+ prompt: string;
11
+ }>;
6
12
  export default generateImageHandler;
@@ -2,12 +2,12 @@ import { z } from 'zod';
2
2
  import mime from 'mime/lite';
3
3
  import { createLogger } from '@unchainedshop/logger';
4
4
  const logger = createLogger('unchained:api:mcp');
5
- let experimental_generateImage;
5
+ let generateImage;
6
6
  let tool;
7
7
  try {
8
8
  const aiTools = await import('ai');
9
9
  tool = aiTools.tool;
10
- experimental_generateImage = aiTools.experimental_generateImage;
10
+ generateImage = aiTools.generateImage;
11
11
  }
12
12
  catch {
13
13
  }
@@ -33,11 +33,10 @@ const inputSchema = z.object({
33
33
  const generateImageHandler = (req) => ({ model, uploadUrl = `${process.env.ROOT_URL}/temp-upload`, }) => {
34
34
  return tool({
35
35
  description: 'Generate an image based on the prompt',
36
- inputSchema: inputSchema,
37
- name: 'generate_image',
36
+ inputSchema,
38
37
  execute: async ({ prompt, size = '1024x1024' }) => {
39
38
  try {
40
- const { image } = await experimental_generateImage({
39
+ const { image } = await generateImage({
41
40
  model,
42
41
  prompt,
43
42
  size: size,
@@ -21,7 +21,7 @@ try {
21
21
  convertToModelMessages = aiTools.convertToModelMessages;
22
22
  stepCountIs = aiTools.stepCountIs;
23
23
  streamText = aiTools.streamText;
24
- createMCPClient = mcpTools.experimental_createMCPClient;
24
+ createMCPClient = mcpTools.createMCPClient;
25
25
  }
26
26
  catch {
27
27
  logger.warn(`optional peer npm packages 'ai', '@ai-sdk/mcp' and '@modelcontextprotocol/sdk' not installed, chat will not work`);
@@ -76,7 +76,7 @@ const setupMCPChatHandler = (chatConfiguration) => {
76
76
  }
77
77
  }
78
78
  catch (e) {
79
- logger.error(`Failed to read resource ${resource.uri}:`, e);
79
+ logger.error(`Failed to read resource ${resource.uri}: ${e.message}`);
80
80
  }
81
81
  return null;
82
82
  }));
@@ -85,7 +85,7 @@ const setupMCPChatHandler = (chatConfiguration) => {
85
85
  }
86
86
  }
87
87
  catch (e) {
88
- logger.error('Failed to fetch MCP resources:', e);
88
+ logger.error(`Failed to fetch MCP resources: ${e.message}`);
89
89
  }
90
90
  const tools = {
91
91
  ...defaultUnchainedTools,
@@ -111,7 +111,7 @@ const setupMCPChatHandler = (chatConfiguration) => {
111
111
  anthropic: { cacheControl: { type: 'ephemeral' } },
112
112
  },
113
113
  };
114
- const normalizedMessages = convertToModelMessages(messages, { tools: cacheControlledTools });
114
+ const normalizedMessages = await convertToModelMessages(messages, { tools: cacheControlledTools });
115
115
  if (normalizedMessages.length > 0) {
116
116
  const lastIndex = normalizedMessages.length - 1;
117
117
  normalizedMessages[lastIndex] = {
@@ -1,6 +1,5 @@
1
1
  import { createLogger } from '@unchainedshop/logger';
2
2
  const logger = createLogger('unchained:erc-metadata');
3
- const { ROOT_URL = 'http://localhost:4010' } = process.env;
4
3
  const methodWrongHandler = (res) => {
5
4
  logger.error('Method not supported, return 404');
6
5
  res.status(404).end();
@@ -11,6 +10,7 @@ const ercMetadataMiddleware = async (req, res) => {
11
10
  if (req.method !== 'GET') {
12
11
  return methodWrongHandler(res);
13
12
  }
13
+ const { ROOT_URL = 'http://localhost:4010' } = process.env;
14
14
  const { services, modules, loaders, locale } = req.unchainedContext;
15
15
  const url = new URL(req.url, ROOT_URL);
16
16
  const pathname = url.pathname;
@@ -64,19 +64,33 @@ const addContext = async function middlewareWithContext(req, res, next) {
64
64
  const { user } = req;
65
65
  if (!user)
66
66
  return false;
67
+ const currentSessionId = req.sessionID;
68
+ const targetSessionId = sessionId || currentSessionId;
67
69
  const tokenObject = {
68
- _id: sessionId || req.sessionID,
70
+ _id: targetSessionId,
69
71
  userId: user._id,
70
72
  };
71
- await new Promise((resolve, reject) => {
72
- req.logout((error, result) => {
73
- if (error) {
74
- return reject(error);
75
- }
76
- req.session.impersonatorId = null;
77
- return resolve(result);
73
+ if (sessionId && sessionId !== currentSessionId) {
74
+ await new Promise((resolve, reject) => {
75
+ req.sessionStore.destroy(sessionId, (error) => {
76
+ if (error) {
77
+ return reject(error);
78
+ }
79
+ return resolve();
80
+ });
78
81
  });
79
- });
82
+ }
83
+ else {
84
+ await new Promise((resolve, reject) => {
85
+ req.logout((error, result) => {
86
+ if (error) {
87
+ return reject(error);
88
+ }
89
+ req.session.impersonatorId = null;
90
+ return resolve(result);
91
+ });
92
+ });
93
+ }
80
94
  await emit(API_EVENTS.API_LOGOUT, tokenObject);
81
95
  return true;
82
96
  };
@@ -20,7 +20,7 @@ try {
20
20
  convertToModelMessages = aiTools.convertToModelMessages;
21
21
  stepCountIs = aiTools.stepCountIs;
22
22
  streamText = aiTools.streamText;
23
- createMCPClient = mcpTools.experimental_createMCPClient;
23
+ createMCPClient = mcpTools.createMCPClient;
24
24
  }
25
25
  catch {
26
26
  logger.warn(`optional peer npm packages 'ai' and '@ai-sdk/mcp' not installed, chat will not work`);
@@ -73,7 +73,7 @@ const setupMCPChatHandler = (chatConfiguration) => {
73
73
  }
74
74
  }
75
75
  catch (e) {
76
- logger.error(`Failed to read resource ${resource.uri}:`, e);
76
+ logger.error(`Failed to read resource ${resource.uri}: ${e.message}`);
77
77
  }
78
78
  return null;
79
79
  }));
@@ -82,7 +82,7 @@ const setupMCPChatHandler = (chatConfiguration) => {
82
82
  }
83
83
  }
84
84
  catch (e) {
85
- logger.error('Failed to fetch MCP resources:', e);
85
+ logger.error(`Failed to fetch MCP resources: ${e.message}`);
86
86
  }
87
87
  const tools = {
88
88
  ...defaultUnchainedTools,
@@ -107,7 +107,7 @@ const setupMCPChatHandler = (chatConfiguration) => {
107
107
  anthropic: { cacheControl: { type: 'ephemeral' } },
108
108
  },
109
109
  };
110
- const normalizedMessages = convertToModelMessages(messages, { tools: cacheControlledTools });
110
+ const normalizedMessages = await convertToModelMessages(messages, { tools: cacheControlledTools });
111
111
  if (normalizedMessages.length > 0) {
112
112
  const lastIndex = normalizedMessages.length - 1;
113
113
  normalizedMessages[lastIndex] = {
@@ -1,7 +1,6 @@
1
1
  import { createLogger } from '@unchainedshop/logger';
2
2
  import { ProductContractStandard } from '@unchainedshop/core-products';
3
3
  const logger = createLogger('unchained:api:erc-metadata');
4
- const { ROOT_URL = 'http://localhost:4010' } = process.env;
5
4
  const notFoundHandler = (res) => {
6
5
  logger.error('Method not supported, return 404');
7
6
  res.status(404);
@@ -9,6 +8,7 @@ const notFoundHandler = (res) => {
9
8
  };
10
9
  const ercMetadataHandler = async (req, res) => {
11
10
  try {
11
+ const { ROOT_URL = 'http://localhost:4010' } = process.env;
12
12
  const { services, modules, locale, loaders } = req.unchainedContext;
13
13
  const url = new URL(req.url, ROOT_URL);
14
14
  if (!url.pathname.toLowerCase().endsWith('.json'))
@@ -14,7 +14,6 @@ export default function addAssortmentFilter(context: Context, params: Params<'AD
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function addAssortmentLink(context: Context, params: Params<'ADD_
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function addAssortmentMedia(context: Context, params: Params<'ADD
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function addAssortmentProduct(context: Context, params: Params<'A
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -15,7 +15,6 @@ export default function createAssortment(context: Context, params: Params<'CREAT
15
15
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
16
16
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
17
17
  isActive: boolean;
18
- isBase: boolean;
19
18
  isRoot: boolean;
20
19
  meta?: any;
21
20
  sequence: number;
@@ -14,7 +14,6 @@ export default function getAssortment(context: Context, params: Params<'GET'>):
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function getAssortmentChildren(context: Context, params: Params<'
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -28,7 +27,6 @@ export default function getAssortmentChildren(context: Context, params: Params<'
28
27
  children: {
29
28
  _id: string;
30
29
  isActive: boolean;
31
- isBase: boolean;
32
30
  isRoot: boolean;
33
31
  meta?: any;
34
32
  sequence: number;
@@ -14,7 +14,6 @@ export default function getAssortmentFilters(context: Context, params: Params<'G
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function getAssortmentLinks(context: Context, params: Params<'GET
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -47,7 +46,6 @@ export default function getAssortmentLinks(context: Context, params: Params<'GET
47
46
  links?: import("@unchainedshop/core-assortments").AssortmentLink[] | undefined;
48
47
  products?: import("@unchainedshop/core-assortments").AssortmentProduct[] | undefined;
49
48
  isActive?: boolean | undefined;
50
- isBase?: boolean | undefined;
51
49
  isRoot?: boolean | undefined;
52
50
  sequence?: number | undefined;
53
51
  slugs?: string[];
@@ -14,7 +14,6 @@ export default function getAssortmentMedia(context: Context, params: Params<'GET
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function getAssortmentProducts(context: Context, params: Params<'
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -23,7 +23,6 @@ import removeAssortmentLink from './removeAssortmentLink.ts';
23
23
  import getAssortmentLinks from './getAssortmentLinks.ts';
24
24
  import reorderAssortmentLinks from './reorderAssortmentLinks.ts';
25
25
  import getAssortmentChildren from './getAssortmentChildren.ts';
26
- import setAssortmentBase from './setAssortmentBase.ts';
27
26
  import searchAssortmentProducts from './searchAssortmentProducts.ts';
28
27
  import getAssortmentTexts from './getAssortmentTexts.ts';
29
28
  import getAssortmentMediaTexts from './getAssortmentMediaTexts.ts';
@@ -53,7 +52,6 @@ declare const _default: {
53
52
  GET_LINKS: typeof getAssortmentLinks;
54
53
  REORDER_LINKS: typeof reorderAssortmentLinks;
55
54
  GET_CHILDREN: typeof getAssortmentChildren;
56
- SET_BASE: typeof setAssortmentBase;
57
55
  SEARCH_PRODUCTS: typeof searchAssortmentProducts;
58
56
  GET_TEXTS: typeof getAssortmentTexts;
59
57
  GET_MEDIA_TEXTS: typeof getAssortmentMediaTexts;
@@ -23,7 +23,6 @@ import removeAssortmentLink from "./removeAssortmentLink.js";
23
23
  import getAssortmentLinks from "./getAssortmentLinks.js";
24
24
  import reorderAssortmentLinks from "./reorderAssortmentLinks.js";
25
25
  import getAssortmentChildren from "./getAssortmentChildren.js";
26
- import setAssortmentBase from "./setAssortmentBase.js";
27
26
  import searchAssortmentProducts from "./searchAssortmentProducts.js";
28
27
  import getAssortmentTexts from "./getAssortmentTexts.js";
29
28
  import getAssortmentMediaTexts from "./getAssortmentMediaTexts.js";
@@ -53,7 +52,6 @@ export default {
53
52
  GET_LINKS: getAssortmentLinks,
54
53
  REORDER_LINKS: reorderAssortmentLinks,
55
54
  GET_CHILDREN: getAssortmentChildren,
56
- SET_BASE: setAssortmentBase,
57
55
  SEARCH_PRODUCTS: searchAssortmentProducts,
58
56
  GET_TEXTS: getAssortmentTexts,
59
57
  GET_MEDIA_TEXTS: getAssortmentMediaTexts,
@@ -14,7 +14,6 @@ export default function listAssortments(context: Context, params: Params<'LIST'>
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -23,7 +23,6 @@ export default function reorderAssortmentLinks(context: Context, params: Params<
23
23
  links?: import("@unchainedshop/core-assortments").AssortmentLink[] | undefined;
24
24
  products?: import("@unchainedshop/core-assortments").AssortmentProduct[] | undefined;
25
25
  isActive?: boolean | undefined;
26
- isBase?: boolean | undefined;
27
26
  isRoot?: boolean | undefined;
28
27
  sequence?: number | undefined;
29
28
  slugs?: string[];
@@ -14,7 +14,6 @@ export default function searchAssortmentProducts(context: Context, params: Param
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function updateAssortment(context: Context, params: Params<'UPDAT
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -14,7 +14,6 @@ export default function updateAssortmentStatus(context: Context, params: Params<
14
14
  links: import("@unchainedshop/core-assortments").AssortmentLink[];
15
15
  products: import("@unchainedshop/core-assortments").AssortmentProduct[];
16
16
  isActive: boolean;
17
- isBase: boolean;
18
17
  isRoot: boolean;
19
18
  meta?: any;
20
19
  sequence: number;
@@ -165,9 +165,6 @@ export declare const actionValidators: {
165
165
  assortmentId: z.ZodString;
166
166
  includeInactive: z.ZodOptional<z.ZodBoolean>;
167
167
  }, z.core.$strip>;
168
- readonly SET_BASE: z.ZodObject<{
169
- assortmentId: z.ZodString;
170
- }, z.core.$strip>;
171
168
  readonly SEARCH_PRODUCTS: z.ZodObject<{
172
169
  queryString: z.ZodOptional<z.ZodString>;
173
170
  includeInactive: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -223,7 +220,6 @@ export declare const AssortmentManagementSchema: {
223
220
  GET_LINKS: "GET_LINKS";
224
221
  REORDER_LINKS: "REORDER_LINKS";
225
222
  GET_CHILDREN: "GET_CHILDREN";
226
- SET_BASE: "SET_BASE";
227
223
  SEARCH_PRODUCTS: "SEARCH_PRODUCTS";
228
224
  }>;
229
225
  assortmentId: z.ZodOptional<z.ZodString>;
@@ -316,7 +312,6 @@ export declare const AssortmentManagementZodSchema: z.ZodObject<{
316
312
  GET_LINKS: "GET_LINKS";
317
313
  REORDER_LINKS: "REORDER_LINKS";
318
314
  GET_CHILDREN: "GET_CHILDREN";
319
- SET_BASE: "SET_BASE";
320
315
  SEARCH_PRODUCTS: "SEARCH_PRODUCTS";
321
316
  }>;
322
317
  assortmentId: z.ZodOptional<z.ZodString>;
@@ -154,9 +154,6 @@ export const actionValidators = {
154
154
  assortmentId: z.string().min(1).describe('Assortment ID (optional for root-level)'),
155
155
  includeInactive: z.boolean().optional().describe('Include inactive children'),
156
156
  }),
157
- SET_BASE: z.object({
158
- assortmentId: z.string().min(1).describe('Assortment ID to set as base'),
159
- }),
160
157
  SEARCH_PRODUCTS: z.object({
161
158
  assortmentId: z.string().min(1).describe('Assortment ID'),
162
159
  ...PaginationSchema,
@@ -197,7 +194,6 @@ export const AssortmentManagementSchema = {
197
194
  'GET_LINKS',
198
195
  'REORDER_LINKS',
199
196
  'GET_CHILDREN',
200
- 'SET_BASE',
201
197
  'SEARCH_PRODUCTS',
202
198
  'GET_TEXTS',
203
199
  'GET_MEDIA_TEXTS',
@@ -76,7 +76,7 @@ export default function confirmOrder(context: Context, params: Params<'CONFIRM_O
76
76
  countryCode: string;
77
77
  currencyCode: string;
78
78
  deliveryId?: string;
79
- fullfilled?: Date;
79
+ fulfilled?: Date;
80
80
  ordered?: Date;
81
81
  orderNumber?: string;
82
82
  originEnrollmentId?: string;